A17 国内(cn) vs 国外(global) 蓝牙差异分析(底层视角)
面向:底层蓝牙适配工程师 + Settings 开发 分支:
dev_a17_0610,对比两个编译变体xcd_cn_a17(国内)vsxcd_global_a17(国外) 产出:2026-07-24 | 方法 = flavor 源集对比 + 运行时判断 grep(非跨分支 diff) 配套:跨分支差异见 适配视角-dev-vs-a17蓝牙差异详解、dev-vs-dev_a17_0610蓝牙差异报告
0. 结论先行(TL;DR)
A17 蓝牙国内外是同一套代码和同一套逻辑。 两个变体的蓝牙核心代码逐字节相同(共享 micarConnectionSettings 的 main + f3dif 源集),差异极小,且全部性质是”海外合规补充”,不是功能分叉。
| 层 | 蓝牙相关差异 | 性质 |
|---|---|---|
| APP 层 | global 多 1 个 BluetoothRequestPermissionActivity(AOSP 原生,为 Google GTS 认证) | 海外合规 |
| APP 层 | 蓝牙 manifest 组件 / 权限 / 代码 / res / 运行时逻辑 | 零差异 |
| lib 层 | settingslib 蓝牙部分(f3dif 共享,src/global 无蓝牙文件) | 零差异 |
一句话:开发蓝牙功能时,cn/global 改一处两版本同步生效,无需为海外单独适配蓝牙逻辑;唯一要注意的是 BluetoothRequestPermissionActivity 只在 global 编译。
1. 怎么界定”差异”(方法论)
cn/global 是同一分支的两个 productFlavor,差异来自编译期选哪些源集(不是 git diff)。三处差异来源:
| 差异源 | cn | global |
|---|---|---|
app/.../src/region/ | region/cn/res(仅 1 个顶层菜单 xml) | region/global/{java,res,AndroidManifest.xml}(location/privacy,无蓝牙) |
globalOnly 模块 | 不依赖 | 依赖(xcd_global_a17Implementation project(":settingsPage:globalOnly")) |
src/global/ 源集 | 不含 | settingslib 与 micarConnectionSettings 均声明含,但实际为空 |
关键查证手段(都做了实证):
- 编译期源集:
git ls-tree -r dev_a17_0610 -- <src/global 路径>→ 看有无蓝牙文件 - 运行时判断:
git grep isGlobal/isCn/region→ 看代码有无动态开关 - 包名预装:互联能力靠运行时查包,代码层不分 cn/global
第一部分:APP 层差异
2.1 APP 层差异总览
| 维度 | cn (xcd_cn_a17) | global (xcd_global_a17) | 蓝牙相关? |
|---|---|---|---|
| 蓝牙核心代码 | main + f3dif | main + f3dif(+ 空的 src/global) | 同一套,零差异 |
BluetoothRequestPermissionActivity | ❌ 无 | ✅ 有(globalOnly 模块) | 是(唯一差异) |
| 蓝牙 manifest 权限/组件 | 共享 micarConnectionSettings/src/main/AndroidManifest.xml | 同左 | 零差异 |
| 蓝牙/连接代码运行时 region 判断 | 无 | 无 | 零差异 |
| 互联能力(CarPlay/CarLink 等) | 运行时查包名 | 运行时查包名 | 代码一致,差异在镜像预装 |
| 蓝牙 res/string | region/cn、src/global 均无蓝牙资源 | 同左 | 零差异 |
| 顶层菜单连接/蓝牙入口 | 一致 | 一致 | 零差异 |
2.2 蓝牙代码:cn/global 完全同一套(实证)
蓝牙核心模块 settingsPage/micarConnectionSettings/ 的 flavor 源集绑定(build.gradle):
xcd_cn_a17: java.srcDirs = ['src/main/java', 'src/f3dif/java']
xcd_global_a17: java.srcDirs = ['src/main/java', 'src/f3dif/java', 'src/global/java']
- 两个 flavor 都包含
main + f3dif—— 蓝牙 14 个核心文件 + settingslib 蓝牙栈 cn/global 完全相同。 - global 多出的
src/global/java:git ls-tree实测目录为空(0 文件)。 micarConnectionSettings/src/main/AndroidManifest.xml:两 flavor 的manifest.srcFile都指向它 → 蓝牙 manifest 组件零差异。
→ 蓝牙核心逻辑、扫描/配对/连接状态机、UI Controller,cn/global 一套代码,不存在任何分支。
2.3 唯一蓝牙差异:BluetoothRequestPermissionActivity(global 独有)
文件:settingsPage/globalOnly/src/main/java/com/android/car/settings/bluetooth/BluetoothRequestPermissionActivity.java
模块:globalOnly(namespace com.android.car.settings.global,仅被 xcd_global_a17 依赖)
来源:AOSP 原生(版权 2019 The Android Open Source Project)
用途:处理系统标准蓝牙权限请求 intent
manifest 声明(globalOnly/src/main/AndroidManifest.xml,注释明写用途):
<!--for google GTS-->
<activity android:name="com.android.car.settings.bluetooth.BluetoothRequestPermissionActivity"
android:exported="true" android:launchMode="singleInstance">
<intent-filter>
<action android:name="android.bluetooth.adapter.action.REQUEST_DISCOVERABLE" />
<action android:name="android.bluetooth.adapter.action.REQUEST_ENABLE" />
<action android:name="android.bluetooth.adapter.action.REQUEST_DISABLE" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>关键代码(请求类型 + 状态机):
static final int REQUEST_ENABLE = 1;
static final int REQUEST_DISABLE = 2;
static final int REQUEST_ENABLE_DISCOVERABLE = 3;
static final int DISCOVERABLE_TIMEOUT_TWO_MINUTES = 120;
static final int DISCOVERABLE_TIMEOUT_ONE_HOUR = 3600;
// 用 settingslib 的 LocalBluetoothManager(注意:是 settingslib 包装类,非标准 BluetoothAdapter)
mLocalBluetoothManager = LocalBluetoothManager.getInstance(getApplicationContext(), null);
mLocalBluetoothAdapter = mLocalBluetoothManager.getBluetoothAdapter();
int btState = mLocalBluetoothAdapter.getState();
switch (mRequest) {
case REQUEST_ENABLE: // 弹"是否开启蓝牙"确认框 → 开启
case REQUEST_DISABLE: // 弹"是否关闭蓝牙"确认框 → 关闭
case REQUEST_ENABLE_DISCOVERABLE: // 设为可发现 N 秒(默认 120s,最大 1h)
}为什么 global 才有:
- 海外版必须通过 Google GTS(Google Test Suite)认证,GTS 会发
android.bluetooth.adapter.action.REQUEST_ENABLE/REQUEST_DISCOVERABLE等标准 intent,要求有 Activity 响应并征求用户同意。 - 国内版不走 Google 认证,蓝牙开关用 Settings 自有 UI(
BluetoothMainEntrySettingsFragment),不响应这些标准 intent。 - cn 编译产物实测不含此类(
app/src/main+micarConnectionSettingsgrepBluetoothRequestPermission= 空)。
对蓝牙同事的影响:
- 改此类只影响海外,不影响国内蓝牙功能。
- 此类用
LocalBluetoothAdapter(settingslib 包装,getState()),与 a17 核心蓝牙模块用的标准BluetoothAdapter(见 适配视角-dev-vs-a17蓝牙差异详解 第 1 节)API 风格不同——它是 AOSP 原样搬来的,没跟着核心模块一起升级到标准 API。 - 若 GTS 测试报蓝牙权限请求相关问题,只排查 global 编译的这个 Activity。
2.4 蓝牙 manifest 组件:cn/global 零差异
micarConnectionSettings/src/main/AndroidManifest.xml(两 flavor 共享),蓝牙相关组件清单一致:
| 组件/权限 | 说明 |
|---|---|
BLUETOOTH / BLUETOOTH_ADMIN / BLUETOOTH_PRIVILEGED / BLUETOOTH_CONNECT | 蓝牙权限,两 flavor 都有 |
BluetoothSettingsActivity | 蓝牙设置主页(响应 android.settings.BLUETOOTH_SETTINGS) |
MiBluetoothPairingDialogActivity | 配对对话框 |
MiCarplayConnectTypeChooseDialogActivity | CarPlay 连接类型选择(注释「CarPlay蓝牙连接选择弹窗」) |
MiBluetoothPickerDialogActivity | 蓝牙设备选择器(响应 com.android.micar.settings.BLUETOOTH_DEVICE_PICKER) |
MiBluetoothPairingRequest | 配对请求(响应 android.bluetooth.device.action.PAIRING_REQUEST) |
BluetoothDeviceService | 蓝牙设备服务 |
→ 国内外蓝牙 UI 入口、权限、后台组件完全相同。CarPlay 相关组件国内也存在(是否可用取决于包预装,见 2.5)。
2.5 互联能力:运行时包名判断(代码层不分 cn/global)
手车互联(CarPlay/CarLink/AndroidAuto/小米设备互联)能力判断在 ConnectionUtils.kt,靠运行时查包是否预装,代码 cn/global 完全一致:
// ConnectionUtils.kt(f3dif,cn/global 共享)
isMiuiShareSupported() → PackageUtils.isPkgInstalled("com.xiaomi.mitv.smartshare")
isCarPlaySupported() → isPkgInstalled("com.mi.car.carplay") || isPkgInstalled("com.desaysv.carplay")
isCarLinkSupported() → isPkgInstalled("com.mi.car.carlink")
isAndroidAutoSupported()→ isPkgInstalled("com.mi.car.androidauto")国内外互联能力差异由系统镜像预装哪些包决定(国外镜像装 CarPlay/AndroidAuto,国内装 CarLink/MiuiShare),不在 Settings 代码里。要改国内外互联支持,改镜像预装包,而非改 Settings。
注:
ConnectionUtils全文 grepisGlobal/isCn/region= 空,证实无运行时 region 开关。
2.6 非蓝牙的 app 层差异(避免混淆,顺带说明)
这些差异与蓝牙无关,列出来防止蓝牙同事误判:
| 差异 | cn | global | 性质 |
|---|---|---|---|
| 双层氛围灯同步 | 有(ATMOSPHERE_LIGHT_SYNCHRONIZE 权限 + Receiver) | 无 | 国内特色 |
| 强制发电弹窗 | 有(EnergyModeForceChargeDialogActivity) | 无 | 国内特色 |
| 辅助驾驶 Fragment | AutopilotSettingsFragment | GlobalAutopilotSettingsFragment | 国内外方案不同 |
| location/privacy 入口 | 无 | 有(LocationSettingsFragment/PrivacySettingsFragment 等) | 海外隐私合规 |
| Activity theme | DarkFullscreenTheme | DarkFullscreenThemeKeepStatusBar(tools:replace) | 海外保留状态栏 |
| app 主 manifest 文件 | src/main/AndroidManifest.xml | src/region/global/AndroidManifest.xml(独立) | — |
第二部分:lib 层差异
3.1 settingslib flavor 绑定
base/settingsLibAndroid/build.gradle:
xcd_cn_a17: java.srcDirs = ['src/main/java', 'src/f3dif/java']
xcd_global_a17: java.srcDirs = ['src/main/java', 'src/f3dif/java', 'src/global/java']
3.2 src/global 蓝牙文件:零(6 个 lib 实证)
git ls-tree -r dev_a17_0610 -- base/<lib>/src/global 对全部 base 库统计蓝牙文件:
| 库 | src/global 蓝牙文件数 |
|---|---|
| settingsLibAndroid | 0 |
| WifiTrackerLib | 0 |
| settingsLibUtils | 0 |
| settingsLibTile | 0 |
| settingsLibAdaptiveIcon | 0 |
| settingsLibDisplayUtils | 0 |
micarConnectionSettings/src/global 同样为空目录。
3.3 结论:lib 层蓝牙 cn/global 零差异
- 蓝牙 profile 栈、事件总线、
LocalBluetoothAdapter/CachedBluetoothDevice等 settingslib 蓝牙类,cn/global 共享 f3dif 同一份。 - global 的
src/global源集里没有任何蓝牙文件(可能有 location/privacy 等非蓝牙内容)。 - → 底层蓝牙库,国内外零差异。
4. 对蓝牙/Settings 同事的评估要点
开发影响清单
| 场景 | cn/global 是否需分别处理 | 说明 |
|---|---|---|
| 改蓝牙扫描/配对/连接逻辑 | ❌ 不需要 | 一套代码,改 main/f3dif 两版本同步 |
| 改蓝牙 UI(列表/详情/配对弹窗) | ❌ 不需要 | 同上 |
| 改蓝牙 manifest 权限/组件 | ❌ 不需要 | 共享 micarConnectionSettings/src/main/AndroidManifest.xml |
| 改互联能力(CarPlay 等)开关 | ❌ 不需要(改代码无效) | 改系统镜像预装包 |
| 改 GTS 蓝牙权限请求流程 | ✅ 只影响 global | 动 BluetoothRequestPermissionActivity(globalOnly 模块) |
| 加新的海外专属蓝牙功能 | ✅ global 独占 | 放 globalOnly 模块或 src/global |
关键提醒
BluetoothRequestPermissionActivity是 global 唯一蓝牙独占代码,用 settingslib 的LocalBluetoothAdapter(AOSP 原样,未跟随核心模块升级到标准 API)。若做 API 统一,此类是 global 侧的历史遗留点。- 国内外蓝牙功能/逻辑/字段/UI 完全一致,差异仅”海外多了个 GTS Activity”。评估蓝牙功能开发工作量时,不需要乘以 2。
- 互联能力差异不在代码层,别在 Settings 里找 CarPlay 国内/国外分支(没有)。
附录:复验命令
# micarConnectionSettings flavor 源集(确认 cn/global 共享 main+f3dif)
git show dev_a17_0610:settingsPage/micarConnectionSettings/build.gradle | sed -n '75,85p'
# global 独有蓝牙 Activity
git show dev_a17_0610:settingsPage/globalOnly/src/main/java/com/android/car/settings/bluetooth/BluetoothRequestPermissionActivity.java
# lib 层 src/global 蓝牙文件数(应为 0)
git ls-tree -r dev_a17_0610 -- base/settingsLibAndroid/src/global | grep -ic bluetooth
# 运行时 region 判断(应为空)
git grep -niE "isGlobal|isCn|region" dev_a17_0610 -- 'settingsPage/micarConnectionSettings/src/main/java/com/android/car/settings/miauto/bluetooth/**'