Bluetooth の権限

アプリで Bluetooth 機能を使用するには、複数の権限を宣言する必要があります。また、アプリで Bluetooth クラシックと Bluetooth Low Energy(BLE)のどちらのサポートが必要かを指定する必要があります。アプリで Bluetooth クラシックや BLE は必要ないものの、これらの技術のメリットを活用できる場合は、実行時に利用可能かどうかを確認できます。

権限を宣言する

アプリで宣言する権限のセットは、アプリのターゲット SDK バージョンによって異なります。

Android 12 以降をターゲットとする

注: Android 8.0(API レベル 26)以降では、コンパニオン デバイス マネージャー(CDM)を使用すると、このセクションで説明する権限よりも効率よくコンパニオン デバイスに接続できます。CDM システムはアプリに代わってペア設定 UI を提供します。位置情報の利用許可は必要ありません。

ペア設定と接続の操作性を細かく制御する場合は、このセクションで説明する権限を使用します。

Bluetooth の権限ダイアログ
付近のデバイスの検出、アドバタイズ、接続を行う権限をアプリに付与するよう求めるシステム権限ダイアログ。

アプリが Android 12(API レベル 31)以上をターゲットとしている場合は、アプリのマニフェスト ファイルで次の権限を宣言します。

  1. BLE 周辺機器など、アプリが Bluetooth デバイスを探す場合は、BLUETOOTH_SCAN 権限を申告します。
  2. アプリが現在のデバイスを他の Bluetooth デバイスから検出可能にする場合は、BLUETOOTH_ADVERTISE 権限を宣言します。
  3. アプリがすでにペア設定されている Bluetooth デバイスと通信する場合は、BLUETOOTH_CONNECT 権限を宣言します。
  4. Bluetooth 関連の従来の権限宣言では、android:maxSdkVersion を 30 に設定します。アプリの互換性に関するこのステップでは、Android 12 以降を搭載したデバイスにインストールされた場合、アプリに必要な Bluetooth 権限のみが付与されます。
  5. アプリが Bluetooth スキャン結果を使用して物理的な位置情報を取得する場合は、ACCESS_FINE_LOCATION 権限を宣言します。それ以外の場合は、アプリが物理的な位置情報を取得しないことを強く表明し、ACCESS_FINE_LOCATION 権限の android:maxSdkVersion を 30 に設定します。

BLUETOOTH_ADVERTISEBLUETOOTH_CONNECTBLUETOOTH_SCAN の各権限は実行時の権限です。そのため、Bluetooth デバイスを探す、デバイスを他のデバイスから検出可能にする、またはすでにペア設定されている Bluetooth デバイスと通信する前に、アプリで明示的にユーザーの承認をリクエストする必要があります。アプリがこれらの権限の少なくとも 1 つをリクエストすると、図 1 に示すように、アプリが付近のデバイスにアクセスすることを許可するよう求めるプロンプトが表示されます。

次のコード スニペットは、アプリが Android 12 以降をターゲットとしている場合に、アプリで Bluetooth 関連の権限を宣言する方法を示しています。

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

アプリが物理的な位置情報を取得しないことを強く表明する

アプリが Bluetooth スキャン結果を使用して物理的な位置情報を取得しない場合は、アプリが物理的な位置情報を取得するために Bluetooth 権限を使用することはないという旨を強く主張できます。そのための手順は次のとおりです。

  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 は、接続のリクエスト、接続の承認、データ転送など、Bluetooth クラシックまたは BLE 通信を実行するために必要です。
  • Android 11 以前では、Bluetooth スキャンを使用してユーザーの位置情報に関する情報を収集できる可能性があるため、ACCESS_FINE_LOCATION が必要です。

位置情報の利用許可は実行時の権限であるため、マニフェストで宣言するとともに、実行時にこれらの権限をリクエストする必要があります。

ローカルの Bluetooth デバイスを検出する

アプリでデバイスの検出を開始したり、Bluetooth の設定を操作したりするには、BLUETOOTH_ADMIN 権限を宣言する必要があります。ほとんどのアプリは、ローカル Bluetooth デバイスを検出するためだけにこの権限が必要です。アプリがユーザーのリクエストに応じて Bluetooth 設定を変更する「電源管理アプリ」でない限り、この権限によって付与される他の機能は使用しないでください。アプリのマニフェスト ファイルで権限を宣言します。次に例を示します。

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

アプリがサービスをサポートし、Android 10(API レベル 29)または Android 11 で実行できる場合は、Bluetooth デバイスを検出するための ACCESS_BACKGROUND_LOCATION 権限も宣言する必要があります。この要件について詳しくは、バックグラウンドでの位置情報へのアクセスをご覧ください。

次のコード スニペットは、ACCESS_BACKGROUND_LOCATION 権限を宣言する方法を示しています。

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

アプリの権限の宣言について詳しくは、<uses-permission> リファレンスをご覧ください。

Bluetooth 機能の使用を指定

Bluetooth がアプリの重要な要素である場合は、この要件を示すフラグをマニフェスト ファイルに追加できます。<uses-feature> 要素を使用すると、アプリで使用するハードウェアのタイプと、そのハードウェアが必須かどうかを指定できます。

次の例は、アプリに Bluetooth クラシックが必要であることを示す方法を示しています。

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

アプリが Bluetooth Low Energy に依存している場合は、以下を使用できます。

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

アプリに必要な機能として宣言すると、その機能が搭載されていないデバイスのユーザーには Google Play ストアでアプリが表示されなくなります。そのため、必須属性を true に設定するのは、その機能がないとアプリが動作しない場合に限ってください。

実行時に機能の可用性を確認する

Bluetooth クラシックまたは 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);