1. 背景
在【android bluetooth 案例分析 04】【Carplay 详解 1】【CarPlay 在车机侧的蓝牙通信原理与角色划分详解】中我们从整理上介绍了车机中 carplay 相关基础概念。 本节 将详细分析 iphone手机主动 连接 车机carplay 这一过程。
先回顾一下 上一节, carplay 整个流程:
-
EIR 广播识别
- iPhone 开启 EIR 广播,包含
UUID_DEVICE_CARPLAY_EIR 2d8d2466-e14d-451c-88bc-7301abea291a
- 车机通过蓝牙扫描识别支持 CarPlay 的 iPhone
- iPhone 开启 EIR 广播,包含
-
蓝牙连接
- 没有配对,需要先配对
- iPhone 主动连接车机的 SPP Server UUID (
UUID_IAP_ACCESSORY 00000000-deca-fade-deca-deafdecacaff
)- 车机需要先 listenUsingRfcommWithServiceRecord
- 车机作为 Client 主动连接 iPhone 暴露的 Server UUID
- (需 iPhone 开启EIR 广播)
-
IAP2 协议交互
- 交换设备信息、认证令牌、能力参数(支持哪种 Wi-Fi 架构)
-
Wi-Fi 建链
- 手机连接车机热点,或车机连接手机热点,完成 IP 建立
-
TCP & mDNS 发现 CarPlay 服务
- 建立 TCP 通信,寻找
_carplay._tcp.local
服务,启动 CarPlay Session
- 建立 TCP 通信,寻找
-
启动投屏/音频/导航服务
上面总过分为 6 步: 但是涉及到蓝牙的只有 1 、 2、 3 步。 那我们就来分别来介绍一下 在当前 手机主动连车机的清晰。这三步是如何具体实操的。
2. 手机主动连车机
1. EIR 广播
EIR 广播识别:
- 车机开启 EIR 广播, 包含
00000000-deca-fade-deca-deafdecacaff
和ec884348-cd41-40a2-9727-575d50bf1fd3
- 手机就可以扫描到 车机支持 carplay
- iPhone 开启 EIR 广播,包含
00000000-deca-fade-deca-deafdecacafe
和2d8d2466-e14d-451c-88bc-7301abea291a
- 车机通过蓝牙扫描识别支持 CarPlay 的 iPhone
1. 手机 开启 EIR 广播
当 iphone 手机进入 设置 -> 通用 -> Carplay 车载 界面时, 此时,车机如果开启 扫描。此时就能从 扫描到的 EIR 中看到如下的广播信息。
c
300 2025-01-01 19:40:57.096358 controller host HCI_EVT 258 Rcvd Extended Inquiry Result
Bluetooth HCI Event - Extended Inquiry Result
Event Code: Extended Inquiry Result (0x2f)
Parameter Total Length: 255
Number of responses: 1
BD_ADDR: Apple_7c:81:36 (84:ad:8d:7c:81:36)
Page Scan Repetition Mode: R1 (0x01)
Reserved: 0x00
Class of Device: 0x7a020c (Phone:Smartphone - services: Networking Capturing ObjectTransfer Audio Telephony)
.110 1101 0010 1011 = Clock Offset: 0x6d2b
RSSI: -38 dBm
Extended Inquiry Response Data
Device Name: Jxl
Length: 4
Type: Device Name (0x09)
Device Name: Jxl
16-bit Service Class UUIDs
Length: 15
Type: 16-bit Service Class UUIDs (0x03)
UUID 16: PnP Information (0x1200)
UUID 16: Handsfree Audio Gateway (0x111f)
UUID 16: Phonebook Access Server (0x112f)
UUID 16: Audio Source (0x110a)
UUID 16: A/V Remote Control Target (0x110c)
UUID 16: Message Access Server (0x1132)
UUID 16: Generic Attribute Profile (0x1801)
32-bit Service Class UUIDs
Length: 1
Type: 32-bit Service Class UUIDs (0x05)
128-bit Service Class UUIDs
Length: 49
Type: 128-bit Service Class UUIDs (0x07)
Custom UUID: 00000000-deca-fade-deca-deafdecacafe (Unknown)
Custom UUID: 02030302-1d19-415f-86f2-22a2106a0a77 (Unknown)
Custom UUID: 2d8d2466-e14d-451c-88bc-7301abea291a (Unknown) // 此时手机 回复的 uuid 中就包含, 识别手机支持 carplay 的 uuid
Manufacturer Specific
Length: 39
Type: Manufacturer Specific (0xff)
Company ID: Unknown (0x4c00)
Data: 022402000000000000000000000000000000000000000000000000000000000000000000
[Expert Info (Note/Undecoded): Undecoded]
[Undecoded]
[Severity level: Note]
[Group: Undecoded]
Unused
2d8d2466-e14d-451c-88bc-7301abea291a
这个 uuid 就是帮助车机筛选 那些手机支持 carplay 功能的。
在协议栈中 我们会将 该 uuid 上报 到 应用侧。如果不明白 如果上报,可以看一下这篇文章
【android bluetooth 协议分析 03】【蓝牙扫描详解 1】【扫描关键函数 btif_dm_search_devices_evt 分析】
此时在车机 carplay 连接 界面就可以看到 当前 iphone 手机。
2. 车机开启EIR 广播
分析到这里, 有人疑惑,车机是 可以看到 手机支持 carplay. 但是此时 手机 应该看不到 车机支持carplay 功能吧。确实是这样子?
我们可以参照手机的操作。 将 carplay 的 uuid 写入 车机的 EIR 中。 这样手机在扫描时 , 就可以扫描 到车机的 EIR. 这块手机就可以发现 车机支持 carplay.
如下是 app 侧的操作 流程:
java
/*我们代码添加IAP的uuid,车机的BT模块里自动添加CP的uuid*/
//IAP2 uuid 使用此uuid,手机才能发起IAP连接
private static final UUID SERVER_SPP_UUID = UUID.fromString("00000000-deca-fade-deca-deafdecacaff");
//CP uuid 使用此uuid,手机CarPlay车载画面能够扫描出来,但是在手机CarPlay车载画面点击车机时,无法连接上
private static final UUID SERVER_SPP_UUID_CP = UUID.fromString("EC884348-CD41-40A2-9727-575D50BF1FD3");
BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
BluetoothServerSocket mServerSocket = adapter.listenUsingRfcommWithServiceRecord("com.running.android.carplay", SERVER_SPP_UUID);
BluetoothSocket mClientSocket = mServerSocket.accept();
- 先调用 listenUsingRfcommWithServiceRecord 方法,在 该 listenUsingRfcommWithServiceRecord 中,就会将 00000000-deca-fade-deca-deafdecacaff 和 EC884348-CD41-40A2-9727-575D50BF1FD3 两个 uuid. 写入到我们的 eir 中。 并创建 一个 spp server.
- mServerSocket.accept(); 等待 手机来连接。 手机连接后,将会返回一个新的 socket.
- 拿到这个 socket. 手机和车机就可以 交互 carplay 连接需要的信息。例如 wifi 热点名字,密码等。
c
105 2025-01-01 19:40:31.420798 host controller HCI_CMD 245 Sent Write Extended Inquiry Response
Frame 105: 245 bytes on wire (1960 bits), 245 bytes captured (1960 bits)
Bluetooth
Bluetooth HCI H4
Bluetooth HCI Command - Write Extended Inquiry Response
Command Opcode: Write Extended Inquiry Response (0x0c52)
Parameter Total Length: 241
FEC Required: true (1)
Extended Inquiry Response Data
Device Name: xxxxxx
16-bit Service Class UUIDs
Length: 13
Type: 16-bit Service Class UUIDs (0x03)
UUID 16: Audio Sink (0x110b)
UUID 16: A/V Remote Control Target (0x110c)
UUID 16: A/V Remote Control (0x110e)
UUID 16: Handsfree (0x111e)
UUID 16: Phonebook Access Client (0x112e)
UUID 16: PnP Information (0x1200)
32-bit Service Class UUIDs
Length: 1
Type: 32-bit Service Class UUIDs (0x05)
128-bit Service Class UUIDs
Length: 129
Type: 128-bit Service Class UUIDs (0x07)
Custom UUID: 00000000-deca-fade-deca-deafdecacaff (Unknown) // 这个是 app 侧下发的 uuid
Custom UUID: ec884348-cd41-40a2-9727-575d50bf1fd3 (Unknown) // 这个我们根据 app 下发的uuid 在协议栈中我们任务加的
Custom UUID: 00000000-0000-0000-0000-000000000000 (Unknown)
Custom UUID: 00000000-0000-0000-0000-000000000000 (Unknown)
Custom UUID: 00000000-0000-0000-0000-000000000000 (Unknown)
Custom UUID: 00000000-0000-0000-0000-000000000000 (Unknown)
Custom UUID: 00000000-0000-0000-0000-000000000000 (Unknown)
Custom UUID: 00000000-0000-0000-0000-000000000000 (Unknown)
Tx Power Level
Length: 2
Type: Tx Power Level (0x0a)
Power Level (dBm): 8
Unused
[Response in frame: 106]
[Command-Response Delta: 28.115ms]
- 此时 我们的手机就可以正确的扫描到 我们的车机也支持 carplay。
2. 蓝牙连接 iap 并通信
没有配对,需要先配对 : 这个是常规操作, 这里不分享了。
这里主要分析一下。 手机 主动连接 车机 iap 的过程:


