同一安卓设备双APP实现BLE GATT Client与Server角色开发咨询
同一设备上实现安卓GATT Client与Peripheral(Server)通信
核心实现步骤(Kotlin示例)
一、GATT Server(Peripheral端)
- 权限配置
在AndroidManifest.xml中添加必要权限:
<!-- Android 12+ 权限 --> <uses-permission android:name="android.permission.BLUETOOTH_ADVERTISE" /> <uses-permission android:name="android.permission.BLUETOOTH_CONNECT" /> <!-- 旧版本兼容 --> <uses-permission android:name="android.permission.BLUETOOTH" android:maxSdkVersion="30" /> <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" android:maxSdkVersion="30" /> <uses-feature android:name="android.hardware.bluetooth_le" android:required="true" />
- 初始化广播与GATT服务
// 获取BluetoothAdapter val bluetoothAdapter = BluetoothAdapter.getDefaultAdapter() // 初始化BLE广播器 val advertiser = bluetoothAdapter.bluetoothLeAdvertiser // 创建自定义服务和特征UUID val serviceUuid = UUID.fromString("0000FFE0-0000-1000-8000-00805F9B34FB") val characteristicUuid = UUID.fromString("0000FFE1-0000-1000-8000-00805F9B34FB") // 创建GATT服务 val gattService = BluetoothGattService(serviceUuid, BluetoothGattService.SERVICE_TYPE_PRIMARY) // 创建可读写、支持通知的特征 val characteristic = BluetoothGattCharacteristic( characteristicUuid, BluetoothGattCharacteristic.PROPERTY_READ or BluetoothGattCharacteristic.PROPERTY_WRITE or BluetoothGattCharacteristic.PROPERTY_NOTIFY, BluetoothGattCharacteristic.PERMISSION_READ or BluetoothGattCharacteristic.PERMISSION_WRITE ) gattService.addCharacteristic(characteristic) // 初始化GATT Server回调 val gattServerCallback = object : BluetoothGattServerCallback() { override fun onConnectionStateChange(device: BluetoothDevice?, status: Int, newState: Int) { super.onConnectionStateChange(device, status, newState) // 处理连接/断开事件 if (newState == BluetoothProfile.STATE_CONNECTED) { // 客户端已连接 } } override fun onCharacteristicWriteRequest( device: BluetoothDevice?, requestId: Int, characteristic: BluetoothGattCharacteristic?, preparedWrite: Boolean, responseNeeded: Boolean, offset: Int, value: ByteArray? ) { super.onCharacteristicWriteRequest(device, requestId, characteristic, preparedWrite, responseNeeded, offset, value) // 处理客户端写入的数据 value?.let { val receivedData = String(it) // 业务逻辑处理 } // 响应客户端写入请求 bluetoothGattServer?.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, 0, null) } } // 启动GATT Server val bluetoothGattServer = bluetoothManager.openGattServer(this, gattServerCallback) bluetoothGattServer?.addService(gattService) // 配置广播参数 val advertiseSettings = AdvertiseSettings.Builder() .setAdvertiseMode(AdvertiseSettings.ADVERTISE_MODE_LOW_LATENCY) .setTxPowerLevel(AdvertiseSettings.ADVERTISE_TX_POWER_HIGH) .setConnectable(true) .build() // 设置广播数据(包含服务UUID) val advertiseData = AdvertiseData.Builder() .addServiceUuid(ParcelUuid(serviceUuid)) .build() // 启动广播 advertiser.startAdvertising(advertiseSettings, advertiseData, object : AdvertiseCallback() { override fun onStartSuccess(settingsInEffect: AdvertiseSettings?) { super.onStartSuccess(settingsInEffect) // 广播启动成功 } override fun onStartFailure(errorCode: Int) { super.onStartFailure(errorCode) // 处理广播启动失败,比如权限不足、蓝牙未开启 } })
二、GATT Client端
- 权限配置
除了Server端的权限,还需要添加扫描权限:
<!-- Android 12+ 扫描权限 --> <uses-permission android:name="android.permission.BLUETOOTH_SCAN" /> <!-- 旧版本需要位置权限 --> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" android:maxSdkVersion="30" />
- 扫描与连接逻辑
val bluetoothAdapter = BluetoothAdapter.getDefaultAdapter() val targetServiceUuid = UUID.fromString("0000FFE0-0000-1000-8000-00805F9B34FB") val characteristicUuid = UUID.fromString("0000FFE1-0000-1000-8000-00805F9B34FB") // 配置扫描过滤器,只扫描目标服务UUID的设备 val scanFilter = ScanFilter.Builder() .setServiceUuid(ParcelUuid(targetServiceUuid)) .build() val scanSettings = ScanSettings.Builder() .setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY) .build() // 启动扫描 bluetoothAdapter.bluetoothLeScanner.startScan( listOf(scanFilter), scanSettings, object : ScanCallback() { override fun onScanResult(callbackType: Int, result: ScanResult?) { super.onScanResult(callbackType, result) result?.device?.let { device -> // 停止扫描 bluetoothAdapter.bluetoothLeScanner.stopScan(this) // 发起GATT连接 device.connectGatt(this@MainActivity, false, object : BluetoothGattCallback() { override fun onConnectionStateChange(gatt: BluetoothGatt?, status: Int, newState: Int) { super.onConnectionStateChange(gatt, status, newState) if (newState == BluetoothProfile.STATE_CONNECTED) { // 连接成功,发现服务 gatt?.discoverServices() } } override fun onServicesDiscovered(gatt: BluetoothGatt?, status: Int) { super.onServicesDiscovered(gatt, status) if (status == BluetoothGatt.GATT_SUCCESS) { // 获取目标服务和特征 gatt?.getService(targetServiceUuid)?.getCharacteristic(characteristicUuid)?.let { characteristic -> // 写入数据到Server val data = "Hello from Client".toByteArray() characteristic.value = data gatt.writeCharacteristic(characteristic) // 监听特征通知(可选) gatt.setCharacteristicNotification(characteristic, true) val descriptor = characteristic.getDescriptor(UUID.fromString("00002902-0000-1000-8000-00805F9B34FB")) descriptor.value = BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE gatt.writeDescriptor(descriptor) } } } override fun onCharacteristicWrite(gatt: BluetoothGatt?, characteristic: BluetoothGattCharacteristic?, status: Int) { super.onCharacteristicWrite(gatt, characteristic, status) if (status == BluetoothGatt.GATT_SUCCESS) { // 数据写入成功 } } }) } } } )
实用学习资源(无外链)
- 在Stack Overflow搜索关键词「Android GATT client same device peripheral」,能找到大量开发者分享的实战代码、权限踩坑、同一设备通信的特殊处理技巧;
- 安卓开发者社区的官方讨论板块中,有不少开发者分享了同一设备BLE通信的完整实现流程,包含版本兼容、广播优先级等细节;
- 专注安卓BLE开发的技术博客合集里,会分章节讲解GATT Server/Client的搭建,以及同一设备运行时的进程隔离、蓝牙资源冲突解决方法。
内容的提问来源于stack exchange,提问作者Ahmer Iqbal
相关产品推荐
相关产品推荐

