react-native-ble-nitro
Version:
High-performance React Native BLE library built on Nitro Modules - drop-in replacement for react-native-ble-plx
88 lines (87 loc) • 4.07 kB
JavaScript
import { AndroidConfig, WarningAggregator, withAndroidManifest, withInfoPlist, } from 'expo/config-plugins';
const BLUETOOTH_PERMISSIONS = [
'android.permission.BLUETOOTH',
'android.permission.BLUETOOTH_ADMIN',
'android.permission.ACCESS_COARSE_LOCATION',
'android.permission.ACCESS_FINE_LOCATION',
];
const BLUETOOTH_PERMISSIONS_API_31 = [
'android.permission.BLUETOOTH_SCAN',
'android.permission.BLUETOOTH_ADVERTISE',
'android.permission.BLUETOOTH_CONNECT',
];
export const withBleNitroAndroid = (config, props = {}) => {
const { isBackgroundEnabled = false, neverForLocation = false } = props;
return withAndroidManifest(config, (config) => {
const androidManifest = config.modResults;
// Add required permissions
AndroidConfig.Permissions.ensurePermissions(config.modResults, [
...BLUETOOTH_PERMISSIONS,
...BLUETOOTH_PERMISSIONS_API_31,
]);
// Add uses-feature for BLE
if (!androidManifest.manifest['uses-feature']) {
androidManifest.manifest['uses-feature'] = [];
}
const usesFeatures = androidManifest.manifest['uses-feature'];
// Add BLE feature requirement
const bleFeature = {
$: {
'android:name': 'android.hardware.bluetooth_le',
'android:required': (isBackgroundEnabled ? 'true' : 'false'),
},
};
if (!usesFeatures.find((f) => f.$?.['android:name'] === 'android.hardware.bluetooth_le')) {
usesFeatures.push(bleFeature);
}
// Handle location permission settings for Android 12+
if (neverForLocation) {
// Add neverForLocation attribute to location permissions for Android 12+
const permissions = androidManifest.manifest['uses-permission'] || [];
permissions.forEach((permission) => {
if (permission.$?.['android:name'] === 'android.permission.ACCESS_FINE_LOCATION' ||
permission.$?.['android:name'] === 'android.permission.ACCESS_COARSE_LOCATION') {
permission.$['android:usesPermissionFlags'] = 'neverForLocation';
}
});
}
return config;
});
};
export const withBleNitroIOS = (config, props = {}) => {
const { modes, bluetoothAlwaysPermission = 'Allow $(PRODUCT_NAME) to connect to bluetooth devices' } = props;
return withInfoPlist(config, (config) => {
// Add NSBluetoothAlwaysUsageDescription
if (bluetoothAlwaysPermission !== false) {
config.modResults.NSBluetoothAlwaysUsageDescription = bluetoothAlwaysPermission;
}
// Add background modes if specified
if (modes && modes.length > 0) {
const backgroundModes = modes.map(mode => `bluetooth-${mode}`);
if (!config.modResults.UIBackgroundModes) {
config.modResults.UIBackgroundModes = [];
}
backgroundModes.forEach(mode => {
if (!config.modResults.UIBackgroundModes.includes(mode)) {
config.modResults.UIBackgroundModes.push(mode);
}
});
}
return config;
});
};
const withBleNitro = (config, props = {}) => {
// Validate props
if (props.neverForLocation && !props.isBackgroundEnabled) {
WarningAggregator.addWarningForPlatform('android', 'react-native-ble-nitro', 'neverForLocation is set to true but isBackgroundEnabled is false. ' +
'This might cause issues with BLE scanning on some Android devices.');
}
if (props.modes && props.modes.some(mode => !['peripheral', 'central'].includes(mode))) {
WarningAggregator.addWarningForPlatform('ios', 'react-native-ble-nitro', 'Invalid background mode specified. Only "peripheral" and "central" are supported.');
}
// Apply platform-specific configurations
config = withBleNitroAndroid(config, props);
config = withBleNitroIOS(config, props);
return config;
};
export default withBleNitro;