react-native-ble-plx library is not working

54 Views Asked by At

I have used 'react-native-ble-plx' library for connecting my device with other devices using bluetooth. I have followed every step according to the documentation. In android, it is able to scan the devices but cannot connect with them but in IOS, it is not even scanning.

AndroidManifext.xml =>

<manifest xmlns:android="http://schemas.android.com/apk/res/android">

    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-feature android:name="android.hardware.bluetooth_le" android:required="true" />
  <uses-permission android:name="android.permission.BLUETOOTH_SCAN"
                     android:usesPermissionFlags="neverForLocation" />
    <!-- Needed if you want to interact with a BLE device. -->
    <uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
    <!-- Needed if your app makes the current device discoverable to other Bluetooth devices. -->
    <uses-permission android:name="android.permission.BLUETOOTH_ADVERTISE" />
    
    <!-- <uses-sdk
                  android:minSdkVersion="18"
                  android:targetSdkVersion="23"/> -->
    
    <application
      android:name=".MainApplication"
      android:label="@string/app_name"
      android:icon="@mipmap/ic_launcher"
      android:roundIcon="@mipmap/ic_launcher_round"
      android:allowBackup="false"
      android:theme="@style/AppTheme">
      <meta-data
     android:name="com.google.android.geo.API_KEY"
     android:value="" />
      <activity
        android:name=".MainActivity"
        android:label="@string/app_name"
        android:configChanges="keyboard|keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize|uiMode"
        android:launchMode="singleTask"
        android:windowSoftInputMode="adjustResize"
        android:exported="true">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />
            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
      </activity>
    </application>
</manifest>

Build gradle=>

apply plugin: "com.android.application"
apply plugin: "org.jetbrains.kotlin.android"
apply plugin: "com.facebook.react"


react {
}


def jscFlavor = 'org.webkit:android-jsc:+'

android {
    ndkVersion rootProject.ext.ndkVersion
    buildToolsVersion rootProject.ext.buildToolsVersion
    compileSdk rootProject.ext.compileSdkVersion

    namespace "com.busappparentapp"
    defaultConfig {
        applicationId "com.busappparentapp"
        minSdkVersion rootProject.ext.minSdkVersion
        targetSdkVersion rootProject.ext.targetSdkVersion
        versionCode 1
        versionName "1.0"
    }
    signingConfigs {
        debug {
            storeFile file('debug.keystore')
            storePassword 'android'
            keyAlias 'androiddebugkey'
            keyPassword 'android'
        }
    }
    buildTypes {
        debug {
            signingConfig signingConfigs.debug
        }
        release {
            // Caution! In production, you need to generate your own keystore file.
            // see https://reactnative.dev/docs/signed-apk-android.
            signingConfig signingConfigs.debug
            minifyEnabled enableProguardInReleaseBuilds
            proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro"
        }
    }
}

dependencies {
    // The version of react-native is set by the React Native Gradle Plugin
    implementation("com.facebook.react:react-android")
    implementation("com.facebook.react:flipper-integration")
    implementation project(':react-native-splash-screen')
    implementation project(':react-native-ble-plx')

    if (hermesEnabled.toBoolean()) {
        implementation("com.facebook.react:hermes-android")
    } else {
        implementation jscFlavor
    }
}