- 手机向 车机发起了 sdp , 这里手机向我们查询的 uuid. 正是我们前面注册的 00000000-deca-fade-deca-deafdecacaff
- 车机回复了 对应的 rfcomm 通道为 3
手机继续 主动查询 车机之前注册的 UUID ec884348-cd41-40a2-9727-575d50bf1fd3


这里车机回复了该uuid 对应的 rfcomm 通道为 4

手机 主动 请求连接车机的 rfcomm channel 3

接下来 车机和手机 通过 channel 3 开始将 后面 carplay 连接需要的 wifi 相关的 热点名字,密码发送给手机。
3. 总结
手机 如果要主动连接车机carplay
车机需要 完成如下步骤:
- 车机 app 侧需要 通过如下代码:
- 开启 车机 EIR 广播:广播
00000000-deca-fade-deca-deafdecacaff
和ec884348-cd41-40a2-9727-575d50bf1fd3
这样 在手机carplay 界面才可以看到车机。 - 向 sdp 数据库中注册 上述 两个uuid. 这样 手机主动发起 上述两个服务的uuid 时, 车机才知道如何回复。
- 开启 车机 EIR 广播:广播
c
BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
// 开启 EIR 和 注册 SDP 数据库,都是通过该调用实现的
BluetoothServerSocket mServerSocket = adapter.listenUsingRfcommWithServiceRecord("com.running.android.carplay", SERVER_SPP_UUID);
- 车机carplay app. 等待 手机连接
c
BluetoothSocket mClientSocket = mServerSocket.accept(); // 当手机主动连接时, 这里将返回,一个新的 socket. 用于 iap 内容交互
-
此时 手机 carplay 界面就可以扫描到 车机, 点击界面发起 对车机的主动连接:
- 此时会看到 手机主动向 车机发起
00000000-deca-fade-deca-deafdecacaff
和ec884348-cd41-40a2-9727-575d50bf1fd3
两个服务的 SDP 查询。 - 车机返回对应的 rfcomm 通道号。 例如
00000000-deca-fade-deca-deafdecacaff iap协议, rfcomm channel= 3
- 此时会看到 手机主动向 车机发起
-
手机主动发起 rfcomm channel 3 , iap 协议的连接。
-
车机和手机,此时就可以通过 iap 协议交互,后续 carplay 连接所需要的 wifi 热点信息。
-
交互完成后,断开rfcomm channel3
-
发起 真正的 carplay 连接, 此时就可以看到 手机将画面 投屏到车机上。
这里的重点是 调用 listenUsingRfcommWithServiceRecord 函数。
该函数的讲解,将在另外的 文章中单独讲解。