MiCarSettings 新人上手总览与学习路线
本篇是整个培训文档集的地图。先读这一篇,建立全局认知,再按学习路线进入各专题文档。 所有文档都在
docs/目录下,建议配合源码一起看。
一、这个项目是什么
MiCarSettings 是小米智能座舱(车机)上的「车辆设置」应用,对应手机上的「设置」App。 用户在车机上调整:充电、显示、灯光、锁车、驾驶模式、媒体、音量、IoT、连接、安全服务、自动驾驶、系统、小爱…… 全部由这个工程提供界面与逻辑。
- 血缘:基于 AOSP(Android 开源项目)的
packages/apps/Car/Settings演进而来。所以你会看到大量 AOSP 的代码风格、com.android.car.settings包名、以及 AOSP 特有的 PreferenceController 范式——这是理解整个工程的钥匙(见 02 篇)。 - 身份:它是 platform 签名的系统特权应用,因此能直接调用
android.car.*车辆 API、读写车辆属性、与车控/车况服务通信。 - 形态:一套代码,三套产物——
dcd(国内平台)、xcd(国内另一平台)、global(海外)。
二、架构总览(一张图看全貌)
flowchart TB subgraph External["外部入口"] V[语音助手] L[桌面快捷方式/其他 App] U[车机首页点击] end subgraph App["app/ · 应用入口层"] DA[DeeplinkActivity] BA[BaseCarSettingsActivity] SA[SubSettingsActivity] end subgraph Common["settingsCommon/ · 横切框架"] R[路由框架 Router] VS[语音搜索映射] RTI[RTI 库] QT[qualitytools 质量工具] end subgraph Pages["settingsPage/ · 16 个功能模块"] P1[灯光/充电/锁车...] P2[每个页面 = Fragment + N 个 Controller] end subgraph Base["base/ · 基础库"] UI[settingsBaseUi<br/>PreferenceController 基类] LIB[settingsBaseLib 工具] VEH[settingsVehicleLib<br/>车辆接口抽象] OTH[其它工具库] end subgraph Vehicle["车辆 / 平台"] CAR[android.car.Car / CarPropertyManager] AIDL[AIDL 服务] DCD[DCD 平台 framework.jar] XCD[XCD 平台 framework.jar] end V --> VS L --> DA U --> BA VS --> R DA --> R R -->|按 URI 查路由表| SA SA -->|加载| P1 P1 --> P2 P2 -->|继承| UI P2 -->|调用| VEH VEH --> CAR VEH --> AIDL CAR --> DCD CAR --> XCD UI -.-> LIB
记住三句话:
- 入口:外部(语音/URI/点击)→
DeeplinkActivity/BaseCarSettingsActivity→ 路由Router→SubSettingsActivity→ 加载目标 Fragment。 - 页面:每个设置页 = 一个
PreferenceFragment+ 若干PreferenceController(Controller 在 XML 里声明,自动实例化)。 - 数据:Controller →
settingsVehicleLib→android.car.*/ AIDL → 车控服务,属性变化再回流到 UI。
三、文档导航
| # | 文档 | 讲什么 | 先读价值 |
|---|---|---|---|
| 00 | 本篇 · 总览与学习路线 | 全局地图、名词表、学习路线 | ⭐ 必读第一篇 |
| 01 | 项目全景与构建体系 | 模块拓扑、Gradle 构建、三 Flavor、平台 jar、签名、质量检查 | ⭐ 必读 |
| 02 | 核心架构-PreferenceController 范式 | Activity/Fragment/Controller 三层、Controller 生命周期、XML 声明 | ⭐⭐ 最核心 |
| 03 | 路由框架详解 | @RouterProvider 注解 → APT 生成路由表 → 运行期跳转 | ⭐ 重要 |
| 04 | 语音搜索插件详解 | 语音 intent → 设置页映射,与路由的关系 | 重要 |
| 05 | 车辆接口层与 IPC | settingsVehicleLib、Car API、AIDL、dcd/xcd 差异屏蔽 | ⭐ 重要 |
| 06 | 典型页面全链路剖析 | 以一个真实页面串起「入口→Controller→车辆→UI 回流」 | ⭐⭐ 实战必读 |
| 07 | 多 Flavor 与海外适配 | dcd/xcd/global 差异、sourceSet 叠加、翻译回填 | 重要 |
| 08 | 开发实战-新增设置页 | 手把手新增页面/开关 + 提交 + 踩坑 Checklist | ⭐⭐ 动手必读 |
| 09 | Setting 打包教程 | 三条打包路径(本地 Gradle / 编进镜像 / CI 发版)+ 签名 + 踩坑 FAQ | ⭐ 动手必读 |
四、推荐学习路线
flowchart LR A["Day1<br/>00 总览"] --> B["01 构建体系<br/>把项目跑起来"] B --> C["02 核心范式<br/>PreferenceController"] C --> D["Day2-3<br/>03 路由 + 04 语音"] D --> E["05 车辆接口层"] E --> F["Day4<br/>06 全链路剖析<br/>走读一个真实页面"] F --> G["07 多Flavor适配"] G --> H["Day5+<br/>08 实战<br/>自己新增一个设置页"]
| 阶段 | 目标 | 看哪几篇 | 验收标准 |
|---|---|---|---|
| 第 1 天 | 把工程构建出来,建立全局观 | 00 → 01 → 02 | 能说出「四层模块、三 Flavor、PreferenceController 范式」是什么 |
| 第 2-3 天 | 理解「页面如何被打开、被语音唤醒」 | 03 → 04 | 能画出 URI → Router → Fragment 的跳转链路 |
| 第 4 天 | 理解「车辆数据怎么读写」 | 05 → 06 | 能对着一个真实页面讲清数据回流 |
| 第 5 天+ | 动手 | 07 → 08 | 独立新增一个开关,通过 detekt 并推到 Gerrit |
💡 捷径:时间紧的话,至少把 00 → 02 → 06 → 08 看完,能最快进入实战。
五、5 分钟快速上手
5.1 工程结构(四层)
app/ ← 应用入口(Activity、Application、路由/语音 kapt 接入)
base/ ← 11 个基础库(UI 骨架、工具、车辆接口、WiFi、图标……)
├─ settingsBaseUi/ ★ PreferenceController 基类(核心)
├─ settingsBaseLib/ 通用工具
├─ settingsVehicleLib/ ★ 车辆接口抽象(核心,dcd/xcd 差异靠编译期 jar 切换屏蔽,详见 05 篇)
└─ ... settingsBasePB / WifiTrackerLib / iconloaderlib / settingsLib*
settingsPage/ ← 16 个功能模块(每个设置页一个模块)
├─ micarLightSettings/ 灯光
├─ micarChargeSettings/ 充电
├─ micarLockSettings/ 锁车
└─ ... display/driving/media/volume/iot/connection/...
settingsCommon/ ← 横切框架与工具
├─ plugin/router/ ★ 路由框架(annotation + routerApt + routerManager)
├─ plugin/voice/ 语音搜索(annotation + apt)
├─ rtiLib/ RTI 库
└─ tools/qualitytools/ 质量工具 + checkstyle/detekt 配置
5.2 构建命令
# 选与目标平台对应的 flavor:dcd / xcd / global
./gradlew :app:assembleXcdDebug # 国内 XCD 平台
./gradlew :app:assembleDcdDebug # 国内 DCD 平台
./gradlew :app:assembleGlobalDebug # 海外
# 代码质量(Gerrit 推送前必跑,否则 detekt 会打回)
./gradlew checkStyleCode # = javaCheckstyle + detekt
# 单测(覆盖较少,主要在 base/ 下几个库)
./gradlew :base:settingsBaseUi:testDebugUnitTest⚠️ 构建前提:各 flavor 的 framework.jar / android.car.jar 来自平台构建产物(settingsCommon/tools/out/target/...),切换 flavor 前需确保对应产物已存在。详见 01 篇。
5.3 代码提交(Gerrit)
仓库远程是 Gerrit(origin → slave.auto.mioffice.cn:29418):
git add <文件>
git commit -s -m "[Feature][All-Vehicle][模块] 简述
详细描述
AI: Claude 日期
Co-authored-by: Claude <noreply@anthropic.com>
Jira: JIRA-12345"
git push origin HEAD:refs/for/dev # 推到 Gerrit 评审完整的 Commit 模板、AI 注释规范、amend 追加改动 等,见 CLAUDE.md 与 AGENTS.md,以及 08 篇。
六、核心名词表(先认识这些人)
| 名词 | 含义 | 出现在 |
|---|---|---|
| PreferenceController | AOSP 范式:一个设置项的业务逻辑单元,在页面 XML 声明、自动实例化。改开关通常 = 加一个它的子类 | base/settingsBaseUi/.../PreferenceController.java |
| PreferenceControllerListHelper | 解析页面 XML,把声明的 Controller 实例化成列表 | base/settingsBaseUi |
| AvailabilityStatus | Controller 的可用状态(可用/禁用/隐藏),决定设置项是否显示 | PreferenceController 内注解 |
| Flavor (dcd/xcd/global) | miPlatform 维度的三套产物:国内两套平台 + 海外 | app/build.gradle 的 productFlavors |
| sourceSet 叠加 | dcd = main + dcddif + region/cn;global = main + xcddif + region/global | app/build.gradle 的 sourceSets |
| Router / 路由框架 | 按 URI 跳转到对应设置页的机制;@RouterProvider 注解 + routerApt 编译期生成路由表 | settingsCommon/plugin/router |
| APT | Annotation Processing Tool,编译期扫注解生成代码。本项目路由、语音都用它 | router/voice 子模块 |
| HomepageActivity | App 真正的主入口:首页点击、外部 URI 最终都汇聚到这里再分发 | app(android.settings.SETTINGS) |
| DeeplinkActivity | 主要服务于语音 widgetKey 的中转入口,最终也启动 HomepageActivity | app/src/main/.../DeeplinkActivity(android.settings.VEHICLE_PROPERTY_DELIVER) |
| SubSettingsActivity | 二级设置页的通用载体 Activity,加载目标 Fragment | app/src/main/.../SubSettingsActivity |
| settings:controller | XML 里挂载 Controller 的属性,值是 Controller 全限定类名(注意不是 app:controller) | 各页面 res/xml/*.xml |
| android:key | Preference 的唯一标识,必须用 @string/pk_xxx,不能硬编码字符串 | 各页面 res/xml/*.xml |
| Car API | android.car.*,系统应用读写车辆属性的入口(Car、CarPropertyManager) | base/settingsVehicleLib |
| AIDL | 跨进程接口,与车控/车况等服务 IPC;本工程含 8 个 .aidl | 各模块 src/main/aidl |
| platform 签名 | 用平台密钥签名,使 App 获得系统特权 | platform.keystore |
| detekt / checkstyle | Kotlin / Java 静态检查,Gerrit 强制 | settingsCommon/tools/checkstyle/ |
七、环境与构建准备 Checklist
- 已 clone 仓库:
origin→slave.auto.mioffice.cn:29418/platform/packages/apps/Car/MiCarSettings - 本地有 JDK 8(sourceCompatibility 1.8)与 Android SDK(compileSdk 33)
- 目标 flavor 的平台产物已就位(
settingsCommon/tools/out/target/...下的 framework/car/wifi-tracker jar) - 能联网访问小米内部 Maven(
pkgs.d.xiaomi.net),Gradle 才能拉到依赖 - 首次构建:
./gradlew :app:assembleXcdDebug成功产出 APK -
./gradlew checkStyleCode通过(否则 Gerrit 推送会被 detekt 拦截)
八、求助与进阶指引
| 我想…… | 去看 |
|---|---|
| 把项目跑起来 | 01 篇 · 构建体系 |
| 理解一个设置页怎么组成 | 02 篇 · PreferenceController 范式 |
| 让页面能被外部 URI 打开 | 03 篇 · 路由框架 |
| 让页面支持语音「打开 XX」 | 04 篇 · 语音搜索 |
| 读写车辆属性 | 05 篇 · 车辆接口层 |
| 看一个页面从头到尾怎么跑 | 06 篇 · 全链路剖析 |
| 区分国内/海外代码 | 07 篇 · 多 Flavor |
| 动手新增一个设置页 | 08 篇 · 开发实战 |
| 查提交规范 / AI 注释规范 | 根目录 CLAUDE.md、AGENTS.md |
| 用代码图谱查影响 / 重构 | GitNexus(见根目录 CLAUDE.md 末尾,本机需 Docker 运行) |
📌 新手记住
- 先建全局,再钻细节:本篇 + 02 篇能让你拿到「理解一切的总钥匙」——PreferenceController 范式。
- 改一个开关 ≠ 改 Fragment:90% 的情况是新增/修改一个
PreferenceController子类,并在页面 XML 里挂上它。 - 三 Flavor 同源:一套
main,靠dcddif/xcddif/region/*叠加出三套产物,写代码时要时刻意识到「这段在三个 flavor 下都成立吗?」。 - 质量门禁前置:Gerrit 强制 detekt,本地先
./gradlew checkStyleCode省得被打回。 - 系统应用身份:能直接用
android.car.*,是因为 platform 签名——丢了签名,车辆 API 全部失效。