react-native-ble-nitro 1.2.0 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. package/README.md +81 -18
  2. package/android/CMakeLists.txt +32 -0
  3. package/android/build.gradle +140 -0
  4. package/android/fix-prefab.gradle +51 -0
  5. package/android/gradle.properties +5 -0
  6. package/android/src/main/AndroidManifest.xml +2 -0
  7. package/android/src/main/cpp/cpp-adapter.cpp +6 -0
  8. package/android/src/main/java/com/margelo/nitro/co/zyke/ble/BleNitroBleManager.kt +899 -0
  9. package/android/src/main/java/com/margelo/nitro/co/zyke/ble/BleNitroPackage.kt +38 -0
  10. package/ios/BleNitroBleManager.swift +7 -3
  11. package/lib/commonjs/index.d.ts +14 -8
  12. package/lib/commonjs/index.d.ts.map +1 -1
  13. package/lib/commonjs/index.js +35 -17
  14. package/lib/commonjs/index.js.map +1 -1
  15. package/lib/commonjs/specs/NativeBleNitro.nitro.d.ts +8 -1
  16. package/lib/commonjs/specs/NativeBleNitro.nitro.d.ts.map +1 -1
  17. package/lib/commonjs/specs/NativeBleNitro.nitro.js +8 -1
  18. package/lib/commonjs/specs/NativeBleNitro.nitro.js.map +1 -1
  19. package/lib/index.d.ts +14 -8
  20. package/lib/index.js +33 -15
  21. package/lib/specs/NativeBleNitro.nitro.d.ts +8 -1
  22. package/lib/specs/NativeBleNitro.nitro.js +7 -0
  23. package/nitrogen/generated/android/BleNitroOnLoad.cpp +2 -2
  24. package/nitrogen/generated/android/c++/JAndroidScanMode.hpp +65 -0
  25. package/nitrogen/generated/android/c++/JFunc_void_std__optional_BLEDevice__std__optional_std__string_.hpp +86 -0
  26. package/nitrogen/generated/android/c++/JHybridNativeBleNitroSpec.cpp +8 -4
  27. package/nitrogen/generated/android/c++/JHybridNativeBleNitroSpec.hpp +1 -1
  28. package/nitrogen/generated/android/c++/JScanFilter.hpp +8 -2
  29. package/nitrogen/generated/android/kotlin/com/margelo/nitro/co/zyke/ble/AndroidScanMode.kt +23 -0
  30. package/nitrogen/generated/android/kotlin/com/margelo/nitro/co/zyke/ble/{Func_void_BLEDevice.kt → Func_void_std__optional_BLEDevice__std__optional_std__string_.kt} +14 -14
  31. package/nitrogen/generated/android/kotlin/com/margelo/nitro/co/zyke/ble/HybridNativeBleNitroSpec.kt +2 -2
  32. package/nitrogen/generated/android/kotlin/com/margelo/nitro/co/zyke/ble/ScanFilter.kt +4 -1
  33. package/nitrogen/generated/ios/BleNitro-Swift-Cxx-Bridge.cpp +5 -5
  34. package/nitrogen/generated/ios/BleNitro-Swift-Cxx-Bridge.hpp +30 -21
  35. package/nitrogen/generated/ios/BleNitro-Swift-Cxx-Umbrella.hpp +3 -0
  36. package/nitrogen/generated/ios/c++/HybridNativeBleNitroSpecSwift.hpp +5 -2
  37. package/nitrogen/generated/ios/swift/AndroidScanMode.swift +48 -0
  38. package/nitrogen/generated/ios/swift/Func_void_std__optional_BLEDevice__std__optional_std__string_.swift +59 -0
  39. package/nitrogen/generated/ios/swift/HybridNativeBleNitroSpec.swift +1 -1
  40. package/nitrogen/generated/ios/swift/HybridNativeBleNitroSpec_cxx.swift +17 -5
  41. package/nitrogen/generated/ios/swift/ScanFilter.swift +13 -2
  42. package/nitrogen/generated/shared/c++/AndroidScanMode.hpp +64 -0
  43. package/nitrogen/generated/shared/c++/HybridNativeBleNitroSpec.hpp +3 -3
  44. package/nitrogen/generated/shared/c++/ScanFilter.hpp +9 -3
  45. package/package.json +1 -1
  46. package/plugin/build/index.d.ts +2 -0
  47. package/plugin/build/index.js +2 -0
  48. package/plugin/build/withBleNitro.d.ts +5 -1
  49. package/plugin/build/withBleNitro.js +18 -7
  50. package/src/__tests__/index.test.ts +48 -13
  51. package/src/index.ts +40 -21
  52. package/src/specs/NativeBleNitro.nitro.ts +9 -1
  53. package/nitrogen/generated/android/c++/JFunc_void_BLEDevice.hpp +0 -85
  54. package/nitrogen/generated/ios/swift/Func_void_BLEDevice.swift +0 -47
