蓝牙权限

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

声明权限

您在应用中声明的权限集取决于您应用的 target 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 权限。否则,您可以明确声明您的应用不会推断物理位置,并将 ACCESS_FINE_LOCATION 权限的 android:maxSdkVersion 设置为 30。

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" />

    <!-- Set maxSdkVersion to 30 if you can strongly assert that, on
         Android 12 and higher, your app never derives physical location from
         Bluetooth scan results and doesn't need location access for any other
         purpose. -->
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"
                     android:maxSdkVersion="30" />
    ...
</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);