如何基于近距离即时连接两台Android设备?APP近邻提醒技术咨询
Android BLE近邻提醒功能实现指引
核心方案确认
你的判断是对的:应用需要同时作为BLE广播端和扫描端,无需依赖GATT服务器就能完成基础的近邻检测(GATT用于后续数据传输,非必要)。
广播与扫描同时实现步骤
1. 权限配置
在AndroidManifest.xml中添加必要权限:
<!-- Android 12+ 蓝牙核心权限 --> <uses-permission android:name="android.permission.BLUETOOTH_ADVERTISE" /> <uses-permission android:name="android.permission.BLUETOOTH_SCAN" /> <uses-permission android:name="android.permission.BLUETOOTH_CONNECT" /> <!-- BLE扫描依赖的位置权限 --> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> <uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" android:maxSdkVersion="32" /> <!-- 声明BLE硬件依赖 --> <uses-feature android:name="android.hardware.bluetooth_le" android:required="true" />
注意:需动态申请权限,处理位置权限和蓝牙权限的用户弹窗请求。
2. BLE广播端实现
使用BluetoothLeAdvertiser发送自定义广播,用唯一Service UUID标识同APP设备:
val bluetoothAdapter = BluetoothAdapter.getDefaultAdapter() val advertiser = bluetoothAdapter.bluetoothLeAdvertiser ?: return // 广播配置:低功耗模式适配后台运行 val advertiseSettings = AdvertiseSettings.Builder() .setAdvertiseMode(AdvertiseSettings.ADVERTISE_MODE_LOW_POWER) .setTxPowerLevel(AdvertiseSettings.ADVERTISE_TX_POWER_LOW) .setConnectable(false) // 仅广播设备存在,无需建立连接 .build() // 广播数据:携带自定义服务UUID val serviceUuid = UUID.fromString("你的唯一服务UUID") val advertiseData = AdvertiseData.Builder() .addServiceUuid(ParcelUuid(serviceUuid)) .build() // 启动广播 advertiser.startAdvertising(advertiseSettings, advertiseData, advertiseCallback)
3. BLE扫描端实现
使用BluetoothLeScanner过滤匹配目标Service UUID的设备,检测到后触发通知:
val scanner = bluetoothAdapter.bluetoothLeScanner ?: return // 扫描过滤:仅接收同APP的广播 val scanFilter = ScanFilter.Builder() .setServiceUuid(ParcelUuid(serviceUuid)) .build() // 扫描配置:后台用低功耗模式,前台可切换为低延迟 val scanSettings = ScanSettings.Builder() .setScanMode(ScanSettings.SCAN_MODE_LOW_POWER) .build() // 启动扫描 scanner.startScan(listOf(scanFilter), scanSettings, scanCallback)
在ScanCallback中处理检测结果:
val scanCallback = object : ScanCallback() { override fun onScanResult(callbackType: Int, result: ScanResult) { super.onScanResult(callbackType, result) // 检测到同APP设备,触发即时通知 showNearbyAlertNotification() } }
4. 同时运行广播与扫描
广播和扫描是独立的BLE API,可在同一个前台服务的线程中并行启动,只要蓝牙处于开启状态且权限齐全,就能同时运行。
持续运行的保障方案
1. 前台服务
必须使用前台服务避免被系统后台杀死:
- 创建前台服务,在
onStartCommand中启动广播和扫描 - 显示持续通知(如"正在进行近邻检测"),符合Android前台服务规范
2. 电池优化豁免
引导用户将应用加入电池优化白名单,防止系统休眠蓝牙模块:
val intent = Intent(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS) intent.data = Uri.parse("package:${context.packageName}") startActivity(intent)
3. 开机自启动(可选)
注册BOOT_COMPLETED广播接收器,开机后自动启动前台服务:
<receiver android:name=".BootCompletedReceiver"> <intent-filter> <action android:name="android.intent.action.BOOT_COMPLETED" /> </intent-filter> </receiver>
GATT服务器的角色补充
基础近邻检测不需要GATT服务器。如果需要传输额外信息(如用户标识),可在扫描到设备后发起GATT连接:
- 一方作为GATT服务器,提供自定义服务和特征
- 另一方作为GATT客户端,连接后读取数据
但此步骤属于功能扩展,非近邻提醒的核心需求。
关键注意事项
- 蓝牙状态监听:注册
BluetoothAdapter.ACTION_STATE_CHANGED广播,蓝牙关闭时重新启动广播/扫描 - 扫描频率控制:后台扫描使用
SCAN_MODE_LOW_POWER,避免过度耗电 - 设备标识:Android 10+限制获取蓝牙MAC,可在广播数据中携带自定义随机UUID作为设备唯一标识
- 通知渠道:Android 8+需提前创建通知渠道才能发送通知
内容的提问来源于stack exchange,提问作者Hasan
相关产品推荐
相关产品推荐

