diff --git a/.gitignore b/.gitignore
index cf966f8..29389c8 100644
--- a/.gitignore
+++ b/.gitignore
@@ -6,3 +6,5 @@
.settings
build/
+
+node_modules/
diff --git a/.vscode/settings.json b/.vscode/settings.json
new file mode 100644
index 0000000..70e34ec
--- /dev/null
+++ b/.vscode/settings.json
@@ -0,0 +1,3 @@
+{
+ "C_Cpp.errorSquiggles": "disabled"
+}
\ No newline at end of file
diff --git a/LICENSE b/LICENSE
index f245d03..27a504d 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,6 +1,6 @@
The MIT License
-Copyright (c) 2019 lg2
+Copyright (c) 2025 Skura
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
diff --git a/RNEddystoneModule.podspec b/RNEddystoneModule.podspec
new file mode 100644
index 0000000..348e518
--- /dev/null
+++ b/RNEddystoneModule.podspec
@@ -0,0 +1,45 @@
+require "json"
+
+package = JSON.parse(File.read(File.join(__dir__, "package.json")))
+
+folly_compiler_flags = '-DFOLLY_NO_CONFIG -DFOLLY_MOBILE=1 -DFOLLY_USE_LIBCPP=1 -Wno-comma -Wno-shorten-64-to-32'
+
+Pod::Spec.new do |s|
+ s.name = "RNEddystoneModule"
+ s.version = package["version"]
+ s.summary = package["description"]
+ s.description = package["description"]
+ s.homepage = package["homepage"]
+ s.license = package["license"]
+ s.platforms = { :ios => "11.0" }
+ s.author = package["author"]
+ s.source = { :git => package["repository"], :tag => "#{s.version}" }
+
+
+ s.source_files = [
+ "ios/**/*.{h,m,mm}",
+ ]
+ # Use install_modules_dependencies helper to install the dependencies if React Native version >=0.71.0.
+ # See https://github.com/facebook/react-native/blob/febf6b7f33fdb4904669f99d795eba4c0f95d7bf/scripts/cocoapods/new_architecture.rb#L79.
+ if respond_to?(:install_modules_dependencies, true)
+ install_modules_dependencies(s)
+ else
+ s.dependency "React-Core"
+
+ # Don't install the dependencies when we run `pod install` in the old architecture.
+ if ENV['RCT_NEW_ARCH_ENABLED'] == '1' then
+ s.compiler_flags = folly_compiler_flags + " -DRCT_NEW_ARCH_ENABLED=1"
+ s.pod_target_xcconfig = {
+ "HEADER_SEARCH_PATHS" => "\"$(PODS_ROOT)/boost\"",
+ "OTHER_CPLUSPLUSFLAGS" => "-DFOLLY_NO_CONFIG -DFOLLY_MOBILE=1 -DFOLLY_USE_LIBCPP=1",
+ "CLANG_CXX_LANGUAGE_STANDARD" => "c++17"
+ }
+ s.dependency "React-Codegen"
+ s.dependency "RCT-Folly"
+ s.dependency "RCTRequired"
+ s.dependency "RCTTypeSafety"
+ s.dependency "ReactCommon/turbomodule/core"
+ end
+ end
+
+end
diff --git a/android/build.gradle b/android/build.gradle
index a28f0dd..8c343d4 100644
--- a/android/build.gradle
+++ b/android/build.gradle
@@ -1,36 +1,50 @@
-
buildscript {
+ ext.safeExtGet = {prop, fallback ->
+ rootProject.ext.has(prop) ? rootProject.ext.get(prop) : fallback
+ }
repositories {
- jcenter()
+ google()
+ gradlePluginPortal()
}
-
dependencies {
- classpath 'com.android.tools.build:gradle:1.3.1'
+ classpath("com.android.tools.build:gradle:7.0.4")
}
}
-
+def isNewArchitectureEnabled() {
+ return project.hasProperty("newArchEnabled") && project.newArchEnabled == "true"
+ }
apply plugin: 'com.android.library'
+if (isNewArchitectureEnabled()) {
+ apply plugin: 'com.facebook.react'
+}
+
android {
- compileSdkVersion 23
- buildToolsVersion "23.0.1"
+ compileSdkVersion safeExtGet('compileSdkVersion', 31)
defaultConfig {
- minSdkVersion 16
- targetSdkVersion 22
- versionCode 1
- versionName "1.0"
- }
- lintOptions {
- abortOnError false
+ minSdkVersion safeExtGet('minSdkVersion', 21)
+ targetSdkVersion safeExtGet('targetSdkVersion', 31)
}
}
repositories {
+ maven {
+ // All of React Native (JS, Obj-C sources, Android binaries) is installed from npm
+ url "$projectDir/../node_modules/react-native/android"
+ }
mavenCentral()
+ google()
}
dependencies {
- compile 'com.facebook.react:react-native:+'
+ implementation 'com.facebook.react:react-native:+'
}
-
\ No newline at end of file
+
+ if (isNewArchitectureEnabled()) {
+ react {
+ jsRootDir = file("../src/")
+ libraryName = "RNEddystoneModule"
+ codegenJavaPackageName = "com.eddystone"
+ }
+ }
diff --git a/android/src/main/AndroidManifest.xml b/android/src/main/AndroidManifest.xml
index c34c720..ffc794f 100644
--- a/android/src/main/AndroidManifest.xml
+++ b/android/src/main/AndroidManifest.xml
@@ -1,6 +1,11 @@
+ package="com.eddystone">
+
+
+
+
+
\ No newline at end of file
diff --git a/android/src/main/java/com/eddystone/EddystoneModule.java b/android/src/main/java/com/eddystone/EddystoneModule.java
new file mode 100644
index 0000000..b296ac2
--- /dev/null
+++ b/android/src/main/java/com/eddystone/EddystoneModule.java
@@ -0,0 +1,347 @@
+package com.eddystone;
+
+import android.Manifest;
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothManager;
+import android.bluetooth.le.BluetoothLeScanner;
+import android.bluetooth.le.ScanCallback;
+import android.bluetooth.le.ScanFilter;
+import android.bluetooth.le.ScanResult;
+import android.bluetooth.le.ScanSettings;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.os.ParcelUuid;
+
+import androidx.annotation.NonNull;
+import androidx.core.app.ActivityCompat;
+
+import com.facebook.react.bridge.Arguments;
+import com.facebook.react.bridge.ReactApplicationContext;
+import com.facebook.react.bridge.ReactMethod;
+import com.facebook.react.bridge.WritableMap;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+
+
+class EddystoneModule extends NativeEddystoneManagerSpec {
+
+ public static final String LOG_TAG = "RNEddystoneModule";
+ /** @property {ReactApplicationContext} The react app context */
+ private final ReactApplicationContext reactContext;
+
+ /** @property {BluetoothAdapter} The Bluetooth Adapter instance */
+ private BluetoothAdapter bluetoothAdapter;
+
+ /** @property {BluetoothLeScanner} The Bluetooth LE scanner instance */
+ private BluetoothLeScanner scanner;
+
+ /** @property ParcelUuid The service id for Eddystone beacons */
+ public static final ParcelUuid SERVICE_UUID = ParcelUuid.fromString("0000FEAA-0000-1000-8000-00805F9B34FB");
+
+ /** @property ParcelUuid The configuration service id for Eddystone beacon */
+ public static final ParcelUuid CONFIGURATION_UUID = ParcelUuid.fromString("a3c87500-8ed3-4bdf-8a39-a01bebede295");
+
+ /** @property byte UID frame type byte identifier */
+ public static final byte FRAME_TYPE_UID = 0x00;
+
+ /** @property byte URL frame type byte identifier */
+ public static final byte FRAME_TYPE_URL = 0x10;
+
+ /** @property byte TLM frame type byte identifier */
+ public static final byte FRAME_TYPE_TLM = 0x20;
+
+ /** @property byte EID frame type byte identifier */
+ public static final byte FRAME_TYPE_EID = 0x30;
+
+ /** @property byte Empty frame type byte identifier */
+ public static final byte FRAME_TYPE_EMPTY = 0x40;
+
+ public ReactApplicationContext getReactContext() {
+ return reactContext;
+ }
+
+ public EddystoneModule(ReactApplicationContext reactContext) {
+ super(reactContext);
+ this.reactContext = reactContext;
+ bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
+
+ }
+ public static final String NAME = "EddystoneModule";
+ @NonNull
+ @Override
+ public String getName() {
+ return NAME;
+ }
+
+ private BluetoothAdapter getBluetoothAdapter() {
+ if (bluetoothAdapter == null) {
+ BluetoothManager manager = (BluetoothManager) reactContext.getSystemService(Context.BLUETOOTH_SERVICE);
+ bluetoothAdapter = manager.getAdapter();
+ }
+ return bluetoothAdapter;
+ }
+
+ /**
+ * Returns a URL scheme based on a URL Frame hexChar
+ *
+ * @param {byte} The hexChar to analyse for a scheme
+ * @returns {String} The URL scheme found
+ * @public
+ */
+ private String getURLScheme(byte hexChar) {
+ switch (hexChar) {
+ case 0x00:
+ return "http://www.";
+ case 0x01:
+ return "https://www.";
+ case 0x02:
+ return "http://";
+ case 0x03:
+ return "https://";
+ default:
+ return null;
+ }
+ }
+
+ /**
+ * Returns an encoded string or URL suffix based on a URL frame hexChar
+ *
+ * @param {byte} hexChar The hexChar to analyse for a scheme
+ * @returns {String} The encoded string or URL suffix found
+ * @public
+ */
+ private String getEncodedString(byte hexChar) {
+ switch (hexChar) {
+ case 0x00:
+ return ".com/";
+ case 0x01:
+ return ".org/";
+ case 0x02:
+ return ".edu/";
+ case 0x03:
+ return ".net/";
+ case 0x04:
+ return ".info/";
+ case 0x05:
+ return ".biz/";
+ case 0x06:
+ return ".gov/";
+ case 0x07:
+ return ".com";
+ case 0x08:
+ return ".org";
+ case 0x09:
+ return ".edu";
+ case 0x0a:
+ return ".net";
+ case 0x0b:
+ return ".info";
+ case 0x0c:
+ return ".biz";
+ case 0x0d:
+ return ".gov";
+ default:
+ byte[] byteArray = new byte[] { hexChar };
+ return new String(byteArray);
+ }
+ }
+
+ /** @property {ScanCallback} Callbacks execute when a device is scanned */
+ ScanCallback scanCallback = new ScanCallback() {
+ /**
+ * Triggered when a device is scanned
+ *
+ * @param {int} callbackType The type of callback triggered
+ * @param {ScanResult} result The device result object
+ * @returns {void}
+ * @public
+ */
+ @Override
+ public void onScanResult(int callbackType, ScanResult result) {
+ handleResult(result);
+ }
+
+ /**
+ * Triggered when many devices were scanned
+ *
+ * @param {List} results The devices results objects
+ * @returns {void}
+ * @public
+ */
+ @Override
+ public void onBatchScanResults(List results) {
+ for (ScanResult result : results) {
+ handleResult(result);
+ }
+ }
+
+ /**
+ * Handles a single device's results
+ *
+ * @param {ScanResult} result The device's result object
+ * @returns {void}
+ * @public
+ */
+ public void handleResult(ScanResult result) {
+ // attempt to get sevice data from eddystone uuid
+ byte[] serviceData = result.getScanRecord().getServiceData(SERVICE_UUID);
+
+ // fallback on configuration uuid if necessary
+ if (serviceData == null || serviceData.length == 0) {
+ serviceData = result.getScanRecord().getServiceData(CONFIGURATION_UUID);
+
+ if (serviceData == null) {
+ return;
+ }
+ }
+
+ // handle all possible frame types
+ byte frameType = serviceData[0];
+ if (frameType == FRAME_TYPE_UID || frameType == FRAME_TYPE_EID) {
+ int length = 18;
+ String event = "onUIDFrame";
+
+ if (frameType == FRAME_TYPE_EID) {
+ length = 8;
+ event = "onEIDFrame";
+ }
+
+ // reconstruct the beacon id from hex array
+ StringBuilder builder = new StringBuilder();
+ for (int i = 2; i < length; i++) {
+ builder.append(Integer.toHexString(serviceData[i] & 0xFF));
+ }
+
+ // create params object for javascript thread
+ WritableMap params = Arguments.createMap();
+ params.putString("id", builder.toString());
+ params.putString("uid", result.getDevice().getAddress());
+ params.putInt("txPower", serviceData[1]);
+ params.putInt("rssi", result.getRssi());
+
+ // dispatch event
+ if (frameType == FRAME_TYPE_UID)
+ emitOnUIDFrame(params);
+ else if (frameType == FRAME_TYPE_EID) {
+ emitOnEIDFrame(params);
+ }
+ // emit(event, params);
+ } else if (frameType == FRAME_TYPE_URL) {
+
+ // build the url from the frame's bytes
+ String url = getURLScheme(serviceData[2]);
+ for (int i = 3; i < 17 + 3; i++) {
+ if (serviceData.length <= i) {
+ break;
+ }
+
+ url += getEncodedString(serviceData[i]);
+ }
+ WritableMap params = Arguments.createMap();
+ params.putString("url", url);
+ // dispatch event
+ // emit("onURLFrame", url);
+ emitOnURLFrame(params);
+ } else if (frameType == FRAME_TYPE_TLM) {
+ // grab the beacon's voltage
+ int voltage = (serviceData[2] & 0xFF) << 8;
+ voltage += (serviceData[3] & 0xFF);
+
+ // grab the beacon's temperature
+ int temp = (serviceData[4] << 8);
+ temp += (serviceData[5] & 0xFF);
+ temp /= 256f;
+
+ // create params object for javascript thread
+ WritableMap params = Arguments.createMap();
+ params.putInt("voltage", voltage);
+ params.putInt("temp", temp);
+
+ // dispatch event
+ // emit("onTelemetryFrame", params);
+ emitOnTelemetryData(params);
+ } else if (frameType == FRAME_TYPE_EMPTY) {
+ // dispatch empty event
+ // emit("onEmptyFrame", null);
+ emitOnEmptyFrame("empty");
+ }
+ }
+ };
+
+ /**
+ * Starts scanning for Eddystone beacons
+ *
+ * @returns {void}
+ * @public
+ */
+ @ReactMethod
+ public void startScanning() {
+ ScanFilter serviceFilter = new ScanFilter.Builder().setServiceUuid(SERVICE_UUID).build();
+
+ ScanFilter configurationFilter = new ScanFilter.Builder().setServiceUuid(CONFIGURATION_UUID).build();
+
+ final List filters = new ArrayList<>();
+ filters.add(serviceFilter);
+ filters.add(configurationFilter);
+
+ ScanSettings settings = new ScanSettings.Builder().setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY).build();
+
+ Objects.requireNonNull(reactContext.getCurrentActivity()).requestPermissions(
+ new String[] { Manifest.permission.ACCESS_COARSE_LOCATION },
+ 1);
+
+ reactContext.getCurrentActivity().requestPermissions(
+ new String[] { Manifest.permission.ACCESS_FINE_LOCATION },
+ 1);
+
+ if (!bluetoothAdapter.isEnabled()) {
+ Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
+ reactContext.getCurrentActivity().startActivityForResult(enableBtIntent, 8123);
+ }
+
+ // start scanning
+ scanner = bluetoothAdapter.getBluetoothLeScanner();
+ scanner = bluetoothAdapter.getBluetoothLeScanner();
+ if (scanner != null) {
+ if (ActivityCompat.checkSelfPermission(this.getReactContext(), Manifest.permission.BLUETOOTH_SCAN) != PackageManager.PERMISSION_GRANTED) {
+ // TODO: Consider calling
+ // ActivityCompat#requestPermissions
+ // here to request the missing permissions, and then overriding
+ // public void onRequestPermissionsResult(int requestCode, String[] permissions,
+ // int[] grantResults)
+ // to handle the case where the user grants the permission. See the documentation
+ // for ActivityCompat#requestPermissions for more details.
+ return;
+ }
+ scanner.startScan(filters, settings, scanCallback);
+ }
+ }
+
+ /**
+ * Stops scanning for Eddystone beacons
+ *
+ * @returns {void}
+ * @public
+ */
+ @ReactMethod
+ public void stopScanning() {
+ if (scanner != null) {
+ if (ActivityCompat.checkSelfPermission(this.getReactContext(), Manifest.permission.BLUETOOTH_SCAN) != PackageManager.PERMISSION_GRANTED) {
+ // TODO: Consider calling
+ // ActivityCompat#requestPermissions
+ // here to request the missing permissions, and then overriding
+ // public void onRequestPermissionsResult(int requestCode, String[] permissions,
+ // int[] grantResults)
+ // to handle the case where the user grants the permission. See the documentation
+ // for ActivityCompat#requestPermissions for more details.
+ return;
+ }
+ scanner.stopScan(scanCallback);
+ }
+ scanner = null;
+ }
+
+}
diff --git a/android/src/main/java/com/eddystone/EddystonePackage.java b/android/src/main/java/com/eddystone/EddystonePackage.java
new file mode 100644
index 0000000..10a5e11
--- /dev/null
+++ b/android/src/main/java/com/eddystone/EddystonePackage.java
@@ -0,0 +1,47 @@
+/**
+ * React Native Eddystone
+ *
+ * A simple Eddystone implementation in React Native for both iOS and Android.
+ *
+ *
+ * @package original @lg2/react-native-eddystone
+ * @package react-native-eddystone
+ * @link https://github.com/lg2/react-native-eddystone
+ * @copyright 2025 Skura
+ * @license MIT
+ */
+
+package com.eddystone;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+import com.facebook.react.ReactPackage;
+import com.facebook.react.bridge.NativeModule;
+import com.facebook.react.bridge.ReactApplicationContext;
+import com.facebook.react.uimanager.ViewManager;
+import com.facebook.react.bridge.JavaScriptModule;
+
+public class EddystonePackage implements ReactPackage {
+
+ public EddystonePackage(){
+ }
+ @Override
+ public List createNativeModules(ReactApplicationContext reactApplicationContext) {
+ List modules = new ArrayList<>();
+
+ modules.add(new EddystoneModule(reactApplicationContext));
+ return modules;
+ }
+
+ public List> createJSModules() {
+ return new ArrayList<>();
+ }
+
+ @Override
+ public List createViewManagers(ReactApplicationContext reactApplicationContext) {
+ return Collections.emptyList();
+ }
+}
\ No newline at end of file
diff --git a/android/src/main/java/com/lg2/eddystone/EddystoneModule.java b/android/src/main/java/com/lg2/eddystone/EddystoneModule.java
deleted file mode 100644
index 86f8ea2..0000000
--- a/android/src/main/java/com/lg2/eddystone/EddystoneModule.java
+++ /dev/null
@@ -1,324 +0,0 @@
-/**
- * React Native Eddystone
- *
- * A simple Eddystone implementation in React Native for both iOS and Android.
- *
- * @package @lg2/react-native-eddystone
- * @link https://github.com/lg2/react-native-eddystone
- * @copyright 2019 lg2
- * @license MIT
- */
-
-package com.lg2.eddystone;
-
-import com.facebook.react.bridge.ReactApplicationContext;
-import com.facebook.react.bridge.ReactContextBaseJavaModule;
-import com.facebook.react.bridge.ReactMethod;
-import com.facebook.react.bridge.WritableMap;
-import com.facebook.react.bridge.Arguments;
-import com.facebook.react.modules.core.DeviceEventManagerModule.RCTDeviceEventEmitter;
-
-import android.Manifest;
-import android.content.*;
-import android.bluetooth.*;
-import android.bluetooth.le.*;
-import android.os.ParcelUuid;
-
-import java.util.List;
-import java.util.ArrayList;
-
-public class EddystoneModule extends ReactContextBaseJavaModule {
- /** @property {ReactApplicationContext} The react app context */
- private final ReactApplicationContext reactContext;
-
- /** @property {BluetoothAdapter} The Bluetooth Adapter instance */
- private BluetoothAdapter bluetoothAdapter;
-
- /** @property {BluetoothLeScanner} The Bluetooth LE scanner instance */
- private BluetoothLeScanner scanner;
-
- /** @property ParcelUuid The service id for Eddystone beacons */
- public static final ParcelUuid SERVICE_UUID = ParcelUuid.fromString("0000FEAA-0000-1000-8000-00805F9B34FB");
-
- /** @property ParcelUuid The configuration service id for Eddystone beacon */
- public static final ParcelUuid CONFIGURATION_UUID = ParcelUuid.fromString("a3c87500-8ed3-4bdf-8a39-a01bebede295");
-
- /** @property byte UID frame type byte identifier */
- public static final byte FRAME_TYPE_UID = 0x00;
-
- /** @property byte URL frame type byte identifier */
- public static final byte FRAME_TYPE_URL = 0x10;
-
- /** @property byte TLM frame type byte identifier */
- public static final byte FRAME_TYPE_TLM = 0x20;
-
- /** @property byte EID frame type byte identifier */
- public static final byte FRAME_TYPE_EID = 0x30;
-
- /** @property byte Empty frame type byte identifier */
- public static final byte FRAME_TYPE_EMPTY = 0x40;
-
- /**
- * EddystoneModule class constructor
- *
- * @param {ReactApplicationContext} reactContext React native application
- * context
- * @constructor
- */
- public EddystoneModule(ReactApplicationContext reactContext) {
- super(reactContext);
- this.reactContext = reactContext;
- bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
- }
-
- /**
- * Returns the name of the module
- *
- * @returns {String} The name of the module
- * @public
- */
- @Override
- public String getName() {
- return "Eddystone";
- }
-
- /**
- * Dispatches an event to the javascript thread
- *
- * @param {String} event The name of the dispatched event
- * @param {Object} params The parameters related to that event
- * @returns {void}
- * @public
- */
- private void emit(String event, Object params) {
- reactContext.getJSModule(RCTDeviceEventEmitter.class).emit(event, params);
- }
-
- /**
- * Returns a URL scheme based on a URL Frame hexChar
- *
- * @param {byte} The hexChar to analyse for a scheme
- * @returns {String} The URL scheme found
- * @public
- */
- private String getURLScheme(byte hexChar) {
- switch (hexChar) {
- case 0x00:
- return "http://www.";
- case 0x01:
- return "https://www.";
- case 0x02:
- return "http://";
- case 0x03:
- return "https://";
- default:
- return null;
- }
- }
-
- /**
- * Returns an encoded string or URL suffix based on a URL frame hexChar
- *
- * @param {byte} hexChar The hexChar to analyse for a scheme
- * @returns {String} The encoded string or URL suffix found
- * @public
- */
- private String getEncodedString(byte hexChar) {
- switch (hexChar) {
- case 0x00:
- return ".com/";
- case 0x01:
- return ".org/";
- case 0x02:
- return ".edu/";
- case 0x03:
- return ".net/";
- case 0x04:
- return ".info/";
- case 0x05:
- return ".biz/";
- case 0x06:
- return ".gov/";
- case 0x07:
- return ".com";
- case 0x08:
- return ".org";
- case 0x09:
- return ".edu";
- case 0x0a:
- return ".net";
- case 0x0b:
- return ".info";
- case 0x0c:
- return ".biz";
- case 0x0d:
- return ".gov";
- default:
- byte[] byteArray = new byte[] { hexChar };
- return new String(byteArray);
- }
- }
-
- /** @property {ScanCallback} Callbacks execute when a device is scanned */
- ScanCallback scanCallback = new ScanCallback() {
- /**
- * Triggered when a device is scanned
- *
- * @param {int} callbackType The type of callback triggered
- * @param {ScanResult} result The device result object
- * @returns {void}
- * @public
- */
- @Override
- public void onScanResult(int callbackType, ScanResult result) {
- handleResult(result);
- }
-
- /**
- * Triggered when many devices were scanned
- *
- * @param {List} results The devices results objects
- * @returns {void}
- * @public
- */
- @Override
- public void onBatchScanResults(List results) {
- for (ScanResult result : results) {
- handleResult(result);
- }
- }
-
- /**
- * Handles a single device's results
- *
- * @param {ScanResult} result The device's result object
- * @returns {void}
- * @public
- */
- public void handleResult(ScanResult result) {
- // attempt to get sevice data from eddystone uuid
- byte[] serviceData = result.getScanRecord().getServiceData(SERVICE_UUID);
-
- // fallback on configuration uuid if necessary
- if (serviceData == null || serviceData.length == 0) {
- serviceData = result.getScanRecord().getServiceData(CONFIGURATION_UUID);
-
- if (serviceData == null) {
- return;
- }
- }
-
- // handle all possible frame types
- byte frameType = serviceData[0];
- if (frameType == FRAME_TYPE_UID || frameType == FRAME_TYPE_EID) {
- int length = 16;
- String event = "onUIDFrame";
-
- if (frameType == FRAME_TYPE_EID) {
- length = 8;
- event = "onEIDFrame";
- }
-
- // reconstruct the beacon id from hex array
- StringBuilder builder = new StringBuilder();
- for (int i = 2; i < length; i++) {
- builder.append(Integer.toHexString(serviceData[i] & 0xFF));
- }
-
- // create params object for javascript thread
- WritableMap params = Arguments.createMap();
- params.putString("id", builder.toString());
- params.putString("uid", result.getDevice().getAddress());
- params.putInt("txPower", serviceData[1]);
- params.putInt("rssi", result.getRssi());
-
- // dispatch event
- emit(event, params);
- } else if (frameType == FRAME_TYPE_URL) {
-
- // build the url from the frame's bytes
- String url = getURLScheme(serviceData[2]);
- for (int i = 3; i < 17 + 3; i++) {
- if (serviceData.length <= i) {
- break;
- }
-
- url += getEncodedString(serviceData[i]);
- }
-
- // dispatch event
- emit("onURLFrame", url);
- } else if (frameType == FRAME_TYPE_TLM) {
- // grab the beacon's voltage
- int voltage = (serviceData[2] & 0xFF) << 8;
- voltage += (serviceData[3] & 0xFF);
-
- // grab the beacon's temperature
- int temp = (serviceData[4] << 8);
- temp += (serviceData[5] & 0xFF);
- temp /= 256f;
-
- // create params object for javascript thread
- WritableMap params = Arguments.createMap();
- params.putInt("voltage", voltage);
- params.putInt("temp", temp);
-
- // dispatch event
- emit("onTelemetryFrame", params);
- } else if (frameType == FRAME_TYPE_EMPTY) {
- // dispatch empty event
- emit("onEmptyFrame", null);
- }
- }
- };
-
- /**
- * Starts scanning for Eddystone beacons
- *
- * @returns {void}
- * @public
- */
- @ReactMethod
- public void startScanning() {
- ScanFilter serviceFilter = new ScanFilter.Builder().setServiceUuid(SERVICE_UUID).build();
-
- ScanFilter configurationFilter = new ScanFilter.Builder().setServiceUuid(CONFIGURATION_UUID).build();
-
- final List filters = new ArrayList<>();
- filters.add(serviceFilter);
- filters.add(configurationFilter);
-
- ScanSettings settings = new ScanSettings.Builder().setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY).build();
-
- getCurrentActivity().requestPermissions(
- new String[]{Manifest.permission.ACCESS_COARSE_LOCATION},
- 1
- );
-
- getCurrentActivity().requestPermissions(
- new String[]{Manifest.permission.ACCESS_FINE_LOCATION},
- 1
- );
-
- if (!bluetoothAdapter.isEnabled()) {
- Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
- getCurrentActivity().startActivityForResult(enableBtIntent, 8123);
- }
-
- // start scanning
- scanner = bluetoothAdapter.getBluetoothLeScanner();
- scanner.startScan(filters, settings, scanCallback);
- }
-
- /**
- * Stops scanning for Eddystone beacons
- *
- * @returns {void}
- * @public
- */
- @ReactMethod
- public void stopScanning() {
- scanner.stopScan(scanCallback);
- scanner = null;
- }
-}
diff --git a/android/src/main/java/com/lg2/eddystone/EddystonePackage.java b/android/src/main/java/com/lg2/eddystone/EddystonePackage.java
deleted file mode 100644
index f47d288..0000000
--- a/android/src/main/java/com/lg2/eddystone/EddystonePackage.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/**
- * React Native Eddystone
- *
- * A simple Eddystone implementation in React Native for both iOS and Android.
- *
- * @package @lg2/react-native-eddystone
- * @link https://github.com/lg2/react-native-eddystone
- * @copyright 2019 lg2
- * @license MIT
- */
-
-package com.lg2.eddystone;
-
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
-
-import com.facebook.react.ReactPackage;
-import com.facebook.react.bridge.NativeModule;
-import com.facebook.react.bridge.ReactApplicationContext;
-import com.facebook.react.uimanager.ViewManager;
-import com.facebook.react.bridge.JavaScriptModule;
-
-public class EddystonePackage implements ReactPackage {
- @Override
- public List createNativeModules(ReactApplicationContext reactContext) {
- return Arrays.asList(new EddystoneModule(reactContext));
- }
-
- // Deprecated from RN 0.47
- public List> createJSModules() {
- return Collections.emptyList();
- }
-
- @Override
- public List createViewManagers(ReactApplicationContext reactContext) {
- return Collections.emptyList();
- }
-}
\ No newline at end of file
diff --git a/examples/basic.js b/examples/basic.js
index 1770b71..8bb8b73 100644
--- a/examples/basic.js
+++ b/examples/basic.js
@@ -1,7 +1,7 @@
import React, { Component } from "react";
import { View } from "react-native";
import Eddystone from "@lg2/react-native-eddystone";
-
+//THIS SHOULD BE UPDATED:..
export default class App extends Component {
componentDidMount() {
// bind eddystone events
diff --git a/ios/Beacon.h b/ios/Beacon.h
index bf432de..9fcb0e6 100644
--- a/ios/Beacon.h
+++ b/ios/Beacon.h
@@ -2,10 +2,10 @@
* React Native Eddystone
*
* A simple Eddystone implementation in React Native for both iOS and Android.
- *
- * @package @lg2/react-native-eddystone
+ * @package original @lg2/react-native-eddystone
+ * @package react-native-eddystone
* @link https://github.com/lg2/react-native-eddystone
- * @copyright 2019 lg2
+ * @copyright 2025 Skura
* @license MIT
*/
diff --git a/ios/Beacon.m b/ios/Beacon.m
index 9dc9b22..a4c43e5 100644
--- a/ios/Beacon.m
+++ b/ios/Beacon.m
@@ -3,9 +3,10 @@
*
* A simple Eddystone implementation in React Native for both iOS and Android.
*
- * @package @lg2/react-native-eddystone
+ * @package original @lg2/react-native-eddystone
+ * @package react-native-eddystone *
* @link https://github.com/lg2/react-native-eddystone
- * @copyright 2019 lg2
+ * @copyright 2020 SKura
* @license MIT
*/
diff --git a/ios/Eddystone.h b/ios/Eddystone.h
deleted file mode 100644
index 5a1cb6b..0000000
--- a/ios/Eddystone.h
+++ /dev/null
@@ -1,21 +0,0 @@
-/**
- * React Native Eddystone
- *
- * A simple Eddystone implementation in React Native for both iOS and Android.
- *
- * @package @lg2/react-native-eddystone
- * @link https://github.com/lg2/react-native-eddystone
- * @copyright 2019 lg2
- * @license MIT
- */
-
-#import
-#import
-
-@interface Eddystone : RCTEventEmitter
-/**
- * Eddystone class initializer
- * @return instancetype
- */
-- (instancetype)init;
-@end
diff --git a/ios/Eddystone.m b/ios/Eddystone.m
deleted file mode 100644
index f036d79..0000000
--- a/ios/Eddystone.m
+++ /dev/null
@@ -1,201 +0,0 @@
-/**
- * React Native Eddystone
- *
- * A simple Eddystone implementation in React Native for both iOS and Android.
- *
- * @package @lg2/react-native-eddystone
- * @link https://github.com/lg2/react-native-eddystone
- * @copyright 2019 lg2
- * @license MIT
- */
-
-#import
-#import "Eddystone.h"
-#import "Beacon.h"
-
-// declare our module interface & implement it as a central manager delegate
-@interface Eddystone () {
-@private
- /** @property BOOL Whether we should be scanning for devices or not */
- BOOL _shouldBeScanning;
-
- // core bluetooth central manager
- CBCentralManager *_centralManager;
-
- // our beacon dispatch queue
- dispatch_queue_t _beaconOperationsQueue;
-}
-@end
-
-@implementation Eddystone
- // react-native module macro
- RCT_EXPORT_MODULE()
-
- // react native methods
- + (BOOL)requiresMainQueueSetup { return NO; }
- - (dispatch_queue_t)methodQueue { return dispatch_get_main_queue(); }
-
- /**
- * Eddystone class initializer
- * @return instancetype
- */
- - (instancetype)init {
- if ((self = [super init]) != nil) {
- _beaconOperationsQueue = dispatch_queue_create("EddystoneBeaconOperationsQueue", NULL);
- _centralManager = [[CBCentralManager alloc] initWithDelegate:self queue:_beaconOperationsQueue];
- }
-
- return self;
- }
-
- /**
- * Lists the supported events for the RCTEventEmitter
- * @return NSArray * The supported events list
- */
- - (NSArray *)supportedEvents {
- return @[
- @"onUIDFrame",
- @"onEIDFrame",
- @"onURLFrame",
- @"onTelemetryFrame",
- @"onEmptyFrame",
- @"onStateChanged"
- ];
- }
-
- /**
- * Exported method that starts scanning for eddystone devices
- * @return void
- */
- RCT_EXPORT_METHOD(startScanning) {
- dispatch_async(_beaconOperationsQueue, ^{
- if (_centralManager.state != CBCentralManagerStatePoweredOn) {
- _shouldBeScanning = YES;
- } else {
- NSArray *services = @[[CBUUID UUIDWithString:SERVICE_ID]];
- NSDictionary *options = @{ CBCentralManagerScanOptionAllowDuplicatesKey : @YES };
- [_centralManager scanForPeripheralsWithServices:services options:options];
- }
- });
- }
-
- /**
- * Exported method that stops scanning for eddystone devices
- * @return void
- */
- RCT_EXPORT_METHOD(stopScanning) {
- _shouldBeScanning = NO;
- [_centralManager stopScan];
- }
-
- /**
- * Executes when the Core Bluetooth Central Manager discovered a peripheral
- * @param CBCentralManager * central Core Bluetooth Central Manager instance
- * @param CBPeripheral * peripheral Core Bluetooth peripheral instance
- * @param NSDictionary * advertisementData Peripheral advertised data
- * @param NSNumber * RSSI The received signal strength indication
- * @return void
- */
- - (void)centralManager:(CBCentralManager *)central
- didDiscoverPeripheral:(CBPeripheral *)peripheral
- advertisementData:(NSDictionary *)advertisementData
- RSSI:(NSNumber *)RSSI {
- // retrieve the beacon data from the advertised data
- NSDictionary *serviceData = advertisementData[CBAdvertisementDataServiceDataKey];
-
- // retrieve the frame type
- FrameType frameType = [Beacon getFrameType:serviceData];
-
- // handle basic beacon broadcasts
- if (frameType == FrameTypeUID || frameType == FrameTypeEID) {
- // create our beacon object based on the frame type
- Beacon *beacon;
- NSString *eventName;
- if (frameType == FrameTypeUID) {
- eventName = @"onUIDFrame";
- beacon = [Beacon initWithUIDFrameType:serviceData rssi:RSSI];
- } else if(frameType == FrameTypeEID) {
- eventName = @"onEIDFrame";
- beacon = [Beacon initWithEIDFrameType:serviceData rssi:RSSI];
- }
-
- // dispatch device event with beacon information
- [self sendEventWithName:eventName
- body:@{
- @"id": [NSString stringWithFormat:@"%@", beacon.id],
- @"uid": [peripheral.identifier UUIDString],
- @"txPower": beacon.txPower,
- @"rssi": beacon.rssi
- }];
- } else if(frameType == FrameTypeURL) {
- // retrive the URL from the beacon broadcast & dispatch
- NSURL *url = [Beacon getUrl:serviceData];
- [self sendEventWithName:@"onURLFrame" body:@{
- @"uid": [peripheral.identifier UUIDString],
- @"url": url.absoluteString
- }];
- } else if (frameType == FrameTypeTelemetry) {
- // retrieve the beacon data
- NSData *beaconData = [Beacon getData:serviceData];
- uint8_t *bytes = (uint8_t *)[beaconData bytes];
-
- // attempt to match a frame type
- if (beaconData) {
- if ([beaconData length] > 1) {
- int voltage = (bytes[2] & 0xFF) << 8;
- voltage += (bytes[3] & 0xFF);
-
- int temp = (bytes[4] << 8);
- temp += (bytes[5] & 0xFF);
- temp /= 256.f;
-
- // dispatch telemetry information
- [self sendEventWithName:@"onTelemetryFrame" body:@{
- @"uid": [peripheral.identifier UUIDString],
- @"voltage": [NSNumber numberWithInt: voltage],
- @"temp": [NSNumber numberWithInt: temp]
- }];
- }
- }
-
- } else if (frameType == FrameTypeEmpty){
- // dispatch empty frame
- [self sendEventWithName:@"onEmptyFrame" body:nil];
- }
- }
-
- /**
- * Executes when the Core Bluetooth Central Manager's state changes
- * @param CBCentralManager manager The Central Manager instance
- * @return void
- */
- - (void)centralManagerDidUpdateState:(nonnull CBCentralManager *)manager {
- switch(manager.state) {
- case CBCentralManagerStatePoweredOn:
- [self sendEventWithName:@"onStateChanged" body:@"on"];
- if(_shouldBeScanning) {
- [self startScanning];
- }
- break;
-
- case CBCentralManagerStatePoweredOff:
- [self sendEventWithName:@"onStateChanged" body:@"off"];
- break;
-
- case CBCentralManagerStateResetting:
- [self sendEventWithName:@"onStateChanged" body:@"resetting"];
- break;
-
- case CBCentralManagerStateUnsupported:
- [self sendEventWithName:@"onStateChanged" body:@"unsupported"];
- break;
-
- case CBCentralManagerStateUnauthorized:
- [self sendEventWithName:@"onStateChanged" body:@"unauthorized"];
- break;
-
- default:
- [self sendEventWithName:@"onStateChanged" body:@"unknown"];
- }
- }
-@end
diff --git a/ios/Eddystone.podspec b/ios/Eddystone.podspec
deleted file mode 100644
index 9a9fe2b..0000000
--- a/ios/Eddystone.podspec
+++ /dev/null
@@ -1,24 +0,0 @@
-
-Pod::Spec.new do |s|
- s.name = "Eddystone"
- s.version = "1.0.0"
- s.summary = "Eddystone"
- s.description = <<-DESC
- Eddystone
- DESC
- s.homepage = "https://github.com/lg2/react-native-eddystone"
- s.license = "MIT"
- # s.license = { :type => "MIT", :file => "FILE_LICENSE" }
- s.author = { "author" => "author@domain.cn" }
- s.platform = :ios, "7.0"
- s.source = { :git => "https://github.com/lg2/react-native-eddystone", :tag => "master" }
- s.source_files = "**/*.{h,m}"
- s.requires_arc = true
-
-
- s.dependency "React"
- #s.dependency "others"
-
-end
-
-
diff --git a/ios/Eddystone.xcodeproj/project.pbxproj b/ios/Eddystone.xcodeproj/project.pbxproj
index 0008a41..eb8d97f 100644
--- a/ios/Eddystone.xcodeproj/project.pbxproj
+++ b/ios/Eddystone.xcodeproj/project.pbxproj
@@ -7,6 +7,7 @@
objects = {
/* Begin PBXBuildFile section */
+ 2E8A60DD2D4C2E8F0030404B /* EddystoneModule.mm in Sources */ = {isa = PBXBuildFile; fileRef = 2E8A60DB2D4C2E8F0030404B /* EddystoneModule.mm */; };
2E9B3B3E21ED254800D52F4E /* Beacon.m in Sources */ = {isa = PBXBuildFile; fileRef = 2E9B3B3B21ED254800D52F4E /* Beacon.m */; };
B3E7B58A1CC2AC0600A0062D /* Eddystone.m in Sources */ = {isa = PBXBuildFile; fileRef = B3E7B5891CC2AC0600A0062D /* Eddystone.m */; };
/* End PBXBuildFile section */
@@ -25,6 +26,9 @@
/* Begin PBXFileReference section */
134814201AA4EA6300B7C361 /* libEddystone.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libEddystone.a; sourceTree = BUILT_PRODUCTS_DIR; };
+ 2E8A60DA2D4C2E8F0030404B /* EddystoneModule.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = EddystoneModule.h; sourceTree = ""; };
+ 2E8A60DB2D4C2E8F0030404B /* EddystoneModule.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = EddystoneModule.mm; sourceTree = ""; };
+ 2E8A60DC2D4C2E8F0030404B /* EddystoneModule-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "EddystoneModule-Bridging-Header.h"; sourceTree = ""; };
2E9B3B3B21ED254800D52F4E /* Beacon.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Beacon.m; sourceTree = ""; };
2E9B3B3D21ED254800D52F4E /* Beacon.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Beacon.h; sourceTree = ""; };
B3E7B5881CC2AC0600A0062D /* Eddystone.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Eddystone.h; sourceTree = ""; };
@@ -53,6 +57,9 @@
58B511D21A9E6C8500147676 = {
isa = PBXGroup;
children = (
+ 2E8A60DA2D4C2E8F0030404B /* EddystoneModule.h */,
+ 2E8A60DB2D4C2E8F0030404B /* EddystoneModule.mm */,
+ 2E8A60DC2D4C2E8F0030404B /* EddystoneModule-Bridging-Header.h */,
2E9B3B3D21ED254800D52F4E /* Beacon.h */,
2E9B3B3B21ED254800D52F4E /* Beacon.m */,
B3E7B5881CC2AC0600A0062D /* Eddystone.h */,
@@ -100,6 +107,7 @@
developmentRegion = English;
hasScannedForEncodings = 0;
knownRegions = (
+ English,
en,
);
mainGroup = 58B511D21A9E6C8500147676;
@@ -119,6 +127,7 @@
files = (
B3E7B58A1CC2AC0600A0062D /* Eddystone.m in Sources */,
2E9B3B3E21ED254800D52F4E /* Beacon.m in Sources */,
+ 2E8A60DD2D4C2E8F0030404B /* EddystoneModule.mm in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
diff --git a/ios/Eddystone.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/ios/Eddystone.xcodeproj/project.xcworkspace/contents.xcworkspacedata
new file mode 100644
index 0000000..919434a
--- /dev/null
+++ b/ios/Eddystone.xcodeproj/project.xcworkspace/contents.xcworkspacedata
@@ -0,0 +1,7 @@
+
+
+
+
+
diff --git a/ios/Eddystone.xcodeproj/project.xcworkspace/xcuserdata/jaio.xcuserdatad/UserInterfaceState.xcuserstate b/ios/Eddystone.xcodeproj/project.xcworkspace/xcuserdata/jaio.xcuserdatad/UserInterfaceState.xcuserstate
new file mode 100644
index 0000000..a42670b
Binary files /dev/null and b/ios/Eddystone.xcodeproj/project.xcworkspace/xcuserdata/jaio.xcuserdatad/UserInterfaceState.xcuserstate differ
diff --git a/ios/Eddystone.xcodeproj/xcuserdata/jaio.xcuserdatad/xcschemes/xcschememanagement.plist b/ios/Eddystone.xcodeproj/xcuserdata/jaio.xcuserdatad/xcschemes/xcschememanagement.plist
new file mode 100644
index 0000000..67e4fb7
--- /dev/null
+++ b/ios/Eddystone.xcodeproj/xcuserdata/jaio.xcuserdatad/xcschemes/xcschememanagement.plist
@@ -0,0 +1,14 @@
+
+
+
+
+ SchemeUserState
+
+ Eddystone.xcscheme_^#shared#^_
+
+ orderHint
+ 0
+
+
+
+
diff --git a/ios/EddystoneModule-Bridging-Header.h b/ios/EddystoneModule-Bridging-Header.h
new file mode 100644
index 0000000..c397775
--- /dev/null
+++ b/ios/EddystoneModule-Bridging-Header.h
@@ -0,0 +1,6 @@
+#import
+#import
+
+#ifdef RCT_NEW_ARCH_ENABLED
+#endif
+
diff --git a/ios/EddystoneModule.h b/ios/EddystoneModule.h
new file mode 100644
index 0000000..6d83888
--- /dev/null
+++ b/ios/EddystoneModule.h
@@ -0,0 +1,37 @@
+#import
+#import
+
+#ifdef RCT_NEW_ARCH_ENABLED
+
+#import
+@class Eddystone;
+
+@interface EddystoneModule : NativeEddystoneModuleSpecBase
+- (void)emitOnUIDFrame:(NSDictionary *)value;
+- (void)emitOnURLFrame:(NSDictionary *)value;
+- (void)emitOnEIDFrame:(NSDictionary *)value;
+- (void)emitOnTelemetryData:(NSDictionary *)value;
+- (void)emitOnEmptyFrame:(NSDictionary *)value;
+- (void)emitOnStateChanged:(NSDictionary *)value;
+//+ (nullable CBCentralManager *)getCentralManager;
+//+ (nullable SwiftBleManager *)getInstance;
+@end
+
+#else
+
+@interface EddystoneModule : NSObject
+- (void)emitOnUIDFrame:(NSDictionary *)value;
+- (void)emitOnURLFrame:(NSDictionary *)value;
+- (void)emitOnEIDFrame:(NSDictionary *)value;
+- (void)emitOnTelemetryData:(NSDictionary *)value;
+- (void)emitOnEmptyFrame:(NSDictionary *)value;
+- (void)emitOnStateChanged:(NSDictionary *)value;
+//+ (nullable CBCentralManager *)getCentralManager;
+//+ (nullable SwiftBleManager *)getInstance;
+@end
+
+#endif
+
+@interface SpecChecker : NSObject
++ (BOOL)isSpecAvailable;
+@end
diff --git a/ios/EddystoneModule.mm b/ios/EddystoneModule.mm
new file mode 100644
index 0000000..60f0d12
--- /dev/null
+++ b/ios/EddystoneModule.mm
@@ -0,0 +1,200 @@
+#import "EddystoneModule.h"
+#import
+#import "Beacon.h"
+
+#ifdef RCT_NEW_ARCH_ENABLED
+#import "EddystoneModuleSpec.h"
+#endif
+
+
+@interface EddystoneModule () {
+@private
+ /** @property BOOL Whether we should be scanning for devices or not */
+ BOOL _shouldBeScanning;
+
+ // core bluetooth central manager
+ CBCentralManager *_centralManager;
+
+ // our beacon dispatch queue
+ dispatch_queue_t _beaconOperationsQueue;
+}
+@end
+
+@implementation EddystoneModule
+
+- (instancetype)init {
+ if ((self = [super init]) != nil) {
+ _beaconOperationsQueue = dispatch_queue_create("EddystoneBeaconOperationsQueue", NULL);
+ _centralManager = [[CBCentralManager alloc] initWithDelegate:self queue:_beaconOperationsQueue];
+ }
+ return self;
+}
+
+
+RCT_EXPORT_MODULE()
+
+- (void)startScanning {
+ dispatch_async(_beaconOperationsQueue, ^{
+ if (self->_centralManager.state != CBCentralManagerStatePoweredOn) {
+ self->_shouldBeScanning = YES;
+ } else {
+ NSArray *services = @[[CBUUID UUIDWithString:SERVICE_ID]];
+ NSDictionary *options = @{ CBCentralManagerScanOptionAllowDuplicatesKey : @YES };
+ [self->_centralManager scanForPeripheralsWithServices:services options:options];
+ }
+ });
+}
+
+
+- (void)stopScannig {
+ _shouldBeScanning = NO;
+ [_centralManager stopScan];
+}
+
+
+//- (void)setName:(NSString *)name {
+// [_eddystone setName:name];
+//}
+
+/**
+ * Executes when the Core Bluetooth Central Manager discovered a peripheral
+ * @param CBCentralManager * central Core Bluetooth Central Manager instance
+ * @param CBPeripheral * peripheral Core Bluetooth peripheral instance
+ * @param NSDictionary * advertisementData Peripheral advertised data
+ * @param NSNumber * RSSI The received signal strength indication
+ * @return void
+ */
+- (void)centralManager:(CBCentralManager *)central
+ didDiscoverPeripheral:(CBPeripheral *)peripheral
+ advertisementData:(NSDictionary *)advertisementData
+ RSSI:(NSNumber *)RSSI {
+ if(hasListeners){
+ // retrieve the beacon data from the advertised data
+ NSDictionary *serviceData = advertisementData[CBAdvertisementDataServiceDataKey];
+
+ // retrieve the frame type
+ FrameType frameType = [Beacon getFrameType:serviceData];
+
+ // handle basic beacon broadcasts
+ if (frameType == FrameTypeUID || frameType == FrameTypeEID) {
+ // create our beacon object based on the frame type
+ Beacon *beacon;
+ NSString *eventName;
+ if (frameType == FrameTypeUID) {
+ eventName = @"onUIDFrame";
+ beacon = [Beacon initWithUIDFrameType:serviceData rssi:RSSI];
+ } else if(frameType == FrameTypeEID) {
+ eventName = @"onEIDFrame";
+ beacon = [Beacon initWithEIDFrameType:serviceData rssi:RSSI];
+ }
+ //dispatch device event with beacon information
+ [_eddystoneModule emitOnUIDFrame:@{
+ @"id": [NSString stringWithFormat:@"%@", beacon.id],
+ @"uid": [peripheral.identifier UUIDString],
+ @"txPower": beacon.txPower,
+ @"rssi": beacon.rssi
+ }];
+ // dispatch device event with beacon information
+ // [self sendEventWithName:eventName
+ // body:@{
+ // @"id": [NSString stringWithFormat:@"%@", beacon.id],
+ // @"uid": [peripheral.identifier UUIDString],
+ // @"txPower": beacon.txPower,
+ // @"rssi": beacon.rssi
+ // }];
+ } else if(frameType == FrameTypeURL) {
+ // retrive the URL from the beacon broadcast & dispatch
+ NSURL *url = [Beacon getUrl:serviceData];
+ [self emitOnURLFrame:@{
+ @"uid": [peripheral.identifier UUIDString],
+ @"url": url.absoluteString
+ }];
+ // [self sendEventWithName:@"onURLFrame" body:@{
+ // @"uid": [peripheral.identifier UUIDString],
+ // @"url": url.absoluteString
+ // }];
+ } else if (frameType == FrameTypeTelemetry) {
+ // retrieve the beacon data
+ NSData *beaconData = [Beacon getData:serviceData];
+ uint8_t *bytes = (uint8_t *)[beaconData bytes];
+
+ // attempt to match a frame type
+ if (beaconData) {
+ if ([beaconData length] > 1) {
+ int voltage = (bytes[2] & 0xFF) << 8;
+ voltage += (bytes[3] & 0xFF);
+
+ int temp = (bytes[4] << 8);
+ temp += (bytes[5] & 0xFF);
+ temp /= 256.f;
+ [self emitOnTelemetryData:@{
+ @"uid": [peripheral.identifier UUIDString],
+ @"voltage": [NSNumber numberWithInt: voltage],
+ @"temp": [NSNumber numberWithInt: temp]
+ }];
+ // // dispatch telemetry information
+ // [self sendEventWithName:@"onTelemetryFrame" body:@{
+ // @"uid": [peripheral.identifier UUIDString],
+ // @"voltage": [NSNumber numberWithInt: voltage],
+ // @"temp": [NSNumber numberWithInt: temp]
+ // }];
+ }
+ }
+
+ } else if (frameType == FrameTypeEmpty){
+ [self emitOnEmptyFrame:@{}];
+ // dispatch empty frame
+ // [self sendEventWithName:@"onEmptyFrame" body:nil];
+ }
+ }
+}
+
+/**
+ * Executes when the Core Bluetooth Central Manager's state changes
+ * @param CBCentralManager manager The Central Manager instance
+ * @return void
+ */
+- (void)centralManagerDidUpdateState:(nonnull CBCentralManager *)manager {
+ switch(manager.state) {
+ case CBManagerStatePoweredOn:
+ // [self sendEventWithName:@"onStateChanged" body:@"on"];
+ [self emitOnStateChanged:@{@"value":@"on"}];
+ if(_shouldBeScanning) {
+ [self startScanning];
+ }
+ break;
+
+ case CBManagerStatePoweredOff:
+ [self emitOnStateChanged:@{@"value":@"off"}];
+ break;
+
+ case CBManagerStateResetting:
+ [self emitOnStateChanged:@{@"value":@"resseting"}];
+ break;
+
+ case CBManagerStateUnsupported:
+ //[self sendEventWithName:@"onStateChanged" body:@"unsupported"];
+ [self emitOnStateChanged:@{@"value":@"unsupported"}];
+
+ break;
+
+ case CBManagerStateUnauthorized:
+ //[self sendEventWithName:@"onStateChanged" body:@"unauthorized"];
+ [self emitOnStateChanged:@{@"value":@"unauthorized"}];
+
+ break;
+
+ default:
+ // [self sendEventWithName:@"onStateChanged" body:@"unknown"];
+ [self emitOnStateChanged:@{@"value":@"unknown"}];
+
+ }
+}
+#ifdef RCT_NEW_ARCH_ENABLED
+- (std::shared_ptr)getTurboModule:
+(const facebook::react::ObjCTurboModule::InitParams &)params
+{
+ return std::make_shared(params);
+}
+#endif
+@end
diff --git a/package.json b/package.json
index 1632971..71005e9 100644
--- a/package.json
+++ b/package.json
@@ -1,23 +1,40 @@
{
- "name": "@lg2/react-native-eddystone",
- "version": "0.1.5",
- "description": "A simple Eddystone implementation in React Native for both iOS and Android.",
- "main": "src/index.js",
- "directories": {
- "example": "examples"
- },
- "scripts": {
- "test": "echo \"Error: no test specified\" && exit 1"
- },
- "repository": {
- "type": "git",
- "url": "git+https://github.com/lg2/react-native-eddystone.git"
- },
- "keywords": ["react", "native", "eddystone"],
- "author": "Nicholas Charbonneau ",
+ "name": "react-native-eddystone",
+ "version": "2.0",
+ "description": "Showcase Turbomodule with backward compatibility",
+ "react-native": "src/index",
+ "source": "src/index",
+ "files": [
+ "src",
+ "android",
+ "ios",
+ "*.podspec",
+ "!android/build",
+ "!ios/build",
+ "!**/__tests__",
+ "!**/__fixtures__",
+ "!**/__mocks__"
+ ],
+ "keywords": [
+ "react-native",
+ "ios",
+ "android"
+ ],
+ "repository": "https://github.com/JaioSkura/react-native-eddystone",
+ "author": " (https://github.com/)",
"license": "MIT",
"bugs": {
- "url": "https://github.com/lg2/react-native-eddystone/issues"
+ "url": "https://github.com/JaioSkura/react-native-eddystone/issues"
+ },
+ "homepage": "https://github.com/JaioSkura/react-native-eddystone#readme",
+ "devDependencies": {},
+ "peerDependencies": {
+ "react": "*",
+ "react-native": "*"
},
- "homepage": "https://github.com/lg2/react-native-eddystone#readme"
+ "codegenConfig": {
+ "name": "EddystoneModuleSpec",
+ "type": "modules",
+ "jsSrcsDir": "src"
+ }
}
diff --git a/src/Beacon.js b/src/Beacon.js
deleted file mode 100644
index 8a04278..0000000
--- a/src/Beacon.js
+++ /dev/null
@@ -1,58 +0,0 @@
-/**
- * React Native Eddystone
- *
- * A simple Eddystone implementation in React Native for both iOS and Android.
- *
- * @package @lg2/react-native-eddystone
- * @link https://github.com/lg2/react-native-eddystone
- * @copyright 2019 lg2
- * @license MIT
- */
-
-class Beacon {
- /**
- * Beacon class constructor
- * @param {BeaconData} data The beacon data to use for creation
- * @param {Manager} manager A reference to the beacon's manager
- */
- constructor(data, manager) {
- this.id = data.id;
- this.uid = data.uid;
- this.rssi = data.rssi;
- this.txPower = data.txPower;
-
- this.url = null;
- this.temp = null;
- this.voltage = null;
-
- this.manager = manager;
- }
-
- /**
- * Sets/resets the beacon' expiration timer
- * @param {number} time The expiration value in milliseconds
- * @returns {void}
- */
- setExpiration(time) {
- if (this.timeout) clearTimeout(this.timeout);
- this.timeout = setTimeout(() => this.manager.onBeaconExpires(this), time);
- }
-
- /**
- * Gets the beacon' approximative distance from the device
- * @returns {number} The aprroximative distance in meters
- */
- getDistance() {
- if (this.rssi == 0) return -1;
-
- const ratio = this.rssi / this.txPower;
-
- return (
- (ratio < 1.0
- ? Math.pow(ratio, 10)
- : 0.89976 * Math.pow(ratio, 7.7095) + 0.111) / 1000
- );
- }
-}
-
-export default Beacon;
diff --git a/src/Manager.js b/src/Manager.js
deleted file mode 100644
index 54e963f..0000000
--- a/src/Manager.js
+++ /dev/null
@@ -1,142 +0,0 @@
-/**
- * React Native Eddystone
- *
- * A simple Eddystone implementation in React Native for both iOS and Android.
- *
- * @package @lg2/react-native-eddystone
- * @link https://github.com/lg2/react-native-eddystone
- * @copyright 2019 lg2
- * @license MIT
- */
-
-import Beacon from "./Beacon";
-import EventEmitter from "eventemitter3";
-import { startScanning, stopScanning } from "./NativeModule";
-import { addListener, removeListener } from "./NativeEventEmitter";
-
-class Manager extends EventEmitter {
- /**
- * Manager class constructor
- * @param {number} expiration Beacon expiration time in milliseconds
- */
- constructor(expiration) {
- super();
-
- this.beacons = [];
- this.expiration = expiration || 10000;
- this.events = {
- addBeacon: this.addBeacon.bind(this),
- addUrl: data => this._onData(data, this.addUrl.bind(this)),
- addTelemetry: data => this._onData(data, this.addTelemetry.bind(this))
- };
- }
-
- /**
- * Starts scanning for beacons
- * @returns {void}
- */
- start() {
- addListener("onUIDFrame", this.events.addBeacon);
- addListener("onEIDFrame", this.events.addBeacon);
- addListener("onURLFrame", this.events.addUrl);
- addListener("onTelemetryFrame", this.events.addTelemetry);
-
- startScanning();
- }
-
- /**
- * Stops scanning for beacons
- * @returns {void}
- */
- stop() {
- removeListener("onUIDFrame", this.events.addBeacon);
- removeListener("onEIDFrame", this.events.addBeacon);
- removeListener("onURLFrame", this.events.addUrl);
- removeListener("onTelemetryFrame", this.events.addTelemetry);
-
- stopScanning();
- }
-
- /**
- * Checks whether or not the manager has cached the beacon uid or not
- * @param {string} uid The beacon uid to look for
- * @returns {boolean}
- */
- has(uid) {
- return this.beacons.filter(beacon => uid === beacon.uid).length > 0;
- }
-
- /**
- * Adds a beacon to the manager's cache if it does not exist
- * @param {BeaconData} data The beacons UID/EID information
- * @returns {void}
- */
- addBeacon(data) {
- if (!this.has(data.uid)) {
- const beacon = new Beacon(data, this);
- beacon.setExpiration(this.expiration);
-
- this.beacons.push(beacon);
-
- this.emit("onBeaconAdded", beacon);
- }
- }
-
- /**
- * Adds a URL to an existing beacon in the cache
- * @param {Beacon} beacon The beacon to add url to
- * @param {URLData} data The data containing the broadcasted URL
- * @returns {void}
- */
- addUrl(beacon, data) {
- beacon.url = data.url;
- beacon.setExpiration(this.expiration);
-
- this.emit("onBeaconUpdated", beacon);
- }
-
- /**
- * Adds telemetry info to an existing beacon in the cache
- * @param {Beacon} beacon The beacon to add telemetry to
- * @param {TelemetryData} data The data containing the broadcasted telemetry
- * @returns {void}
- */
- addTelemetry(beacon, data) {
- beacon.temp = data.temp;
- beacon.voltage = data.voltage;
- beacon.setExpiration(this.expiration);
-
- this.emit("onBeaconUpdated", beacon);
- }
-
- /**
- * Triggered when a beacon has reached the end of its life
- * @param {Beacon} beacon The expired beacon
- * @returns {void}
- */
- onBeaconExpires(beacon) {
- if (this.has(beacon.uid)) {
- this.beacons.splice(
- this.beacons.findIndex(({ uid }) => beacon.uid === uid),
- 1
- );
-
- this.emit("onBeaconExpired", beacon);
- }
- }
-
- /**
- * Triggered when a beacon message has been received by the bluetooth manager
- * @param {BeaconData|URLData|TelemetryData} data The data received from the beacon
- * @param {Function} callback The callback that will handle this data
- * @returns {void}
- */
- _onData(data, callback) {
- if (this.has(data.uid)) {
- const index = this.beacons.findIndex(beacon => beacon.uid === data.uid);
- callback(this.beacons[index], data);
- }
- }
-}
-
-export default Manager;
diff --git a/src/NativeEddystoneManager.ts b/src/NativeEddystoneManager.ts
new file mode 100644
index 0000000..26eba3c
--- /dev/null
+++ b/src/NativeEddystoneManager.ts
@@ -0,0 +1,53 @@
+import { TurboModule, TurboModuleRegistry } from 'react-native';
+// @ts-ignore Ignore since it comes from codegen types.
+import type { EventEmitter } from 'react-native/Libraries/Types/CodegenTypes';
+
+/**
+ * This represents the Turbo Module version of react-native-ble-manager.
+ * This adds the codegen definition to react-native generate the c++ bindings on compile time.
+ * That should work only on 0.75 and higher.
+ * Don't remove it! and please modify with caution! Knowing that can create wrong bindings into jsi and break at compile or execution time.
+ * - Knowing that also every type needs to match the current Objective C++ and Java callbacks types and callbacks type definitions and be aware of the current differences between implementation in both platforms.
+ */
+
+export interface Spec extends TurboModule {
+
+ startScanning(): void;
+
+ stopScanning(): void;
+
+ /**
+ * Supported events.
+ */
+
+ readonly onUIDFrame: EventEmitter;
+ readonly onEIDFrame: EventEmitter;
+ readonly onURLFrame: EventEmitter;
+ readonly onTelemetryData: EventEmitter;
+ readonly onEmptyFrame: EventEmitter;
+ readonly onStateChanged: EventEmitter;
+
+
+}
+
+export default TurboModuleRegistry.get('EddystoneModule') as Spec;
+
+export type BeaconData ={
+ id: string;
+ uid: string;
+ rssi: number;
+ txPower: number;
+}
+
+
+export type TelemetryData ={
+ uid: string;
+ voltaje: number;
+ temp: number;
+}
+
+
+export type URLData ={
+ uid: string;
+ url: string;
+}
\ No newline at end of file
diff --git a/src/NativeEventEmitter.js b/src/NativeEventEmitter.js
deleted file mode 100644
index 39b3f13..0000000
--- a/src/NativeEventEmitter.js
+++ /dev/null
@@ -1,25 +0,0 @@
-/**
- * React Native Eddystone
- *
- * A simple Eddystone implementation in React Native for both iOS and Android.
- *
- * @package @lg2/react-native-eddystone
- * @link https://github.com/lg2/react-native-eddystone
- * @copyright 2019 lg2
- * @license MIT
- */
-
-import { NativeModules, NativeEventEmitter } from "react-native";
-
-const { Eddystone } = NativeModules;
-const EddystoneEventEmitter = new NativeEventEmitter(Eddystone);
-
-const addListener = EddystoneEventEmitter.addListener.bind(
- EddystoneEventEmitter
-);
-
-const removeListener = EddystoneEventEmitter.removeListener.bind(
- EddystoneEventEmitter
-);
-
-export { addListener, removeListener };
diff --git a/src/NativeModule.js b/src/NativeModule.js
deleted file mode 100644
index 9be9684..0000000
--- a/src/NativeModule.js
+++ /dev/null
@@ -1,17 +0,0 @@
-/**
- * React Native Eddystone
- *
- * A simple Eddystone implementation in React Native for both iOS and Android.
- *
- * @package @lg2/react-native-eddystone
- * @link https://github.com/lg2/react-native-eddystone
- * @copyright 2019 lg2
- * @license MIT
- */
-
-import { NativeModules } from "react-native";
-
-const { Eddystone } = NativeModules;
-const { startScanning, stopScanning } = Eddystone;
-
-export { startScanning, stopScanning };
diff --git a/src/index.js b/src/index.js
deleted file mode 100644
index b9ed999..0000000
--- a/src/index.js
+++ /dev/null
@@ -1,22 +0,0 @@
-/**
- * React Native Eddystone
- *
- * A simple Eddystone implementation in React Native for both iOS and Android.
- *
- * @package @lg2/react-native-eddystone
- * @link https://github.com/lg2/react-native-eddystone
- * @copyright 2019 lg2
- * @license MIT
- */
-
-import Manager from "./Manager";
-import { startScanning, stopScanning } from "./NativeModule.js";
-import { addListener, removeListener } from "./NativeEventEmitter";
-
-export default {
- startScanning,
- stopScanning,
- addListener,
- removeListener,
- Manager
-};
diff --git a/src/index.ts b/src/index.ts
new file mode 100644
index 0000000..11eea80
--- /dev/null
+++ b/src/index.ts
@@ -0,0 +1,58 @@
+import {
+ EventSubscription,
+ NativeModules,
+} from 'react-native';
+
+import {
+ URLData,
+ BeaconData,
+ TelemetryData,
+} from './types';
+export * from './types';
+
+
+// @ts-expect-error This applies the turbo module version only when turbo is enabled for backwards compatibility.
+const isTurboModuleEnabled = global?.__turboModuleProxy != null;
+
+const EddystoneModule = isTurboModuleEnabled
+ ? require('./NativeEddystoneManager').default
+ : NativeModules.EddystoneModule;
+
+class EddystoneManager {
+ constructor() {
+ if (!EddystoneModule) {
+ throw new Error('EddystoneManagerModule not found');
+ }
+ }
+
+ startScanning() {
+ EddystoneModule.startScanning();
+ };
+
+ stopScanning() {
+ EddystoneModule.stopScanning();
+ };
+
+
+ onUIDFrame(callback: any): EventSubscription {
+ return EddystoneModule.onUIDFrame(callback);
+ }
+
+ onEIDFrame(callback: any): EventSubscription {
+ return EddystoneModule.onEIDFrame(callback);
+ }
+ onURLFrame(callback: any): EventSubscription {
+ return EddystoneModule.onURLFrame(callback);
+ }
+ onTelemetryData(callback: any): EventSubscription {
+ return EddystoneModule.onTelemetryData(callback);
+ }
+ onEmptyFrame(callback: any): EventSubscription {
+ return EddystoneModule.onEmptyFrame(callback);
+ }
+ onStateChanged(callback: any): EventSubscription {
+ return EddystoneModule.onStateChanged(callback);
+ }
+}
+
+export default new EddystoneManager();
diff --git a/src/types.ts b/src/types.ts
new file mode 100644
index 0000000..a0b5084
--- /dev/null
+++ b/src/types.ts
@@ -0,0 +1,21 @@
+export interface BeaconData {
+ id: string,
+ uid: string,
+ rssi: number,
+ txPower: number
+}
+
+export interface TelemetryData {
+ uid: string,
+ voltage: number,
+ temp: number
+}
+
+export interface URLData {
+ uid: string,
+ url: string
+}
+
+
+
+