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

记住三句话:

  1. 入口:外部(语音/URI/点击)→ DeeplinkActivity/BaseCarSettingsActivity路由 RouterSubSettingsActivity → 加载目标 Fragment
  2. 页面:每个设置页 = 一个 PreferenceFragment + 若干 PreferenceController(Controller 在 XML 里声明,自动实例化)。
  3. 数据:Controller → settingsVehicleLibandroid.car.* / AIDL → 车控服务,属性变化再回流到 UI。

三、文档导航

#文档讲什么先读价值
00本篇 · 总览与学习路线全局地图、名词表、学习路线⭐ 必读第一篇
01项目全景与构建体系模块拓扑、Gradle 构建、三 Flavor、平台 jar、签名、质量检查⭐ 必读
02核心架构-PreferenceController 范式Activity/Fragment/Controller 三层、Controller 生命周期、XML 声明⭐⭐ 最核心
03路由框架详解@RouterProvider 注解 → APT 生成路由表 → 运行期跳转⭐ 重要
04语音搜索插件详解语音 intent → 设置页映射,与路由的关系重要
05车辆接口层与 IPCsettingsVehicleLib、Car API、AIDL、dcd/xcd 差异屏蔽⭐ 重要
06典型页面全链路剖析以一个真实页面串起「入口→Controller→车辆→UI 回流」⭐⭐ 实战必读
07多 Flavor 与海外适配dcd/xcd/global 差异、sourceSet 叠加、翻译回填重要
08开发实战-新增设置页手把手新增页面/开关 + 提交 + 踩坑 Checklist⭐⭐ 动手必读
09Setting 打包教程三条打包路径(本地 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)

仓库远程是 Gerritoriginslave.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.mdAGENTS.md,以及 08 篇


六、核心名词表(先认识这些人)

名词含义出现在
PreferenceControllerAOSP 范式:一个设置项的业务逻辑单元,在页面 XML 声明、自动实例化。改开关通常 = 加一个它的子类base/settingsBaseUi/.../PreferenceController.java
PreferenceControllerListHelper解析页面 XML,把声明的 Controller 实例化成列表base/settingsBaseUi
AvailabilityStatusController 的可用状态(可用/禁用/隐藏),决定设置项是否显示PreferenceController 内注解
Flavor (dcd/xcd/global)miPlatform 维度的三套产物:国内两套平台 + 海外app/build.gradleproductFlavors
sourceSet 叠加dcd = main + dcddif + region/cn;global = main + xcddif + region/globalapp/build.gradlesourceSets
Router / 路由框架按 URI 跳转到对应设置页的机制;@RouterProvider 注解 + routerApt 编译期生成路由表settingsCommon/plugin/router
APTAnnotation Processing Tool,编译期扫注解生成代码。本项目路由、语音都用它router/voice 子模块
HomepageActivityApp 真正的主入口:首页点击、外部 URI 最终都汇聚到这里再分发appandroid.settings.SETTINGS
DeeplinkActivity主要服务于语音 widgetKey 的中转入口,最终也启动 HomepageActivityapp/src/main/.../DeeplinkActivityandroid.settings.VEHICLE_PROPERTY_DELIVER
SubSettingsActivity二级设置页的通用载体 Activity,加载目标 Fragmentapp/src/main/.../SubSettingsActivity
settings:controllerXML 里挂载 Controller 的属性,值是 Controller 全限定类名(注意不是 app:controller各页面 res/xml/*.xml
android:keyPreference 的唯一标识,必须@string/pk_xxx,不能硬编码字符串各页面 res/xml/*.xml
Car APIandroid.car.*,系统应用读写车辆属性的入口(CarCarPropertyManagerbase/settingsVehicleLib
AIDL跨进程接口,与车控/车况等服务 IPC;本工程含 8 个 .aidl各模块 src/main/aidl
platform 签名用平台密钥签名,使 App 获得系统特权platform.keystore
detekt / checkstyleKotlin / Java 静态检查,Gerrit 强制settingsCommon/tools/checkstyle/

七、环境与构建准备 Checklist

  • 已 clone 仓库:originslave.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.mdAGENTS.md
用代码图谱查影响 / 重构GitNexus(见根目录 CLAUDE.md 末尾,本机需 Docker 运行)

📌 新手记住

  1. 先建全局,再钻细节:本篇 + 02 篇能让你拿到「理解一切的总钥匙」——PreferenceController 范式。
  2. 改一个开关 ≠ 改 Fragment:90% 的情况是新增/修改一个 PreferenceController 子类,并在页面 XML 里挂上它。
  3. 三 Flavor 同源:一套 main,靠 dcddif/xcddif/region/* 叠加出三套产物,写代码时要时刻意识到「这段在三个 flavor 下都成立吗?」。
  4. 质量门禁前置:Gerrit 强制 detekt,本地先 ./gradlew checkStyleCode 省得被打回。
  5. 系统应用身份:能直接用 android.car.*,是因为 platform 签名——丢了签名,车辆 API 全部失效。