Search code examples
androidreact-nativebluetoothbluetooth-lowenergy

React native Android Manifest permission setting with BLE


I would using the react native to develop the mobile application
I need to using the application to connect the Bluetooth Low Energy (BLE)

I has some question about the Android permission setting on the AndroidManifest.xml and react native

  1. If I have a old device, such as xiaomi mobile is running Android 10 (sdk 28 or sdk 29), do it is allow to use the bluetooth function or not ? I need to set the android:maxSdkVersion="30" to lower?

  2. Would any new permission are needed with Android 13 for the BLE.

I added the use permission on AndroidManifest.xml,

<uses-permission android:name="android.permission.BLUETOOTH" android:maxSdkVersion="30" />
    <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" android:maxSdkVersion="30" />

    
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>

    <uses-permission android:name="android.permission.BLUETOOTH_CONNECT"
        android:usesPermissionFlags="neverForLocation"
        tools:targetApi="s" />

    <!-- Needed only if your app looks for Bluetooth devices. -->
    <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" />
    <uses-permission android:name="android.permission.ACCESS_BLUETOOTH_ADMIN" />
    <uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />

On the other hand, I would added a checking when I scan the device

  requestPermissionBluetoothConnectAndroid = async () => {
    const status = await PermissionsAndroid.request(
      PermissionsAndroid.PERMISSIONS.BLUETOOTH_CONNECT,
    );

    if (status === PermissionsAndroid.RESULTS.GRANTED) {
      return true;
    }

    if (status === PermissionsAndroid.RESULTS.DENIED) {
      ToastAndroid.show(
        'Location permission denied by user.',
        ToastAndroid.LONG,
      );
    } else if (status === PermissionsAndroid.RESULTS.NEVER_ASK_AGAIN) {
      ToastAndroid.show(
        'Location permission revoked by user.',
        ToastAndroid.LONG,
      );
    }
  };

However, the application would be crashed when I scan the BLE devices


Solution

  • Bluetooth Scan permission must also be obtained from the user. I think this might be the reason why you are getting the error.

    You must obtain Bluetooth and location permissions from the user as follows and check them before each scan;

    const handleAndroidPermissionCheck = async (cb: (granted: boolean) => void) => {
      if (Platform.OS === 'android') {
        try {
          const fineLocationPermission = await PermissionsAndroid.request(
            PermissionsAndroid.PERMISSIONS.ACCESS_FINE_LOCATION,
          );
    
          const bluetoothPermissions = await PermissionsAndroid.requestMultiple([
            PermissionsAndroid.PERMISSIONS.BLUETOOTH_SCAN,
            PermissionsAndroid.PERMISSIONS.BLUETOOTH_CONNECT,
          ]);
    
          const allPermissionsGranted = 
            fineLocationPermission === PermissionsAndroid.RESULTS.GRANTED &&
            bluetoothPermissions[PermissionsAndroid.PERMISSIONS.BLUETOOTH_SCAN] === PermissionsAndroid.RESULTS.GRANTED &&
            bluetoothPermissions[PermissionsAndroid.PERMISSIONS.BLUETOOTH_CONNECT] === PermissionsAndroid.RESULTS.GRANTED;
    
          cb(allPermissionsGranted);
        } catch (error) {
          cb(false);
        }
      } else {
        cb(true);
      }
    };
    
    const startScan = () => {
      handleAndroidPermissionCheck((granted) => {
        if (granted) {
          try {
            BleManager.scan([SERVICE_UUID], seconds, false)
              .then(() => {
                console.log('Scan started successfully');
              })
              .catch((error) => {
                console.error('Scan failed', error);
              });
          } catch (error) {
            console.error('Error scan', error);
          }
        } else {
          console.log('Permissions not granted');
        }
      });
    };
    

    AndroidManifest should look like this;

    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
    <uses-permission android:name="android.permission.BLUETOOTH" />
    <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
    <uses-permission android:name="android.permission.BLUETOOTH_SCAN" />
    <uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
    <uses-feature android:name="android.hardware.bluetooth_le" android:required="true" />
    

    My build gradle is like this;

    buildToolsVersion = "33.0.0"
    minSdkVersion = 23
    compileSdkVersion = 33
    targetSdkVersion = 33