Why Android asks for Bluetooth permissions
Bluetooth lets an app find, identify and talk to devices around the user, and Android treats that as sensitive. An app declares the Bluetooth permissions it needs in its manifest, and some of them must also be granted by the user while the app runs. Which ones depends on the Android version the app targets, and the rules changed sharply with Android 12 (API level 31).
The app can also state whether it needs Bluetooth at all. Declaring android.hardware.bluetooth_le with required="true" hides the app on Google Play from devices without Bluetooth LE. With required="false", the app installs everywhere and checks for the feature at runtime with PackageManager.hasSystemFeature().
Android 12 and higher: three permissions
An app that targets Android 12 or higher declares one permission per kind of Bluetooth activity:
| Permission | What it covers |
|---|---|
BLUETOOTH_SCAN | Looking for Bluetooth devices, such as BLE peripherals |
BLUETOOTH_ADVERTISE | Making this device discoverable to other Bluetooth devices |
BLUETOOTH_CONNECT | Communicating with Bluetooth devices that are already paired |
All three are runtime permissions. The app must ask the user before it scans, advertises or communicates, and when it requests any of them the system shows a single prompt to allow access to Nearby devices.
An app that only connects to an accessory may need just BLUETOOTH_SCAN and BLUETOOTH_CONNECT. An app that links two phones runs both BLE roles, scanning on one side and advertising on the other, so it asks for all three.
Android’s guide also says to keep the legacy BLUETOOTH and BLUETOOTH_ADMIN declarations for older devices but cap them with android:maxSdkVersion="30", so that Android 12 and higher grant only the new permissions.
Location and neverForLocation
Before Android 12, scanning for Bluetooth devices required the location permission. Android’s reasoning is that on Android 11 and lower a Bluetooth scan could be used to gather information about the user’s location. So an app targeting Android 11 or lower declares BLUETOOTH, BLUETOOTH_ADMIN (to start device discovery) and ACCESS_FINE_LOCATION, and requests the location permission at runtime. An app with a service that can run on Android 10 or 11 must also declare ACCESS_BACKGROUND_LOCATION to discover Bluetooth devices.
From Android 12, location is needed only if the app uses Bluetooth scan results to derive physical location. An app that does not can say so firmly:
- Add
android:usesPermissionFlags="neverForLocation"to itsBLUETOOTH_SCANdeclaration. - Remove
ACCESS_FINE_LOCATION, or setandroid:maxSdkVersion="30"on it so it still applies to older devices.
The assertion has a cost. Android notes that with neverForLocation, some BLE beacons are filtered from scan results, and the BluetoothLeScanner reference says it may restrict the types of devices the app can interact with. An app that works with BLE beacons should check that the beacons it needs still appear.
Background work and foreground services
Permissions decide what an app may do. Android’s background rules decide when. A BLE app that has to keep scanning, advertising or holding connections while the user is in another app usually runs a foreground service, which shows a status bar notification so the user knows the work is happening.
- Declare the type. For apps targeting API level 34 or higher, each foreground service is declared with an
android:foregroundServiceType, and starting one whose type is not declared throwsMissingForegroundServiceTypeException. Bluetooth work usesconnectedDevice, with theFOREGROUND_SERVICE_CONNECTED_DEVICEpermission. - Hold a Bluetooth permission first. A
connectedDeviceservice has a runtime prerequisite, which Bluetooth apps meet by being granted at least one ofBLUETOOTH_CONNECT,BLUETOOTH_ADVERTISEorBLUETOOTH_SCAN. - Ask to post notifications. From Android 13,
POST_NOTIFICATIONSis a runtime permission. An app does not need it to start a foreground service, but if the user denies it, the service’s notice appears only in the Task Manager, not in the notification drawer. - Filter scans. The
BluetoothLeScannerreference says unfiltered scans stop when the screen turns off and resume when it turns on. A scan with aScanFilteravoids this. - Declare it in Play Console. Apps targeting Android 14 or higher also declare their foreground service types in the Play Console.
Android’s background BLE guide adds one more option: calling startScan() with a PendingIntent lets the system wake the app when a matching device is seen, instead of keeping the process alive to scan.
Putting it together
For an app that links two phones over BLE, the usual checklist is:
- Declare the three Android 12 permissions, with
neverForLocationonBLUETOOTH_SCANif the app never derives location. - Keep
BLUETOOTH,BLUETOOTH_ADMINandACCESS_FINE_LOCATIONcapped atmaxSdkVersion="30"for older devices. - At runtime, request the Nearby devices permissions on Android 12 and higher, or location on Android 11 and lower, plus notifications on Android 13 and higher.
- Declare a
connectedDeviceforeground service if the link must survive the app leaving the screen.
Offline Protocol’s React Native mesh SDK is a concrete example: its installation guide says the SDK’s own manifest declares the Bluetooth and foreground service permissions, while the app adds location for Android 11 and lower and POST_NOTIFICATIONS, and must request the runtime permissions itself, because the SDK checks them but never asks. iOS works differently, and Can a BLE app run in the background on iOS? covers that side.