You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何基于近距离即时连接两台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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.02 07:20:11