expo-beacon 0.6.16 → 0.6.17
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/android/src/main/java/expo/modules/beacon/BeaconApiForwarder.kt +8 -2
- package/android/src/main/java/expo/modules/beacon/ExpoBeaconModule.kt +2 -2
- package/build/ExpoBeaconModule.d.ts +2 -1
- package/build/ExpoBeaconModule.d.ts.map +1 -1
- package/build/ExpoBeaconModule.js.map +1 -1
- package/ios/BeaconApiForwarder.swift +12 -2
- package/ios/ExpoBeaconModule.swift +2 -2
- package/package.json +1 -1
- package/src/ExpoBeaconModule.ts +2 -1
|
@@ -13,6 +13,7 @@ import java.util.concurrent.Executors
|
|
|
13
13
|
private const val API_PREFS = "expo.beacon.api_config"
|
|
14
14
|
private const val API_URL_KEY = "api_url"
|
|
15
15
|
private const val API_KEY_KEY = "api_key"
|
|
16
|
+
private const val ID_KEY = "id"
|
|
16
17
|
private const val MAX_RETRIES = 3
|
|
17
18
|
|
|
18
19
|
/**
|
|
@@ -30,18 +31,21 @@ internal class BeaconApiForwarder(private val context: Context) {
|
|
|
30
31
|
val isConfigured: Boolean
|
|
31
32
|
get() = prefs.getString(API_URL_KEY, null)?.isNotEmpty() == true
|
|
32
33
|
|
|
33
|
-
fun configure(url: String, apiKey: String?) {
|
|
34
|
+
fun configure(url: String, apiKey: String?, id: String? = null) {
|
|
34
35
|
prefs.edit().apply {
|
|
35
36
|
putString(API_URL_KEY, url)
|
|
36
37
|
if (apiKey != null) putString(API_KEY_KEY, apiKey)
|
|
37
38
|
else remove(API_KEY_KEY)
|
|
39
|
+
if (id != null) putString(ID_KEY, id)
|
|
40
|
+
else remove(ID_KEY)
|
|
38
41
|
}.apply()
|
|
39
42
|
}
|
|
40
43
|
|
|
41
44
|
fun getConfig(): Map<String, String?> {
|
|
42
45
|
return mapOf(
|
|
43
46
|
"url" to prefs.getString(API_URL_KEY, null),
|
|
44
|
-
"apiKey" to prefs.getString(API_KEY_KEY, null)
|
|
47
|
+
"apiKey" to prefs.getString(API_KEY_KEY, null),
|
|
48
|
+
"id" to prefs.getString(ID_KEY, null)
|
|
45
49
|
)
|
|
46
50
|
}
|
|
47
51
|
|
|
@@ -55,10 +59,12 @@ internal class BeaconApiForwarder(private val context: Context) {
|
|
|
55
59
|
if (url.isNullOrEmpty()) return
|
|
56
60
|
|
|
57
61
|
val apiKey = prefs.getString(API_KEY_KEY, null)
|
|
62
|
+
val id = prefs.getString(ID_KEY, null)
|
|
58
63
|
val payload = JSONObject().apply {
|
|
59
64
|
for ((k, v) in params) {
|
|
60
65
|
put(k, v ?: JSONObject.NULL)
|
|
61
66
|
}
|
|
67
|
+
if (!id.isNullOrEmpty()) put("id", id)
|
|
62
68
|
put("timestamp", System.currentTimeMillis())
|
|
63
69
|
put("platform", "android")
|
|
64
70
|
put("sdkVersion", Build.VERSION.SDK_INT)
|
|
@@ -458,10 +458,10 @@ class ExpoBeaconModule : Module(), BeaconConsumer {
|
|
|
458
458
|
|
|
459
459
|
// MARK: - API Forwarding
|
|
460
460
|
|
|
461
|
-
Function("setApiEndpoint") { url: String, apiKey: String? ->
|
|
461
|
+
Function("setApiEndpoint") { url: String, apiKey: String?, id: String? ->
|
|
462
462
|
val ctx = appContext.reactContext
|
|
463
463
|
?: throw IllegalStateException("React context is not available")
|
|
464
|
-
BeaconApiForwarder(ctx).configure(url, apiKey)
|
|
464
|
+
BeaconApiForwarder(ctx).configure(url, apiKey, id)
|
|
465
465
|
}
|
|
466
466
|
|
|
467
467
|
// MARK: - Battery Optimization
|
|
@@ -109,8 +109,9 @@ declare class ExpoBeaconModule extends NativeModule<ExpoBeaconModuleEvents> {
|
|
|
109
109
|
*
|
|
110
110
|
* @param url The API endpoint URL to POST events to.
|
|
111
111
|
* @param apiKey Optional API key sent as X-API-Key header.
|
|
112
|
+
* @param id Optional identifier appended to every forwarded event payload.
|
|
112
113
|
*/
|
|
113
|
-
setApiEndpoint(url: string, apiKey?: string): void;
|
|
114
|
+
setApiEndpoint(url: string, apiKey?: string, id?: string): void;
|
|
114
115
|
}
|
|
115
116
|
declare const _default: ExpoBeaconModule;
|
|
116
117
|
export default _default;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ExpoBeaconModule.d.ts","sourceRoot":"","sources":["../src/ExpoBeaconModule.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAuB,MAAM,MAAM,CAAC;AAEzD,OAAO,EACL,sBAAsB,EACtB,gBAAgB,EAChB,mBAAmB,EACnB,YAAY,EACZ,eAAe,EACf,kBAAkB,EAClB,iBAAiB,EACjB,oBAAoB,EACpB,aAAa,EACd,MAAM,oBAAoB,CAAC;AAE5B,OAAO,OAAO,gBAAiB,SAAQ,YAAY,CAAC,sBAAsB,CAAC;IACzE;;;;;;;;;;;OAWG;IACH,mBAAmB,CACjB,KAAK,CAAC,EAAE,MAAM,EAAE,EAChB,YAAY,CAAC,EAAE,MAAM,GACpB,OAAO,CAAC,gBAAgB,EAAE,CAAC;IAE9B;;;;;OAKG;IACH,sBAAsB,CACpB,YAAY,CAAC,EAAE,MAAM,GACpB,OAAO,CAAC,mBAAmB,EAAE,CAAC;IAEjC;;OAEG;IACH,UAAU,CACR,UAAU,EAAE,MAAM,EAClB,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,MAAM,EACb,IAAI,CAAC,EAAE,MAAM,EACb,cAAc,CAAC,EAAE,MAAM,GACtB,IAAI;IAEP;;OAEG;IACH,YAAY,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI;IAEtC;;OAEG;IACH,gBAAgB,IAAI,YAAY,EAAE;IAElC;;OAEG;IACH,aAAa,CACX,UAAU,EAAE,MAAM,EAClB,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,MAAM,EAChB,IAAI,CAAC,EAAE,MAAM,EACb,cAAc,CAAC,EAAE,MAAM,GACtB,IAAI;IAEP;;OAEG;IACH,eAAe,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI;IAEzC;;OAEG;IACH,mBAAmB,IAAI,eAAe,EAAE;IAExC;;;OAGG;IACH,qBAAqB,CAAC,MAAM,EAAE,kBAAkB,GAAG,IAAI;IAEvD;;;;;;;OAOG;IACH,eAAe,CAAC,OAAO,CAAC,EAAE,iBAAiB,GAAG,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAEpE;;OAEG;IACH,cAAc,IAAI,OAAO,CAAC,IAAI,CAAC;IAE/B;;;OAGG;IACH,mBAAmB,IAAI,IAAI;IAE3B,iEAAiE;IACjE,kBAAkB,IAAI,IAAI;IAE1B;;;OAGG;IACH,UAAU,IAAI,IAAI;IAElB,yEAAyE;IACzE,uBAAuB,IAAI,OAAO,CAAC,OAAO,CAAC;IAE3C;;;OAGG;IACH,2BAA2B,IAAI,OAAO;IAEtC;;;;;OAKG;IACH,mCAAmC,IAAI,OAAO,CAAC,OAAO,CAAC;IAEvD,4FAA4F;IAC5F,kBAAkB,IAAI,IAAI;IAE1B,oEAAoE;IACpE,mBAAmB,IAAI,IAAI;IAE3B;;;OAGG;IACH,YAAY,CAAC,OAAO,CAAC,EAAE,oBAAoB,GAAG,aAAa,EAAE;IAE7D,kDAAkD;IAClD,cAAc,IAAI,IAAI;IAEtB,mEAAmE;IACnE,gBAAgB,IAAI,IAAI;IAExB
|
|
1
|
+
{"version":3,"file":"ExpoBeaconModule.d.ts","sourceRoot":"","sources":["../src/ExpoBeaconModule.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAuB,MAAM,MAAM,CAAC;AAEzD,OAAO,EACL,sBAAsB,EACtB,gBAAgB,EAChB,mBAAmB,EACnB,YAAY,EACZ,eAAe,EACf,kBAAkB,EAClB,iBAAiB,EACjB,oBAAoB,EACpB,aAAa,EACd,MAAM,oBAAoB,CAAC;AAE5B,OAAO,OAAO,gBAAiB,SAAQ,YAAY,CAAC,sBAAsB,CAAC;IACzE;;;;;;;;;;;OAWG;IACH,mBAAmB,CACjB,KAAK,CAAC,EAAE,MAAM,EAAE,EAChB,YAAY,CAAC,EAAE,MAAM,GACpB,OAAO,CAAC,gBAAgB,EAAE,CAAC;IAE9B;;;;;OAKG;IACH,sBAAsB,CACpB,YAAY,CAAC,EAAE,MAAM,GACpB,OAAO,CAAC,mBAAmB,EAAE,CAAC;IAEjC;;OAEG;IACH,UAAU,CACR,UAAU,EAAE,MAAM,EAClB,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,MAAM,EACb,IAAI,CAAC,EAAE,MAAM,EACb,cAAc,CAAC,EAAE,MAAM,GACtB,IAAI;IAEP;;OAEG;IACH,YAAY,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI;IAEtC;;OAEG;IACH,gBAAgB,IAAI,YAAY,EAAE;IAElC;;OAEG;IACH,aAAa,CACX,UAAU,EAAE,MAAM,EAClB,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,MAAM,EAChB,IAAI,CAAC,EAAE,MAAM,EACb,cAAc,CAAC,EAAE,MAAM,GACtB,IAAI;IAEP;;OAEG;IACH,eAAe,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI;IAEzC;;OAEG;IACH,mBAAmB,IAAI,eAAe,EAAE;IAExC;;;OAGG;IACH,qBAAqB,CAAC,MAAM,EAAE,kBAAkB,GAAG,IAAI;IAEvD;;;;;;;OAOG;IACH,eAAe,CAAC,OAAO,CAAC,EAAE,iBAAiB,GAAG,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAEpE;;OAEG;IACH,cAAc,IAAI,OAAO,CAAC,IAAI,CAAC;IAE/B;;;OAGG;IACH,mBAAmB,IAAI,IAAI;IAE3B,iEAAiE;IACjE,kBAAkB,IAAI,IAAI;IAE1B;;;OAGG;IACH,UAAU,IAAI,IAAI;IAElB,yEAAyE;IACzE,uBAAuB,IAAI,OAAO,CAAC,OAAO,CAAC;IAE3C;;;OAGG;IACH,2BAA2B,IAAI,OAAO;IAEtC;;;;;OAKG;IACH,mCAAmC,IAAI,OAAO,CAAC,OAAO,CAAC;IAEvD,4FAA4F;IAC5F,kBAAkB,IAAI,IAAI;IAE1B,oEAAoE;IACpE,mBAAmB,IAAI,IAAI;IAE3B;;;OAGG;IACH,YAAY,CAAC,OAAO,CAAC,EAAE,oBAAoB,GAAG,aAAa,EAAE;IAE7D,kDAAkD;IAClD,cAAc,IAAI,IAAI;IAEtB,mEAAmE;IACnE,gBAAgB,IAAI,IAAI;IAExB;;;;;;;;OAQG;IACH,cAAc,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,EAAE,EAAE,CAAC,EAAE,MAAM,GAAG,IAAI;CAChE;;AAED,wBAAmE"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ExpoBeaconModule.js","sourceRoot":"","sources":["../src/ExpoBeaconModule.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,mBAAmB,EAAE,MAAM,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"ExpoBeaconModule.js","sourceRoot":"","sources":["../src/ExpoBeaconModule.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,mBAAmB,EAAE,MAAM,MAAM,CAAC;AAwKzD,eAAe,mBAAmB,CAAmB,YAAY,CAAC,CAAC","sourcesContent":["import { NativeModule, requireNativeModule } from \"expo\";\r\n\r\nimport {\r\n ExpoBeaconModuleEvents,\r\n BeaconScanResult,\r\n EddystoneScanResult,\r\n PairedBeacon,\r\n PairedEddystone,\r\n NotificationConfig,\r\n MonitoringOptions,\r\n EventLogQueryOptions,\r\n EventLogEntry,\r\n} from \"./ExpoBeacon.types\";\r\n\r\ndeclare class ExpoBeaconModule extends NativeModule<ExpoBeaconModuleEvents> {\r\n /**\r\n * Start a one-shot iBeacon scan. Resolves with discovered beacons after scanDuration ms.\r\n *\r\n * Pass one or more UUIDs to scan for specific beacons (uses CoreLocation on iOS).\r\n * On iOS, at least one UUID is required — Apple strips iBeacon data from BLE\r\n * advertisements, making wildcard discovery impossible. When you pass an empty\r\n * array, the module automatically uses UUIDs from paired beacons.\r\n * On Android, pass an empty array to discover all nearby iBeacons.\r\n *\r\n * @param uuids Proximity UUIDs to filter by. Empty/omitted = use paired UUIDs (iOS) or wildcard (Android).\r\n * @param scanDuration Duration in ms (default 5000)\r\n */\r\n scanForBeaconsAsync(\r\n uuids?: string[],\r\n scanDuration?: number,\r\n ): Promise<BeaconScanResult[]>;\r\n\r\n /**\r\n * Start a one-shot Eddystone beacon scan using BLE.\r\n * Discovers Eddystone-UID and Eddystone-URL frames.\r\n *\r\n * @param scanDuration Duration in ms (default 5000)\r\n */\r\n scanForEddystonesAsync(\r\n scanDuration?: number,\r\n ): Promise<EddystoneScanResult[]>;\r\n\r\n /**\r\n * Register a beacon for persistent region monitoring.\r\n */\r\n pairBeacon(\r\n identifier: string,\r\n uuid: string,\r\n major: number,\r\n minor: number,\r\n name?: string,\r\n timeoutSeconds?: number,\r\n ): void;\r\n\r\n /**\r\n * Remove a previously paired beacon.\r\n */\r\n unpairBeacon(identifier: string): void;\r\n\r\n /**\r\n * Return all currently paired beacons.\r\n */\r\n getPairedBeacons(): PairedBeacon[];\r\n\r\n /**\r\n * Register an Eddystone-UID beacon for persistent monitoring.\r\n */\r\n pairEddystone(\r\n identifier: string,\r\n namespace: string,\r\n instance: string,\r\n name?: string,\r\n timeoutSeconds?: number,\r\n ): void;\r\n\r\n /**\r\n * Remove a previously paired Eddystone beacon.\r\n */\r\n unpairEddystone(identifier: string): void;\r\n\r\n /**\r\n * Return all currently paired Eddystone beacons.\r\n */\r\n getPairedEddystones(): PairedEddystone[];\r\n\r\n /**\r\n * Set persistent notification configuration. Settings are saved and applied to all\r\n * subsequent monitoring sessions until explicitly changed.\r\n */\r\n setNotificationConfig(config: NotificationConfig): void;\r\n\r\n /**\r\n * Start background region monitoring for all paired beacons.\r\n * On Android starts a foreground service.\r\n * On iOS starts CLLocationManager region monitoring.\r\n *\r\n * Accepts a plain number (backward-compatible maxDistance shorthand) or a\r\n * MonitoringOptions object with maxDistance and/or notification overrides.\r\n */\r\n startMonitoring(options?: MonitoringOptions | number): Promise<void>;\r\n\r\n /**\r\n * Stop background region monitoring.\r\n */\r\n stopMonitoring(): Promise<void>;\r\n\r\n /**\r\n * Start a continuous BLE scan. Fires `onBeaconFound` events as beacons are detected.\r\n * Call stopContinuousScan() to end the scan.\r\n */\r\n startContinuousScan(): void;\r\n\r\n /** Stop the continuous scan started by startContinuousScan(). */\r\n stopContinuousScan(): void;\r\n\r\n /**\r\n * Cancel any in-progress one-shot scan (iBeacon or Eddystone).\r\n * The pending promise will be rejected with code \"SCAN_CANCELLED\".\r\n */\r\n cancelScan(): void;\r\n\r\n /** Request Bluetooth + Location permissions. Returns true if granted. */\r\n requestPermissionsAsync(): Promise<boolean>;\r\n\r\n /**\r\n * Check whether the app is exempt from Android battery optimizations.\r\n * Always returns true on iOS and web (no equivalent concept).\r\n */\r\n isBatteryOptimizationExempt(): boolean;\r\n\r\n /**\r\n * Request exemption from Android battery optimizations.\r\n * Opens the system dialog asking the user to whitelist this app.\r\n * Returns true if the dialog was shown (or already exempt), false on failure.\r\n * Always resolves true on iOS and web.\r\n */\r\n requestBatteryOptimizationExemption(): Promise<boolean>;\r\n\r\n /** Enable SQLite event logging. All beacon events will be persisted to a local database. */\r\n enableEventLogging(): void;\r\n\r\n /** Disable event logging. Previously logged events are retained. */\r\n disableEventLogging(): void;\r\n\r\n /**\r\n * Retrieve logged beacon events from the SQLite database.\r\n * @param options Optional filters (limit, eventType, sinceTimestamp).\r\n */\r\n getEventLogs(options?: EventLogQueryOptions): EventLogEntry[];\r\n\r\n /** Delete all logged events from the database. */\r\n clearEventLogs(): void;\r\n\r\n /** Delete the entire event log database. Also disables logging. */\r\n destroyEventLogs(): void;\r\n\r\n /**\r\n * Configure a remote API endpoint for native event forwarding.\r\n * Once set, beacon events are POSTed directly from native code,\r\n * ensuring delivery even when the JS bridge is not active (app backgrounded).\r\n *\r\n * @param url The API endpoint URL to POST events to.\r\n * @param apiKey Optional API key sent as X-API-Key header.\r\n * @param id Optional identifier appended to every forwarded event payload.\r\n */\r\n setApiEndpoint(url: string, apiKey?: string, id?: string): void;\r\n}\r\n\r\nexport default requireNativeModule<ExpoBeaconModule>(\"ExpoBeacon\");\r\n"]}
|
|
@@ -3,6 +3,7 @@ import os.log
|
|
|
3
3
|
|
|
4
4
|
private let API_URL_KEY = "expo.beacon.api_url"
|
|
5
5
|
private let API_KEY_KEY = "expo.beacon.api_key"
|
|
6
|
+
private let ID_KEY = "expo.beacon.id"
|
|
6
7
|
private let MAX_RETRIES = 3
|
|
7
8
|
|
|
8
9
|
/// Fire-and-forget HTTP event forwarder for beacon events.
|
|
@@ -28,19 +29,25 @@ final class BeaconApiForwarder {
|
|
|
28
29
|
self.session = URLSession(configuration: config)
|
|
29
30
|
}
|
|
30
31
|
|
|
31
|
-
func configure(url: String, apiKey: String?) {
|
|
32
|
+
func configure(url: String, apiKey: String?, id: String? = nil) {
|
|
32
33
|
defaults.set(url, forKey: API_URL_KEY)
|
|
33
34
|
if let key = apiKey {
|
|
34
35
|
defaults.set(key, forKey: API_KEY_KEY)
|
|
35
36
|
} else {
|
|
36
37
|
defaults.removeObject(forKey: API_KEY_KEY)
|
|
37
38
|
}
|
|
39
|
+
if let id = id {
|
|
40
|
+
defaults.set(id, forKey: ID_KEY)
|
|
41
|
+
} else {
|
|
42
|
+
defaults.removeObject(forKey: ID_KEY)
|
|
43
|
+
}
|
|
38
44
|
}
|
|
39
45
|
|
|
40
46
|
func getConfig() -> [String: String?] {
|
|
41
47
|
return [
|
|
42
48
|
"url": defaults.string(forKey: API_URL_KEY),
|
|
43
|
-
"apiKey": defaults.string(forKey: API_KEY_KEY)
|
|
49
|
+
"apiKey": defaults.string(forKey: API_KEY_KEY),
|
|
50
|
+
"id": defaults.string(forKey: ID_KEY)
|
|
44
51
|
]
|
|
45
52
|
}
|
|
46
53
|
|
|
@@ -55,6 +62,9 @@ final class BeaconApiForwarder {
|
|
|
55
62
|
let apiKey = defaults.string(forKey: API_KEY_KEY)
|
|
56
63
|
|
|
57
64
|
var payload = params
|
|
65
|
+
if let id = defaults.string(forKey: ID_KEY), !id.isEmpty {
|
|
66
|
+
payload["id"] = id
|
|
67
|
+
}
|
|
58
68
|
payload["timestamp"] = Int64(Date().timeIntervalSince1970 * 1000)
|
|
59
69
|
payload["platform"] = "ios"
|
|
60
70
|
payload["sdkVersion"] = ProcessInfo.processInfo.operatingSystemVersion.majorVersion
|
|
@@ -503,8 +503,8 @@ public class ExpoBeaconModule: Module {
|
|
|
503
503
|
|
|
504
504
|
// MARK: - API Forwarding
|
|
505
505
|
|
|
506
|
-
Function("setApiEndpoint") { (url: String, apiKey: String?) -> Void in
|
|
507
|
-
self.apiForwarder.configure(url: url, apiKey: apiKey)
|
|
506
|
+
Function("setApiEndpoint") { (url: String, apiKey: String?, id: String?) -> Void in
|
|
507
|
+
self.apiForwarder.configure(url: url, apiKey: apiKey, id: id)
|
|
508
508
|
}
|
|
509
509
|
|
|
510
510
|
// MARK: - Battery Optimization (Android-only; no-op on iOS)
|
package/package.json
CHANGED
package/src/ExpoBeaconModule.ts
CHANGED
|
@@ -161,8 +161,9 @@ declare class ExpoBeaconModule extends NativeModule<ExpoBeaconModuleEvents> {
|
|
|
161
161
|
*
|
|
162
162
|
* @param url The API endpoint URL to POST events to.
|
|
163
163
|
* @param apiKey Optional API key sent as X-API-Key header.
|
|
164
|
+
* @param id Optional identifier appended to every forwarded event payload.
|
|
164
165
|
*/
|
|
165
|
-
setApiEndpoint(url: string, apiKey?: string): void;
|
|
166
|
+
setApiEndpoint(url: string, apiKey?: string, id?: string): void;
|
|
166
167
|
}
|
|
167
168
|
|
|
168
169
|
export default requireNativeModule<ExpoBeaconModule>("ExpoBeacon");
|