From c724a211efe517d98d8bd9c423f3bf2b68d36b2e Mon Sep 17 00:00:00 2001 From: Jaio Skura Date: Mon, 7 Sep 2020 22:04:17 +0200 Subject: [PATCH 01/36] android uid last 2 bytes lost fixed --- android/src/main/java/com/lg2/eddystone/EddystoneModule.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/android/src/main/java/com/lg2/eddystone/EddystoneModule.java b/android/src/main/java/com/lg2/eddystone/EddystoneModule.java index 86f8ea2..7cf99a5 100644 --- a/android/src/main/java/com/lg2/eddystone/EddystoneModule.java +++ b/android/src/main/java/com/lg2/eddystone/EddystoneModule.java @@ -211,7 +211,7 @@ public void handleResult(ScanResult result) { // handle all possible frame types byte frameType = serviceData[0]; if (frameType == FRAME_TYPE_UID || frameType == FRAME_TYPE_EID) { - int length = 16; + int length = 18; String event = "onUIDFrame"; if (frameType == FRAME_TYPE_EID) { From 3a32f9c66f5fc2e5beed99f62983bec1db9dfbd7 Mon Sep 17 00:00:00 2001 From: JaioSkura Date: Wed, 17 Apr 2024 09:35:39 +0200 Subject: [PATCH 02/36] Update build.gradle --- android/build.gradle | 58 ++++++++++++++++++++++---------------------- 1 file changed, 29 insertions(+), 29 deletions(-) diff --git a/android/build.gradle b/android/build.gradle index a28f0dd..8cb41f2 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -1,36 +1,36 @@ - buildscript { - repositories { - jcenter() - } + repositories { + google() + jcenter() + } - dependencies { - classpath 'com.android.tools.build:gradle:1.3.1' - } -} + dependencies { + classpath 'com.android.tools.build:gradle:8.2.0' + } + } -apply plugin: 'com.android.library' + apply plugin: 'com.android.library' -android { - compileSdkVersion 23 - buildToolsVersion "23.0.1" + android { + compileSdkVersion 33 + buildToolsVersion "33.0.0" - defaultConfig { - minSdkVersion 16 - targetSdkVersion 22 - versionCode 1 - versionName "1.0" - } - lintOptions { - abortOnError false - } -} + defaultConfig { + minSdkVersion 26 + targetSdkVersion 33 + versionCode 1 + versionName "1.0" + } + lintOptions { + abortOnError false + } + } -repositories { - mavenCentral() -} + repositories { + google() + mavenCentral() + } -dependencies { - compile 'com.facebook.react:react-native:+' -} - \ No newline at end of file + dependencies { + implementation 'com.facebook.react:react-native:+' + } From 265b49edfd4bca29f101cdde61e238c9ad25713a Mon Sep 17 00:00:00 2001 From: JaioSkura Date: Wed, 17 Apr 2024 09:36:58 +0200 Subject: [PATCH 03/36] Update NativeEventEmitter.js --- src/NativeEventEmitter.js | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/NativeEventEmitter.js b/src/NativeEventEmitter.js index 39b3f13..bf3d484 100644 --- a/src/NativeEventEmitter.js +++ b/src/NativeEventEmitter.js @@ -2,6 +2,7 @@ * React Native Eddystone * * A simple Eddystone implementation in React Native for both iOS and Android. + * Changed by JaioSkura * * @package @lg2/react-native-eddystone * @link https://github.com/lg2/react-native-eddystone @@ -15,11 +16,7 @@ const { Eddystone } = NativeModules; const EddystoneEventEmitter = new NativeEventEmitter(Eddystone); const addListener = EddystoneEventEmitter.addListener.bind( - EddystoneEventEmitter -); +EddystoneEventEmitter); -const removeListener = EddystoneEventEmitter.removeListener.bind( - EddystoneEventEmitter -); +export { addListener}; -export { addListener, removeListener }; From 822e27e86cf49f496049fa4a2bd10c50253d741c Mon Sep 17 00:00:00 2001 From: JaioSkura Date: Wed, 17 Apr 2024 09:39:14 +0200 Subject: [PATCH 04/36] Update EddystoneModule.java --- .../java/com/lg2/eddystone/EddystoneModule.java | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/android/src/main/java/com/lg2/eddystone/EddystoneModule.java b/android/src/main/java/com/lg2/eddystone/EddystoneModule.java index 7cf99a5..444d20a 100644 --- a/android/src/main/java/com/lg2/eddystone/EddystoneModule.java +++ b/android/src/main/java/com/lg2/eddystone/EddystoneModule.java @@ -307,7 +307,10 @@ public void startScanning() { // start scanning scanner = bluetoothAdapter.getBluetoothLeScanner(); - scanner.startScan(filters, settings, scanCallback); + scanner = bluetoothAdapter.getBluetoothLeScanner(); + if(scanner!=null){ + scanner.startScan(filters, settings, scanCallback); + } } /** @@ -317,8 +320,11 @@ public void startScanning() { * @public */ @ReactMethod - public void stopScanning() { - scanner.stopScan(scanCallback); - scanner = null; + public void stopScanning() { + if(scanner!=null){ + scanner.stopScan(scanCallback); + } + scanner = null; } + } From a83486d8051a246204246c3f9ba2e9faadbd3933 Mon Sep 17 00:00:00 2001 From: JaioSkura Date: Wed, 30 Oct 2024 22:57:01 +0100 Subject: [PATCH 05/36] Update Manager.js changed eventemitter libray --- src/Manager.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Manager.js b/src/Manager.js index 54e963f..4645fe1 100644 --- a/src/Manager.js +++ b/src/Manager.js @@ -10,7 +10,7 @@ */ import Beacon from "./Beacon"; -import EventEmitter from "eventemitter3"; +import EventEmitter from "react-native/Libraries/vendor/emitter/EventEmitter"; import { startScanning, stopScanning } from "./NativeModule"; import { addListener, removeListener } from "./NativeEventEmitter"; From 40c7792901f3f5c6ab3908567fa4f843af5e6c4f Mon Sep 17 00:00:00 2001 From: Jaio Date: Wed, 15 Jan 2025 16:13:37 +0100 Subject: [PATCH 06/36] new architecture --- RNEddystoneManager.podspec | 36 ++ android/bin/build.gradle | 36 ++ android/bin/src/main/AndroidManifest.xml | 6 + .../com/lg2/eddystone/EddystoneModule.class | Bin 0 -> 8616 bytes .../com/lg2/eddystone/EddystonePackage.class | Bin 0 -> 3268 bytes android/build.gradle | 72 ++- android/src/main/AndroidManifest.xml | 2 + .../com/lg2/eddystone/EddystoneModule.java | 585 +++++++++--------- .../com/lg2/eddystone/EddystonePackage.java | 28 +- ios/Eddystone.m | 150 +++-- package.json | 48 +- src/Beacon.js | 58 -- src/Manager.js | 142 ----- src/NativeEddystoneManager.ts | 53 ++ src/NativeEventEmitter.js | 22 - src/NativeModule.js | 17 - src/index.js | 22 - src/index.ts | 58 ++ src/types.ts | 21 + 19 files changed, 681 insertions(+), 675 deletions(-) create mode 100644 RNEddystoneManager.podspec create mode 100644 android/bin/build.gradle create mode 100644 android/bin/src/main/AndroidManifest.xml create mode 100644 android/bin/src/main/java/com/lg2/eddystone/EddystoneModule.class create mode 100644 android/bin/src/main/java/com/lg2/eddystone/EddystonePackage.class delete mode 100644 src/Beacon.js delete mode 100644 src/Manager.js create mode 100644 src/NativeEddystoneManager.ts delete mode 100644 src/NativeEventEmitter.js delete mode 100644 src/NativeModule.js delete mode 100644 src/index.js create mode 100644 src/index.ts create mode 100644 src/types.ts diff --git a/RNEddystoneManager.podspec b/RNEddystoneManager.podspec new file mode 100644 index 0000000..e51f361 --- /dev/null +++ b/RNEddystoneManager.podspec @@ -0,0 +1,36 @@ +require "json" + +package = JSON.parse(File.read(File.join(__dir__, "package.json"))) + +folly_version = '2021.06.28.00-v2' +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 = "RNEddysotenModule" + 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,swift}" + + s.dependency "React-Core" + # This guard prevent to 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\"", + "CLANG_CXX_LANGUAGE_STANDARD" => "c++17" + } + + s.dependency "React-Codegen" + s.dependency "RCT-Folly", folly_version + s.dependency "RCTRequired" + s.dependency "RCTTypeSafety" + s.dependency "ReactCommon/turbomodule/core" +end +end \ No newline at end of file diff --git a/android/bin/build.gradle b/android/bin/build.gradle new file mode 100644 index 0000000..8cb41f2 --- /dev/null +++ b/android/bin/build.gradle @@ -0,0 +1,36 @@ +buildscript { + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:8.2.0' + } + } + + apply plugin: 'com.android.library' + + android { + compileSdkVersion 33 + buildToolsVersion "33.0.0" + + defaultConfig { + minSdkVersion 26 + targetSdkVersion 33 + versionCode 1 + versionName "1.0" + } + lintOptions { + abortOnError false + } + } + + repositories { + google() + mavenCentral() + } + + dependencies { + implementation 'com.facebook.react:react-native:+' + } diff --git a/android/bin/src/main/AndroidManifest.xml b/android/bin/src/main/AndroidManifest.xml new file mode 100644 index 0000000..c34c720 --- /dev/null +++ b/android/bin/src/main/AndroidManifest.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/android/bin/src/main/java/com/lg2/eddystone/EddystoneModule.class b/android/bin/src/main/java/com/lg2/eddystone/EddystoneModule.class new file mode 100644 index 0000000000000000000000000000000000000000..1c9935ee34b67cdaeefd87c56a64a82d700f8a02 GIT binary patch literal 8616 zcmeHMTXP#V6h50?d?D#2q?ELUZp)<(6q}ZN)0^!$t;;$IjvXcsOh?{TY?Zwjt?a2^ z_*V=wFaz)W0N(i{3`e`ZY?4hZ2Y1rW^ufE9baZs|N$2R>qrd+B?GFIB2lWKZXpr-{ znR5tpbI(YZSczD$DtH+h!&a%yauq%hFmH;DNob~faU24yt-^j+pMabJTgnFCQ=+S1@;(X((paQw5Q^(b-f@g!W= z&i_+)IrTleOD!Fjwax5c9rQN$8a8$OJ9;`*Yf)YF+EkYcvT{MQ;ezTCWKZY~st=T8 z^|H{JuQS(T9M|0LVbc!f)HQL09qu_;{;7j)mYy|j;`{mzv#EcKqZ9)xracvl;_T!s z+qizDN%iXpZx+2KJM^0Cy5&({mk2sUm@Qo((DZp5VT<-d-^)th%Lef8*Aha zT*H`Ed6h+oYjKa^?%cQ6cFpQ#77G@xBbYsI5{C;0!LlDA3&f{S&>h2g8>3ejo=yU{ zO{WfsvSWJf4YsP{!{9rn!zd2_AHj5LT6&I#($RVy72Ez<7z0>3wce$iGmFMFMmNKz z;LL4KL+HRmAUfR9@TnGSE40f@TIy0)lpH3I0ZhZ@>CHZR9*?sua&(UoRb52XSfzf) z#)!W!E=J*3)Mqe%oF+M6r6H#;I2{jU+)vLFQE< z?J+Bx=gp3T&f&+%rBg~1l*G=VqUBk7lZtv3IcAGGG}Gt_x)hQ%Nl60kw};_}tj?F1 zN)dep zaCB9UJ?wBWag1*Bq4-OuU)3NP!UkEAn1eAoS@n>7bXZ=1*^?TRhO6-YEL?#PG`Ns4 zNXmt0+_Fp(oi#ALtaY3Q{A)<=aC<(`PW_@_mwNa) zMp|}^Ln{)v*NpHrBa}RPcr2YeqP@Xo{q!hv=y?rHMPJGeUXkCcO3_ zz9*reY3Zp(@`;U~xP$s^M;@aHJ+iP(uY-4|7;+_#+mjIruBVU;lrhia`j}6|FRsUo za=dMA^%C$1&+y@F`aYU~GBV9!?a+<{e2asP(iRD*XmIg>OmYI&HMkTs#@>x2;5%H{ zC@u-uL}T_6VHB!_S*#k~b^34(@PNm=*f(GvPQhvXHv1Tc^YNpwe$^q&IbR}kb$M3?j!gZrEd16KEd}uo9q*6%f@Kih|z{O z*KjLhkHjg|a63lB4>1~Ma2{VoG>m5SWsHVatcI@-(C|%+hM!|JXs`@-BbeNa#pM2e uZQ5e2wucJZ@-f;9G1^W*5v`el6)52wpoYJB+i~}7u%}gH^TiJ-(k}Jsz z`^(C-Gw|Nu(%;bOk)2K4#K8*_;K8Oc z8?a8Ol1|)T>F_8T8mlDl+#jueX5nwF&pntTa3L3tne2BS?LOh5C2($4NMY9qOtzPH z2uy9L2xXfDW{+g=Yprwx&XZ~Li`3kxc)%lyI#UrdE0mC#pJmmpis$DD=spp+_NL#?7LXML;rXu!1=5w8&o1gbq* z5oM%@SX=|XrJ^jZL(A=3Po3#`MQ$i*`Lj9&>sqs+sj#Bed=1@Wc(Rd~?yJ3hfbF6e zYLVKpJl;@ojP-@xr`mzDOT&)fPq&!FCW<^e(Zb3Jd$TOmc+!Ffd@uvk@F9Uq?ck^_ z_pBDO-*s(!HbC}1%#vNMw;6U~0&{^1S-iuvaPJ2nr|iBk1XhCAJw3Vv=0nYy-<0m~#OmkL{v^0&I@}+6(8dY$IG;SYiBqTJ zi3i^hm?;;O2R?x-r+DJQGK%Lv4@cY;0_RI1^5E|O=GdHSxM@omgPn65hg1U#fU_@7 z)&Ntunuc?D_wem5ekJ&9{RNF*=URWj%u9TmfLXjd8NllT-e(Fa_z33mZ}V^wcV5Ev z1YCwI_;k`A<8y>Mf$IYGY6a@mO4MucDdH8VpB*9{+4p$`()CItTC#7U#=gZ0)EgD3 hlki3E@0aiuJ^}9GHHXL6*RTY);9KaxZMXxI{{i)){R;p9 literal 0 HcmV?d00001 diff --git a/android/build.gradle b/android/build.gradle index 8cb41f2..9946311 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -1,36 +1,50 @@ buildscript { - repositories { - google() - jcenter() - } + ext.safeExtGet = {prop, fallback -> + rootProject.ext.has(prop) ? rootProject.ext.get(prop) : fallback + } + repositories { + google() + gradlePluginPortal() + } + dependencies { + classpath("com.android.tools.build:gradle:7.0.4") + } +} +def isNewArchitectureEnabled() { + return project.hasProperty("newArchEnabled") && project.newArchEnabled == "true" + } +apply plugin: 'com.android.library' - dependencies { - classpath 'com.android.tools.build:gradle:8.2.0' - } - } +if (isNewArchitectureEnabled()) { + apply plugin: 'com.facebook.react' +} - apply plugin: 'com.android.library' +android { + compileSdkVersion safeExtGet('compileSdkVersion', 31) - android { - compileSdkVersion 33 - buildToolsVersion "33.0.0" + defaultConfig { + minSdkVersion safeExtGet('minSdkVersion', 21) + targetSdkVersion safeExtGet('targetSdkVersion', 31) + } +} - defaultConfig { - minSdkVersion 26 - targetSdkVersion 33 - versionCode 1 - versionName "1.0" - } - lintOptions { - abortOnError false - } - } +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() +} - repositories { - google() - mavenCentral() - } +dependencies { + implementation 'com.facebook.react:react-native:+' +} - dependencies { - implementation 'com.facebook.react:react-native:+' - } + if (isNewArchitectureEnabled()) { + react { + jsRootDir = file("../src/") + libraryName = "RNEddystoneModule" + codegenJavaPackageName = "com.lg2.eddystone" + } + } \ No newline at end of file diff --git a/android/src/main/AndroidManifest.xml b/android/src/main/AndroidManifest.xml index c34c720..97c3a9e 100644 --- a/android/src/main/AndroidManifest.xml +++ b/android/src/main/AndroidManifest.xml @@ -2,5 +2,7 @@ + + \ 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 index 444d20a..346f9f6 100644 --- a/android/src/main/java/com/lg2/eddystone/EddystoneModule.java +++ b/android/src/main/java/com/lg2/eddystone/EddystoneModule.java @@ -1,330 +1,337 @@ -/** - * 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 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.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; +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 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); + 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; } - } - /** @property {ScanCallback} Callbacks execute when a device is scanned */ - ScanCallback scanCallback = new ScanCallback() { /** - * Triggered when a device is scanned + * Returns a URL scheme based on a URL Frame hexChar * - * @param {int} callbackType The type of callback triggered - * @param {ScanResult} result The device result object - * @returns {void} + * @param {byte} The hexChar to analyse for a scheme + * @returns {String} The URL scheme found * @public */ - @Override - public void onScanResult(int callbackType, ScanResult result) { - handleResult(result); + 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; + } } /** - * Triggered when many devices were scanned + * Returns an encoded string or URL suffix based on a URL frame hexChar * - * @param {List} results The devices results objects - * @returns {void} + * @param {byte} hexChar The hexChar to analyse for a scheme + * @returns {String} The encoded string or URL suffix found * @public */ - @Override - public void onBatchScanResults(List results) { - for (ScanResult result : results) { - handleResult(result); - } + 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"); + } + } + }; + /** - * Handles a single device's results + * Starts scanning for Eddystone beacons * - * @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); + @ReactMethod + public void startScanning() { + ScanFilter serviceFilter = new ScanFilter.Builder().setServiceUuid(SERVICE_UUID).build(); - // fallback on configuration uuid if necessary - if (serviceData == null || serviceData.length == 0) { - serviceData = result.getScanRecord().getServiceData(CONFIGURATION_UUID); + ScanFilter configurationFilter = new ScanFilter.Builder().setServiceUuid(CONFIGURATION_UUID).build(); - if (serviceData == null) { - return; - } - } + final List filters = new ArrayList<>(); + filters.add(serviceFilter); + filters.add(configurationFilter); - // handle all possible frame types - byte frameType = serviceData[0]; - if (frameType == FRAME_TYPE_UID || frameType == FRAME_TYPE_EID) { - int length = 18; - String event = "onUIDFrame"; + ScanSettings settings = new ScanSettings.Builder().setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY).build(); - if (frameType == FRAME_TYPE_EID) { - length = 8; - event = "onEIDFrame"; - } + Objects.requireNonNull(reactContext.getCurrentActivity()).requestPermissions( + new String[] { Manifest.permission.ACCESS_COARSE_LOCATION }, + 1); - // 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)); - } + reactContext.getCurrentActivity().requestPermissions( + new String[] { Manifest.permission.ACCESS_FINE_LOCATION }, + 1); - // 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]); + if (!bluetoothAdapter.isEnabled()) { + Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE); + reactContext.getCurrentActivity().startActivityForResult(enableBtIntent, 8123); } - // 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 = 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); + } } - // start scanning - scanner = bluetoothAdapter.getBluetoothLeScanner(); - scanner = bluetoothAdapter.getBluetoothLeScanner(); - if(scanner!=null){ - scanner.startScan(filters, settings, scanCallback); + /** + * Stops scanning for Eddystone beacons + * + * @returns {void} + * @public + */ + @ReactMethod + public void stopScanning() { + if (scanner != null) { + scanner.stopScan(scanCallback); + } + scanner = null; } - } - - /** - * Stops scanning for Eddystone beacons - * - * @returns {void} - * @public - */ - @ReactMethod - public void stopScanning() { - if(scanner!=null){ - 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 index f47d288..8044bb2 100644 --- a/android/src/main/java/com/lg2/eddystone/EddystonePackage.java +++ b/android/src/main/java/com/lg2/eddystone/EddystonePackage.java @@ -11,6 +11,7 @@ package com.lg2.eddystone; +import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; @@ -22,18 +23,23 @@ 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(); + public EddystonePackage(){ } - @Override - public List createViewManagers(ReactApplicationContext reactContext) { - return Collections.emptyList(); - } + 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/ios/Eddystone.m b/ios/Eddystone.m index f036d79..2687741 100644 --- a/ios/Eddystone.m +++ b/ios/Eddystone.m @@ -28,12 +28,26 @@ @interface Eddystone () { @end @implementation Eddystone +{ + bool hasListeners; +} // react-native module macro RCT_EXPORT_MODULE() +// Will be called when this module's first listener is added. +-(void)startObserving { + hasListeners = YES; + // Set up any upstream listeners or background tasks as necessary +} + +// Will be called when this module's last listener is removed, or on dealloc. +-(void)stopObserving { + hasListeners = NO; + // Remove upstream listeners, stop unnecessary background tasks +} // react native methods + (BOOL)requiresMainQueueSetup { return NO; } - - (dispatch_queue_t)methodQueue { return dispatch_get_main_queue(); } + // - (dispatch_queue_t)methodQueue { return dispatch_get_main_queue(); } /** * Eddystone class initializer @@ -100,68 +114,70 @@ - (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; + if(hasListeners){ + // retrieve the beacon data from the advertised data + NSDictionary *serviceData = advertisementData[CBAdvertisementDataServiceDataKey]; - // dispatch telemetry information - [self sendEventWithName:@"onTelemetryFrame" body:@{ - @"uid": [peripheral.identifier UUIDString], - @"voltage": [NSNumber numberWithInt: voltage], - @"temp": [NSNumber numberWithInt: temp] - }]; - } + // 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]; + } } - - } else if (frameType == FrameTypeEmpty){ - // dispatch empty frame - [self sendEventWithName:@"onEmptyFrame" body:nil]; - } } /** @@ -171,26 +187,26 @@ - (void)centralManager:(CBCentralManager *)central */ - (void)centralManagerDidUpdateState:(nonnull CBCentralManager *)manager { switch(manager.state) { - case CBCentralManagerStatePoweredOn: - [self sendEventWithName:@"onStateChanged" body:@"on"]; + case CBManagerStatePoweredOn: + [self sendEventWithName:@"onStateChanged" body:@"on"]; if(_shouldBeScanning) { [self startScanning]; } break; - case CBCentralManagerStatePoweredOff: + case CBManagerStatePoweredOff: [self sendEventWithName:@"onStateChanged" body:@"off"]; break; - case CBCentralManagerStateResetting: + case CBManagerStateResetting: [self sendEventWithName:@"onStateChanged" body:@"resetting"]; break; - case CBCentralManagerStateUnsupported: + case CBManagerStateUnsupported: [self sendEventWithName:@"onStateChanged" body:@"unsupported"]; break; - case CBCentralManagerStateUnauthorized: + case CBManagerStateUnauthorized: [self sendEventWithName:@"onStateChanged" body:@"unauthorized"]; break; diff --git a/package.json b/package.json index 1632971..1ef8af0 100644 --- a/package.json +++ b/package.json @@ -1,23 +1,35 @@ { "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 ", + "version": "0.0.2", + "description": "Showcase Turbomodule with backward compatibility", + "react-native": "src/index", + "source": "src/index", + "files": [ + "src", + "android", + "ios", + "RNEddystoneManager.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/lg2/react-native-eddystone#readme" -} + "homepage": "https://github.com/JaioSkura/react-native-eddystone#readme", + "devDependencies": {}, + "peerDependencies": { + "react": "*", + "react-native": "*" + } +} \ No newline at end of file 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 4645fe1..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 "react-native/Libraries/vendor/emitter/EventEmitter"; -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 bf3d484..0000000 --- a/src/NativeEventEmitter.js +++ /dev/null @@ -1,22 +0,0 @@ -/** - * React Native Eddystone - * - * A simple Eddystone implementation in React Native for both iOS and Android. - * Changed by JaioSkura - * - * @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); - -export { addListener}; - 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 +} + + + + From 2123ae905d9422db977aa566c774cb9cd7ceb43a Mon Sep 17 00:00:00 2001 From: Jaio Date: Wed, 15 Jan 2025 16:23:32 +0100 Subject: [PATCH 07/36] changed version name --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 1ef8af0..e043f94 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@lg2/react-native-eddystone", - "version": "0.0.2", + "version": "2.0", "description": "Showcase Turbomodule with backward compatibility", "react-native": "src/index", "source": "src/index", From ffe1615dd037e5ee4ee0f870cfb3d5940d9ef812 Mon Sep 17 00:00:00 2001 From: Jaio Date: Thu, 16 Jan 2025 13:10:12 +0100 Subject: [PATCH 08/36] Permissions problems fixed --- android/bin/src/main/AndroidManifest.xml | 3 +++ .../main/java/com/lg2/eddystone/EddystoneModule.java | 10 ++++++++++ 2 files changed, 13 insertions(+) diff --git a/android/bin/src/main/AndroidManifest.xml b/android/bin/src/main/AndroidManifest.xml index c34c720..27e1e9f 100644 --- a/android/bin/src/main/AndroidManifest.xml +++ b/android/bin/src/main/AndroidManifest.xml @@ -2,5 +2,8 @@ + + + \ 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 index 346f9f6..41f0803 100644 --- a/android/src/main/java/com/lg2/eddystone/EddystoneModule.java +++ b/android/src/main/java/com/lg2/eddystone/EddystoneModule.java @@ -329,6 +329,16 @@ public void startScanning() { @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; From 425fd87f41a38b5ffcefafa1fa23da820f7dafda Mon Sep 17 00:00:00 2001 From: Jaio Date: Thu, 16 Jan 2025 13:17:24 +0100 Subject: [PATCH 09/36] Permissions problems fixed --- android/src/main/AndroidManifest.xml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/android/src/main/AndroidManifest.xml b/android/src/main/AndroidManifest.xml index 97c3a9e..0210aac 100644 --- a/android/src/main/AndroidManifest.xml +++ b/android/src/main/AndroidManifest.xml @@ -4,5 +4,8 @@ + + + \ No newline at end of file From debb4485eb499955256033899a4a4ebbd45b72e1 Mon Sep 17 00:00:00 2001 From: Jaio Date: Thu, 30 Jan 2025 14:59:42 +0100 Subject: [PATCH 10/36] podsspec changed --- ios/Eddystone.m | 2 +- ios/Eddystone.podspec | 24 ------------------- ....podspec => react-native-eddystone.podspec | 2 +- 3 files changed, 2 insertions(+), 26 deletions(-) delete mode 100644 ios/Eddystone.podspec rename RNEddystoneManager.podspec => react-native-eddystone.podspec (96%) diff --git a/ios/Eddystone.m b/ios/Eddystone.m index 2687741..f88992c 100644 --- a/ios/Eddystone.m +++ b/ios/Eddystone.m @@ -32,7 +32,7 @@ @implementation Eddystone bool hasListeners; } // react-native module macro - RCT_EXPORT_MODULE() + RCT_EXPORT_MODULE(Eddystone) // Will be called when this module's first listener is added. -(void)startObserving { 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/RNEddystoneManager.podspec b/react-native-eddystone.podspec similarity index 96% rename from RNEddystoneManager.podspec rename to react-native-eddystone.podspec index e51f361..00c1a49 100644 --- a/RNEddystoneManager.podspec +++ b/react-native-eddystone.podspec @@ -6,7 +6,7 @@ folly_version = '2021.06.28.00-v2' 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 = "RNEddysotenModule" + s.name = "react-native-eddystone" s.version = package["version"] s.summary = package["description"] s.description = package["description"] From cdc78d7711465e6b11c5e36751c215551b573871 Mon Sep 17 00:00:00 2001 From: Jaio Date: Thu, 30 Jan 2025 16:23:14 +0100 Subject: [PATCH 11/36] more changes for iOS --- ios/Eddystone.h | 8 ++------ ios/{Eddystone.m => Eddystone.mm} | 11 +++++++++-- package.json | 9 +++++++++ 3 files changed, 20 insertions(+), 8 deletions(-) rename ios/{Eddystone.m => Eddystone.mm} (95%) diff --git a/ios/Eddystone.h b/ios/Eddystone.h index 5a1cb6b..41867ed 100644 --- a/ios/Eddystone.h +++ b/ios/Eddystone.h @@ -12,10 +12,6 @@ #import #import -@interface Eddystone : RCTEventEmitter -/** - * Eddystone class initializer - * @return instancetype - */ -- (instancetype)init; +@interface Eddystone : NSObject + @end diff --git a/ios/Eddystone.m b/ios/Eddystone.mm similarity index 95% rename from ios/Eddystone.m rename to ios/Eddystone.mm index f88992c..0b3941a 100644 --- a/ios/Eddystone.m +++ b/ios/Eddystone.mm @@ -81,7 +81,7 @@ - (instancetype)init { * Exported method that starts scanning for eddystone devices * @return void */ - RCT_EXPORT_METHOD(startScanning) { + RCT_REMAP_METHOD(startScanning) { dispatch_async(_beaconOperationsQueue, ^{ if (_centralManager.state != CBCentralManagerStatePoweredOn) { _shouldBeScanning = YES; @@ -97,7 +97,7 @@ - (instancetype)init { * Exported method that stops scanning for eddystone devices * @return void */ - RCT_EXPORT_METHOD(stopScanning) { + RCT_REMAP_METHOD(stopScanning) { _shouldBeScanning = NO; [_centralManager stopScan]; } @@ -214,4 +214,11 @@ - (void)centralManagerDidUpdateState:(nonnull CBCentralManager *)manager { [self sendEventWithName:@"onStateChanged" body:@"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 e043f94..9329415 100644 --- a/package.json +++ b/package.json @@ -31,5 +31,14 @@ "peerDependencies": { "react": "*", "react-native": "*" + }, + "codegenConfig": { + "libraries": [ + { + "name": "RNCalculatorSpec", + "type": "modules", + "jsSrcsDir": "src" + } + ] } } \ No newline at end of file From 4c78c10c5ee31f8e9b480b3b34e1a73ce2cba02a Mon Sep 17 00:00:00 2001 From: Jaio Date: Thu, 30 Jan 2025 17:34:09 +0100 Subject: [PATCH 12/36] added node_modules in gitiginore --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index cf966f8..29389c8 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,5 @@ .settings build/ + +node_modules/ From 1c3a7270b1581e834514d87231f2ef28c0f01398 Mon Sep 17 00:00:00 2001 From: Jaio Date: Thu, 30 Jan 2025 23:42:37 +0100 Subject: [PATCH 13/36] crazy test --- ios/{Eddystone.mm => Eddystone.m} | 36 +++++++----- ios/Eddystone.xcodeproj/project.pbxproj | 9 +++ .../contents.xcworkspacedata | 7 +++ .../UserInterfaceState.xcuserstate | Bin 0 -> 29523 bytes .../xcschemes/xcschememanagement.plist | 14 +++++ ios/EddystoneModule-Bridging-Header.h | 6 ++ ios/EddystoneModule.h | 24 ++++++++ ios/EddystoneModule.mm | 53 ++++++++++++++++++ 8 files changed, 136 insertions(+), 13 deletions(-) rename ios/{Eddystone.mm => Eddystone.m} (88%) create mode 100644 ios/Eddystone.xcodeproj/project.xcworkspace/contents.xcworkspacedata create mode 100644 ios/Eddystone.xcodeproj/project.xcworkspace/xcuserdata/jaio.xcuserdatad/UserInterfaceState.xcuserstate create mode 100644 ios/Eddystone.xcodeproj/xcuserdata/jaio.xcuserdatad/xcschemes/xcschememanagement.plist create mode 100644 ios/EddystoneModule-Bridging-Header.h create mode 100644 ios/EddystoneModule.h create mode 100644 ios/EddystoneModule.mm diff --git a/ios/Eddystone.mm b/ios/Eddystone.m similarity index 88% rename from ios/Eddystone.mm rename to ios/Eddystone.m index 0b3941a..731c8c4 100644 --- a/ios/Eddystone.mm +++ b/ios/Eddystone.m @@ -24,6 +24,8 @@ @interface Eddystone () { // our beacon dispatch queue dispatch_queue_t _beaconOperationsQueue; + + EddystoneModule _eddystoneModule; } @end @@ -32,7 +34,6 @@ @implementation Eddystone bool hasListeners; } // react-native module macro - RCT_EXPORT_MODULE(Eddystone) // Will be called when this module's first listener is added. -(void)startObserving { @@ -53,15 +54,18 @@ + (BOOL)requiresMainQueueSetup { return NO; } * Eddystone class initializer * @return instancetype */ - - (instancetype)init { +- (instancetype)init() { if ((self = [super init]) != nil) { _beaconOperationsQueue = dispatch_queue_create("EddystoneBeaconOperationsQueue", NULL); _centralManager = [[CBCentralManager alloc] initWithDelegate:self queue:_beaconOperationsQueue]; + _eddystone =[Eddystone init]; } return self; } + + /** * Lists the supported events for the RCTEventEmitter * @return NSArray * The supported events list @@ -81,7 +85,7 @@ - (instancetype)init { * Exported method that starts scanning for eddystone devices * @return void */ - RCT_REMAP_METHOD(startScanning) { + -(void)startScanning{ dispatch_async(_beaconOperationsQueue, ^{ if (_centralManager.state != CBCentralManagerStatePoweredOn) { _shouldBeScanning = YES; @@ -97,7 +101,7 @@ - (instancetype)init { * Exported method that stops scanning for eddystone devices * @return void */ - RCT_REMAP_METHOD(stopScanning) { + -(void)stopScanning { _shouldBeScanning = NO; [_centralManager stopScan]; } @@ -133,15 +137,21 @@ - (void)centralManager:(CBCentralManager *)central 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 - }]; + //dispatch device event with beacon information + [_eddystone 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]; 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 0000000000000000000000000000000000000000..181b2dbf977f61c8108e604f94f01d899334475e GIT binary patch literal 29523 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

^7PLkL!E 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 J&Hrkj`F~iG3grL* literal 0 HcmV?d00001 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..e275a87 --- /dev/null +++ b/ios/EddystoneModule.h @@ -0,0 +1,24 @@ +#import +#import + + + +#import +@class Eddystone; + +@interface EddystoneModule : NativeEddystoneModuleSpecBase +- (void)emitOnUIDFrame:(NSDictionary *)value; +- (void)emitOnURLFrame:(NSDictionary *)value; +- (void)emitOnEIDFrame:(NSDictionary *)value; +- (void)emitOnURLFrame:(NSDictionary *)value; +- (void)emitOnTelemetryData:(NSDictionary *)value; +- (void)emitOnEmptyFrame:(NSDictionary *)value; +- (void)emitOnStateChanged:(NSDictionary *)value; +//+ (nullable CBCentralManager *)getCentralManager; +//+ (nullable SwiftBleManager *)getInstance; +@end + + +@interface SpecChecker : NSObject ++ (BOOL)isSpecAvailable; +@end diff --git a/ios/EddystoneModule.mm b/ios/EddystoneModule.mm new file mode 100644 index 0000000..9056680 --- /dev/null +++ b/ios/EddystoneModule.mm @@ -0,0 +1,53 @@ +#import "EddystoneModule.h" +#import "Eddystone.h" + +@implementation SpecChecker + ++ (BOOL)isSpecAvailable { +#ifdef RCT_NEW_ARCH_ENABLED + return YES; +#else + return NO; +#endif +} + +@end + +@implementation EddystoneModule { + Eddystone *_eddystone; +} + +- (instancetype)init { + self = [super init]; + if (self) { + _eddystone = [[Eddystone alloc] init:self]; + } + return self; +} + +- (Eddystone *)eddystone { + return _eddystone; +} + +RCT_EXPORT_MODULE() + +- (std::shared_ptr)getTurboModule: + (const facebook::react::ObjCTurboModule::InitParams &)params { + return std::make_shared(params); +} + +- (void)startScanning:() { + [_eddystone startScanning]; +} + + +- (void)stopScannig:() { + [_eddystone stopScannig]; +} + + +- (void)setName:(NSString *)name { + [_eddystone setName:name]; +} + +@end From ddedbab9545877cf503178f845b17aace66f3907 Mon Sep 17 00:00:00 2001 From: JaioSkura Date: Fri, 31 Jan 2025 10:15:29 +0100 Subject: [PATCH 14/36] Update package.json --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 9329415..37616b7 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,5 @@ { - "name": "@lg2/react-native-eddystone", + "name": "react-native-eddystone", "version": "2.0", "description": "Showcase Turbomodule with backward compatibility", "react-native": "src/index", @@ -41,4 +41,4 @@ } ] } -} \ No newline at end of file +} From 92491897836bf66f73323b945d36ba0ae4aa729e Mon Sep 17 00:00:00 2001 From: JaioSkura Date: Fri, 31 Jan 2025 13:10:55 +0100 Subject: [PATCH 15/36] Rename react-native-eddystone.podspec to RNEddystoneManager.podspec --- react-native-eddystone.podspec => RNEddystoneManager.podspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename react-native-eddystone.podspec => RNEddystoneManager.podspec (99%) diff --git a/react-native-eddystone.podspec b/RNEddystoneManager.podspec similarity index 99% rename from react-native-eddystone.podspec rename to RNEddystoneManager.podspec index 00c1a49..2a27f31 100644 --- a/react-native-eddystone.podspec +++ b/RNEddystoneManager.podspec @@ -33,4 +33,4 @@ if ENV['RCT_NEW_ARCH_ENABLED'] == '1' then s.dependency "RCTTypeSafety" s.dependency "ReactCommon/turbomodule/core" end -end \ No newline at end of file +end From cf2d8f47befd424ac5d5b4325a2148797a21c185 Mon Sep 17 00:00:00 2001 From: JaioSkura Date: Fri, 31 Jan 2025 15:50:46 +0100 Subject: [PATCH 16/36] Update package.json --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 37616b7..d28ca02 100644 --- a/package.json +++ b/package.json @@ -35,7 +35,7 @@ "codegenConfig": { "libraries": [ { - "name": "RNCalculatorSpec", + "name": "EddystoneModuleSpec", "type": "modules", "jsSrcsDir": "src" } From 1fa249bf7fba34df04f3e3bf3b37b1bb054163a1 Mon Sep 17 00:00:00 2001 From: JaioSkura Date: Fri, 31 Jan 2025 15:54:40 +0100 Subject: [PATCH 17/36] Update RNEddystoneManager.podspec --- RNEddystoneManager.podspec | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/RNEddystoneManager.podspec b/RNEddystoneManager.podspec index 2a27f31..a0a1984 100644 --- a/RNEddystoneManager.podspec +++ b/RNEddystoneManager.podspec @@ -2,9 +2,6 @@ require "json" package = JSON.parse(File.read(File.join(__dir__, "package.json"))) -folly_version = '2021.06.28.00-v2' -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 = "react-native-eddystone" s.version = package["version"] @@ -19,18 +16,4 @@ Pod::Spec.new do |s| s.source_files = "ios/**/*.{h,m,mm,swift}" s.dependency "React-Core" - # This guard prevent to 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\"", - "CLANG_CXX_LANGUAGE_STANDARD" => "c++17" - } - - s.dependency "React-Codegen" - s.dependency "RCT-Folly", folly_version - s.dependency "RCTRequired" - s.dependency "RCTTypeSafety" - s.dependency "ReactCommon/turbomodule/core" -end end From 29d63b30a2e8299970a3e922c79c17dabe3331ef Mon Sep 17 00:00:00 2001 From: JaioSkura Date: Fri, 31 Jan 2025 15:59:06 +0100 Subject: [PATCH 18/36] Update RNEddystoneManager.podspec --- RNEddystoneManager.podspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/RNEddystoneManager.podspec b/RNEddystoneManager.podspec index a0a1984..6503f63 100644 --- a/RNEddystoneManager.podspec +++ b/RNEddystoneManager.podspec @@ -3,7 +3,7 @@ require "json" package = JSON.parse(File.read(File.join(__dir__, "package.json"))) Pod::Spec.new do |s| - s.name = "react-native-eddystone" + s.name = RNEddystoneManager" s.version = package["version"] s.summary = package["description"] s.description = package["description"] From 47af3182a4731f5fee159e0e67a12c34a173aeca Mon Sep 17 00:00:00 2001 From: JaioSkura Date: Fri, 31 Jan 2025 16:02:21 +0100 Subject: [PATCH 19/36] Update RNEddystoneManager.podspec --- RNEddystoneManager.podspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/RNEddystoneManager.podspec b/RNEddystoneManager.podspec index 6503f63..0f80096 100644 --- a/RNEddystoneManager.podspec +++ b/RNEddystoneManager.podspec @@ -3,7 +3,7 @@ require "json" package = JSON.parse(File.read(File.join(__dir__, "package.json"))) Pod::Spec.new do |s| - s.name = RNEddystoneManager" + s.name = "RNEddystoneManager" s.version = package["version"] s.summary = package["description"] s.description = package["description"] From 829dc920c6f172e4b064f070a028063f2a9d7afa Mon Sep 17 00:00:00 2001 From: Jaio Date: Tue, 4 Feb 2025 23:06:19 +0100 Subject: [PATCH 20/36] package.json changed --- .../UserInterfaceState.xcuserstate | Bin 29523 -> 30763 bytes package.json | 4 ++-- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ios/Eddystone.xcodeproj/project.xcworkspace/xcuserdata/jaio.xcuserdatad/UserInterfaceState.xcuserstate b/ios/Eddystone.xcodeproj/project.xcworkspace/xcuserdata/jaio.xcuserdatad/UserInterfaceState.xcuserstate index 181b2dbf977f61c8108e604f94f01d899334475e..a42670b1c670a2ca025465e33b934a8dadb4268c 100644 GIT binary patch delta 15618 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 Date: Tue, 4 Feb 2025 23:52:51 +0100 Subject: [PATCH 21/36] changing podspec --- ...stoneManager.podspec => react-native-eddystone.podspec | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) rename RNEddystoneManager.podspec => react-native-eddystone.podspec (75%) diff --git a/RNEddystoneManager.podspec b/react-native-eddystone.podspec similarity index 75% rename from RNEddystoneManager.podspec rename to react-native-eddystone.podspec index 0f80096..d607bc3 100644 --- a/RNEddystoneManager.podspec +++ b/react-native-eddystone.podspec @@ -3,7 +3,7 @@ require "json" package = JSON.parse(File.read(File.join(__dir__, "package.json"))) Pod::Spec.new do |s| - s.name = "RNEddystoneManager" + s.name = "react-native-eddystone" s.version = package["version"] s.summary = package["description"] s.description = package["description"] @@ -13,7 +13,11 @@ Pod::Spec.new do |s| s.author = package["author"] s.source = { :git => package["repository"], :tag => "#{s.version}" } - s.source_files = "ios/**/*.{h,m,mm,swift}" + s.compiler_flags = '-x objective-c++' + s.source_files = [ + "ios/**/*.{h,m,mm}", + "cpp/**/*.{hpp,cpp,c,h}", + ] s.dependency "React-Core" end From b6579a34adc5c120f552d0f8fce054029814d49a Mon Sep 17 00:00:00 2001 From: JaioSkura Date: Wed, 5 Feb 2025 00:50:18 +0100 Subject: [PATCH 22/36] Rename react-native-eddystone.podspec to RNEddystoneModule.podspec --- react-native-eddystone.podspec => RNEddystoneModule.podspec | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename react-native-eddystone.podspec => RNEddystoneModule.podspec (100%) diff --git a/react-native-eddystone.podspec b/RNEddystoneModule.podspec similarity index 100% rename from react-native-eddystone.podspec rename to RNEddystoneModule.podspec From 31b367ba080ef7d4a6a9294caded9d5a84e52fd4 Mon Sep 17 00:00:00 2001 From: JaioSkura Date: Wed, 5 Feb 2025 00:53:26 +0100 Subject: [PATCH 23/36] Update build.gradle --- android/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/android/build.gradle b/android/build.gradle index 9946311..8c343d4 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -45,6 +45,6 @@ dependencies { react { jsRootDir = file("../src/") libraryName = "RNEddystoneModule" - codegenJavaPackageName = "com.lg2.eddystone" + codegenJavaPackageName = "com.eddystone" } - } \ No newline at end of file + } From 7d8e76ed1cb639363e5dc80788eb6432049ad886 Mon Sep 17 00:00:00 2001 From: JaioSkura Date: Wed, 5 Feb 2025 01:13:22 +0100 Subject: [PATCH 24/36] Update package.json --- package.json | 3 --- 1 file changed, 3 deletions(-) diff --git a/package.json b/package.json index d28ca02..8d78a13 100644 --- a/package.json +++ b/package.json @@ -33,12 +33,9 @@ "react-native": "*" }, "codegenConfig": { - "libraries": [ - { "name": "EddystoneModuleSpec", "type": "modules", "jsSrcsDir": "src" - } ] } } From e4c8806cc6126684e9276bfd80a22d6f0ec5c0d4 Mon Sep 17 00:00:00 2001 From: JaioSkura Date: Wed, 5 Feb 2025 10:33:54 +0100 Subject: [PATCH 25/36] Update package.json --- package.json | 1 - 1 file changed, 1 deletion(-) diff --git a/package.json b/package.json index 8d78a13..46ede04 100644 --- a/package.json +++ b/package.json @@ -36,6 +36,5 @@ "name": "EddystoneModuleSpec", "type": "modules", "jsSrcsDir": "src" - ] } } From 9ab090a2cfe6061614800953376fba6e53814b44 Mon Sep 17 00:00:00 2001 From: JaioSkura Date: Wed, 5 Feb 2025 10:39:21 +0100 Subject: [PATCH 26/36] Update package.json --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 46ede04..e6d464f 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,7 @@ "src", "android", "ios", - "RNEddystoneManager.podspec", + "RNEddystoneModule.podspec", "!android/build", "!ios/build", "!**/__tests__", From 65b91a0af247a0eeaf479d11fef6e2fd56e4c822 Mon Sep 17 00:00:00 2001 From: Jaio Date: Wed, 5 Feb 2025 10:46:59 +0100 Subject: [PATCH 27/36] bin removed and Android folders refactored --- android/bin/build.gradle | 36 ------------------ android/bin/src/main/AndroidManifest.xml | 9 ----- .../com/lg2/eddystone/EddystoneModule.class | Bin 8616 -> 0 bytes .../com/lg2/eddystone/EddystonePackage.class | Bin 3268 -> 0 bytes android/build.gradle | 2 +- .../{lg2 => }/eddystone/EddystoneModule.java | 0 .../{lg2 => }/eddystone/EddystonePackage.java | 0 package.json | 2 +- 8 files changed, 2 insertions(+), 47 deletions(-) delete mode 100644 android/bin/build.gradle delete mode 100644 android/bin/src/main/AndroidManifest.xml delete mode 100644 android/bin/src/main/java/com/lg2/eddystone/EddystoneModule.class delete mode 100644 android/bin/src/main/java/com/lg2/eddystone/EddystonePackage.class rename android/src/main/java/com/{lg2 => }/eddystone/EddystoneModule.java (100%) rename android/src/main/java/com/{lg2 => }/eddystone/EddystonePackage.java (100%) diff --git a/android/bin/build.gradle b/android/bin/build.gradle deleted file mode 100644 index 8cb41f2..0000000 --- a/android/bin/build.gradle +++ /dev/null @@ -1,36 +0,0 @@ -buildscript { - repositories { - google() - jcenter() - } - - dependencies { - classpath 'com.android.tools.build:gradle:8.2.0' - } - } - - apply plugin: 'com.android.library' - - android { - compileSdkVersion 33 - buildToolsVersion "33.0.0" - - defaultConfig { - minSdkVersion 26 - targetSdkVersion 33 - versionCode 1 - versionName "1.0" - } - lintOptions { - abortOnError false - } - } - - repositories { - google() - mavenCentral() - } - - dependencies { - implementation 'com.facebook.react:react-native:+' - } diff --git a/android/bin/src/main/AndroidManifest.xml b/android/bin/src/main/AndroidManifest.xml deleted file mode 100644 index 27e1e9f..0000000 --- a/android/bin/src/main/AndroidManifest.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/android/bin/src/main/java/com/lg2/eddystone/EddystoneModule.class b/android/bin/src/main/java/com/lg2/eddystone/EddystoneModule.class deleted file mode 100644 index 1c9935ee34b67cdaeefd87c56a64a82d700f8a02..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8616 zcmeHMTXP#V6h50?d?D#2q?ELUZp)<(6q}ZN)0^!$t;;$IjvXcsOh?{TY?Zwjt?a2^ z_*V=wFaz)W0N(i{3`e`ZY?4hZ2Y1rW^ufE9baZs|N$2R>qrd+B?GFIB2lWKZXpr-{ znR5tpbI(YZSczD$DtH+h!&a%yauq%hFmH;DNob~faU24yt-^j+pMabJTgnFCQ=+S1@;(X((paQw5Q^(b-f@g!W= z&i_+)IrTleOD!Fjwax5c9rQN$8a8$OJ9;`*Yf)YF+EkYcvT{MQ;ezTCWKZY~st=T8 z^|H{JuQS(T9M|0LVbc!f)HQL09qu_;{;7j)mYy|j;`{mzv#EcKqZ9)xracvl;_T!s z+qizDN%iXpZx+2KJM^0Cy5&({mk2sUm@Qo((DZp5VT<-d-^)th%Lef8*Aha zT*H`Ed6h+oYjKa^?%cQ6cFpQ#77G@xBbYsI5{C;0!LlDA3&f{S&>h2g8>3ejo=yU{ zO{WfsvSWJf4YsP{!{9rn!zd2_AHj5LT6&I#($RVy72Ez<7z0>3wce$iGmFMFMmNKz z;LL4KL+HRmAUfR9@TnGSE40f@TIy0)lpH3I0ZhZ@>CHZR9*?sua&(UoRb52XSfzf) z#)!W!E=J*3)Mqe%oF+M6r6H#;I2{jU+)vLFQE< z?J+Bx=gp3T&f&+%rBg~1l*G=VqUBk7lZtv3IcAGGG}Gt_x)hQ%Nl60kw};_}tj?F1 zN)dep zaCB9UJ?wBWag1*Bq4-OuU)3NP!UkEAn1eAoS@n>7bXZ=1*^?TRhO6-YEL?#PG`Ns4 zNXmt0+_Fp(oi#ALtaY3Q{A)<=aC<(`PW_@_mwNa) zMp|}^Ln{)v*NpHrBa}RPcr2YeqP@Xo{q!hv=y?rHMPJGeUXkCcO3_ zz9*reY3Zp(@`;U~xP$s^M;@aHJ+iP(uY-4|7;+_#+mjIruBVU;lrhia`j}6|FRsUo za=dMA^%C$1&+y@F`aYU~GBV9!?a+<{e2asP(iRD*XmIg>OmYI&HMkTs#@>x2;5%H{ zC@u-uL}T_6VHB!_S*#k~b^34(@PNm=*f(GvPQhvXHv1Tc^YNpwe$^q&IbR}kb$M3?j!gZrEd16KEd}uo9q*6%f@Kih|z{O z*KjLhkHjg|a63lB4>1~Ma2{VoG>m5SWsHVatcI@-(C|%+hM!|JXs`@-BbeNa#pM2e uZQ5e2wucJZ@-f;9G1^W*5v`el6)52wpoYJB+i~}7u%}gH^TiJ-(k}Jsz z`^(C-Gw|Nu(%;bOk)2K4#K8*_;K8Oc z8?a8Ol1|)T>F_8T8mlDl+#jueX5nwF&pntTa3L3tne2BS?LOh5C2($4NMY9qOtzPH z2uy9L2xXfDW{+g=Yprwx&XZ~Li`3kxc)%lyI#UrdE0mC#pJmmpis$DD=spp+_NL#?7LXML;rXu!1=5w8&o1gbq* z5oM%@SX=|XrJ^jZL(A=3Po3#`MQ$i*`Lj9&>sqs+sj#Bed=1@Wc(Rd~?yJ3hfbF6e zYLVKpJl;@ojP-@xr`mzDOT&)fPq&!FCW<^e(Zb3Jd$TOmc+!Ffd@uvk@F9Uq?ck^_ z_pBDO-*s(!HbC}1%#vNMw;6U~0&{^1S-iuvaPJ2nr|iBk1XhCAJw3Vv=0nYy-<0m~#OmkL{v^0&I@}+6(8dY$IG;SYiBqTJ zi3i^hm?;;O2R?x-r+DJQGK%Lv4@cY;0_RI1^5E|O=GdHSxM@omgPn65hg1U#fU_@7 z)&Ntunuc?D_wem5ekJ&9{RNF*=URWj%u9TmfLXjd8NllT-e(Fa_z33mZ}V^wcV5Ev z1YCwI_;k`A<8y>Mf$IYGY6a@mO4MucDdH8VpB*9{+4p$`()CItTC#7U#=gZ0)EgD3 hlki3E@0aiuJ^}9GHHXL6*RTY);9KaxZMXxI{{i)){R;p9 diff --git a/android/build.gradle b/android/build.gradle index 9946311..7e2d1cf 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -45,6 +45,6 @@ dependencies { react { jsRootDir = file("../src/") libraryName = "RNEddystoneModule" - codegenJavaPackageName = "com.lg2.eddystone" + codegenJavaPackageName = "com.eddystone" } } \ No newline at end of file diff --git a/android/src/main/java/com/lg2/eddystone/EddystoneModule.java b/android/src/main/java/com/eddystone/EddystoneModule.java similarity index 100% rename from android/src/main/java/com/lg2/eddystone/EddystoneModule.java rename to android/src/main/java/com/eddystone/EddystoneModule.java diff --git a/android/src/main/java/com/lg2/eddystone/EddystonePackage.java b/android/src/main/java/com/eddystone/EddystonePackage.java similarity index 100% rename from android/src/main/java/com/lg2/eddystone/EddystonePackage.java rename to android/src/main/java/com/eddystone/EddystonePackage.java diff --git a/package.json b/package.json index d28ca02..40a13e7 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,7 @@ "src", "android", "ios", - "RNEddystoneManager.podspec", + "react-native-eddystone.podspec", "!android/build", "!ios/build", "!**/__tests__", From 7ea7e22729c1190a12d7734b89149a7239d70bef Mon Sep 17 00:00:00 2001 From: Jaio Date: Wed, 5 Feb 2025 11:01:46 +0100 Subject: [PATCH 28/36] package folders changed --- LICENSE | 2 +- android/src/main/AndroidManifest.xml | 2 +- android/src/main/java/com/eddystone/EddystoneModule.java | 2 +- android/src/main/java/com/eddystone/EddystonePackage.java | 8 +++++--- ios/Beacon.h | 6 +++--- ios/Beacon.m | 5 +++-- ios/Eddystone.h | 6 +++--- 7 files changed, 17 insertions(+), 14 deletions(-) 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/android/src/main/AndroidManifest.xml b/android/src/main/AndroidManifest.xml index 0210aac..ffc794f 100644 --- a/android/src/main/AndroidManifest.xml +++ b/android/src/main/AndroidManifest.xml @@ -1,6 +1,6 @@ + package="com.eddystone"> diff --git a/android/src/main/java/com/eddystone/EddystoneModule.java b/android/src/main/java/com/eddystone/EddystoneModule.java index 41f0803..b296ac2 100644 --- a/android/src/main/java/com/eddystone/EddystoneModule.java +++ b/android/src/main/java/com/eddystone/EddystoneModule.java @@ -1,4 +1,4 @@ -package com.lg2.eddystone; +package com.eddystone; import android.Manifest; import android.bluetooth.BluetoothAdapter; diff --git a/android/src/main/java/com/eddystone/EddystonePackage.java b/android/src/main/java/com/eddystone/EddystonePackage.java index 8044bb2..10a5e11 100644 --- a/android/src/main/java/com/eddystone/EddystonePackage.java +++ b/android/src/main/java/com/eddystone/EddystonePackage.java @@ -3,13 +3,15 @@ * * 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 */ -package com.lg2.eddystone; +package com.eddystone; import java.util.ArrayList; import java.util.Arrays; 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 index 41867ed..88d6aa9 100644 --- a/ios/Eddystone.h +++ b/ios/Eddystone.h @@ -3,9 +3,9 @@ * * 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 + * @package original @lg2/react-native-eddystone + * @package react-native-eddystone * @link https://github.com/lg2/react-native-eddystone + * @copyright 2025 Skura * @license MIT */ From 2d344a58d76a9a58838ae2f1481f56b1b662e55a Mon Sep 17 00:00:00 2001 From: JaioSkura Date: Wed, 5 Feb 2025 14:22:44 +0100 Subject: [PATCH 29/36] Update package.json --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index e6d464f..71005e9 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,7 @@ "src", "android", "ios", - "RNEddystoneModule.podspec", + "*.podspec", "!android/build", "!ios/build", "!**/__tests__", From 99048a95d70ee0eebcd1b0e86c7d526b56a99bff Mon Sep 17 00:00:00 2001 From: JaioSkura Date: Wed, 5 Feb 2025 15:15:11 +0100 Subject: [PATCH 30/36] Update RNEddystoneModule.podspec --- RNEddystoneModule.podspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/RNEddystoneModule.podspec b/RNEddystoneModule.podspec index d607bc3..5e66b14 100644 --- a/RNEddystoneModule.podspec +++ b/RNEddystoneModule.podspec @@ -3,7 +3,7 @@ require "json" package = JSON.parse(File.read(File.join(__dir__, "package.json"))) Pod::Spec.new do |s| - s.name = "react-native-eddystone" + s.name = "RNEddystoneModule" s.version = package["version"] s.summary = package["description"] s.description = package["description"] From a3810ce9ca280d7108fdb2380c394288f68375ea Mon Sep 17 00:00:00 2001 From: Jaio Date: Thu, 6 Feb 2025 16:02:15 +0100 Subject: [PATCH 31/36] updated ios version1 --- examples/basic.js | 2 +- ios/Eddystone.h | 8 + ios/Eddystone.m | 348 ++++++++++++++++++++++------------------- ios/EddystoneModule.h | 15 +- ios/EddystoneModule.mm | 18 ++- 5 files changed, 219 insertions(+), 172 deletions(-) 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/Eddystone.h b/ios/Eddystone.h index 88d6aa9..b235491 100644 --- a/ios/Eddystone.h +++ b/ios/Eddystone.h @@ -14,4 +14,12 @@ @interface Eddystone : NSObject +- (instancetype)init; + +- (void)startScanning; +- (void)stopScanning; + +- (void)setName:(NSString*)value; + + @end diff --git a/ios/Eddystone.m b/ios/Eddystone.m index 731c8c4..f136a77 100644 --- a/ios/Eddystone.m +++ b/ios/Eddystone.m @@ -8,32 +8,34 @@ * @copyright 2019 lg2 * @license MIT */ - + #import #import "Eddystone.h" #import "Beacon.h" +#import "EddystoneModule.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; - - EddystoneModule _eddystoneModule; + /** @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; + + EddystoneModule *_eddystoneModule; } @end @implementation Eddystone { - bool hasListeners; + bool hasListeners; } - // react-native module macro +// react-native module macro // Will be called when this module's first listener is added. -(void)startObserving { @@ -46,187 +48,203 @@ -(void)stopObserving { hasListeners = NO; // Remove upstream listeners, stop unnecessary background tasks } - // react native methods - + (BOOL)requiresMainQueueSetup { return NO; } - // - (dispatch_queue_t)methodQueue { return dispatch_get_main_queue(); } +// react native methods ++ (BOOL)requiresMainQueueSetup { return NO; } +// - (dispatch_queue_t)methodQueue { return dispatch_get_main_queue(); } - /** - * Eddystone class initializer - * @return instancetype - */ -- (instancetype)init() { +/** + * 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]; - _eddystone =[Eddystone init]; + _beaconOperationsQueue = dispatch_queue_create("EddystoneBeaconOperationsQueue", NULL); + _centralManager = [[CBCentralManager alloc] initWithDelegate:self queue:_beaconOperationsQueue]; + _eddystoneModule =[Eddystone init]; } - + return self; - } +} - /** - * Lists the supported events for the RCTEventEmitter - * @return NSArray * The supported events list - */ - - (NSArray *)supportedEvents { +/** + * Lists the supported events for the RCTEventEmitter + * @return NSArray * The supported events list + */ +- (NSArray *)supportedEvents { return @[ - @"onUIDFrame", - @"onEIDFrame", - @"onURLFrame", - @"onTelemetryFrame", - @"onEmptyFrame", - @"onStateChanged" - ]; - } + @"onUIDFrame", + @"onEIDFrame", + @"onURLFrame", + @"onTelemetryFrame", + @"onEmptyFrame", + @"onStateChanged" + ]; +} - /** - * Exported method that starts scanning for eddystone devices - * @return void - */ - -(void)startScanning{ +/** + * Exported method that starts scanning for eddystone devices + * @return void + */ +-(void)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]; - } + 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 - */ - -(void)stopScanning { +/** + * Exported method that stops scanning for eddystone devices + * @return void + */ +-(void)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 { - 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 - [_eddystone 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 sendEventWithName:@"onURLFrame" body:@{ +/** + * 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]; + [_eddystoneModule emitOnURLFrame:@{ @"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:@{ + }]; + // [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; + [_eddystoneModule emitOnTelemetryData:@{ @"uid": [peripheral.identifier UUIDString], @"voltage": [NSNumber numberWithInt: voltage], @"temp": [NSNumber numberWithInt: temp] - }]; - } - } - - } else if (frameType == FrameTypeEmpty){ - // dispatch empty frame - [self sendEventWithName:@"onEmptyFrame" body:nil]; - } - } - } + }]; + // // dispatch telemetry information + // [self sendEventWithName:@"onTelemetryFrame" body:@{ + // @"uid": [peripheral.identifier UUIDString], + // @"voltage": [NSNumber numberWithInt: voltage], + // @"temp": [NSNumber numberWithInt: temp] + // }]; + } + } + + } else if (frameType == FrameTypeEmpty){ + [_eddystoneModule 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 { +/** + * 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"]; - if(_shouldBeScanning) { - [self startScanning]; - } - break; - + // [self sendEventWithName:@"onStateChanged" body:@"on"]; + [_eddystoneModule emitOnStateChanged:@{@"value":@"on"}]; + if(_shouldBeScanning) { + [self startScanning]; + } + break; + case CBManagerStatePoweredOff: - [self sendEventWithName:@"onStateChanged" body:@"off"]; - break; - + [_eddystoneModule emitOnStateChanged:@{@"value":@"off"}]; + break; + case CBManagerStateResetting: - [self sendEventWithName:@"onStateChanged" body:@"resetting"]; - break; - + [_eddystoneModule emitOnStateChanged:@{@"value":@"resseting"}]; + break; + case CBManagerStateUnsupported: - [self sendEventWithName:@"onStateChanged" body:@"unsupported"]; - break; - + //[self sendEventWithName:@"onStateChanged" body:@"unsupported"]; + [_eddystoneModule emitOnStateChanged:@{@"value":@"unsupported"}]; + + break; + case CBManagerStateUnauthorized: - [self sendEventWithName:@"onStateChanged" body:@"unauthorized"]; - break; - - default: - [self sendEventWithName:@"onStateChanged" body:@"unknown"]; + //[self sendEventWithName:@"onStateChanged" body:@"unauthorized"]; + [_eddystoneModule emitOnStateChanged:@{@"value":@"unauthorized"}]; + + break; + + default: + // [self sendEventWithName:@"onStateChanged" body:@"unknown"]; + [_eddystoneModule emitOnStateChanged:@{@"value":@"unknown"}]; + } - } - #ifdef RCT_NEW_ARCH_ENABLED +} +#ifdef RCT_NEW_ARCH_ENABLED - (std::shared_ptr)getTurboModule: - (const facebook::react::ObjCTurboModule::InitParams &)params +(const facebook::react::ObjCTurboModule::InitParams &)params { return std::make_shared(params); } diff --git a/ios/EddystoneModule.h b/ios/EddystoneModule.h index e275a87..6d83888 100644 --- a/ios/EddystoneModule.h +++ b/ios/EddystoneModule.h @@ -1,7 +1,7 @@ #import #import - +#ifdef RCT_NEW_ARCH_ENABLED #import @class Eddystone; @@ -10,7 +10,19 @@ - (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; @@ -18,6 +30,7 @@ //+ (nullable SwiftBleManager *)getInstance; @end +#endif @interface SpecChecker : NSObject + (BOOL)isSpecAvailable; diff --git a/ios/EddystoneModule.mm b/ios/EddystoneModule.mm index 9056680..aa4a5f2 100644 --- a/ios/EddystoneModule.mm +++ b/ios/EddystoneModule.mm @@ -1,6 +1,10 @@ #import "EddystoneModule.h" #import "Eddystone.h" +#ifdef RCT_NEW_ARCH_ENABLED +#import "EddystoneModuleSpec.h" +#endif + @implementation SpecChecker + (BOOL)isSpecAvailable { @@ -13,14 +17,14 @@ + (BOOL)isSpecAvailable { @end -@implementation EddystoneModule { +@implementation EddystoneModule { Eddystone *_eddystone; } - (instancetype)init { self = [super init]; if (self) { - _eddystone = [[Eddystone alloc] init:self]; + _eddystone = [[Eddystone alloc] init]; } return self; } @@ -31,18 +35,20 @@ - (Eddystone *)eddystone { RCT_EXPORT_MODULE() +#ifdef RCT_NEW_ARCH_ENABLED - (std::shared_ptr)getTurboModule: (const facebook::react::ObjCTurboModule::InitParams &)params { return std::make_shared(params); } +#endif -- (void)startScanning:() { +- (void)startScanning { [_eddystone startScanning]; } -- (void)stopScannig:() { - [_eddystone stopScannig]; +- (void)stopScannig { + [_eddystone stopScanning]; } @@ -50,4 +56,6 @@ - (void)setName:(NSString *)name { [_eddystone setName:name]; } + + @end From d1efae751e040f3393fc43e70f22f854253c5a74 Mon Sep 17 00:00:00 2001 From: Jaio Date: Fri, 7 Feb 2025 23:49:54 +0100 Subject: [PATCH 32/36] podspec updated --- RNEddystoneModule.podspec | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/RNEddystoneModule.podspec b/RNEddystoneModule.podspec index 5e66b14..27d555a 100644 --- a/RNEddystoneModule.podspec +++ b/RNEddystoneModule.podspec @@ -2,6 +2,9 @@ require "json" package = JSON.parse(File.read(File.join(__dir__, "package.json"))) +folly_version = '2021.06.28.00-v2' +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"] @@ -20,4 +23,20 @@ Pod::Spec.new do |s| "cpp/**/*.{hpp,cpp,c,h}", ] s.dependency "React-Core" + + # This guard prevent to 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\"", + "CLANG_CXX_LANGUAGE_STANDARD" => "c++17" + } + + s.dependency "React-Codegen" + s.dependency "RCT-Folly", folly_version + s.dependency "RCTRequired" + s.dependency "RCTTypeSafety" + s.dependency "ReactCommon/turbomodule/core" +end + end From 5a8e2b574f6bde8f6e0996dd40a5fba079e21804 Mon Sep 17 00:00:00 2001 From: Jaio Date: Tue, 11 Feb 2025 12:31:11 +0100 Subject: [PATCH 33/36] podspec changed --- .vscode/settings.json | 3 + RNEddystoneModule.podspec | 41 ++++--- ios/Eddystone.h | 25 ---- ios/Eddystone.m | 252 -------------------------------------- ios/EddystoneModule.mm | 194 +++++++++++++++++++++++++---- 5 files changed, 197 insertions(+), 318 deletions(-) create mode 100644 .vscode/settings.json delete mode 100644 ios/Eddystone.h delete mode 100644 ios/Eddystone.m 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/RNEddystoneModule.podspec b/RNEddystoneModule.podspec index 27d555a..ec1fbf8 100644 --- a/RNEddystoneModule.podspec +++ b/RNEddystoneModule.podspec @@ -2,7 +2,6 @@ require "json" package = JSON.parse(File.read(File.join(__dir__, "package.json"))) -folly_version = '2021.06.28.00-v2' 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| @@ -16,27 +15,31 @@ Pod::Spec.new do |s| s.author = package["author"] s.source = { :git => package["repository"], :tag => "#{s.version}" } - s.compiler_flags = '-x objective-c++' s.source_files = [ "ios/**/*.{h,m,mm}", - "cpp/**/*.{hpp,cpp,c,h}", ] - s.dependency "React-Core" - - # This guard prevent to 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\"", - "CLANG_CXX_LANGUAGE_STANDARD" => "c++17" - } - - s.dependency "React-Codegen" - s.dependency "RCT-Folly", folly_version - s.dependency "RCTRequired" - s.dependency "RCTTypeSafety" - s.dependency "ReactCommon/turbomodule/core" -end + 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/ios/Eddystone.h b/ios/Eddystone.h deleted file mode 100644 index b235491..0000000 --- a/ios/Eddystone.h +++ /dev/null @@ -1,25 +0,0 @@ -/** - * 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 - */ - -#import -#import - -@interface Eddystone : NSObject - -- (instancetype)init; - -- (void)startScanning; -- (void)stopScanning; - -- (void)setName:(NSString*)value; - - -@end diff --git a/ios/Eddystone.m b/ios/Eddystone.m deleted file mode 100644 index f136a77..0000000 --- a/ios/Eddystone.m +++ /dev/null @@ -1,252 +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" -#import "EddystoneModule.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; - - EddystoneModule *_eddystoneModule; -} -@end - -@implementation Eddystone -{ - bool hasListeners; -} -// react-native module macro - -// Will be called when this module's first listener is added. --(void)startObserving { - hasListeners = YES; - // Set up any upstream listeners or background tasks as necessary -} - -// Will be called when this module's last listener is removed, or on dealloc. --(void)stopObserving { - hasListeners = NO; - // Remove upstream listeners, stop unnecessary background tasks -} -// 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]; - _eddystoneModule =[Eddystone init]; - } - - 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 - */ --(void)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 - */ --(void)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 { - 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]; - [_eddystoneModule 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; - [_eddystoneModule 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){ - [_eddystoneModule 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"]; - [_eddystoneModule emitOnStateChanged:@{@"value":@"on"}]; - if(_shouldBeScanning) { - [self startScanning]; - } - break; - - case CBManagerStatePoweredOff: - [_eddystoneModule emitOnStateChanged:@{@"value":@"off"}]; - break; - - case CBManagerStateResetting: - [_eddystoneModule emitOnStateChanged:@{@"value":@"resseting"}]; - break; - - case CBManagerStateUnsupported: - //[self sendEventWithName:@"onStateChanged" body:@"unsupported"]; - [_eddystoneModule emitOnStateChanged:@{@"value":@"unsupported"}]; - - break; - - case CBManagerStateUnauthorized: - //[self sendEventWithName:@"onStateChanged" body:@"unauthorized"]; - [_eddystoneModule emitOnStateChanged:@{@"value":@"unauthorized"}]; - - break; - - default: - // [self sendEventWithName:@"onStateChanged" body:@"unknown"]; - [_eddystoneModule 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/ios/EddystoneModule.mm b/ios/EddystoneModule.mm index aa4a5f2..51018e9 100644 --- a/ios/EddystoneModule.mm +++ b/ios/EddystoneModule.mm @@ -1,5 +1,6 @@ #import "EddystoneModule.h" -#import "Eddystone.h" +#import +#import "Beacon.h" #ifdef RCT_NEW_ARCH_ENABLED #import "EddystoneModuleSpec.h" @@ -17,45 +18,194 @@ + (BOOL)isSpecAvailable { @end -@implementation EddystoneModule { - Eddystone *_eddystone; +@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 { - self = [super init]; - if (self) { - _eddystone = [[Eddystone alloc] init]; + if ((self = [super init]) != nil) { + _beaconOperationsQueue = dispatch_queue_create("EddystoneBeaconOperationsQueue", NULL); + _centralManager = [[CBCentralManager alloc] initWithDelegate:self queue:_beaconOperationsQueue]; } return self; } -- (Eddystone *)eddystone { - return _eddystone; -} RCT_EXPORT_MODULE() -#ifdef RCT_NEW_ARCH_ENABLED -- (std::shared_ptr)getTurboModule: - (const facebook::react::ObjCTurboModule::InitParams &)params { - return std::make_shared(params); -} -#endif - - (void)startScanning { - [_eddystone 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 { - [_eddystone stopScanning]; + _shouldBeScanning = NO; + [_centralManager stopScan]; } -- (void)setName:(NSString *)name { - [_eddystone setName:name]; +//- (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 From 182fdee9484e69643f8c64bf2b9f00ec3949f680 Mon Sep 17 00:00:00 2001 From: JaioSkura Date: Tue, 11 Feb 2025 14:36:06 +0100 Subject: [PATCH 34/36] Update RNEddystoneModule.podspec --- RNEddystoneModule.podspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/RNEddystoneModule.podspec b/RNEddystoneModule.podspec index ec1fbf8..348e518 100644 --- a/RNEddystoneModule.podspec +++ b/RNEddystoneModule.podspec @@ -19,7 +19,7 @@ Pod::Spec.new do |s| s.source_files = [ "ios/**/*.{h,m,mm}", ] - Use install_modules_dependencies helper to install the dependencies if React Native version >=0.71.0. + # 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) From 07b06fc57c9222cc6687b555e57304f281628738 Mon Sep 17 00:00:00 2001 From: JaioSkura Date: Tue, 11 Feb 2025 15:53:11 +0100 Subject: [PATCH 35/36] Update EddystoneModule.mm --- ios/EddystoneModule.mm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ios/EddystoneModule.mm b/ios/EddystoneModule.mm index 51018e9..006fc36 100644 --- a/ios/EddystoneModule.mm +++ b/ios/EddystoneModule.mm @@ -205,7 +205,7 @@ - (void)centralManagerDidUpdateState:(nonnull CBCentralManager *)manager { - (std::shared_ptr)getTurboModule: (const facebook::react::ObjCTurboModule::InitParams &)params { - return std::make_shared(params); + return std::make_shared(params); } #endif @end From 23ac57fd564a43ce2f12932c42a003561936f50b Mon Sep 17 00:00:00 2001 From: JaioSkura Date: Tue, 11 Feb 2025 16:32:07 +0100 Subject: [PATCH 36/36] Update EddystoneModule.mm --- ios/EddystoneModule.mm | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/ios/EddystoneModule.mm b/ios/EddystoneModule.mm index 006fc36..60f0d12 100644 --- a/ios/EddystoneModule.mm +++ b/ios/EddystoneModule.mm @@ -6,17 +6,6 @@ #import "EddystoneModuleSpec.h" #endif -@implementation SpecChecker - -+ (BOOL)isSpecAvailable { -#ifdef RCT_NEW_ARCH_ENABLED - return YES; -#else - return NO; -#endif -} - -@end @interface EddystoneModule () { @private