Nearby Connections 重大变更:不再自动开启 Wi-Fi / 蓝牙,适配指南

7 月 20 日,Android Developers Blog 发了一条 Nearby Connections API 的变更通知。

到 2026 年底以后,Nearby Connections 不会再帮 1P 和 3P 应用自动打开 Wi-Fi / Bluetooth。应用在调用发现、广播和连接前,要自己确认无线开关状态;如果用户关了开关,就要让用户手动打开。

这类变化看起来只影响一个 SDK 行为,实际会改掉很多近场连接功能的失败路径。以前用户点了"搜索附近设备",SDK 可能在背后把需要的无线能力拉起来;后面这个动作要回到应用自己的 UI 和状态机里。

影响

Nearby Connections 是 Google Play services 里的近场 P2P API,用来做附近设备发现、连接和数据交换。它底层会用到 Bluetooth、BLE 和 Wi-Fi,开发者不用自己拼这些无线协议。

常见入口是两个:一台设备调用 startAdvertising() 让自己可被发现,另一台设备调用 startDiscovery() 搜索附近端点。找到端点以后再 requestConnection(),双方接受连接后用 sendPayload() 传 bytes、file 或 stream。

代码大概是这样:

bash 复制代码
private const val SERVICE_ID = "com.example.nearby"
private val STRATEGY = Strategy.P2P_POINT_TO_POINT

fun startDiscovery(context: Context) {
    val options = DiscoveryOptions.Builder()
        .setStrategy(STRATEGY)
        .build()

    Nearby.getConnectionsClient(context)
        .startDiscovery(SERVICE_ID, endpointDiscoveryCallback, options)
        .addOnSuccessListener {
            // 开始发现附近设备
        }
        .addOnFailureListener { error ->
            // 这里要展示明确失败原因,而不是一直停在搜索中
        }
}

这段代码变化在调用它之前。以前很多项目把权限判断放在最前面,权限过了就直接启动发现或广播。后面还要补一个无线开关判断,否则用户关着 Wi-Fi 或 Bluetooth 时,页面可能只会表现成"搜不到设备"。

连接前检查

状态检查不需要写得很复杂,核心是把"权限没给"和"开关没开"分成两个 UI 状态。权限没给,走运行时权限;开关没开,走系统设置面板或系统设置页。

一个简单的状态对象可以这样写:

bash 复制代码
data class NearbyRadioState(
    val wifiEnabled: Boolean,
    val bluetoothEnabled: Boolean,
) {
    val disabledItems: List<String>
        get() = buildList {
            if (!wifiEnabled) add("Wi-Fi")
            if (!bluetoothEnabled) add("Bluetooth")
        }
}

fun Context.nearbyRadioState(): NearbyRadioState {
    val wifiManager = getSystemService(WifiManager::class.java)
    val bluetoothManager = getSystemService(BluetoothManager::class.java)
    val adapter = bluetoothManager.adapter

    return NearbyRadioState(
        wifiEnabled = wifiManager.isWifiEnabled,
        bluetoothEnabled = adapter?.isEnabled == true,
    )
}

这里没有去调用 setWifiEnabled(true)BluetoothAdapter.enable()。原因也很直接:面向新系统和新 target 的普通应用,已经不能靠这两个 API 静默打开无线开关。

WifiManager.setWifiEnabled() 从 Android 10 开始对 target Q 及以上应用会失败并返回 falseBluetoothAdapter.enable() 从 Android 13 开始对 target TIRAMISU 及以上应用也会失败并返回 false。设备管理器、Profile Owner、系统应用有豁免,普通业务 App 不应该把它当兜底方案。

引导用户打开

Wi-Fi 这边可以优先用 Settings Panel。它是 Android 10 加的浮层设置入口,Settings.Panel.ACTION_WIFI 会展示包含 Wi-Fi 控件的系统面板,用户处理完以后回到当前 App。

Bluetooth 没有同样的通用 Panel 常量,通常跳到蓝牙设置页:

bash 复制代码
fun Activity.openWifiSettings() {
    val intent = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
        Intent(Settings.Panel.ACTION_WIFI)
    } else {
        Intent(Settings.ACTION_WIFI_SETTINGS)
    }
    startActivity(intent)
}

fun Activity.openBluetoothSettings() {
    startActivity(Intent(Settings.ACTION_BLUETOOTH_SETTINGS))
}

页面文案不要写成"应用正在打开蓝牙"。更准确的表达是"需要打开 Bluetooth 才能搜索附近设备",然后给一个跳转设置的按钮。用户从设置页回来以后,重新读取 nearbyRadioState(),状态满足再调用 Nearby Connections。

如果两个开关都关着,不建议连续弹两个系统页面。先在业务页把缺失项列出来,让用户知道为什么不能继续。点"去设置"以后,可以先处理 Wi-Fi,再让用户处理 Bluetooth;也可以放两个明确按钮,避免用户在系统设置里来回找。

权限别混在一起

