expo-beacon 0.10.7 → 0.10.8
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/package.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"withBeaconAndroid.d.ts","sourceRoot":"","sources":["../src/withBeaconAndroid.ts"],"names":[],"mappings":"AAAA,OAAO,EAEN,YAAY,EAGZ,MAAM,sBAAsB,CAAC;AAM9B;;;;;;;;;;;GAWG;AACH,MAAM,MAAM,mBAAmB,GAAG,UAAU,GAAG,OAAO,GAAG,cAAc,CAAC;AAExE,MAAM,MAAM,wBAAwB,GAAG;IACtC;;;;;;OAMG;IACH,qBAAqB,CAAC,EAAE,OAAO,CAAC;IAChC;;;;;;;;;;OAUG;IACH,WAAW,CAAC,EAAE;QACb;2EACmE;QACnE,QAAQ,CAAC,EAAE,OAAO,CAAC;QACnB;qCAC6B;QAC7B,QAAQ,CAAC,EAAE,mBAAmB,CAAC;KAC/B,CAAC;CACF,CAAC;AAIF,wBAAgB,sBAAsB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,
|
|
1
|
+
{"version":3,"file":"withBeaconAndroid.d.ts","sourceRoot":"","sources":["../src/withBeaconAndroid.ts"],"names":[],"mappings":"AAAA,OAAO,EAEN,YAAY,EAGZ,MAAM,sBAAsB,CAAC;AAM9B;;;;;;;;;;;GAWG;AACH,MAAM,MAAM,mBAAmB,GAAG,UAAU,GAAG,OAAO,GAAG,cAAc,CAAC;AAExE,MAAM,MAAM,wBAAwB,GAAG;IACtC;;;;;;OAMG;IACH,qBAAqB,CAAC,EAAE,OAAO,CAAC;IAChC;;;;;;;;;;OAUG;IACH,WAAW,CAAC,EAAE;QACb;2EACmE;QACnE,QAAQ,CAAC,EAAE,OAAO,CAAC;QACnB;qCAC6B;QAC7B,QAAQ,CAAC,EAAE,mBAAmB,CAAC;KAC/B,CAAC;CACF,CAAC;AAIF,wBAAgB,sBAAsB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CA2KlE;AA8ND,QAAA,MAAM,iBAAiB,EAAE,YAAY,CAAC,wBAAwB,GAAG,IAAI,CA0BpE,CAAC;AAEF,eAAe,iBAAiB,CAAC"}
|
|
@@ -7,66 +7,72 @@ const path = require("path");
|
|
|
7
7
|
// ─── Generated Kotlin file ────────────────────────────────────────────────────
|
|
8
8
|
function getAndroidPluginKotlin(packageName) {
|
|
9
9
|
return `\
|
|
10
|
-
package ${packageName}
|
|
10
|
+
package ${packageName}
|
|
11
|
+
|
|
12
|
+
import android.app.AlarmManager
|
|
13
|
+
import android.app.PendingIntent
|
|
14
|
+
import android.content.BroadcastReceiver
|
|
15
|
+
import android.content.Context
|
|
16
|
+
import android.content.Intent
|
|
17
|
+
import android.os.Handler
|
|
18
|
+
import android.os.Looper
|
|
19
|
+
import android.os.SystemClock
|
|
20
|
+
import com.transistorsoft.locationmanager.adapter.BackgroundGeolocation
|
|
21
|
+
import com.transistorsoft.locationmanager.adapter.callback.TSCallback
|
|
22
|
+
import com.transistorsoft.locationmanager.adapter.callback.TSSyncCallback
|
|
23
|
+
import com.transistorsoft.locationmanager.data.LocationModel
|
|
24
|
+
import expo.modules.beacon.BeaconEventPlugin
|
|
11
25
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
import com.transistorsoft.locationmanager.data.LocationModel
|
|
19
|
-
import expo.modules.beacon.BeaconEventPlugin
|
|
20
|
-
|
|
21
|
-
class BeaconGeoPlugin(ctx: Context) : BeaconEventPlugin {
|
|
22
|
-
private val bgGeo = BackgroundGeolocation.getInstance(ctx, null)
|
|
23
|
-
private val noOp = object : TSCallback {
|
|
24
|
-
override fun onSuccess() {}
|
|
25
|
-
override fun onFailure(error: String) {}
|
|
26
|
+
class BeaconGeoPlugin(ctx: Context) : BeaconEventPlugin {
|
|
27
|
+
private val appContext = ctx.applicationContext
|
|
28
|
+
private val bgGeo = BackgroundGeolocation.getInstance(ctx, null)
|
|
29
|
+
private val noOp = object : TSCallback {
|
|
30
|
+
override fun onSuccess() {}
|
|
31
|
+
override fun onFailure(error: String) {}
|
|
26
32
|
}
|
|
27
33
|
private val noOpSync = object : TSSyncCallback {
|
|
28
|
-
override fun onSuccess(records: MutableList<LocationModel>) {}
|
|
29
|
-
override fun onFailure(error: String) {}
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
private
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
bgGeo.
|
|
45
|
-
bgGeo.
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
pendingCarPlayStop
|
|
65
|
-
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
override fun onBeaconEnter(identifier: String, uuid: String, major: Int, minor: Int, distance: Double) =
|
|
69
|
-
startTracking()
|
|
34
|
+
override fun onSuccess(records: MutableList<LocationModel>) {}
|
|
35
|
+
override fun onFailure(error: String) {}
|
|
36
|
+
}
|
|
37
|
+
private val mainHandler = Handler(Looper.getMainLooper())
|
|
38
|
+
private var pendingCarPlayStop: Runnable? = null
|
|
39
|
+
private val carPlayStopDelayMs = 30_000L
|
|
40
|
+
|
|
41
|
+
private fun startTracking() {
|
|
42
|
+
cancelPendingCarPlayStop()
|
|
43
|
+
bgGeo.start(noOp)
|
|
44
|
+
bgGeo.changePace(true, noOp)
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
private fun stopTracking() {
|
|
48
|
+
cancelPendingCarPlayStop()
|
|
49
|
+
bgGeo.sync(noOpSync)
|
|
50
|
+
bgGeo.changePace(false, noOp)
|
|
51
|
+
bgGeo.stop(noOp)
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
private fun stopTrackingForCarPlay() {
|
|
55
|
+
bgGeo.sync(noOpSync)
|
|
56
|
+
bgGeo.changePace(false, noOp)
|
|
57
|
+
cancelPendingCarPlayStop()
|
|
58
|
+
val token = SystemClock.elapsedRealtimeNanos().toString()
|
|
59
|
+
val stop = Runnable {
|
|
60
|
+
pendingCarPlayStop = null
|
|
61
|
+
BeaconGeoCarPlayStop.performIfCurrent(appContext, token)
|
|
62
|
+
}
|
|
63
|
+
pendingCarPlayStop = stop
|
|
64
|
+
BeaconGeoCarPlayStop.schedule(appContext, token, carPlayStopDelayMs)
|
|
65
|
+
mainHandler.postDelayed(stop, carPlayStopDelayMs)
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
private fun cancelPendingCarPlayStop() {
|
|
69
|
+
pendingCarPlayStop?.let { mainHandler.removeCallbacks(it) }
|
|
70
|
+
pendingCarPlayStop = null
|
|
71
|
+
BeaconGeoCarPlayStop.cancel(appContext)
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
override fun onBeaconEnter(identifier: String, uuid: String, major: Int, minor: Int, distance: Double) =
|
|
75
|
+
startTracking()
|
|
70
76
|
override fun onBeaconExit(identifier: String, uuid: String, major: Int, minor: Int, distance: Double) =
|
|
71
77
|
stopTracking()
|
|
72
78
|
override fun onBeaconTimeout(identifier: String, uuid: String, major: Int, minor: Int, distance: Double) =
|
|
@@ -77,16 +83,98 @@ class BeaconGeoPlugin(ctx: Context) : BeaconEventPlugin {
|
|
|
77
83
|
stopTracking()
|
|
78
84
|
override fun onEddystoneTimeout(identifier: String, namespace: String, instance: String, distance: Double) =
|
|
79
85
|
stopTracking()
|
|
80
|
-
// Start tracking when the device connects to Android Auto; stop
|
|
81
|
-
// grace period
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
startTracking()
|
|
85
|
-
}
|
|
86
|
-
override fun onCarPlayDisconnected() {
|
|
87
|
-
stopTrackingForCarPlay()
|
|
88
|
-
}
|
|
89
|
-
}
|
|
86
|
+
// Start tracking when the device connects to Android Auto; stop after a
|
|
87
|
+
// grace period when it disconnects. The delayed stop is backed by
|
|
88
|
+
// AlarmManager so it can still fire if the process idles or is killed.
|
|
89
|
+
override fun onCarPlayConnected(transport: String) {
|
|
90
|
+
startTracking()
|
|
91
|
+
}
|
|
92
|
+
override fun onCarPlayDisconnected() {
|
|
93
|
+
stopTrackingForCarPlay()
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
private object BeaconGeoCarPlayStop {
|
|
98
|
+
private const val ACTION_STOP = "${packageName}.expo_beacon.CARPLAY_STOP_TRACKING"
|
|
99
|
+
private const val EXTRA_TOKEN = "token"
|
|
100
|
+
private const val PREFS = "expo_beacon_geo_plugin"
|
|
101
|
+
private const val KEY_PENDING_TOKEN = "pending_carplay_stop_token"
|
|
102
|
+
private const val REQUEST_CODE = 0xBEEA
|
|
103
|
+
|
|
104
|
+
fun schedule(context: Context, token: String, delayMs: Long) {
|
|
105
|
+
val appContext = context.applicationContext
|
|
106
|
+
appContext.getSharedPreferences(PREFS, Context.MODE_PRIVATE)
|
|
107
|
+
.edit()
|
|
108
|
+
.putString(KEY_PENDING_TOKEN, token)
|
|
109
|
+
.apply()
|
|
110
|
+
val alarmManager = appContext.getSystemService(AlarmManager::class.java) ?: return
|
|
111
|
+
val triggerAt = SystemClock.elapsedRealtime() + delayMs
|
|
112
|
+
try {
|
|
113
|
+
alarmManager.setAndAllowWhileIdle(
|
|
114
|
+
AlarmManager.ELAPSED_REALTIME_WAKEUP,
|
|
115
|
+
triggerAt,
|
|
116
|
+
pendingIntent(appContext, token, PendingIntent.FLAG_UPDATE_CURRENT),
|
|
117
|
+
)
|
|
118
|
+
} catch (_: SecurityException) {
|
|
119
|
+
alarmManager.set(
|
|
120
|
+
AlarmManager.ELAPSED_REALTIME_WAKEUP,
|
|
121
|
+
triggerAt,
|
|
122
|
+
pendingIntent(appContext, token, PendingIntent.FLAG_UPDATE_CURRENT),
|
|
123
|
+
)
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
fun cancel(context: Context) {
|
|
128
|
+
val appContext = context.applicationContext
|
|
129
|
+
appContext.getSharedPreferences(PREFS, Context.MODE_PRIVATE)
|
|
130
|
+
.edit()
|
|
131
|
+
.remove(KEY_PENDING_TOKEN)
|
|
132
|
+
.apply()
|
|
133
|
+
val alarmManager = appContext.getSystemService(AlarmManager::class.java) ?: return
|
|
134
|
+
alarmManager.cancel(pendingIntent(appContext, null, PendingIntent.FLAG_UPDATE_CURRENT))
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
fun performIfCurrent(context: Context, token: String?) {
|
|
138
|
+
if (token == null) return
|
|
139
|
+
val appContext = context.applicationContext
|
|
140
|
+
val prefs = appContext.getSharedPreferences(PREFS, Context.MODE_PRIVATE)
|
|
141
|
+
if (prefs.getString(KEY_PENDING_TOKEN, null) != token) return
|
|
142
|
+
prefs.edit().remove(KEY_PENDING_TOKEN).apply()
|
|
143
|
+
val bgGeo = BackgroundGeolocation.getInstance(appContext, null)
|
|
144
|
+
val noOp = object : TSCallback {
|
|
145
|
+
override fun onSuccess() {}
|
|
146
|
+
override fun onFailure(error: String) {}
|
|
147
|
+
}
|
|
148
|
+
val noOpSync = object : TSSyncCallback {
|
|
149
|
+
override fun onSuccess(records: MutableList<LocationModel>) {}
|
|
150
|
+
override fun onFailure(error: String) {}
|
|
151
|
+
}
|
|
152
|
+
bgGeo.sync(noOpSync)
|
|
153
|
+
bgGeo.changePace(false, noOp)
|
|
154
|
+
bgGeo.stop(noOp)
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
fun tokenFrom(intent: Intent): String? = intent.getStringExtra(EXTRA_TOKEN)
|
|
158
|
+
|
|
159
|
+
private fun pendingIntent(context: Context, token: String?, flags: Int): PendingIntent {
|
|
160
|
+
val intent = Intent(context, BeaconGeoStopReceiver::class.java).apply {
|
|
161
|
+
action = ACTION_STOP
|
|
162
|
+
token?.let { putExtra(EXTRA_TOKEN, it) }
|
|
163
|
+
}
|
|
164
|
+
return PendingIntent.getBroadcast(
|
|
165
|
+
context,
|
|
166
|
+
REQUEST_CODE,
|
|
167
|
+
intent,
|
|
168
|
+
flags or PendingIntent.FLAG_IMMUTABLE,
|
|
169
|
+
)
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
class BeaconGeoStopReceiver : BroadcastReceiver() {
|
|
174
|
+
override fun onReceive(context: Context, intent: Intent) {
|
|
175
|
+
BeaconGeoCarPlayStop.performIfCurrent(context, BeaconGeoCarPlayStop.tokenFrom(intent))
|
|
176
|
+
}
|
|
177
|
+
}
|
|
90
178
|
`;
|
|
91
179
|
}
|
|
92
180
|
// ─── Helpers ──────────────────────────────────────────────────────────────────
|
|
@@ -116,6 +204,7 @@ function modifyMainApplication(contents) {
|
|
|
116
204
|
const AA_META_DATA_NAME = "com.google.android.gms.car.application";
|
|
117
205
|
const AA_META_DATA_RESOURCE = "@xml/automotive_app_desc";
|
|
118
206
|
const AA_RES_FILE = "automotive_app_desc.xml";
|
|
207
|
+
const BEACON_GEO_STOP_RECEIVER = "BeaconGeoStopReceiver";
|
|
119
208
|
function getAutomotiveAppDescXml(usesName) {
|
|
120
209
|
return `<?xml version="1.0" encoding="utf-8"?>
|
|
121
210
|
<!--
|
|
@@ -179,6 +268,30 @@ function withAndroidAutoDescriptor(usesName) {
|
|
|
179
268
|
* the `backgroundGeolocation` plugin prop (default: enabled).
|
|
180
269
|
*/
|
|
181
270
|
const withBeaconGeoPlugin = (config) => {
|
|
271
|
+
config = (0, config_plugins_1.withAndroidManifest)(config, (config) => {
|
|
272
|
+
var _a, _b;
|
|
273
|
+
const pkgName = (_a = config.android) === null || _a === void 0 ? void 0 : _a.package;
|
|
274
|
+
if (!pkgName)
|
|
275
|
+
return config;
|
|
276
|
+
const app = config_plugins_1.AndroidConfig.Manifest.getMainApplicationOrThrow(config.modResults);
|
|
277
|
+
const receiverName = `${pkgName}.${BEACON_GEO_STOP_RECEIVER}`;
|
|
278
|
+
const receivers = ((_b = app.receiver) !== null && _b !== void 0 ? _b : (app.receiver = []));
|
|
279
|
+
const exists = receivers.some((receiver) => {
|
|
280
|
+
var _a, _b;
|
|
281
|
+
return ((_a = receiver === null || receiver === void 0 ? void 0 : receiver.$) === null || _a === void 0 ? void 0 : _a["android:name"]) === receiverName ||
|
|
282
|
+
((_b = receiver === null || receiver === void 0 ? void 0 : receiver.$) === null || _b === void 0 ? void 0 : _b["android:name"]) === `.${BEACON_GEO_STOP_RECEIVER}`;
|
|
283
|
+
});
|
|
284
|
+
if (!exists) {
|
|
285
|
+
receivers.push({
|
|
286
|
+
$: {
|
|
287
|
+
"android:name": receiverName,
|
|
288
|
+
"android:enabled": "true",
|
|
289
|
+
"android:exported": "false",
|
|
290
|
+
},
|
|
291
|
+
});
|
|
292
|
+
}
|
|
293
|
+
return config;
|
|
294
|
+
});
|
|
182
295
|
// Step 1 – write BeaconGeoPlugin.kt into the app source tree.
|
|
183
296
|
config = (0, config_plugins_1.withDangerousMod)(config, [
|
|
184
297
|
"android",
|