如何将Android设备配置为BLE设备,使其可被其他设备检测?
兄弟,我来帮你搞定把Android设备变成BLE外设的问题——之前你做的是中心设备(搜索连接其他BLE设备),现在要转成外设模式让其他设备发现你,其实Android从API 21(Android 5.0)开始就支持这个功能了,我给你一步步拆解,连常见坑都给你列出来:
先确认前提条件
- 你的Android设备必须运行Android 5.0(API 21)及以上,这是BLE外设模式的最低系统要求。
- 部分低端设备可能硬件不支持该模式,先通过代码确认:
val bluetoothAdapter = (getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager).adapter if (!bluetoothAdapter.isMultipleAdvertisementSupported) { Toast.makeText(this, "当前设备不支持BLE外设模式", Toast.LENGTH_SHORT).show() return }
步骤1:配置权限
根据Android版本不同,权限要求有差异,先在AndroidManifest.xml里添加基础权限:
<!-- 基础BLE权限(Android 11及以下) --> <uses-permission android:name="android.permission.BLUETOOTH" android:maxSdkVersion="30" /> <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" android:maxSdkVersion="30" /> <!-- Android 12+ 外设模式核心权限 --> <uses-permission android:name="android.permission.BLUETOOTH_ADVERTISE" /> <uses-permission android:name="android.permission.BLUETOOTH_CONNECT" /> <!-- 定位权限(Android 10及以下扫描需要,部分设备外设模式也要求) --> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" android:maxSdkVersion="30" /> <uses-feature android:name="android.hardware.bluetooth_le" android:required="true" />
Android 12+需要动态申请BLUETOOTH_ADVERTISE和BLUETOOTH_CONNECT权限:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { val permissions = arrayOf( Manifest.permission.BLUETOOTH_ADVERTISE, Manifest.permission.BLUETOOTH_CONNECT ) if (ContextCompat.checkSelfPermission(this, permissions[0]) != PackageManager.PERMISSION_GRANTED) { ActivityCompat.requestPermissions(this, permissions, 1001) } }
步骤2:初始化BLE外设核心组件
你需要用到BluetoothLeAdvertiser(负责广播)和BluetoothGattServer(处理设备连接、读写请求):
val bluetoothManager = getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager val bluetoothAdapter = bluetoothManager.adapter // 获取广播器 val advertiser = bluetoothAdapter.bluetoothLeAdvertiser ?: run { Toast.makeText(this, "无法获取BLE广播组件", Toast.LENGTH_SHORT).show() return }
步骤3:创建GATT服务与特征
外设需要提供可被中心设备读写的服务和特征,这是BLE通信的核心载体:
// 自定义服务和特征的UUID(可以自己生成,也用通用UUID) val SERVICE_UUID = UUID.fromString("0000FFE0-0000-1000-8000-00805F9B34FB") val CHAR_UUID = UUID.fromString("0000FFE1-0000-1000-8000-00805F9B34FB") // 创建主服务 val gattService = BluetoothGattService(SERVICE_UUID, BluetoothGattService.SERVICE_TYPE_PRIMARY) // 创建特征:支持读、写、通知 val gattChar = BluetoothGattCharacteristic( CHAR_UUID, BluetoothGattCharacteristic.PROPERTY_READ or BluetoothGattCharacteristic.PROPERTY_WRITE or BluetoothGattCharacteristic.PROPERTY_NOTIFY, BluetoothGattCharacteristic.PERMISSION_READ or BluetoothGattCharacteristic.PERMISSION_WRITE ) gattService.addCharacteristic(gattChar) // 启动GattServer,处理连接和读写事件 val gattServer = bluetoothManager.openGattServer(this, object : BluetoothGattServerCallback() { override fun onConnectionStateChange(device: BluetoothDevice?, status: Int, newState: Int) { super.onConnectionStateChange(device, status, newState) when(newState) { BluetoothProfile.STATE_CONNECTED -> Log.d("BLE外设", "已连接设备: ${device?.name}") BluetoothProfile.STATE_DISCONNECTED -> Log.d("BLE外设", "设备已断开") } } override fun onCharacteristicReadRequest(device: BluetoothDevice?, requestId: Int, offset: Int, characteristic: BluetoothGattCharacteristic?) { super.onCharacteristicReadRequest(device, requestId, offset, characteristic) // 返回特征数据给请求设备 gattServer.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, offset, characteristic?.value) } 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 { Log.d("BLE外设", "收到数据: ${String(it)}") } if (responseNeeded) { gattServer.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, offset, null) } } }) // 将服务添加到GattServer gattServer.addService(gattService)
步骤4:启动BLE广播
配置广播参数和数据,让其他设备能发现你的设备:
// 广播设置:低功耗模式,允许连接,持续广播 val advertiseSettings = AdvertiseSettings.Builder() .setAdvertiseMode(AdvertiseSettings.ADVERTISE_MODE_LOW_POWER) .setTxPowerLevel(AdvertiseSettings.ADVERTISE_TX_POWER_MEDIUM) .setConnectable(true) .setTimeout(0) // 0表示无限广播 .build() // 广播数据:包含设备名称和服务UUID(让中心设备知道你提供的服务) val advertiseData = AdvertiseData.Builder() .setIncludeDeviceName(true) .addServiceUuid(ParcelUuid(SERVICE_UUID)) .build() // 启动广播 advertiser.startAdvertising(advertiseSettings, advertiseData, object : AdvertiseCallback() { override fun onStartSuccess(settingsInEffect: AdvertiseSettings?) { super.onStartSuccess(settingsInEffect) Log.d("BLE外设", "广播启动成功") } override fun onStartFailure(errorCode: Int) { super.onStartFailure(errorCode) val errorMsg = when(errorCode) { ADVERTISE_FAILED_ALREADY_STARTED -> "广播已启动" ADVERTISE_FAILED_DATA_TOO_LARGE -> "广播数据过大(超过31字节)" ADVERTISE_FAILED_FEATURE_UNSUPPORTED -> "设备不支持该广播特性" ADVERTISE_FAILED_INTERNAL_ERROR -> "系统内部错误" ADVERTISE_FAILED_TOO_MANY_ADVERTISERS -> 当前环境广播设备过多" else -> "未知错误: $errorCode" } Log.e("BLE外设", "广播启动失败: $errorMsg") } })
常见问题排查
- 其他设备搜不到你的设备:
- 检查权限是否申请成功,特别是Android 12+的
BLUETOOTH_ADVERTISE权限。 - 广播数据不要超过31字节,比如设备名称过长会导致广播失败。
- 确认
setConnectable(true)已设置,否则中心设备可能无法发现。
- 检查权限是否申请成功,特别是Android 12+的
- 能发现但无法连接:
- 检查GattServer是否正确添加了服务,回调是否正常工作。
- 部分设备需要开启定位才能扫描BLE设备,让测试设备打开定位试试。
- 广播启动失败:
- 根据
onStartFailure的错误码针对性排查,比如ADVERTISE_FAILED_TOO_MANY_ADVERTISERS可以换个环境试试。
- 根据
内容的提问来源于stack exchange,提问作者Grigoriy Park
相关产品推荐
相关产品推荐