apply from: file("../../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesAppBuildGradle(project)

Info.plist(IOS)=>


    <key>NSBluetoothAlwaysUsageDescription</key>
    <string>App needs bluetooth access to connect to nearby devices.</string>
    <key>NSBluetoothPeripheralUsageDescription</key>
    <string>App needs bluetooth access to connect to nearby devices.</string>
    

This is my component=>

// BluetoothScanner.js
import React, { useState, useEffect } from 'react';
import { View, Text, Button, FlatList, Platform, PermissionsAndroid, Linking, TouchableOpacity, ScrollView, Alert } from 'react-native';
import { BleManager } from 'react-native-ble-plx'
import { dark_theme, light_theme, theme_color } from '../utilities/colors';
import { useSelector } from 'react-redux';
import { Sidebar_Toggle_Bar } from './Sidebar/Sidebar_Toggle';

const BluetoothScanner = ({ navigation }) => {


  const theme = useSelector(state => state?.themeReducer?.theme);
  const theme_config = theme == 'light' ? light_theme : dark_theme;
  const { text_color, backgroundColor, shadowColor, grey } = theme_config;


  const manager = new BleManager();
  const [devices, setDevices] = useState([]);

  const req_location = async () => {
    if (Platform.OS === 'android' && Platform.Version >= 31) {
      try {
        const granted = await PermissionsAndroid.requestMultiple([
          PermissionsAndroid.PERMISSIONS.BLUETOOTH_SCAN,
          PermissionsAndroid.PERMISSIONS.BLUETOOTH_CONNECT,
          PermissionsAndroid.PERMISSIONS.BLUETOOTH_ADVERTISE,
        ]);
        // Handle the result
        if (
          granted['android.permission.BLUETOOTH_SCAN'] === PermissionsAndroid.RESULTS.GRANTED &&
          granted['android.permission.BLUETOOTH_CONNECT'] === PermissionsAndroid.RESULTS.GRANTED &&
          granted['android.permission.BLUETOOTH_ADVERTISE'] === PermissionsAndroid.RESULTS.GRANTED
        ) {
          console.log('Bluetooth permissions granted');
          scan_devices();
        } else {
          console.log('Bluetooth permissions denied');
        }
      } catch (err) {
        console.warn(err);
      }
    }
  }



  const scan_devices = () => {
    const subscription = manager.startDeviceScan(null, null, (error, device) => {
      if (error) {
        console.error({ error });
        return;
      }
      setDevices(prevDevices => {
        const existingDeviceIndex = prevDevices.findIndex(d => d.id === device.id);
        if (existingDeviceIndex !== -1) {
          // Update existing device
          prevDevices[existingDeviceIndex] = device;



          return [...prevDevices];
        } else {
          // Add new device
          return [...prevDevices, device];
        }
      });
    });

    return () => {
      manager.stopDeviceScan();
      subscription.remove();
    };
  }

  useEffect(() => {
    req_location();
  }, []);

  const connectToDevice = async (deviceId) => {
    try {
      const res = await manager.connectToDevice(deviceId, { autoConnect: true });
      console.log(`Connected to device: ${deviceId}`);
      console.warn({ res });
      // Add your Bluetooth communication logic here
    } catch (error) {
      console.error(`Error connecting to device: ${deviceId}`, error);
    }
  };

  const checkConnection = async (dev_id) => {
    const isConnected = await manager.isDeviceConnected(dev_id);
    console.warn({ isConnected });
    // return isConnected;
  };

  const RenderItem = ({ item }) => {
    return (
      <View
        // key={index}
        style={{
          display: "flex",
          justifyContent: "space-between",
          alignItems: "center",
          flexDirection: "row",
          width: "100%",
          paddingLeft: 15,
          paddingRight: 25,
          paddingVertical: 22,
          borderBottomColor: text_color,
          borderBottomWidth: 0.5
        }}
      >
        <View
          style={{
            display: "flex",
            justifyContent: "start",
            alignItems: "start",
            width: "80%"
          }}
        >
          <Text
            style={{
              fontSize: 18,
              color: text_color,
            }}
          >
            {(item?.name || item?.localName) || 'Unnamed Device'}
          </Text>
          <Text
            style={{
              fontSize: 13,
              color: text_color,
            }}
          >
            {item?.id}
          </Text>
        </View>
        <TouchableOpacity
          onPress={() => {
            checkConnection(item.id);
            // connectToDevice(item.id);
            // console.warn(item);
          }}
        >
          <Text
            style={{
              fontSize: 18,
              color: theme_color,
              textDecorationLine: "underline"
            }}
          >
            Connect
          </Text>
        </TouchableOpacity>
      </View>
    )
  };

  return (
    <>
      <Sidebar_Toggle_Bar
        func={() => {
          navigation.openDrawer();
        }}
        label={'Available Devices'}
      />
      <View
        style={{
          flex: 1,
          backgroundColor,
          padding: 20,
          paddingTop:0
        }}
      >
        <View
          style={{
            flex: 1
          }}
        >
          <FlatList
            data={devices}
            keyExtractor={item => item.id}
            renderItem={({ item }) => (
              <>
                <View
                  // key={index}
                  style={{
                    display: "flex",
                    justifyContent: "space-between",
                    alignItems: "center",
                    flexDirection: "row",
                    width: "100%",
                    paddingLeft: 15,
                    paddingRight: 25,
                    paddingVertical: 22,
                    borderBottomColor: text_color,
                    borderBottomWidth: 0.5
                  }}
                >
                  <View
                    style={{
                      display: "flex",
                      justifyContent: "start",
                      alignItems: "start",
                      width: "80%"
                    }}
                  >
                    <Text
                      style={{
                        fontSize: 18,
                        color: text_color,
                      }}
                    >
                      {(item?.name || item?.localName) || 'Unnamed Device'}
                    </Text>
                    <Text
                      style={{
                        fontSize: 13,
                        color: text_color,
                      }}
                    >
                      {item?.id}
                    </Text>
                  </View>
                  <TouchableOpacity
                    onPress={async () => {
                      // checkConnection(item.id);
                      console.warn('pressed');
                      try {
                        const isConnected = await manager.isDeviceConnected(item.id);
                      console.warn({ isConnected });
                      if (isConnected) {
                        Alert.alert('Already connected!');
                      }
                      else {
                        connectToDevice(item.id);
                      }
                      } catch (error) {
                        console.log('====================================');
                        console.log({error});
                        console.log('====================================');
                      }
                      
                      // console.warn(item);
                    }}
                  >
                    <Text
                      style={{
                        fontSize: 18,
                        color: theme_color,
                        textDecorationLine: "underline"
                      }}
                    >
                      Connect
                    </Text>
                  </TouchableOpacity>
                </View>
              </>
            )}
          />
          {/* <ScrollView>
            {
              devices?.length > 0 &&
              devices.map(async (item, index) => {
                return (
                  <RenderItem item={item} key={index} />
                )
              })
            }
          </ScrollView> */}
        </View>
      </View >
    </>
  );
};

export default BluetoothScanner;

0

There are 0 best solutions below