蓝牙权限

要在您的应用中使用蓝牙功能,您必须声明多个权限。您还应指定您的应用是否需要支持经典蓝牙或蓝牙低功耗 (BLE)。如果您的应用不需要经典蓝牙或 BLE,但仍然可以从这些技术中受益,则可以在运行时检查可用性

声明权限

在您的应用中声明的权限集取决于您的应用的目标 SDK 版本。

目标 Android 12 或更高版本

注意:在 Android 8.0(API 级别 26)及更高版本上,配套设备管理器 (CDM) 提供了一种比本节中描述的权限更简化的连接配套设备的方法。CDM 系统代表您的应用提供配对 UI,并且不需要位置权限。

如果您想要更好地控制配对和连接体验,请使用本节中描述的权限。

Bluetooth permissions dialog
系统权限对话框,要求用户授予应用发现、宣传和连接附近设备的权限。

如果您的应用的目标是 Android 12(API 级别 31)或更高版本,请在应用的清单文件中声明以下权限

  1. 如果您的应用查找蓝牙设备(例如 BLE 外设),请声明BLUETOOTH_SCAN 权限。
  2. 如果您的应用使当前设备可被其他蓝牙设备发现,请声明BLUETOOTH_ADVERTISE 权限。
  3. 如果您的应用与已配对的蓝牙设备通信,请声明BLUETOOTH_CONNECT 权限。
  4. 对于您旧的蓝牙相关权限声明,请将android:maxSdkVersion 设置为30。此应用兼容性步骤可帮助系统仅在安装在运行 Android 12 或更高版本的设备上时授予您的应用所需的蓝牙权限。
  5. 如果您的应用使用蓝牙扫描结果来推导出物理位置,请声明ACCESS_FINE_LOCATION 权限。否则,您可以强烈声明您的应用不会推导出物理位置

BLUETOOTH_ADVERTISEBLUETOOTH_CONNECTBLUETOOTH_SCAN 权限是运行时权限。因此,在查找蓝牙设备、使设备可被其他设备发现或与已配对的蓝牙设备通信之前,您必须在应用中显式请求用户批准。当您的应用请求至少其中一个权限时,系统会提示用户允许您的应用访问附近的设备,如图 1 所示。

以下代码片段演示了如何在应用中声明蓝牙相关权限,前提是您的应用面向 Android 12 或更高版本。

<manifest>
    <!-- Request legacy Bluetooth permissions on older devices. -->
    <uses-permission android:name="android.permission.BLUETOOTH"
                     android:maxSdkVersion="30" />
    <uses-permission android:name="android.permission.BLUETOOTH_ADMIN"
                     android:maxSdkVersion="30" />

    <!-- Needed only if your app looks for Bluetooth devices.
         If your app doesn't use Bluetooth scan results to derive physical
         location information, you can
         <a href="#assert-never-for-location">strongly assert that your app
         doesn't derive physical location</a>. -->
    <uses-permission android:name="android.permission.BLUETOOTH_SCAN" />

    <!-- Needed only if your app makes the device discoverable to Bluetooth
         devices. -->
    <uses-permission android:name="android.permission.BLUETOOTH_ADVERTISE" />

    <!-- Needed only if your app communicates with already-paired Bluetooth
         devices. -->
    <uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />

    <!-- Needed only if your app uses Bluetooth scan results to derive physical location. -->
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
    ...
</manifest>

强烈声明您的应用不会推导出物理位置

如果您的应用不使用蓝牙扫描结果来推导出物理位置,您可以强烈声明您的应用绝不会使用蓝牙权限来推导出物理位置。为此,请完成以下步骤

  1. android:usesPermissionFlags属性添加到您的BLUETOOTH_SCAN权限声明中,并将此属性的值设置为neverForLocation

  2. 如果您的应用不需要位置信息,请从应用清单文件中删除ACCESS_FINE_LOCATION权限。

以下代码片段显示了如何更新应用的清单文件

<manifest>
    <!-- Include "neverForLocation" only if you can strongly assert that
         your app never derives physical location from Bluetooth scan results. -->
    <uses-permission android:name="android.permission.BLUETOOTH_SCAN"
                     android:usesPermissionFlags="neverForLocation" />

    <!-- Not needed if you can strongly assert that your app never derives
         physical location from Bluetooth scan results and doesn't need location
         access for any other purpose. -->
    <strike><uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /></strike>
    ...
</manifest>

面向 Android 11 或更低版本

如果您的应用面向 Android 11(API 级别 30)或更低版本,请在应用的清单文件中声明以下权限

  • BLUETOOTH 是执行任何蓝牙经典或 BLE 通信(例如请求连接、接受连接和传输数据)所必需的。
  • ACCESS_FINE_LOCATION 是必需的,因为在 Android 11 及更低版本中,蓝牙扫描可能会被用于收集有关用户位置的信息。

由于位置权限是运行时权限,因此您必须在运行时请求这些权限,并在清单文件中声明它们。

发现本地蓝牙设备

如果希望您的应用启动设备发现或操作蓝牙设置,则必须声明BLUETOOTH_ADMIN权限。大多数应用仅需要此权限才能发现本地蓝牙设备。除非应用是“电源管理器”(在用户请求时修改蓝牙设置),否则不要使用此权限授予的其他功能。在应用的清单文件中声明此权限。例如

<manifest>
...
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
...
</manifest>

如果您的应用支持服务并且可以在 Android 10(API 级别 29)或 Android 11 上运行,则还必须声明ACCESS_BACKGROUND_LOCATION权限才能发现蓝牙设备。有关此要求的更多信息,请参阅在后台访问位置

以下代码片段显示了如何声明ACCESS_BACKGROUND_LOCATION权限

<manifest>
...
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
...
</manifest>

有关声明应用权限的更多信息,请参阅<uses-permission>参考。

指定蓝牙功能的使用

如果蓝牙是应用的关键部分,则可以将标志添加到清单文件中以指示此要求。<uses-feature>元素允许您指定应用使用的硬件类型以及它是否必不可少。

此示例演示了如何指示蓝牙经典功能对于您的应用是必需的。

<uses-feature android:name="android.hardware.bluetooth" android:required="true"/>

如果您的应用依赖于蓝牙低功耗,您可以使用以下内容

<uses-feature android:name="android.hardware.bluetooth_le" android:required="true"/>

如果您声明该功能对于您的应用是必需的,那么 Google Play 商店将对缺少这些功能的设备上的用户隐藏您的应用。因此,只有在您的应用无法在没有该功能的情况下工作时,才应将required属性设置为true

在运行时检查功能可用性

为了使您的应用可用于不支持蓝牙经典或 BLE 的设备,您仍然应该在应用的清单文件中包含<uses-feature>元素,但将required="false"。然后,在运行时,您可以使用PackageManager.hasSystemFeature()确定功能可用性

Kotlin

// Check to see if the Bluetooth classic feature is available.
val bluetoothAvailable = packageManager.hasSystemFeature(PackageManager.FEATURE_BLUETOOTH)

// Check to see if the BLE feature is available.
val bluetoothLEAvailable = packageManager.hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)

Java

// Use this check to determine whether Bluetooth classic is supported on the device.
// Then you can selectively disable BLE-related features.
boolean bluetoothAvailable = getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH);

// Use this check to determine whether BLE is supported on the device. Then
// you can selectively disable BLE-related features.
boolean bluetoothLEAvailable = getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE);