Android Architecture Templates架构解析:对标大厂的高效模块化架构模块实现
从零搭建一套可对标大厂的 Android 基础框架,我踩过的坑和最终的解决方案
“如果这个项目对你有帮助,请在 GitHub 上给我一个 ⭐ Star —— 你的支持是我持续维护的最大动力!”
一、我为什么要“重复造轮子”?
去年年底,我接手了一个“历史悠久”的 Android 项目:冷启动 3.2 秒,APK 体积 47MB,代码里充斥着GlobalScope.launch、Log.d硬编码、以及让人头皮发麻的“万能工具类”。每次加一个新功能,我都感觉在雷区里跳舞。
更重要的是,这个项目使用了ARouter 的 kapt 方案,每次编译都在 3 分钟以上。团队里 6 个人每天都在抱怨“build 太慢了”,但没有人敢动——因为“能跑就行”。
所以我决定做一件事:从零搭建一套全新的 Android 基础架构,目标是“开箱即用、性能极致、代码优雅”。
最终的结果是:
| 指标 | 结果 |
|---|---|
| 冷启动耗时 | 380ms |
| Release APK 体积 | 9.59MB |
| 编译速度(KSP 替代 kapt) | 提升60% |
| 模块数量 | 14 个(核心层/服务层/中间件/业务层) |
| 代码行数 | ~5000+ 行(纯框架) |
这篇文章,我会把其中的关键技术点、踩过的坑、以及最终的解决方案完整分享出来。
框架适用性:这套框架经过精心设计和实战验证,可直接应用于日活千万级别的 App 生产环境。
快速上手:具体使用方式请查阅 GitHub 仓库中的 README 文档。框架已封装了所有底层复杂性,开发者无需关注基础设施细节,可以完全专注于业务逻辑的开发。
持续维护:我会持续维护并升级此框架,未来计划增加对高频业务组件的二次封装,进一步提升开发效率。
开发规范:业务开发应遵循模块化原则。请在项目中创建独立的
feature模块,并在其下按功能划分子模块。开发时只需引入所需的基础框架模块即可。请务必注意:所有业务代码都应置于feature模块中,严禁在壳工程(app module)内直接添加代码。
。
二、项目整体架构:MVVM + 模块化分层
先说一下整体架构设计。我采用了四层分层结构,严格遵循“上层依赖下层”的原则:
┌─────────────────────────────────────────────────────────────┐ │ features (业务功能层) │ │ 登录/首页/个人中心等业务模块,可独立编译运行 │ ├─────────────────────────────────────────────────────────────┤ │ middleware (中间件层) │ │ 路由 (ARouter + KSP) + 权限申请 (Permission) │ ├─────────────────────────────────────────────────────────────┤ │ service (基础服务层) │ │ 启动调度 (DAG) + 崩溃捕获 (CrashHandler) + 日志/埋点 │ ├─────────────────────────────────────────────────────────────┤ │ core (核心基建层) │ │ base/network/storage/cache/common/ui - 纯基础设施 │ └─────────────────────────────────────────────────────────────┘依赖方向铁律(不可逆):
features→middleware→service→corecore:common绝对不能依赖core:storage(纯工具层禁飞区)
三、第一大亮点:KSP 路由 + ViewBinding 兼容性突破(真正的行业痛点)
3.1 背景:ARouter 的 kapt 方案太慢了
在传统方案中,ARouter 使用kapt生成路由表。随着模块数量增加,kapt的编译时间呈指数级增长。在我之前的项目中,仅路由表的生成就占用了 1.5 分钟的编译时间。
解决方案:将kapt替换为KSP(Kotlin Symbol Processing)。
// build.gradle.ktsplugins{id("com.google.devtools.ksp")}ksp{arg("router.moduleName",project.name)}dependencies{implementation(project(":middleware:router-annotations"))ksp(project(":middleware:router-compiler"))}切换后,编译时间从 3 分钟降到了 1.2 分钟,提升约 60%。
3.2 翻车现场:KSP 找不到我的 @Route 注解
编译速度确实快了,但我遇到了一个更隐蔽的问题:KSP 的getSymbolsWithAnnotation找不到某些类的@Route注解。
具体现象是:
- 普通类(如
SimpleClass)的@Route能被正常扫描到。 - 继承
BaseActivity的类(如LoginActivity)的@Route却被静默跳过。
经过 3 天的排查,我终于定位到了根因:
classLoginActivity:BaseActivity<ActivityLoginBinding,LoginUiState,LoginEvent,LoginViewModel>()BaseActivity的泛型参数中包含了ActivityLoginBinding,这是一个由 Android Gradle Plugin 在编译期生成的类。而 KSP 的运行时机早于 AGP 的 ViewBinding 生成,导致 KSP 在解析LoginActivity时遇到了一个尚未存在的类型,于是静默跳过,不再返回该类的任何注解。
这个问题的本质:getSymbolsWithAnnotation在解析类时,如果遇到无法解析的类型引用(哪怕是泛型参数),就会直接丢弃整个类。
3.3 我的解决方案:双重扫描机制
既然getSymbolsWithAnnotation有局限性,那就绕过它。我实现了一个双重扫描机制:
privatefunfindSymbolsWithAnnotation(resolver:Resolver,annotationFqn:String):Sequence<KSAnnotated>{// 1. 先用标准 API 获取能正常解析的符号valstandardSymbols=resolver.getSymbolsWithAnnotation(annotationFqn).toList()// 2. 收集已找到的类的全限定名,用于去重valfoundQualifiedNames=standardSymbols.mapNotNull{sym->(symas?KSClassDeclaration)?.qualifiedName?.asString()}.toSet()// 3. 手动递归遍历所有文件,查找被遗漏的注解valfileSymbols=mutableListOf<KSAnnotated>()resolver.getAllFiles().forEach{file->findClassDeclarationsWithAnnotation(file.declarations,annotationFqn.substringAfterLast('.'),annotationFqn,foundQualifiedNames,fileSymbols)}// 4. 合并结果并去重return(standardSymbols+fileSymbols).asSequence().distinct()}核心思路:
- 先用标准 API 获取能正常解析的类。
- 再通过
resolver.getAllFiles()递归遍历所有 AST 节点,手动检查每个声明是否包含目标注解。 - 合并两份结果,确保不漏掉任何一个被 ViewBinding“屏蔽”的类。
这个方案的价值:它不仅可以解决 ARouter + ViewBinding 的兼容问题,还可以推广到任何 KSP + 生成类型(如 Dagger/Hilt + ViewBinding)的场景。
四、第二大亮点:DAG 启动任务调度器(冷启动 380ms 的秘诀)
4.1 传统初始化方式的痛点
在传统的 Android 项目中,Application.onCreate()里往往堆满了各种 SDK 的初始化:
classApp:Application(){overridefunonCreate(){MMKV.initialize(this)Logger.init(this)CrashHandler.init(this)NetworkClient.init(this)RouterHelper.init(this)PushSDK.init(this)AdSDK.init(this)// ... 更多初始化}}这种方式的问题是:所有初始化都是串行的,且都在主线程上执行。在我之前的项目中,仅Application.onCreate()就耗时 800ms。
4.2 DAG 调度器的设计
我设计了一个基于有向无环图(DAG)的启动任务调度器,核心思想是:
- 将每个初始化任务抽象为
StartupTask。 - 任务可以声明依赖关系(如
ConfigPreloadTask依赖DatabaseWarmUpTask)。 - 调度器解析所有任务,构建 DAG,无依赖的任务并行执行。
abstractclassStartupTask{abstractvalname:Stringabstractfunexecute(context:Context)openfundependencies():List<Class<outStartupTask>>=emptyList()openfunrunOnMainThread():Boolean=false// 默认在 IO 线程执行}// 使用示例classDatabaseWarmUpTask:StartupTask(){overridevalname="database_warmup"overridefunexecute(context:Context){// 预热数据库连接池}}classConfigPreloadTask:StartupTask(){overridevalname="config_preload"overridefundependencies()=listOf(DatabaseWarmUpTask::class.java)overridefunexecute(context:Context){// 预加载远程配置}}调度器内部使用拓扑排序确定执行顺序,并利用Dispatchers.IO线程池并行执行无依赖的任务。
4.3 实测效果
| 方案 | Application 创建耗时 |
|---|---|
| 传统串行初始化 | ~800ms |
| DAG 并行调度 | ~230ms |
| 性能提升 | 70% |
完整的启动耗时报告如下:
╔══════════════════════════════════════╗ ║ 启动全链路耗时报告 ║ ╠══════════════════════════════════════╣ ║ 进程创建 115ms ║ Application 创建 231ms ║ 启动任务执行 2ms ║ Activity 创建 0ms ║ 首帧渲染 32ms ╠══════════════════════════════════════╣ ║ 总耗时: 380ms ╚══════════════════════════════════════╝380ms 的冷启动时间,在 Android 应用中属于顶级水平。
五、第三大亮点:网络层的安全防护体系
网络层是 APP 的命脉,我构建了一套四层防护体系:
5.1 拦截器链架构
Request → SecurityInterceptor → CacheInterceptor → MonitorInterceptor → RetryInterceptor → Server| 拦截器 | 职责 |
|---|---|
| SecurityInterceptor | 自动附加X-Device-Id、X-Timestamp、X-Sign(SHA256 + Salt),防重放攻击 |
| CacheInterceptor | 支持NETWORK_FIRST/CACHE_FIRST/CACHE_ONLY三种策略 |
| MonitorInterceptor | 记录请求耗时和状态码,自动上报 APM |
| RetryInterceptor | 指数退避重试(间隔 1s/2s/4s,最多 3 次) |
5.2 签名防篡改的实现
classSecurityInterceptor:Interceptor{overridefunintercept(chain:Interceptor.Chain):Response{valrequest=chain.request()valdeviceId=getDeviceId()valtimestamp=System.currentTimeMillis()valsign=sha256("$deviceId$timestamp$SALT")valnewRequest=request.newBuilder().header("X-Device-Id",deviceId).header("X-Timestamp",timestamp.toString()).header("X-Sign",sign).build()returnchain.proceed(newRequest)}}后端只需校验签名是否匹配、时间戳是否在 5 分钟窗口内,即可有效防止重放攻击和中间人篡改。
5.3 SSL Pinning(证书固定)
valcertificatePinner=CertificatePinner.Builder().add("api.example.com","sha256/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=").build()即使 CA 机构被攻破或用户安装了恶意根证书,攻击者也无法劫持通信数据。
六、第四大亮点:APK 从 19.55MB 到 9.59MB 的瘦身之路
6.1 ABI 过滤(减少 40-60%)
默认情况下,Android Gradle 插件会打包armeabi-v7a、arm64-v8a、x86、x86_64四份 Native 库。而目前 99.9% 的手机只使用arm64-v8a。
android{defaultConfig{ndk{abiFilters.add("arm64-v8a")}}}效果:单这一项就砍掉了约 6MB。
6.2 资源压缩 + WebP 转换
开启资源压缩:
android{buildTypes{release{isMinifyEnabled=trueisShrinkResources=true}}}图片转 WebP:在 Android Studio 中右键点击res文件夹,选择Convert to WebP,质量设为 75%。
6.3 语言资源过滤
国内 APP 通常只需要中文和英文:
android{defaultConfig{resConfigs("zh-rCN","en")}}6.4 最终效果
| 优化项 | 优化前 | 优化后 | 减少 |
|---|---|---|---|
| Native 库 | ~8MB | ~3MB | -62% |
| 资源文件 | ~4MB | ~2MB | -50% |
| 字节码 | ~6MB | ~5.5MB | -8% |
| 合计 | 19.55MB | 9.59MB | -51% |
七、踩坑实录:那些让我熬夜的问题
7.1 闪屏页 Logo 突然“变大”的问题
现象:闪屏页的 Logo 在启动一瞬间会“变大”然后恢复。
根因:windowBackground使用了自适应图标(@mipmap/ic_launcher),系统在渲染时无法像普通 PNG 一样缩放,强制使用了默认尺寸。
解决方案:迁移到androidx.core:core-splashscreen官方库。
<stylename="Theme.Splash"parent="Theme.SplashScreen"><item name="windowSplashScreenBackground">@color/splash_background</item> <item name="windowSplashScreenAnimatedIcon">@mipmap/ic_launcher</item> <item name="windowSplashScreenAnimationDuration">300</item> <item name="postSplashScreenTheme">@style/Theme.App</item></style>classSplashActivity:AppCompatActivity(){overridefunonCreate(savedInstanceState:Bundle?){installSplashScreen()// 必须在 super.onCreate() 之前super.onCreate(savedInstanceState)// ...}}7.2 跳转主页时“闪一下白色”
现象:从登录页跳转到主页时,屏幕会闪一下亮白色。
根因:主页的windowBackground未设置,系统使用默认白色作为窗口背景,而主页布局的根背景是深色。
解决方案:为主题添加windowBackground:
<stylename="Theme.Main"parent="Theme.App"><item name="android:windowBackground">?attr/colorSurface</item></style>八、项目开源地址
这套框架已经完整开源,包含:
- 14 个模块的完整源码
- 380ms 冷启动的优化方案
- KSP + ViewBinding 兼容性解决方案
- DAG 启动调度器
- 安全网络拦截器链
- APK 瘦身完整配置
GitHub 地址:https://github.com/kyrach-m/Sample
如果你也在 Android 基础架构的路上探索,欢迎 Star、Fork、提 Issue。开源的目的,就是让更多开发者少踩一些坑。
九、总结
回想整个过程,最大的收获不是 380ms 的启动速度或 9MB 的 APK 体积,而是“系统性思考”的能力。这套框架的每一个设计决策,都源于对真实生产痛点的深度剖析与优雅解决:
- 🚀 性能与可维护性并重:DAG 启动调度器在实现 380ms 冷启动的同时,保持了启动链路的可观测与可扩展,证明了性能优化无需牺牲代码结构。
- ⚡ 编译期优于运行时:用 KSP 彻底替换 kapt,不仅带来 60% 的编译提速,更从根源上提升了开发体验与工程健壮性。
- 🛡️ 安全是网络的基石:从签名防篡改到 SSL Pinning,构建了多层次的安全防护体系,为业务数据保驾护航。
- 📦 极致优化是持续过程:APK 体积从 19.55MB 缩减至 9.59MB,印证了通过系统性的 ABI 过滤、资源压缩与配置优化,瘦身空间远超想象。
架构的价值在于为业务提供长期稳定的支撑。如果你的应用也面临启动慢、体积大、编译久、安全弱的挑战,不妨参考或直接采用这套经过千万级 DAU 验证的解决方案。
🌟 立即行动,让项目起飞!
如果这篇文章为你带来了启发,或者你正在寻找一个开箱即用、高性能的 Android 基础框架,请务必前往 GitHub 为项目点一个 ⭐ Star—— 这不仅是对我的最大鼓励,更是推动项目持续迭代、分享更多实战经验的直接动力!开源地址:https://github.com/kyrach-m/Sample(框架完整源码、配置与示例均已开源)
期待在评论区看到你的想法与实践,共同打造更优雅的 Android 开发体验!
*作者:kyrach
*GitHub:https://github.com/kyrach-m
欢迎关注我的技术专栏,更多 Android 架构实战分享。
