从 AOSP 剥离 Settings 模块成为(Android Studio)独立工程

0 阅读5分钟

最近履新任职到新公司,刚到 +1 给我安排了一个他口中 “地狱难度” 任务,从 AOSP 把 Settings 模块剥离到 Android Studio 能独立运行独立打包 APK。

接到这个任务我确实是蒙的,刚来环境还没熟悉给我安排一个这么高难度的任务,但是转念一想如果要在舒适区也不会来现在这个公司了,我就当是我入职试用期的考核,不成功便成仁,硬头皮接下来了。

之前做系统应用开发一般都是拾人牙慧,都是别的团队摘好了解耦完毕的,属于是前人栽树后人乘凉,今天我也要做一把这个前人了。

先来看阶段性的效果吧

image.png

通过上图我们已经能看到 从 AOSP 剥离的 settings 模块已经解耦能跑起来独立 apk,页面也拉起来了。

  • 拆解的意义

解耦的事情比较难做,但是我们还在做,那做了好处和回报在哪儿呢?

对比维度原生 AOSP 内置 Settings解耦独立版 Settings APK拆解 / 解耦的核心价值
编译与开发效率必须完整 AOSP 环境、全源码编译;修改后常需重刷系统可在普通 Android Studio 工程独立开发 / 编译;秒编译、秒安装调试开发效率提升 10~50 倍,脱离巨型源码树
版本升级与迭代只能随系统 OTA 升级;不能单独热更 / 覆盖可像普通 App 一样单独升级、覆盖安装、灰度发布迭代速度极快,Bug / 功能不依赖系统版本
跨 Android 版本兼容强绑定对应 API Level,跨版本基本不可用一套代码可适配多 Android 版本(10~14),接口做兼容层一次开发多版本复用,大幅减少维护成本
定制与扩展能力深度耦合系统隐藏 API、internal 类、Framework 私有接口解耦后通过标准 SDK API + 桩库 / 兼容层实现系统能力定制更安全、更可控,不污染系统源码
交付与部署方式只能内置到 system.img;无法单独分发可作为独立 APK 预装 / 下载安装;支持多设备 / 多项目复用灵活交付:厂商预装、企业 MDM、第三方设备都可用
代码解耦与稳定性与 SystemUI、Framework、其他系统 App 强耦合边界清晰、依赖明确;问题只在本模块内,不扩散稳定性更高、问题易定位,改一处不牵一发而动全身
权限与安全必须 platform 签名、系统权限;易被系统升级覆盖可自定义包名(如 com.oem.settings)、独立签名;不被系统覆盖安全可控、防覆盖,适合企业 / 定制场景
适用场景仅原生 AOSP / 官方 ROM 使用OEM 定制、车机 / 电视 / 平板、行业设备、企业 MDM、第三方 ROM场景全覆盖,从手机到 IoT 都能用
系统裁剪与瘦身必须保留在 /system 分区,占用空间可移至 /product、/vendor 或不预制,按需安装支持系统轻量化裁剪,释放空间
  • 拆解的难度
难度等级难点为什么难后果
⭐⭐⭐⭐⭐大量依赖 @hide 隐藏 API /framework 内部接口官方 SDK 没有,反射不稳定,版本碎片化严重代码跑不起来、功能残缺、高版本闪退
⭐⭐⭐⭐⭐强依赖 系统签名 & 系统权限普通 APK 拿不到 android.permission.WRITE_SECURE_SETTINGS大部分设置项点击无效、闪退
⭐⭐⭐⭐依赖系统私有类:com.android.internal.*非公开 API,各厂商 ROM 都不一样编译不过、运行异常
⭐⭐⭐⭐与 SystemUI、SystemServer、SettingsProvider 深度耦合广播、服务、ContentObserver 互相绑定亮度、音量、网络、账户功能异常
⭐⭐⭐依赖 AOSP 编译系统(Soong / Android.bp/ Ninja)无法直接在 AS 编译,依赖路径复杂无法打成独立 APK
⭐⭐⭐ ⭐⭐资源冲突、包名冲突、R 类冲突系统资源 com.android:id/ 无法访问布局错乱、崩溃
⭐⭐多设备适配(手机 / 平板 / 车机)不同设备资源、条件编译不同界面错乱、功能缺失
⭐⭐依赖系统内置服务(网络、蓝牙、NFC、账户)普通三方 App 无权限调用对应设置项不可用
  • 环境

LineageOS(源码)

breakfast akita (设备)

  • 拆解的知识储备

    需要较强的

    • Settings
    • Gradle
    • .kts
    • kotlin
    • protocl buffer
    • .bp
    • 依赖注入(annotationProcessor)
    • aconfig
    • aidl

    等知识储备,以及海量的文件 module 的依赖解耦关系处理。

  • 拆解思路

    • 总体原则

      1 先解决 gradle 等依赖和静态检查问题

      2 再解 run 工程不过报错的问题

      3 最后解决运行时 crash 问题

    • 具体实施

    1. Settings 独立建仓 ,创建一个空工程,确认 gradle 版本 , 构建 toml 编写通用依赖 androidx kotlin 等

    2. 创建 app 主 module , 移植 /android/lineage/packages/apps/Settings 的 src res libs protos 到其中

    3. 解构 settingsLib ,settingsLib 在 /android/lineage/frameworks/base/packages/SettingsLib 目录,该包包含 58 个子 module 需要处理 58 个 module 的依赖关系 ,子module中还存在子嵌套,初步先完成 58 个子 module .bp to .gradle 构建,找不到的依赖先注释

    4. /lineage/external/setupcompat(开机向导)

    5. /lineage/external/setupdesign(开机向导)

    6. Iconloaderlib (launcher3)

    7. Wmshellshared (wmshell)

    8. Wifitrackerlib (WIFI)

    9. 需要完成 Android resource linking failed 的修复,存在大量的 resource 资源缺失分为三类:

      A androidPrv 类

      B @android: 报错 is private

      C Not found 资源类

      style color strings dimen drawable attr 共计约上千处私有报错完成对其平替或者注释不影响编译

    10. 大量私有 style 平替成 material style

其他:

apk 在 系统中的位置

/android/lineage/out/target/product/akita/system_ext/priv-app/Settings

framework.jar 在系统整编后的位置

out/target/common/obj/JAVA_LIBRARIES/framework_intermediates

out/target/common/obj/JAVA_LIBRARIES/framework-minus-apex_intermediates

签名用 AOSP debug 签名

处理完上述 10 个问题 apk 基本能正常 build 其中资源问题花了我两天时间,解耦的难点也在考验毅力和耐心,因为你在不停的解决报错,这个解决后下面还有无穷无尽的报错等你处理,比较考验心态的是这个无底洞不不知道什么时候才算解决完毕,可能解决下一个就完成了,也可能后续还有999+报错等着你,但是自己有耐心毅力再加上现在有AI的辅助,一定是可以成功。