1. 什么是 SPP(Serial Port Profile)
SPP 是一种经典蓝牙协议(基于 RFCOMM),用于模拟串口通信。
应用场景:设备间简单的数据传输,如串口打印机、蓝牙 OBD 车载诊断仪、蓝牙扫描枪、蓝牙调试工具、车载系统认证通信等。
特点:基于 RFCOMM 传输,应用层可读写类似串口的数据。
2. SPP 通信整体流程
阶段 | Client 端 | Server 端 |
---|---|---|
1. UUID 协议识别 | 使用固定的 SPP UUID(00001101-0000-1000-8000-00805F9B34FB )或自定义 UUID |
注册并广播 UUID 到 SDP(服务发现协议)中 |
2. Socket 创建 | 使用 createRfcommSocketToServiceRecord(UUID) 创建 RFCOMM socket |
使用 listenUsingRfcommWithServiceRecord(name, UUID) 创建监听 socket |
3. 连接建立 | 调用 connect() 主动连接 |
调用 accept() 等待连接 |
4. 数据传输 | 使用 InputStream / OutputStream 收发数据 |
同样使用流进行读写 |
5. 关闭连接 | 调用 close() 关闭连接 |
同上 |
3. Server 与 Client 示例代码
1. Server 端代码
public class BluetoothSppServer extends Thread {
private final BluetoothServerSocket serverSocket;
private static final UUID SPP_UUID =
UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");
public BluetoothSppServer(BluetoothAdapter adapter) throws IOException {
serverSocket = adapter.listenUsingRfcommWithServiceRecord("SPP_SERVER", SPP_UUID);
}
public void run() {
BluetoothSocket socket;
while (true) {
try {
socket = serverSocket.accept(); // 阻塞等待连接
} catch (IOException e) {
break;
}
if (socket != null) {
new SppConnectionHandler(socket).start(); // 启动数据处理线程
}
}
}
public void cancel() throws IOException {
serverSocket.close();
}
}
2. Client 端代码
public class BluetoothSppClient extends Thread {
private final BluetoothSocket socket;
private static final UUID SPP_UUID =
UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");
public BluetoothSppClient(BluetoothDevice device) throws IOException {
socket = device.createRfcommSocketToServiceRecord(SPP_UUID);
}
public void run() {
try {
socket.connect(); // 主动连接
OutputStream out = socket.getOutputStream();
InputStream in = socket.getInputStream();
out.write("Hello Server!".getBytes());
byte[] buffer = new byte[1024];
int bytes = in.read(buffer);
String response = new String(buffer, 0, bytes);
Log.d("SPPClient", "Received: " + response);
} catch (IOException e) {
e.printStackTrace();
}
}
public void cancel() throws IOException {
socket.close();
}
}
4. SPP 在车机中的应用场景
应用场景 | 是否使用 SPP | 说明 |
---|---|---|
车载蓝牙调试端口 | ✅ | 开发人员通过串口协议调试 ECU 等设备 |
蓝牙 OBD 读码器 | ✅ | 车机与 OBD 通信获取车辆状态信息 |
CarPlay 蓝牙认证 | ✅(使用相同 API) | 虽不使用标准 SPP 协议,但使用 RFCOMM 套接字建立 iAP2 通道 |
蓝牙打印机 | ✅ | 一些车载小票打印应用 |
远程诊断工具(带蓝牙) | ✅ | 蓝牙串口传输指令和日志数据 |
5. CarPlay 与 SPP 的联系和区别
虽然 CarPlay 并不严格遵循 Bluetooth SIG 定义的 SPP profile,但其 iAP2 over Bluetooth 的认证阶段仍然使用 listenUsingRfcommWithServiceRecord
与 createRfcommSocketToServiceRecord
进行连接,因此其流程与 SPP 本质上相同,只是:
项目 | SPP | CarPlay |
---|---|---|
使用 UUID | 标准 UUID (00001101... ) |
Apple 自定义 iAP2 UUID |
协议内容 | 串口透明数据 | Apple 私有 iAP2 协议帧 |
应用层数据 | 任意串口数据 | MFi 授权认证帧等 |
是否公开 | ✅ | ❌ 私有 |
因此我们可以说:
CarPlay 使用的是“SPP 风格”的 Bluetooth RFCOMM 通道,但走的是 Apple 私有协议(iAP2)。
6. 总结
项目 | 内容 |
---|---|
listenUsingRfcommWithServiceRecord |
Server 端使用,注册服务并等待连接(通过 SDP 广播 UUID) |
createRfcommSocketToServiceRecord |
Client 端使用,连接指定 UUID 的服务 |
SPP 场景 | 串口调试、OBD 读码器、蓝牙打印、CarPlay 认证等 |
CarPlay 与 SPP 区别 | 协议不同,机制类似,使用相同的 Android API |
是否可以使用 SPP 做调试通道? | ✅ 非常适合,Android 支持良好,使用简单 |