Nearby Connections 的权限声明这些年已经变得比较碎。老版本里会看到 ACCESS_WIFI_STATECHANGE_WIFI_STATEBLUETOOTHBLUETOOTH_ADMIN,Android 12 以后又有 BLUETOOTH_ADVERTISEBLUETOOTH_CONNECTBLUETOOTH_SCAN,Android 13 以后还会碰到 NEARBY_WIFI_DEVICES

如果项目 target 到 Android 17,并且使用 WIFI_LAN,文档里还列了 ACCESS_LOCAL_NETWORK。这类权限要按项目的 SDK、策略和 payload 类型裁剪,不能直接拿旧 Manifest 混过去。

示例可以先写成这样,再按项目实际入口收敛:

bash 复制代码
<!-- Nearby Connections: legacy permissions -->
<uses-permission
    android:name="android.permission.ACCESS_WIFI_STATE"
    android:maxSdkVersion="31" />
<uses-permission
    android:name="android.permission.CHANGE_WIFI_STATE"
    android:maxSdkVersion="31" />
<uses-permission
    android:name="android.permission.BLUETOOTH"
    android:maxSdkVersion="30" />
<uses-permission
    android:name="android.permission.BLUETOOTH_ADMIN"
    android:maxSdkVersion="30" />

<!-- Android 12+ Bluetooth runtime permissions -->
<uses-permission
    android:name="android.permission.BLUETOOTH_ADVERTISE"
    android:minSdkVersion="31" />
<uses-permission
    android:name="android.permission.BLUETOOTH_CONNECT"
    android:minSdkVersion="31" />
<uses-permission
    android:name="android.permission.BLUETOOTH_SCAN"
    android:minSdkVersion="31" />

<!-- Android 13+ nearby Wi-Fi permission -->
<uses-permission android:name="android.permission.NEARBY_WIFI_DEVICES" />

这里要分清两件事:权限允许 App 使用相关能力,开关状态决定设备当前是否能执行对应无线动作。用户同意了蓝牙权限,但系统蓝牙开关是关的,Nearby Connections 仍然不能按预期发现和连接。

失败状态

这次变化最容易漏的是失败展示。很多"搜索附近设备"的页面只有 loading 和空列表,用户看到的是一直转圈,开发者日志里才有失败异常。无线开关不再自动打开以后,这种 UI 会更容易出问题。

我会把启动发现拆成三个判断:运行时权限、无线开关、Nearby 调用结果。前两个是同步的业务状态,最后一个才是 SDK 返回。

bash 复制代码
fun startNearbyDiscovery(context: Context) {
    if (!hasNearbyPermissions(context)) {
        showPermissionRequest()
        return
    }

    val radioState = context.nearbyRadioState()
    if (radioState.disabledItems.isNotEmpty()) {
        showRadioDisabled(radioState.disabledItems)
        return
    }

    Nearby.getConnectionsClient(context)
        .startDiscovery(SERVICE_ID, endpointDiscoveryCallback, discoveryOptions)
        .addOnFailureListener { error ->
            showNearbyError(error)
        }
}

showRadioDisabled() 里不要只给一句"连接失败"。更有用的是把缺失项写出来,例如"打开 Wi-Fi 后再搜索附近设备"。用户打开设置返回 App 后,页面重新检查状态;如果状态还没变,就继续停在引导页,不要立刻进入搜索 loading。

还有一个细节是恢复流程。Activity 回到前台时重新读一次无线状态,连接页从 RadioDisabled 切到 Ready 后再启动发现。不要只依赖设置页返回结果,因为系统设置页通常不会给业务 App 返回"用户确实打开了开关"的强语义结果。

最后

Nearby Connections 后面不会再替应用自动打开 Wi-Fi / Bluetooth。调用 startAdvertising()startDiscovery() 前,把运行时权限和无线开关分开检查;缺开关时引导用户到系统设置,回来后重新读状态。

这个改动不需要重写 Nearby Connections 连接流程,但会影响搜索页、配网页、面对面传输、本地多人游戏这类入口的失败处理。

#Android #NearbyConnections #GooglePlayServices #Android开发

相关推荐
恋猫de小郭2 小时前
Flutter 全新真 3D 实现,用 flutter_scene 能开发一个「我的世界」
android·前端·flutter
HLC++15 小时前
Linux的进程间通信
android·linux·服务器
爱笑鱼19 小时前
Binder(二):AIDL 生成的 Proxy、Stub 和 Parcel 到底在做什么?
android
爱笑鱼19 小时前
Binder(一):一次方法调用,究竟怎样跨进程执行?
android
壮哥_icon20 小时前
【Android 系统开发】使用 BAT 脚本高效自动化管理 /system/priv-app/ 系统应用(安装与卸载)
android·运维·自动化
用户69371750013841 天前
Claude Code终端日志Token占用实测:一个过滤器砍掉60%-90%
android·前端·后端
蝉蜕日记1 天前
AccumuPDF高级版 v2.57 | 视图文转换PDF,合并分割压缩
android·智能手机·pdf·生活·软件需求
吐了啊取名字太难1 天前
美颜系统AI修图本地跑并支持Mac、win、安卓、iOS不卡顿
android·人工智能·windows·数码相机·mac·ai编程
阿pin1 天前
Android随笔-Retrofit
android·retrofit