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;