package/README.md CHANGED
@@ -11,7 +11,7 @@ Originally developed for [Zyke Band](https://zykeband.com?utm_source=github&utm_
11
11
 
12
12
  - 🚀 **High Performance**: Built on Nitro Modules with JSI for zero-overhead native communication
13
13
  - 📱 **iOS Support**: Complete iOS implementation with Swift and Core Bluetooth
14
- - 🤖 **Android Support**: Currently in development - iOS fully functional
14
+ - 🤖 **Android Support**: Complete Android implementation with Kotlin and Android BLE APIs
15
15
  - 🎯 **Type-Safe**: Full TypeScript support with comprehensive type definitions
16
16
  - 🔧 **Expo Ready**: Built-in Expo config plugin for easy setup
17
17
  - 🏗️ **New Architecture**: Full support for React Native's new architecture
@@ -66,12 +66,10 @@ npx pod-install # iOS only
66
66
 
67
67
  ## 📖 Usage
68
68
 
69
- > **📱 Platform Support**: Currently iOS only. Android implementation is in development.
70
-
71
69
  ### Basic Setup
72
70
 
73
71
  ```typescript
74
- import { BleNitro, BLEState, type BLEDevice } from 'react-native-ble-nitro';
72
+ import { BleNitro, BLEState, AndroidScanMode, type BLEDevice } from 'react-native-ble-nitro';
75
73
 
76
74
  // Get the singleton instance
77
75
  const ble = BleNitro.instance();
@@ -111,9 +109,13 @@ await ble.openSettings();
111
109
  ble.startScan({
112
110
  serviceUUIDs: ['180d'], // Optional: filter by service UUIDs
113
111
  rssiThreshold: -80, // Optional: minimum signal strength
114
- allowDuplicates: false // Optional: allow duplicate discoveries
112
+ allowDuplicates: false, // Optional: allow duplicate discoveries
113
+ androidScanMode: AndroidScanMode.Balanced // Optional: Android scan mode
115
114
  }, (device) => {
116
- console.log('Found device:', device.name, device.id);
115
+ console.log('Discovered device:', device);
116
+ }, (error) => {
117
+ // only called on Android
118
+ console.error('Scan error:', error);
117
119
  });
118
120
 
119
121
  // Stop scanning
@@ -152,6 +154,11 @@ const isConnected = ble.isConnected(deviceId);
152
154
  // MTU negotiation (Android only, as iOS manages MTU automatically)
153
155
  // iOS returns current MTU size
154
156
  const mtu = await ble.requestMTU(deviceId, 256); // Request MTU size
157
+
158
+ // MTU negotiation (Android only)
159
+ // iOS manages MTU automatically, this method returns current MTU size
160
+ const newMTU = ble.requestMTU(deviceId, 247);
161
+ console.log('MTU set to:', newMTU);
155
162
  ```
156
163
 
157
164
  #### 🔧 Service Discovery
@@ -181,11 +188,12 @@ const characteristics2 = ble.getCharacteristics(deviceId, '0000180d-0000-1000-80
181
188
  ```typescript
182
189
  // Read a characteristic value
183
190
  const data = await ble.readCharacteristic(deviceId, serviceUUID, characteristicUUID);
184
- // Returns: number[] - array of bytes
191
+ // Returns: ArrayBuffer - binary data
185
192
 
186
193
  // Example: Reading battery level
187
194
  const batteryData = await ble.readCharacteristic(deviceId, '180f', '2a19');
188
- const batteryLevel = batteryData[0]; // First byte is battery percentage
195
+ const batteryArray = new Uint8Array(batteryData);
196
+ const batteryLevel = batteryArray[0]; // First byte is battery percentage
189
197
  console.log('Battery level:', batteryLevel + '%');
190
198
  ```
191
199
 
@@ -193,11 +201,12 @@ console.log('Battery level:', batteryLevel + '%');
193
201
 
194
202
  ```typescript
195
203
  // Write to a characteristic with response
204
+ const data = new Uint8Array([0x01, 0x02, 0x03]);
196
205
  await ble.writeCharacteristic(
197
206
  deviceId,
198
207
  serviceUUID,
199
208
  characteristicUUID,
200
- [0x01, 0x02, 0x03], // Data as byte array
209
+ data.buffer, // Data as ArrayBuffer
201
210
  true // withResponse = true (default)
202
211
  );
203
212
 
@@ -206,7 +215,7 @@ await ble.writeCharacteristic(
206
215
  deviceId,
207
216
  serviceUUID,
208
217
  characteristicUUID,
209
- [0x01, 0x02, 0x03],
218
+ data.buffer,
210
219
  false // withResponse = false
211
220
  );
212
221
  ```
@@ -249,7 +258,8 @@ const subscription = ble.subscribeToCharacteristic(
249
258
  HEART_RATE_SERVICE,
250
259
  HEART_RATE_MEASUREMENT,
251
260
  (_, data) => {
252
- const heartRate = data[1]; // Second byte contains BPM
261
+ const dataArray = new Uint8Array(data);
262
+ const heartRate = dataArray[1]; // Second byte contains BPM
253
263
  console.log('Heart rate:', heartRate, 'BPM');
254
264
  }
255
265
  );
@@ -269,7 +279,8 @@ const batteryData = await ble.readCharacteristic(
269
279
  BATTERY_SERVICE,
270
280
  BATTERY_LEVEL_CHARACTERISTIC
271
281
  );
272
- const batteryPercentage = batteryData[0];
282
+ const batteryArray = new Uint8Array(batteryData);
283
+ const batteryPercentage = batteryArray[0];
273
284
  console.log('Battery:', batteryPercentage + '%');
274
285
  ```
275
286
 
@@ -280,12 +291,12 @@ const CUSTOM_SERVICE = 'your-custom-service-uuid';
280
291
  const COMMAND_CHARACTERISTIC = 'your-command-characteristic-uuid';
281
292
 
282
293
  // Send a custom command
283
- const enableLedCommand = [0x01, 0x1f, 0x01]; // Your protocol
294
+ const enableLedCommand = new Uint8Array([0x01, 0x1f, 0x01]); // Your protocol
284
295
  await ble.writeCharacteristic(
285
296
  deviceId,
286
297
  CUSTOM_SERVICE,
287
298
  COMMAND_CHARACTERISTIC,
288
- enableLedCommand
299
+ enableLedCommand.buffer
289
300
  );
290
301
  ```
291
302
 
@@ -335,6 +346,7 @@ interface ScanFilter {
335
346
  serviceUUIDs?: string[];
336
347
  rssiThreshold?: number;
337
348
  allowDuplicates?: boolean;
349
+ androidScanMode?: AndroidScanMode;
338
350
  }
339
351
 
340
352
  interface Subscription {
@@ -350,9 +362,19 @@ enum BLEState {
350
362
  PoweredOn = 'PoweredOn'
351
363
  }
352
364
 
365
+ enum AndroidScanMode {
366
+ LowLatency = 'LowLatency', // Highest power, fastest discovery
367
+ Balanced = 'Balanced', // Balanced power/discovery (default)
368
+ LowPower = 'LowPower', // Lowest power, slower discovery
369
+ Opportunistic = 'Opportunistic', // Only when other apps are scanning
370
+ }
371
+
353
372
  // Callback types
373
+ type StateChangeCallback = (state: BLEState) => void;
374
+ type ScanEventCallback = (device: BLEDevice) => void;
375
+ type ScanErrorCallback = (error: string) => void; // Android only
354
376
  type DisconnectEventCallback = (deviceId: string, interrupted: boolean, error: string) => void;
355
- type CharacteristicUpdateCallback = (characteristicId: string, data: number[]) => void;
377
+ type CharacteristicUpdateCallback = (characteristicId: string, data: ArrayBuffer) => void;
356
378
  ```
357
379
 
358
380
  ## 🏗️ Architecture
@@ -369,7 +391,7 @@ Built on [Nitro Modules](https://nitro.margelo.com/) for:
369
391
  ### Platform Implementation
370
392
 
371
393
  - **iOS**: ✅ Complete Swift implementation using Core Bluetooth
372
- - **Android**: 🚧 Kotlin implementation in development using Android BLE APIs
394
+ - **Android**: Complete Kotlin implementation using Android BLE APIs
373
395
  - **Shared C++**: Common logic and type definitions via Nitro Modules
374
396
 
375
397
  ### Compatibility Layer
@@ -392,6 +414,7 @@ interface BleNitroPluginProps {
392
414
  neverForLocation?: boolean; // Assert no location derivation [Android 12+]
393
415
  modes?: ('peripheral' | 'central')[]; // iOS background modes
394
416
  bluetoothAlwaysPermission?: string | false; // iOS permission message
417
+ androidAdvertisingEnabled?: boolean; // Android Peripheral mode (advertising)
395
418
  }
396
419
  ```
397
420
 
@@ -409,7 +432,7 @@ Adds these to `Info.plist`:
409
432
 
410
433
  ### Android Permissions
411
434
 
412
- Automatically adds required permissions:
435
+ Automatically adds required permissions and also handling neverForLocation and advertise mode.
413
436
 
414
437
  ```xml
415
438
  <!-- Basic Bluetooth -->
@@ -417,7 +440,6 @@ Automatically adds required permissions:
417
440
  <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
418
441
 
419
442
  <!-- Location (required for BLE scanning) -->
420
- <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
421
443
  <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
422
444
 
423
445
  <!-- Android 12+ -->
@@ -429,6 +451,47 @@ Automatically adds required permissions:
429
451
  <uses-feature android:name="android.hardware.bluetooth_le" android:required="false" />
430
452
  ```
431
453
 
454
+ ## Android Flow with Permission Handling
455
+
456
+ ```ts
457
+ import { PermissionsAndroid, Platform } from 'react-native';
458
+
459
+ const requestPermissionsAndroid = async () => {
460
+ if (Platform.OS !== 'android') {
461
+ return true
462
+ }
463
+ if (Platform.OS === 'android' && PermissionsAndroid.PERMISSIONS.ACCESS_FINE_LOCATION) {
464
+ const apiLevel = parseInt(Platform.Version.toString(), 10);
465
+ if (apiLevel < 31) {
466
+ const result = await PermissionsAndroid.request(PermissionsAndroid.PERMISSIONS.ACCESS_FINE_LOCATION);
467
+ return (
468
+ result === PermissionsAndroid.RESULTS.GRANTED
469
+ );
470
+ }
471
+ if (PermissionsAndroid.PERMISSIONS.BLUETOOTH_SCAN && PermissionsAndroid.PERMISSIONS.BLUETOOTH_CONNECT) {
472
+ const result = await PermissionsAndroid.requestMultiple([
473
+ PermissionsAndroid.PERMISSIONS.BLUETOOTH_SCAN,
474
+ PermissionsAndroid.PERMISSIONS.BLUETOOTH_CONNECT,
475
+ PermissionsAndroid.PERMISSIONS.ACCESS_FINE_LOCATION
476
+ ])
477
+
478
+ return (
479
+ result['android.permission.BLUETOOTH_CONNECT'] === PermissionsAndroid.RESULTS.GRANTED &&
480
+ result['android.permission.BLUETOOTH_SCAN'] === PermissionsAndroid.RESULTS.GRANTED &&
481
+ result['android.permission.ACCESS_FINE_LOCATION'] === PermissionsAndroid.RESULTS.GRANTED
482
+ )
483
+ }
484
+
485
+ logMessage('Request permissions failed');
486
+ throw new Error('Request permissions failed');
487
+ }
488
+ };
489
+
490
+ const hasPermissions = await requestPermissionsAndroid();
491
+
492
+ // Then start scanning or other operations
493
+ ```
494
+
432
495
  ## 🔧 Development
433
496
 
434
497
  ### Building the Library
@@ -0,0 +1,32 @@
1
+ project(BleNitro)
2
+ cmake_minimum_required(VERSION 3.9.0)
3
+
4
+ set (PACKAGE_NAME BleNitro)
5
+ set (CMAKE_VERBOSE_MAKEFILE ON)
6
+ set (CMAKE_CXX_STANDARD 20)
7
+
8
+ # Enable Raw Props parsing in react-native (for Nitro Views)
9
+ add_compile_options(-DRN_SERIALIZABLE_STATE=1)
10
+
11
+ # Define C++ library and add all sources
12
+ add_library(${PACKAGE_NAME} SHARED
13
+ src/main/cpp/cpp-adapter.cpp
14
+ )
15
+
16
+ # Add Nitrogen specs :)
17
+ include(${CMAKE_SOURCE_DIR}/../nitrogen/generated/android/BleNitro+autolinking.cmake)
18
+
19
+ # Set up local includes
20
+ include_directories(
21
+ "src/main/cpp"
22
+ "../cpp"
23
+ )
24
+
25
+ find_library(LOG_LIB log)
26
+
27
+ # Link all libraries together
28
+ target_link_libraries(
29
+ ${PACKAGE_NAME}
30
+ ${LOG_LIB}
31
+ android # <-- Android core
32
+ )
@@ -0,0 +1,140 @@
1
+ buildscript {
2
+ repositories {
3
+ google()
4
+ mavenCentral()
5
+ }
6
+
7
+ dependencies {
8
+ classpath "com.android.tools.build:gradle:8.12.1"
9
+ }
10
+ }
11
+
12
+ def reactNativeArchitectures() {
13
+ def value = rootProject.getProperties().get("reactNativeArchitectures")
14
+ return value ? value.split(",") : ["armeabi-v7a", "x86", "x86_64", "arm64-v8a"]
15
+ }
16
+
17
+ def isNewArchitectureEnabled() {
18
+ return rootProject.hasProperty("newArchEnabled") && rootProject.getProperty("newArchEnabled") == "true"
19
+ }
20
+
21
+ apply plugin: "com.android.library"
22
+ apply plugin: 'org.jetbrains.kotlin.android'
23
+ apply from: '../nitrogen/generated/android/BleNitro+autolinking.gradle'
24
+ apply from: "./fix-prefab.gradle"
25
+
26
+ if (isNewArchitectureEnabled()) {
27
+ apply plugin: "com.facebook.react"
28
+ }
29
+
30
+ def getExtOrDefault(name) {
31
+ return rootProject.ext.has(name) ? rootProject.ext.get(name) : project.properties["BleNitro_" + name]
32
+ }
33
+
34
+ def getExtOrIntegerDefault(name) {
35
+ return rootProject.ext.has(name) ? rootProject.ext.get(name) : (project.properties["BleNitro_" + name]).toInteger()
36
+ }
37
+
38
+ android {
39
+ namespace "com.margelo.nitro.co.zyke.ble"
40
+
41
+ ndkVersion getExtOrDefault("ndkVersion")
42
+ compileSdkVersion getExtOrIntegerDefault("compileSdkVersion")
43
+
44
+ defaultConfig {
45
+ minSdkVersion getExtOrIntegerDefault("minSdkVersion")
46
+ targetSdkVersion getExtOrIntegerDefault("targetSdkVersion")
47
+ buildConfigField "boolean", "IS_NEW_ARCHITECTURE_ENABLED", isNewArchitectureEnabled().toString()
48
+
49
+ externalNativeBuild {
50
+ cmake {
51
+ cppFlags "-frtti -fexceptions -Wall -Wextra -fstack-protector-all"
52
+ arguments "-DANDROID_STL=c++_shared", "-DANDROID_SUPPORT_FLEXIBLE_PAGE_SIZES=ON"
53
+ abiFilters (*reactNativeArchitectures())
54
+
55
+ buildTypes {
56
+ debug {
57
+ cppFlags "-O1 -g"
58
+ }
59
+ release {
60
+ cppFlags "-O2"
61
+ }
62
+ }
63
+ }
64
+ }
65
+ }
66
+
67
+ externalNativeBuild {
68
+ cmake {
69
+ path "CMakeLists.txt"
70
+ }
71
+ }
72
+
73
+ packagingOptions {
74
+ excludes = [
75
+ "META-INF",
76
+ "META-INF/**",
77
+ "**/libc++_shared.so",
78
+ "**/libfbjni.so",
79
+ "**/libjsi.so",
80
+ "**/libfolly_json.so",
81
+ "**/libfolly_runtime.so",
82
+ "**/libglog.so",
83
+ "**/libhermes.so",
84
+ "**/libhermes-executor-debug.so",
85
+ "**/libhermes_executor.so",
86
+ "**/libreactnative.so",
87
+ "**/libreactnativejni.so",
88
+ "**/libturbomodulejsijni.so",
89
+ "**/libreact_nativemodule_core.so",
90
+ "**/libjscexecutor.so"
91
+ ]
92
+ }
93
+
94
+ buildFeatures {
95
+ buildConfig true
96
+ prefab true
97
+ }
98
+
99
+ buildTypes {
100
+ release {
101
+ minifyEnabled false
102
+ }
103
+ }
104
+
105
+ lintOptions {
106
+ disable "GradleCompatible"
107
+ }
108
+
109
+ compileOptions {
110
+ sourceCompatibility JavaVersion.VERSION_1_8
111
+ targetCompatibility JavaVersion.VERSION_1_8
112
+ }
113
+
114
+ sourceSets {
115
+ main {
116
+ if (isNewArchitectureEnabled()) {
117
+ java.srcDirs += [
118
+ // React Codegen files
119
+ "${project.buildDir}/generated/source/codegen/java"
120
+ ]
121
+ }
122
+ }
123
+ }
124
+ }
125
+
126
+ repositories {
127
+ mavenCentral()
128
+ google()
129
+ }
130
+
131
+
132
+ dependencies {
133
+ // For < 0.71, this will be from the local maven repo
134
+ // For > 0.71, this will be replaced by `com.facebook.react:react-android:$version` by react gradle plugin
135
+ //noinspection GradleDynamicVersion
136
+ implementation "com.facebook.react:react-native:+"
137
+
138
+ // Add a dependency on NitroModules
139
+ implementation project(":react-native-nitro-modules")
140
+ }
@@ -0,0 +1,51 @@
1
+ tasks.configureEach { task ->
2
+ // Make sure that we generate our prefab publication file only after having built the native library
3
+ // so that not a header publication file, but a full configuration publication will be generated, which
4
+ // will include the .so file
5
+
6
+ def prefabConfigurePattern = ~/^prefab(.+)ConfigurePackage$/
7
+ def matcher = task.name =~ prefabConfigurePattern
8
+ if (matcher.matches()) {
9
+ def variantName = matcher[0][1]
10
+ task.outputs.upToDateWhen { false }
11
+ task.dependsOn("externalNativeBuild${variantName}")
12
+ }
13
+ }
14
+
15
+ afterEvaluate {
16
+ def abis = reactNativeArchitectures()
17
+ rootProject.allprojects.each { proj ->
18
+ if (proj === rootProject) return
19
+
20
+ def dependsOnThisLib = proj.configurations.findAll { it.canBeResolved }.any { config ->
21
+ config.dependencies.any { dep ->
22
+ dep.group == project.group && dep.name == project.name
23
+ }
24
+ }
25
+ if (!dependsOnThisLib && proj != project) return
26
+
27
+ if (!proj.plugins.hasPlugin('com.android.application') && !proj.plugins.hasPlugin('com.android.library')) {
28
+ return
29
+ }
30
+
31
+ def variants = proj.android.hasProperty('applicationVariants') ? proj.android.applicationVariants : proj.android.libraryVariants
32
+ // Touch the prefab_config.json files to ensure that in ExternalNativeJsonGenerator.kt we will re-trigger the prefab CLI to
33
+ // generate a libnameConfig.cmake file that will contain our native library (.so).
34
+ // See this condition: https://cs.android.com/android-studio/platform/tools/base/+/mirror-goog-studio-main:build-system/gradle-core/src/main/java/com/android/build/gradle/tasks/ExternalNativeJsonGenerator.kt;l=207-219?q=createPrefabBuildSystemGlue
35
+ variants.all { variant ->
36
+ def variantName = variant.name
37
+ abis.each { abi ->
38
+ def searchDir = new File(proj.projectDir, ".cxx/${variantName}")
39
+ if (!searchDir.exists()) return
40
+ def matches = []
41
+ searchDir.eachDir { randomDir ->
42
+ def prefabFile = new File(randomDir, "${abi}/prefab_config.json")
43
+ if (prefabFile.exists()) matches << prefabFile
44
+ }
45
+ matches.each { prefabConfig ->
46
+ prefabConfig.setLastModified(System.currentTimeMillis())
47
+ }
48
+ }
49
+ }
50
+ }
51
+ }
@@ -0,0 +1,5 @@
1
+ BleNitro_kotlinVersion=2.1.20
2
+ BleNitro_minSdkVersion=23
3
+ BleNitro_targetSdkVersion=36
4
+ BleNitro_compileSdkVersion=36
5
+ BleNitro_ndkVersion=27.1.12297006
@@ -0,0 +1,2 @@
1
+ <manifest xmlns:android="http://schemas.android.com/apk/res/android">
2
+ </manifest>
@@ -0,0 +1,6 @@
1
+ #include <jni.h>
2
+ #include "BleNitroOnLoad.hpp"
3
+
4
+ JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void*) {
5
+ return margelo::nitro::co::zyke::ble::initialize(vm);
6
+ }