expo-beacon 0.8.8 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +44 -0
- package/android/build.gradle +7 -1
- package/android/src/main/AndroidManifest.xml +10 -0
- package/android/src/main/java/expo/modules/beacon/BeaconForegroundService.kt +61 -2
- package/android/src/main/java/expo/modules/beacon/BootReceiver.kt +102 -3
- package/android/src/main/java/expo/modules/beacon/CarPlayMonitor.kt +37 -2
- package/android/src/main/java/expo/modules/beacon/CarPlayWatchdogWorker.kt +97 -0
- package/android/src/main/java/expo/modules/beacon/ExpoBeaconModule.kt +14 -0
- package/build/ExpoBeacon.types.d.ts +55 -0
- package/build/ExpoBeacon.types.d.ts.map +1 -1
- package/build/ExpoBeacon.types.js.map +1 -1
- package/build/ExpoBeaconModule.d.ts +11 -1
- package/build/ExpoBeaconModule.d.ts.map +1 -1
- package/build/ExpoBeaconModule.js.map +1 -1
- package/build/index.d.ts +1 -1
- package/build/index.d.ts.map +1 -1
- package/build/index.js.map +1 -1
- package/ios/ExpoBeaconModule.swift +25 -0
- package/package.json +1 -1
- package/plugin/build/index.d.ts +2 -0
- package/plugin/build/index.d.ts.map +1 -1
- package/plugin/build/index.js +1 -1
- package/plugin/build/withBeaconAndroid.d.ts +35 -1
- package/plugin/build/withBeaconAndroid.d.ts.map +1 -1
- package/plugin/build/withBeaconAndroid.js +74 -1
- package/src/ExpoBeacon.types.ts +56 -0
- package/src/ExpoBeaconModule.ts +12 -0
- package/src/index.ts +1 -0
package/README.md
CHANGED
|
@@ -744,6 +744,50 @@ CarPlay observation is **persistent** — the enabled flag is stored in native p
|
|
|
744
744
|
- On iOS, if the JS bundle is suspended in the background, the JS event delivery is deferred until the app resumes, but the native lifecycle delegate (used by the geolocation plugin) fires immediately on connect.
|
|
745
745
|
- On Android, when CarPlay monitoring is enabled without beacon monitoring, the foreground service shows a generic "Connected device monitoring active" notification.
|
|
746
746
|
|
|
747
|
+
**Android Auto registration (automatic via config plugin)**
|
|
748
|
+
|
|
749
|
+
On Android 14+ — and especially with **wireless Android Auto** — `CarConnection.getType()` silently returns `NOT_CONNECTED` for any app that has not declared itself Android-Auto-aware. The bundled config plugin handles this for you: on the next `expo prebuild` it injects a `com.google.android.gms.car.application` meta-data entry into `AndroidManifest.xml` and writes `res/xml/automotive_app_desc.xml` with `<uses name="template"/>`. No manual native edits are required.
|
|
750
|
+
|
|
751
|
+
If you need to disable this (e.g. you already ship your own Android Auto template app and don't want a duplicate registration) or you need to declare a different capability than `template`, configure the plugin in your app config:
|
|
752
|
+
|
|
753
|
+
```json
|
|
754
|
+
{
|
|
755
|
+
"expo": {
|
|
756
|
+
"plugins": [
|
|
757
|
+
["expo-beacon", {
|
|
758
|
+
"android": {
|
|
759
|
+
"androidAuto": {
|
|
760
|
+
"register": true,
|
|
761
|
+
"usesName": "template"
|
|
762
|
+
}
|
|
763
|
+
}
|
|
764
|
+
}]
|
|
765
|
+
]
|
|
766
|
+
}
|
|
767
|
+
}
|
|
768
|
+
```
|
|
769
|
+
|
|
770
|
+
`usesName` accepts any value supported by Android's [`automotiveApp` schema](https://developer.android.com/training/cars/apps#manifest) (`template`, `media`, `notification`, …). Setting `register: false` skips both the meta-data and the resource file.
|
|
771
|
+
|
|
772
|
+
**Diagnostics**
|
|
773
|
+
|
|
774
|
+
If `onCarPlayConnected` never fires on Android, call `getCarPlayDiagnostics()` to inspect the native state:
|
|
775
|
+
|
|
776
|
+
```ts
|
|
777
|
+
const d = await ExpoBeacon.getCarPlayDiagnostics();
|
|
778
|
+
// {
|
|
779
|
+
// platform: "android",
|
|
780
|
+
// carPlayEnabled: true,
|
|
781
|
+
// isCarAppMetadataPresent: true, // false → config plugin didn't run; prebuild again
|
|
782
|
+
// isCarProviderQueryable: true, // false → Android Auto app not installed on device
|
|
783
|
+
// lastRawConnectionType: 0, // 0=DISCONNECTED 1=PROJECTION 2=NATIVE
|
|
784
|
+
// observerActive: true,
|
|
785
|
+
// serviceAlive: true,
|
|
786
|
+
// }
|
|
787
|
+
```
|
|
788
|
+
|
|
789
|
+
A response with `isCarAppMetadataPresent: false` indicates the AA registration didn't make it into the built APK — re-run `expo prebuild --clean` to apply the plugin changes.
|
|
790
|
+
|
|
747
791
|
---
|
|
748
792
|
|
|
749
793
|
## Full API Reference
|
package/android/build.gradle
CHANGED
|
@@ -22,5 +22,11 @@ dependencies {
|
|
|
22
22
|
implementation 'org.altbeacon:android-beacon-library:2.21.2'
|
|
23
23
|
// androidx.car.app provides CarConnection LiveData for detecting Android Auto sessions.
|
|
24
24
|
// No Android Auto certification or extra permissions required for read-only state.
|
|
25
|
-
|
|
25
|
+
// 1.7.0 fixes known wireless-AA + Android 14 issues that existed in 1.4.0/1.5.x.
|
|
26
|
+
implementation 'androidx.car.app:app:1.7.0'
|
|
27
|
+
// WorkManager powers the CarPlay watchdog (periodic restart of the foreground
|
|
28
|
+
// service if it was killed by the OS / OEM cleaners while CarPlay observation
|
|
29
|
+
// is enabled). Minimum periodic interval is 15 min; an AlarmManager loop in
|
|
30
|
+
// BootReceiver covers the sub-15-min gap.
|
|
31
|
+
implementation 'androidx.work:work-runtime-ktx:2.9.1'
|
|
26
32
|
}
|
|
@@ -79,8 +79,18 @@
|
|
|
79
79
|
android:exported="true">
|
|
80
80
|
<intent-filter>
|
|
81
81
|
<action android:name="android.intent.action.BOOT_COMPLETED" />
|
|
82
|
+
<!-- Direct-boot phase boot (Android 7+). Harmless without
|
|
83
|
+
directBootAware="true"; declaring early so the only
|
|
84
|
+
follow-up needed for true direct-boot support is that
|
|
85
|
+
single attribute. -->
|
|
86
|
+
<action android:name="android.intent.action.LOCKED_BOOT_COMPLETED" />
|
|
87
|
+
<!-- Restart observers after the host app is updated. -->
|
|
88
|
+
<action android:name="android.intent.action.MY_PACKAGE_REPLACED" />
|
|
82
89
|
<!-- Self-scheduled retry when BT isn't ready at boot -->
|
|
83
90
|
<action android:name="expo.modules.beacon.ACTION_RETRY_MONITORING" />
|
|
91
|
+
<!-- Self-scheduled CarPlay watchdog (11-min cadence; above
|
|
92
|
+
setExactAndAllowWhileIdle per-app quota). -->
|
|
93
|
+
<action android:name="expo.modules.beacon.ACTION_CARPLAY_WATCHDOG" />
|
|
84
94
|
</intent-filter>
|
|
85
95
|
</receiver>
|
|
86
96
|
</application>
|
|
@@ -131,6 +131,11 @@ class BeaconForegroundService : Service(), BeaconConsumer {
|
|
|
131
131
|
// observer with no JS interaction required.
|
|
132
132
|
if (isCarPlayEnabled(this)) {
|
|
133
133
|
startCarPlayObserverInternal()
|
|
134
|
+
// Re-arm the WorkManager watchdog on every cold start. KEEP policy
|
|
135
|
+
// makes this a cheap no-op if a schedule already exists, but it
|
|
136
|
+
// recovers the schedule if WorkManager's DB was wiped by an OEM
|
|
137
|
+
// cleaner or by a `pm clear` from adb.
|
|
138
|
+
CarPlayWatchdogWorker.schedule(this)
|
|
134
139
|
}
|
|
135
140
|
}
|
|
136
141
|
|
|
@@ -153,8 +158,12 @@ class BeaconForegroundService : Service(), BeaconConsumer {
|
|
|
153
158
|
Log.e(TAG, "startForeground failed (retry=$retryCount) — stopping service", e)
|
|
154
159
|
sendErrorBroadcast(null, "SERVICE_START_FAILED", "startForeground failed (retry=$retryCount): ${e.message}")
|
|
155
160
|
// Schedule a retry so monitoring can recover without user interaction, capped to
|
|
156
|
-
// avoid infinite crash loops.
|
|
157
|
-
|
|
161
|
+
// avoid infinite crash loops. Retry if EITHER beacon monitoring OR CarPlay
|
|
162
|
+
// observation is supposed to be active — without the CarPlay branch the
|
|
163
|
+
// service silently dies when the very first startCarPlayMonitoring() call
|
|
164
|
+
// races with a transient BT permission / FGS-restriction failure.
|
|
165
|
+
if (retryCount < MAX_STARTFOREGROUND_RETRIES &&
|
|
166
|
+
(isMonitoringActive(this) || isCarPlayEnabled(this))) {
|
|
158
167
|
scheduleServiceRetry(retryCount + 1)
|
|
159
168
|
}
|
|
160
169
|
stopSelf()
|
|
@@ -1133,6 +1142,12 @@ class BeaconForegroundService : Service(), BeaconConsumer {
|
|
|
1133
1142
|
setCarPlayEnabled(context, true)
|
|
1134
1143
|
ensureNotificationChannel(context)
|
|
1135
1144
|
ensureCarPlayNotificationChannel(context)
|
|
1145
|
+
// Arm the WorkManager watchdog (15-min periodic safety net) and the
|
|
1146
|
+
// AlarmManager loop (~11-min cadence, above the OS quota). Both
|
|
1147
|
+
// call back into this same idempotent entry point if the service
|
|
1148
|
+
// is killed while CarPlay observation is enabled.
|
|
1149
|
+
CarPlayWatchdogWorker.schedule(context)
|
|
1150
|
+
BootReceiver.scheduleCarPlayWatchdogAlarm(context)
|
|
1136
1151
|
val intent = Intent(context, BeaconForegroundService::class.java)
|
|
1137
1152
|
.setAction(ACTION_ENABLE_CARPLAY)
|
|
1138
1153
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
|
@@ -1148,6 +1163,10 @@ class BeaconForegroundService : Service(), BeaconConsumer {
|
|
|
1148
1163
|
*/
|
|
1149
1164
|
fun disableCarPlay(context: Context) {
|
|
1150
1165
|
setCarPlayEnabled(context, false)
|
|
1166
|
+
// Stop the safety-net watchdogs — without this they would keep
|
|
1167
|
+
// restarting the service on every tick.
|
|
1168
|
+
CarPlayWatchdogWorker.cancel(context)
|
|
1169
|
+
BootReceiver.cancelCarPlayWatchdogAlarm(context)
|
|
1151
1170
|
// Wipe the monitor's persisted last-known connection so a future
|
|
1152
1171
|
// re-enable starts from a clean slate (no stale "was connected"
|
|
1153
1172
|
// assumption that would arm the bootstrap-grace re-check).
|
|
@@ -1211,6 +1230,46 @@ class BeaconForegroundService : Service(), BeaconConsumer {
|
|
|
1211
1230
|
return mapOf("connected" to connected)
|
|
1212
1231
|
}
|
|
1213
1232
|
|
|
1233
|
+
/**
|
|
1234
|
+
* Returns a diagnostic snapshot of the CarPlay / Android Auto detection
|
|
1235
|
+
* pipeline. Probes for the host-app AA registration meta-data and the
|
|
1236
|
+
* resolvability of the CarConnection content provider so callers can
|
|
1237
|
+
* tell from JS whether the underlying detection requirements are met.
|
|
1238
|
+
*/
|
|
1239
|
+
fun getCarPlayDiagnostics(context: Context): Map<String, Any?> {
|
|
1240
|
+
val pm = context.packageManager
|
|
1241
|
+
// 1) Is the host app declared as an Android-Auto-aware app?
|
|
1242
|
+
val metadataPresent = try {
|
|
1243
|
+
val ai = pm.getApplicationInfo(
|
|
1244
|
+
context.packageName,
|
|
1245
|
+
android.content.pm.PackageManager.GET_META_DATA,
|
|
1246
|
+
)
|
|
1247
|
+
ai.metaData?.containsKey("com.google.android.gms.car.application") == true
|
|
1248
|
+
} catch (_: Throwable) { false }
|
|
1249
|
+
|
|
1250
|
+
// 2) Can the system resolve any provider for the CAR_PROVIDER action?
|
|
1251
|
+
// This combines (a) <queries> visibility on API 30+, and (b) a
|
|
1252
|
+
// Gearhead / AAOS install that actually advertises the provider.
|
|
1253
|
+
val providerQueryable = try {
|
|
1254
|
+
val intent = Intent("androidx.car.app.connection.action.CAR_PROVIDER")
|
|
1255
|
+
val resolved = pm.queryIntentContentProviders(intent, 0)
|
|
1256
|
+
resolved.isNotEmpty()
|
|
1257
|
+
} catch (_: Throwable) { false }
|
|
1258
|
+
|
|
1259
|
+
val monitor = activeService?.carPlayMonitor
|
|
1260
|
+
val lastRaw: Int? = if (monitor != null && monitor.hasObservedValue) monitor.lastObservedType else null
|
|
1261
|
+
val observerActive = monitor?.isObserving() == true
|
|
1262
|
+
val serviceAlive = activeService != null
|
|
1263
|
+
|
|
1264
|
+
return mapOf(
|
|
1265
|
+
"isCarAppMetadataPresent" to metadataPresent,
|
|
1266
|
+
"isCarProviderQueryable" to providerQueryable,
|
|
1267
|
+
"lastRawConnectionType" to lastRaw,
|
|
1268
|
+
"observerActive" to observerActive,
|
|
1269
|
+
"serviceAlive" to serviceAlive,
|
|
1270
|
+
)
|
|
1271
|
+
}
|
|
1272
|
+
|
|
1214
1273
|
/**
|
|
1215
1274
|
* Ensure the notification channel exists. Must be called before building
|
|
1216
1275
|
* a notification from a non-service context (e.g. ExpoBeaconModule).
|
|
@@ -11,8 +11,24 @@ import android.os.SystemClock
|
|
|
11
11
|
import android.util.Log
|
|
12
12
|
|
|
13
13
|
private const val ACTION_RETRY_MONITORING = "expo.modules.beacon.ACTION_RETRY_MONITORING"
|
|
14
|
+
/**
|
|
15
|
+
* Periodic self-rescheduling watchdog action handled by [BootReceiver].
|
|
16
|
+
* Public on the manifest so the AlarmManager can route back to us after the
|
|
17
|
+
* process has been killed.
|
|
18
|
+
*/
|
|
19
|
+
internal const val ACTION_CARPLAY_WATCHDOG = "expo.modules.beacon.ACTION_CARPLAY_WATCHDOG"
|
|
14
20
|
private const val RETRY_DELAY_MS = 10_000L
|
|
15
21
|
private const val RETRY_REQUEST_CODE = 0x424F4F54 // "BOOT"
|
|
22
|
+
private const val CARPLAY_WATCHDOG_REQUEST_CODE = 0x43504C57 // "CPLW"
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Cadence for the AlarmManager-based CarPlay watchdog. Set to **11 minutes**
|
|
26
|
+
* so we stay safely above Android's per-app rate limit on
|
|
27
|
+
* `setExactAndAllowWhileIdle()` (~10 minutes on API 23+, tightened again on
|
|
28
|
+
* API 31+). Going lower risks silent coalescing or dropping by the framework.
|
|
29
|
+
* This still beats WorkManager's 15-minute periodic floor.
|
|
30
|
+
*/
|
|
31
|
+
private const val CARPLAY_WATCHDOG_INTERVAL_MS = 11L * 60L * 1000L
|
|
16
32
|
|
|
17
33
|
/**
|
|
18
34
|
* Restarts beacon monitoring after device reboot if it was active before shutdown.
|
|
@@ -25,13 +41,19 @@ private const val RETRY_REQUEST_CODE = 0x424F4F54 // "BOOT"
|
|
|
25
41
|
class BootReceiver : BroadcastReceiver() {
|
|
26
42
|
override fun onReceive(context: Context, intent: Intent) {
|
|
27
43
|
when (intent.action) {
|
|
28
|
-
Intent.ACTION_BOOT_COMPLETED
|
|
44
|
+
Intent.ACTION_BOOT_COMPLETED,
|
|
45
|
+
Intent.ACTION_LOCKED_BOOT_COMPLETED,
|
|
46
|
+
Intent.ACTION_MY_PACKAGE_REPLACED -> {
|
|
29
47
|
logMemoryKillDiagnostics(context)
|
|
30
48
|
if (BeaconForegroundService.isMonitoringActive(context)) {
|
|
31
49
|
tryStartService(context)
|
|
32
|
-
}
|
|
33
|
-
|
|
50
|
+
}
|
|
51
|
+
if (BeaconForegroundService.isCarPlayEnabled(context)) {
|
|
52
|
+
// CarPlay observation: re-attach the observer so it survives
|
|
53
|
+
// reboot / app update / direct-boot, and arm the
|
|
54
|
+
// self-rescheduling alarm loop.
|
|
34
55
|
tryEnableCarPlay(context)
|
|
56
|
+
scheduleCarPlayWatchdogAlarm(context)
|
|
35
57
|
}
|
|
36
58
|
}
|
|
37
59
|
ACTION_RETRY_MONITORING -> {
|
|
@@ -41,6 +63,18 @@ class BootReceiver : BroadcastReceiver() {
|
|
|
41
63
|
tryEnableCarPlay(context)
|
|
42
64
|
}
|
|
43
65
|
}
|
|
66
|
+
ACTION_CARPLAY_WATCHDOG -> {
|
|
67
|
+
if (!BeaconForegroundService.isCarPlayEnabled(context)) {
|
|
68
|
+
// CarPlay was disabled since the alarm was set — let the
|
|
69
|
+
// chain die. cancelCarPlayWatchdogAlarm() is also called
|
|
70
|
+
// from disableCarPlay(), this is just defence-in-depth.
|
|
71
|
+
Log.d(TAG, "BootReceiver: watchdog tick skipped (CarPlay disabled)")
|
|
72
|
+
return
|
|
73
|
+
}
|
|
74
|
+
tryEnableCarPlay(context)
|
|
75
|
+
// Reschedule the next tick. setExactAndAllowWhileIdle is one-shot.
|
|
76
|
+
scheduleCarPlayWatchdogAlarm(context)
|
|
77
|
+
}
|
|
44
78
|
}
|
|
45
79
|
}
|
|
46
80
|
|
|
@@ -102,4 +136,69 @@ class BootReceiver : BroadcastReceiver() {
|
|
|
102
136
|
}
|
|
103
137
|
}
|
|
104
138
|
}
|
|
139
|
+
|
|
140
|
+
companion object {
|
|
141
|
+
/**
|
|
142
|
+
* Arm (or re-arm) the AlarmManager-based CarPlay watchdog. One-shot
|
|
143
|
+
* alarm using `setExactAndAllowWhileIdle` — the receiver re-schedules
|
|
144
|
+
* itself on each fire as long as CarPlay observation remains enabled.
|
|
145
|
+
*
|
|
146
|
+
* Cadence is governed by [CARPLAY_WATCHDOG_INTERVAL_MS], deliberately
|
|
147
|
+
* above the per-app exact-alarm quota.
|
|
148
|
+
*
|
|
149
|
+
* Safe to call from any context; idempotent thanks to
|
|
150
|
+
* `FLAG_UPDATE_CURRENT` on the PendingIntent.
|
|
151
|
+
*/
|
|
152
|
+
@JvmStatic
|
|
153
|
+
fun scheduleCarPlayWatchdogAlarm(context: Context) {
|
|
154
|
+
val alarmManager = context.getSystemService(AlarmManager::class.java) ?: return
|
|
155
|
+
val intent = Intent(context, BootReceiver::class.java).apply {
|
|
156
|
+
action = ACTION_CARPLAY_WATCHDOG
|
|
157
|
+
// Explicit package so the implicit-broadcast restriction on
|
|
158
|
+
// Android 8+ doesn't drop the delivery.
|
|
159
|
+
`package` = context.packageName
|
|
160
|
+
}
|
|
161
|
+
val pendingIntent = PendingIntent.getBroadcast(
|
|
162
|
+
context,
|
|
163
|
+
CARPLAY_WATCHDOG_REQUEST_CODE,
|
|
164
|
+
intent,
|
|
165
|
+
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE,
|
|
166
|
+
)
|
|
167
|
+
try {
|
|
168
|
+
alarmManager.setExactAndAllowWhileIdle(
|
|
169
|
+
AlarmManager.ELAPSED_REALTIME_WAKEUP,
|
|
170
|
+
SystemClock.elapsedRealtime() + CARPLAY_WATCHDOG_INTERVAL_MS,
|
|
171
|
+
pendingIntent,
|
|
172
|
+
)
|
|
173
|
+
Log.d(TAG, "BootReceiver: CarPlay watchdog alarm armed (${CARPLAY_WATCHDOG_INTERVAL_MS}ms)")
|
|
174
|
+
} catch (t: Throwable) {
|
|
175
|
+
// Defensive: setExactAndAllowWhileIdle can throw SecurityException on
|
|
176
|
+
// some configurations even though it doesn't strictly require
|
|
177
|
+
// SCHEDULE_EXACT_ALARM. Fall back is the WorkManager 15-min job.
|
|
178
|
+
Log.w(TAG, "BootReceiver: failed to arm CarPlay watchdog alarm", t)
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/** Cancel the periodic CarPlay watchdog alarm. */
|
|
183
|
+
@JvmStatic
|
|
184
|
+
fun cancelCarPlayWatchdogAlarm(context: Context) {
|
|
185
|
+
val alarmManager = context.getSystemService(AlarmManager::class.java) ?: return
|
|
186
|
+
val intent = Intent(context, BootReceiver::class.java).apply {
|
|
187
|
+
action = ACTION_CARPLAY_WATCHDOG
|
|
188
|
+
`package` = context.packageName
|
|
189
|
+
}
|
|
190
|
+
val pendingIntent = PendingIntent.getBroadcast(
|
|
191
|
+
context,
|
|
192
|
+
CARPLAY_WATCHDOG_REQUEST_CODE,
|
|
193
|
+
intent,
|
|
194
|
+
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE,
|
|
195
|
+
)
|
|
196
|
+
try {
|
|
197
|
+
alarmManager.cancel(pendingIntent)
|
|
198
|
+
Log.d(TAG, "BootReceiver: CarPlay watchdog alarm cancelled")
|
|
199
|
+
} catch (t: Throwable) {
|
|
200
|
+
Log.w(TAG, "BootReceiver: failed to cancel CarPlay watchdog alarm", t)
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
}
|
|
105
204
|
}
|
|
@@ -47,7 +47,18 @@ internal class CarPlayMonitor(private val context: Context) {
|
|
|
47
47
|
*/
|
|
48
48
|
private var pendingDisconnectCheck: Runnable? = null
|
|
49
49
|
/** Most recent raw type seen from the LiveData; used by the grace re-check. */
|
|
50
|
-
@Volatile
|
|
50
|
+
@Volatile internal var lastObservedType: Int = CarConnection.CONNECTION_TYPE_NOT_CONNECTED
|
|
51
|
+
private set
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Whether the observer has ever received a value from the LiveData since
|
|
55
|
+
* [start] was called. Useful for diagnostics — if this is `false` 5+
|
|
56
|
+
* seconds after `start()`, the `CarConnection` content provider isn't
|
|
57
|
+
* resolving (most commonly because the host app isn't registered as an
|
|
58
|
+
* Android Auto app via `automotive_app_desc.xml`).
|
|
59
|
+
*/
|
|
60
|
+
@Volatile internal var hasObservedValue: Boolean = false
|
|
61
|
+
private set
|
|
51
62
|
|
|
52
63
|
/**
|
|
53
64
|
* Begin observing connection state. Idempotent — calling twice replaces the
|
|
@@ -68,7 +79,23 @@ internal class CarPlayMonitor(private val context: Context) {
|
|
|
68
79
|
observer = obs
|
|
69
80
|
try {
|
|
70
81
|
liveData.observeForever(obs)
|
|
71
|
-
Log.d(TAG, "CarPlay monitoring started (seeded lastConnected=$lastConnected)")
|
|
82
|
+
Log.d(TAG, "CarPlay monitoring started (seeded lastConnected=$lastConnected, lib=androidx.car.app)")
|
|
83
|
+
// Diagnostic safety-net: if no value arrives within
|
|
84
|
+
// [DIAGNOSTIC_PROBE_MS], emit a loud warning. The most
|
|
85
|
+
// common cause is a missing `com.google.android.gms.car.application`
|
|
86
|
+
// meta-data entry in the host app's manifest — Gearhead
|
|
87
|
+
// then silently returns NOT_CONNECTED and the LiveData
|
|
88
|
+
// never updates beyond the bootstrap value.
|
|
89
|
+
mainHandler.postDelayed({
|
|
90
|
+
if (!hasObservedValue) {
|
|
91
|
+
Log.w(TAG, "CarPlay diagnostic: no CarConnection value received after ${DIAGNOSTIC_PROBE_MS}ms. " +
|
|
92
|
+
"Host app is likely missing the AndroidAuto registration meta-data " +
|
|
93
|
+
"(<meta-data android:name=\"com.google.android.gms.car.application\" android:resource=\"@xml/automotive_app_desc\"/>). " +
|
|
94
|
+
"Enable the expo-beacon plugin's `android.androidAuto.register` option (default in 0.9+) and re-run `expo prebuild`.")
|
|
95
|
+
} else {
|
|
96
|
+
Log.d(TAG, "CarPlay diagnostic: lastObservedType=$lastObservedType after ${DIAGNOSTIC_PROBE_MS}ms (OK)")
|
|
97
|
+
}
|
|
98
|
+
}, DIAGNOSTIC_PROBE_MS)
|
|
72
99
|
} catch (e: Exception) {
|
|
73
100
|
Log.w(TAG, "Failed to start CarPlay monitoring: ${e.message}")
|
|
74
101
|
}
|
|
@@ -122,6 +149,7 @@ internal class CarPlayMonitor(private val context: Context) {
|
|
|
122
149
|
|
|
123
150
|
private fun handleType(type: Int) {
|
|
124
151
|
lastObservedType = type
|
|
152
|
+
hasObservedValue = true
|
|
125
153
|
val connected = type != CarConnection.CONNECTION_TYPE_NOT_CONNECTED
|
|
126
154
|
val previous = lastConnected
|
|
127
155
|
|
|
@@ -248,6 +276,13 @@ internal class CarPlayMonitor(private val context: Context) {
|
|
|
248
276
|
* (e.g. after the app is swiped away and START_STICKY revives us).
|
|
249
277
|
*/
|
|
250
278
|
private const val BOOTSTRAP_GRACE_MS = 3_000L
|
|
279
|
+
/**
|
|
280
|
+
* Delay after which [start] emits a loud diagnostic log if the
|
|
281
|
+
* LiveData has not delivered a single value. 5 s comfortably covers
|
|
282
|
+
* the cold-start content-provider resolution path even on slow
|
|
283
|
+
* devices.
|
|
284
|
+
*/
|
|
285
|
+
private const val DIAGNOSTIC_PROBE_MS = 5_000L
|
|
251
286
|
// ISO 8601 UTC with millisecond precision. Safe for all supported APIs (minSdk 23).
|
|
252
287
|
private val ISO_FORMAT = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", Locale.US).apply {
|
|
253
288
|
timeZone = TimeZone.getTimeZone("UTC")
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
package expo.modules.beacon
|
|
2
|
+
|
|
3
|
+
import android.content.Context
|
|
4
|
+
import android.util.Log
|
|
5
|
+
import androidx.work.ExistingPeriodicWorkPolicy
|
|
6
|
+
import androidx.work.PeriodicWorkRequestBuilder
|
|
7
|
+
import androidx.work.WorkManager
|
|
8
|
+
import androidx.work.Worker
|
|
9
|
+
import androidx.work.WorkerParameters
|
|
10
|
+
import java.util.concurrent.TimeUnit
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Periodic safety-net that re-arms the [BeaconForegroundService] whenever
|
|
14
|
+
* CarPlay observation is enabled but the service has been killed (low memory,
|
|
15
|
+
* OEM cleaners, etc.).
|
|
16
|
+
*
|
|
17
|
+
* [BeaconForegroundService.enableCarPlay] is idempotent: if the service is
|
|
18
|
+
* alive this is a cheap no-op; if it is dead it cold-starts a fresh
|
|
19
|
+
* foreground instance and re-attaches [CarPlayMonitor].
|
|
20
|
+
*
|
|
21
|
+
* WorkManager guarantees a minimum 15-minute period. A second AlarmManager
|
|
22
|
+
* loop in [BootReceiver] covers the sub-15-min gap AND — critically on
|
|
23
|
+
* API 31+ — is the path the OS allows to call startForegroundService from
|
|
24
|
+
* background: broadcast receivers running an exact-alarm trigger are granted
|
|
25
|
+
* the brief foreground-importance window required. If enableCarPlay throws
|
|
26
|
+
* here from a background worker (ForegroundServiceStartNotAllowedException),
|
|
27
|
+
* the next alarm tick will recover.
|
|
28
|
+
*/
|
|
29
|
+
internal class CarPlayWatchdogWorker(
|
|
30
|
+
appContext: Context,
|
|
31
|
+
params: WorkerParameters,
|
|
32
|
+
) : Worker(appContext, params) {
|
|
33
|
+
|
|
34
|
+
override fun doWork(): Result {
|
|
35
|
+
val ctx = applicationContext
|
|
36
|
+
if (!BeaconForegroundService.isCarPlayEnabled(ctx)) {
|
|
37
|
+
Log.d(TAG, "Watchdog tick: CarPlay disabled, no action")
|
|
38
|
+
return Result.success()
|
|
39
|
+
}
|
|
40
|
+
try {
|
|
41
|
+
BeaconForegroundService.enableCarPlay(ctx)
|
|
42
|
+
Log.d(TAG, "Watchdog tick: ensured BeaconForegroundService is running for CarPlay")
|
|
43
|
+
} catch (t: Throwable) {
|
|
44
|
+
// Expected on API 31+ when the worker runs while the app is fully
|
|
45
|
+
// backgrounded — startForegroundService is blocked. The AlarmManager
|
|
46
|
+
// loop in BootReceiver runs in a receiver context and IS permitted
|
|
47
|
+
// to make the same call, so recovery still happens within ~11 min.
|
|
48
|
+
Log.d(
|
|
49
|
+
TAG,
|
|
50
|
+
"Watchdog tick: enableCarPlay deferred to alarm loop (${t.javaClass.simpleName}): ${t.message}",
|
|
51
|
+
)
|
|
52
|
+
}
|
|
53
|
+
// Always success — don't burn WorkManager's retry budget on a known
|
|
54
|
+
// OS-level background restriction.
|
|
55
|
+
return Result.success()
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
companion object {
|
|
59
|
+
private const val TAG = "CarPlayWatchdog"
|
|
60
|
+
private const val WORK_NAME = "expo-beacon-carplay-watchdog"
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Schedule the periodic watchdog. Idempotent — [ExistingPeriodicWorkPolicy.KEEP]
|
|
64
|
+
* preserves the existing schedule across calls so we don't reset the
|
|
65
|
+
* next-run timer every time the user re-enables CarPlay.
|
|
66
|
+
*/
|
|
67
|
+
@JvmStatic
|
|
68
|
+
fun schedule(context: Context) {
|
|
69
|
+
try {
|
|
70
|
+
val request = PeriodicWorkRequestBuilder<CarPlayWatchdogWorker>(
|
|
71
|
+
15, TimeUnit.MINUTES,
|
|
72
|
+
).addTag(WORK_NAME).build()
|
|
73
|
+
WorkManager.getInstance(context.applicationContext)
|
|
74
|
+
.enqueueUniquePeriodicWork(
|
|
75
|
+
WORK_NAME,
|
|
76
|
+
ExistingPeriodicWorkPolicy.KEEP,
|
|
77
|
+
request,
|
|
78
|
+
)
|
|
79
|
+
Log.d(TAG, "Watchdog scheduled (15 min period)")
|
|
80
|
+
} catch (t: Throwable) {
|
|
81
|
+
Log.w(TAG, "Failed to schedule CarPlay watchdog", t)
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/** Cancel the periodic watchdog. Safe to call when not scheduled. */
|
|
86
|
+
@JvmStatic
|
|
87
|
+
fun cancel(context: Context) {
|
|
88
|
+
try {
|
|
89
|
+
WorkManager.getInstance(context.applicationContext)
|
|
90
|
+
.cancelUniqueWork(WORK_NAME)
|
|
91
|
+
Log.d(TAG, "Watchdog cancelled")
|
|
92
|
+
} catch (t: Throwable) {
|
|
93
|
+
Log.w(TAG, "Failed to cancel CarPlay watchdog", t)
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
@@ -611,6 +611,20 @@ class ExpoBeaconModule : Module(), BeaconConsumer {
|
|
|
611
611
|
BeaconForegroundService.getCarPlayStatus(ctx)
|
|
612
612
|
}
|
|
613
613
|
|
|
614
|
+
Function("getCarPlayDiagnostics") {
|
|
615
|
+
val ctx = appContext.reactContext
|
|
616
|
+
if (ctx == null) {
|
|
617
|
+
return@Function mapOf(
|
|
618
|
+
"isCarAppMetadataPresent" to false,
|
|
619
|
+
"isCarProviderQueryable" to false,
|
|
620
|
+
"lastRawConnectionType" to null,
|
|
621
|
+
"observerActive" to false,
|
|
622
|
+
"serviceAlive" to false,
|
|
623
|
+
)
|
|
624
|
+
}
|
|
625
|
+
BeaconForegroundService.getCarPlayDiagnostics(ctx)
|
|
626
|
+
}
|
|
627
|
+
|
|
614
628
|
OnCreate {
|
|
615
629
|
// Register this module instance for best-effort JS-bridge fan-out
|
|
616
630
|
// of CarPlay events emitted by the foreground service. The service
|
|
@@ -333,6 +333,61 @@ export type CarPlayConnectionStatus = {
|
|
|
333
333
|
/** ISO 8601 UTC timestamp of last connect. Present only when `connected` is `true`. */
|
|
334
334
|
timestampIso?: string;
|
|
335
335
|
};
|
|
336
|
+
/**
|
|
337
|
+
* Diagnostic snapshot for troubleshooting CarPlay / Android Auto detection.
|
|
338
|
+
* Returned by {@link ExpoBeaconModule.getCarPlayDiagnostics}.
|
|
339
|
+
*
|
|
340
|
+
* The most common failure mode on Android is that the host app is not
|
|
341
|
+
* registered as an Android Auto-aware app (missing
|
|
342
|
+
* `com.google.android.gms.car.application` meta-data + `automotive_app_desc.xml`
|
|
343
|
+
* resource). When that happens, Gearhead silently reports
|
|
344
|
+
* `CONNECTION_TYPE_NOT_CONNECTED` to the app regardless of `<queries>`
|
|
345
|
+
* declarations, so `onCarPlayConnected` events never fire.
|
|
346
|
+
*
|
|
347
|
+
* Inspect this object after calling `startCarPlayMonitoring()` and confirming
|
|
348
|
+
* Android Auto is connected on the head unit. If `isCarAppMetadataPresent` or
|
|
349
|
+
* `isCarProviderQueryable` is `false`, the consumer app needs to enable the
|
|
350
|
+
* config plugin's `android.androidAuto.register` option (default in recent
|
|
351
|
+
* versions) and re-run `expo prebuild`.
|
|
352
|
+
*
|
|
353
|
+
* On iOS the diagnostic is a best-effort stub — most fields are not applicable
|
|
354
|
+
* because CarPlay detection uses `AVAudioSession` rather than a content
|
|
355
|
+
* provider.
|
|
356
|
+
*/
|
|
357
|
+
export type CarPlayDiagnostics = {
|
|
358
|
+
/**
|
|
359
|
+
* Android: `true` if the host app's manifest declares the
|
|
360
|
+
* `com.google.android.gms.car.application` meta-data tag (required for
|
|
361
|
+
* Gearhead to expose connection state to the app). iOS: always `true`.
|
|
362
|
+
*/
|
|
363
|
+
isCarAppMetadataPresent: boolean;
|
|
364
|
+
/**
|
|
365
|
+
* Android: `true` if the system can resolve at least one provider for the
|
|
366
|
+
* `androidx.car.app.connection.action.CAR_PROVIDER` intent (requires the
|
|
367
|
+
* `<queries>` declaration shipped by this library AND a compatible Gearhead
|
|
368
|
+
* / AAOS install on the device). iOS: always `true`.
|
|
369
|
+
*/
|
|
370
|
+
isCarProviderQueryable: boolean;
|
|
371
|
+
/**
|
|
372
|
+
* Android: most recent raw value read from `CarConnection.getType()`.
|
|
373
|
+
* `0` = `NOT_CONNECTED`, `1` = `NATIVE` (AAOS), `2` = `PROJECTION`.
|
|
374
|
+
* `null` if the observer has not yet received any value (or is not running).
|
|
375
|
+
* iOS: `null`.
|
|
376
|
+
*/
|
|
377
|
+
lastRawConnectionType: number | null;
|
|
378
|
+
/**
|
|
379
|
+
* `true` if the underlying connection observer is currently active.
|
|
380
|
+
* On Android, equivalent to "the foreground service is running AND
|
|
381
|
+
* `CarPlayMonitor.start()` succeeded". On iOS, the audio-session observer
|
|
382
|
+
* is registered.
|
|
383
|
+
*/
|
|
384
|
+
observerActive: boolean;
|
|
385
|
+
/**
|
|
386
|
+
* Android: `true` if the foreground service hosting the observer is alive.
|
|
387
|
+
* iOS: always `true` (no background service involved).
|
|
388
|
+
*/
|
|
389
|
+
serviceAlive: boolean;
|
|
390
|
+
};
|
|
336
391
|
/** Payload for native beacon error events (monitoring/ranging failures). */
|
|
337
392
|
export type BeaconErrorEvent = {
|
|
338
393
|
/** Region or constraint identifier, empty string if unavailable. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ExpoBeacon.types.d.ts","sourceRoot":"","sources":["../src/ExpoBeacon.types.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ExpoBeacon.types.d.ts","sourceRoot":"","sources":["../src/ExpoBeacon.types.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ExpoBeacon.types.js","sourceRoot":"","sources":["../src/ExpoBeacon.types.ts"],"names":[],"mappings":"","sourcesContent":["/** Raw beacon discovered during a scan. */\r\nexport type BeaconScanResult = {\r\n uuid: string; // iBeacon proximity UUID (uppercase, formatted)\r\n major: number; // iBeacon major value (0–65535)\r\n minor: number; // iBeacon minor value (0–65535)\r\n rssi: number; // Signal strength in dBm (negative number)\r\n distance: number; // Estimated distance in meters\r\n txPower: number; // Calibrated TX power\r\n /** BLE advertising device name. May be undefined on iOS (CoreLocation does not expose it for iBeacon). */\r\n name?: string;\r\n};\r\n\r\n/**\r\n * A beacon that has been paired/registered for monitoring.\r\n *\r\n * Note: Paired beacon data is stored unencrypted in UserDefaults (iOS) /\r\n * SharedPreferences (Android) and may be included in device backups.\r\n */\r\nexport type PairedBeacon = {\r\n identifier: string; // User-defined label (e.g. \"lobby-door\")\r\n uuid: string;\r\n major: number;\r\n minor: number;\r\n /** BLE advertising device name, if provided at pairing time. */\r\n name?: string;\r\n /**\r\n * Timeout in seconds. When set, the module fires `onBeaconTimeout` once\r\n * after the beacon has been continuously in range for this duration.\r\n * The timer resets if the beacon exits and re-enters range.\r\n *\r\n * The timeout countdown also starts if no BLE readings are received\r\n * for 60 seconds (e.g. due to Doze mode or background throttling).\r\n */\r\n timeoutSeconds?: number;\r\n};\r\n\r\n/** Payload for enter/exit region events. */\r\nexport type BeaconRegionEvent = {\r\n identifier: string; // Matches PairedBeacon.identifier\r\n uuid: string;\r\n major: number;\r\n minor: number;\r\n event: \"enter\" | \"exit\";\r\n /** Measured distance in metres at the time of the event (–1 if unavailable). */\r\n distance: number;\r\n /** Signal strength in dBm at the time of the event (0 if unavailable). */\r\n rssi?: number;\r\n};\r\n\r\n/** Payload for periodic distance update events during monitoring. */\r\nexport type BeaconDistanceEvent = {\r\n identifier: string;\r\n uuid: string;\r\n major: number;\r\n minor: number;\r\n distance: number;\r\n /** Signal strength in dBm (0 if unavailable). */\r\n rssi?: number;\r\n};\r\n\r\n/** Payload for beacon timeout events (beacon in range for configured duration). */\r\nexport type BeaconTimeoutEvent = {\r\n identifier: string;\r\n uuid: string;\r\n major: number;\r\n minor: number;\r\n /** Current distance in metres at the time the timeout fired. */\r\n distance: number;\r\n};\r\n\r\n/** Configuration for beacon enter/exit event notifications. */\r\nexport type BeaconNotificationConfig = {\r\n /** Whether to show enter/exit notifications. Default: true. */\r\n enabled?: boolean;\r\n /** Notification title on beacon enter. Default: \"Beacon Entered\". */\r\n enterTitle?: string;\r\n /** Notification title on beacon exit. Default: \"Beacon Exited\". */\r\n exitTitle?: string;\r\n /** Notification title on beacon timeout. Default: \"Beacon Timeout\". */\r\n timeoutTitle?: string;\r\n /**\r\n * Notification body template. Supports {identifier} and {event} placeholders.\r\n * Default: \"{identifier} region {event}ed\".\r\n */\r\n body?: string;\r\n /** Play a sound with the notification (iOS only). Default: true. */\r\n sound?: boolean;\r\n /** Android drawable resource name for the notification icon (e.g. \"ic_notification\"). */\r\n icon?: string;\r\n};\r\n\r\n/** Configuration for the Android foreground service notification (persistent status bar entry). */\r\nexport type ForegroundServiceConfig = {\r\n /** Title of the persistent notification. Default: \"Beacon Monitoring Active\". */\r\n title?: string;\r\n /** Body text of the persistent notification. Default: \"Monitoring for iBeacons in the background\". */\r\n text?: string;\r\n /** Android drawable resource name for the notification icon. */\r\n icon?: string;\r\n};\r\n\r\n/** Configuration for the Android notification channel. */\r\nexport type NotificationChannelConfig = {\r\n /** Channel display name shown in system settings. Default: \"Beacon Monitoring\". */\r\n name?: string;\r\n /** Channel description shown in system settings. Default: \"Used for background iBeacon region monitoring\". */\r\n description?: string;\r\n /**\r\n * Channel importance level. Default: 'low'.\r\n * Note: Android may ignore decreases in importance after first channel creation until the app is reinstalled.\r\n */\r\n importance?: \"low\" | \"default\" | \"high\";\r\n};\r\n\r\n/** Configuration for CarPlay / Android Auto connect/disconnect notifications. */\r\nexport type CarPlayNotificationConfig = {\r\n /** Whether to show CarPlay connect/disconnect notifications. Default: true. */\r\n enabled?: boolean;\r\n /** Notification title on CarPlay/Android Auto connect. Default: \"CarPlay Connected\". */\r\n connectedTitle?: string;\r\n /** Notification title on CarPlay/Android Auto disconnect. Default: \"CarPlay Disconnected\". */\r\n disconnectedTitle?: string;\r\n /**\r\n * Notification body template. Supports `{event}` (\"connected\"/\"disconnected\") and\r\n * `{transport}` (e.g. \"wired\", \"wireless\", \"projection\", \"native\", \"unknown\") placeholders.\r\n * Note: `{transport}` is only meaningful for connect events; on disconnect it is replaced with an empty string.\r\n * Default: \"CarPlay session {event}\".\r\n */\r\n body?: string;\r\n /** Play a sound with the notification (iOS only). Default: true. */\r\n sound?: boolean;\r\n /** Android drawable resource name for the notification icon (e.g. \"ic_notification\"). */\r\n icon?: string;\r\n};\r\n\r\n/** Configuration for the Android notification channel used for CarPlay events. */\r\nexport type CarPlayChannelConfig = {\r\n /** Channel display name shown in system settings. Default: \"CarPlay / Android Auto\". */\r\n name?: string;\r\n /** Channel description shown in system settings. Default: \"CarPlay and Android Auto connect/disconnect notifications\". */\r\n description?: string;\r\n /**\r\n * Channel importance level. Default: 'default' (so connect/disconnect events make a sound).\r\n * Note: Android may ignore decreases in importance after first channel creation until the app is reinstalled.\r\n */\r\n importance?: \"low\" | \"default\" | \"high\";\r\n};\r\n\r\n/** Combined notification configuration for all notification types. */\r\nexport type NotificationConfig = {\r\n /** Settings for beacon enter/exit event notifications. */\r\n beaconEvents?: BeaconNotificationConfig;\r\n /** Settings for CarPlay / Android Auto connect/disconnect notifications. */\r\n carPlayEvents?: CarPlayNotificationConfig;\r\n /** Settings for the persistent foreground service notification (Android only). */\r\n foregroundService?: ForegroundServiceConfig;\r\n /** Settings for the Android notification channel (Android only). */\r\n channel?: NotificationChannelConfig;\r\n /** Settings for the Android notification channel used for CarPlay events (Android only). */\r\n carPlayChannel?: CarPlayChannelConfig;\r\n};\r\n\r\n/** Snapshot of the current monitoring configuration and active state. */\r\nexport type MonitoringConfig = {\r\n /** Whether background monitoring is currently active. */\r\n isMonitoring: boolean;\r\n maxDistance?: number;\r\n exitDistance?: number;\r\n minRssi?: number;\r\n level?: 'all' | 'events';\r\n /** Seconds after last beacon sighting before an exit event fires. Default: 300. */\r\n exitTimeoutSeconds?: number;\r\n notifications?: NotificationConfig;\r\n};\r\n\r\n/** Current state snapshot for a paired monitored device. */\r\nexport type MonitoredDeviceState =\r\n | {\r\n kind: \"ibeacon\";\r\n identifier: string;\r\n uuid: string;\r\n major: number;\r\n minor: number;\r\n state: \"entered\" | \"exited\";\r\n /** Current distance in metres, or null when exited or no live reading is available. */\r\n distance: number | null;\r\n }\r\n | {\r\n kind: \"eddystone\";\r\n identifier: string;\r\n namespace: string;\r\n instance: string;\r\n state: \"entered\" | \"exited\";\r\n /** Current distance in metres, or null when exited or no live reading is available. */\r\n distance: number | null;\r\n };\r\n\r\n/** Options accepted by startMonitoring(). */\r\nexport type MonitoringOptions = {\r\n /**\r\n * Maximum distance in metres for distance-based enter events.\r\n * Exit events are always emitted when the region is lost.\r\n */\r\n maxDistance?: number;\r\n /**\r\n * Distance in metres at which exit events fire (must be ≥ maxDistance).\r\n * Creates a hysteresis band between enter and exit thresholds to prevent\r\n * rapid toggling near the boundary.\r\n *\r\n * Default when omitted: `maxDistance + min(maxDistance × 0.5, 2.5)`.\r\n * Only used when `maxDistance` is set.\r\n */\r\n exitDistance?: number;\r\n /**\r\n * Minimum RSSI (dBm) for a beacon reading to be considered valid.\r\n * Readings below this threshold are discarded as unreliable, preventing\r\n * false detections from reflected or distant signals.\r\n *\r\n * Default: -85. Typical range: -100 (very permissive) to -70 (strict).\r\n */\r\n minRssi?: number;\r\n /**\r\n * Controls which event types are emitted, logged, and forwarded to the API.\r\n *\r\n * - `'all'` (default): distance + enter + exit + timeout events.\r\n * - `'events'`: enter + exit + timeout only (no distance events).\r\n */\r\n level?: 'all' | 'events';\r\n /**\r\n * Seconds after last beacon sighting before an exit event fires when the beacon\r\n * disappears without moving outside the exit distance threshold.\r\n *\r\n * Default: 300 (5 minutes). Minimum: 1.\r\n */\r\n exitTimeoutSeconds?: number;\r\n /** Notification configuration overrides to apply for this monitoring session. */\r\n notifications?: NotificationConfig;\r\n};\r\n\r\n/** Eddystone frame type. */\r\nexport type EddystoneFrameType = \"uid\" | \"url\";\r\n\r\n/** Raw Eddystone beacon discovered during a scan. */\r\nexport type EddystoneScanResult = {\r\n frameType: EddystoneFrameType;\r\n /** 10-byte namespace ID as hex string (20 chars). Present for UID frames. */\r\n namespace?: string;\r\n /** 6-byte instance ID as hex string (12 chars). Present for UID frames. */\r\n instance?: string;\r\n /** Decoded URL. Present for URL frames. */\r\n url?: string;\r\n rssi: number;\r\n distance: number;\r\n txPower: number;\r\n /** BLE advertising device name. */\r\n name?: string;\r\n};\r\n\r\n/**\r\n * An Eddystone-UID beacon that has been paired/registered for monitoring.\r\n *\r\n * Note: Paired beacon data is stored unencrypted in UserDefaults (iOS) /\r\n * SharedPreferences (Android) and may be included in device backups.\r\n */\r\nexport type PairedEddystone = {\r\n identifier: string;\r\n /** 10-byte namespace ID as hex string (20 chars). */\r\n namespace: string;\r\n /** 6-byte instance ID as hex string (12 chars). */\r\n instance: string;\r\n /** BLE advertising device name, if provided at pairing time. */\r\n name?: string;\r\n /**\r\n * Timeout in seconds. When set, the module fires `onEddystoneTimeout` once\r\n * after the beacon has been continuously in range for this duration.\r\n * The timer resets if the beacon exits and re-enters range.\r\n *\r\n * The timeout countdown also starts if no BLE readings are received\r\n * for 60 seconds (e.g. due to Doze mode or background throttling).\r\n */\r\n timeoutSeconds?: number;\r\n};\r\n\r\n/** Payload for Eddystone enter/exit region events. */\r\nexport type EddystoneRegionEvent = {\r\n identifier: string;\r\n namespace: string;\r\n instance: string;\r\n event: \"enter\" | \"exit\";\r\n /** Measured distance in metres at the time of the event (–1 if unavailable). */\r\n distance: number;\r\n /** Signal strength in dBm at the time of the event (0 if unavailable). */\r\n rssi?: number;\r\n};\r\n\r\n/** Payload for periodic Eddystone distance update events during monitoring. */\r\nexport type EddystoneDistanceEvent = {\r\n identifier: string;\r\n namespace: string;\r\n instance: string;\r\n distance: number;\r\n /** Signal strength in dBm (0 if unavailable). */\r\n rssi?: number;\r\n};\r\n\r\n/** Payload for Eddystone timeout events (beacon in range for configured duration). */\r\nexport type EddystoneTimeoutEvent = {\r\n identifier: string;\r\n namespace: string;\r\n instance: string;\r\n /** Current distance in metres at the time the timeout fired. */\r\n distance: number;\r\n};\r\n\r\n/** Transport reported with CarPlay / Android Auto connection events. */\r\nexport type CarPlayTransport =\r\n | \"wired\" // iOS CarPlay over USB / Lightning\r\n | \"wireless\" // iOS CarPlay over Bluetooth + Wi-Fi\r\n | \"projection\" // Android Auto projection (phone projecting to head unit)\r\n | \"native\" // Android Automotive OS (running on the head unit)\r\n | \"unknown\";\r\n\r\n/** Payload fired when the device connects to a CarPlay or Android Auto session. */\r\nexport type CarPlayConnectedEvent = {\r\n transport: CarPlayTransport;\r\n /** Timestamp in milliseconds since epoch. */\r\n timestamp: number;\r\n /** ISO 8601 UTC representation of {@link timestamp} (e.g. \"2026-05-12T14:23:45.678Z\"). */\r\n timestampIso?: string;\r\n};\r\n\r\n/** Payload fired when the device disconnects from a CarPlay or Android Auto session. */\r\nexport type CarPlayDisconnectedEvent = {\r\n /** Timestamp in milliseconds since epoch. */\r\n timestamp: number;\r\n /** ISO 8601 UTC representation of {@link timestamp} (e.g. \"2026-05-12T14:23:45.678Z\"). */\r\n timestampIso?: string;\r\n /**\r\n * Reason this disconnect was emitted. Absent for normal real-time disconnects.\r\n * `\"reconciled\"` indicates the disconnect was synthesized after the module was\r\n * recreated in a new process and detected that the previously persisted CarPlay\r\n * state no longer matches the current connection — i.e. the disconnect happened\r\n * off-process (force-quit, OS reclaim, abrupt cable yank) and is being delivered\r\n * post-hoc. Emitted on both iOS and Android.\r\n */\r\n reason?: \"reconciled\";\r\n};\r\n\r\n/**\r\n * Snapshot of the current CarPlay / Android Auto connection state, returned by\r\n * {@link ExpoBeaconModule.getCarPlayConnectionStatus}.\r\n */\r\nexport type CarPlayConnectionStatus = {\r\n /** `true` if a CarPlay or Android Auto session is currently active. */\r\n connected: boolean;\r\n /**\r\n * Connection transport type. Present only when `connected` is `true`.\r\n * See {@link CarPlayTransport} for possible values.\r\n */\r\n transport?: CarPlayTransport;\r\n /** Unix-millisecond timestamp of last connect. Present only when `connected` is `true`. */\r\n timestamp?: number;\r\n /** ISO 8601 UTC timestamp of last connect. Present only when `connected` is `true`. */\r\n timestampIso?: string;\r\n};\r\n\r\n/** Payload for native beacon error events (monitoring/ranging failures). */\r\nexport type BeaconErrorEvent = {\r\n /** Region or constraint identifier, empty string if unavailable. */\r\n identifier: string;\r\n /** Machine-readable error code (e.g. \"MONITORING_FAILED\", \"RANGING_FAILED\", \"SECURITY_EXCEPTION\"). */\r\n code: string;\r\n /** Human-readable error message from the native layer. */\r\n message: string;\r\n};\r\n\r\n/** Module event map. */\r\nexport type ExpoBeaconModuleEvents = {\r\n onBeaconEnter: (params: BeaconRegionEvent) => void;\r\n onBeaconExit: (params: BeaconRegionEvent) => void;\r\n onBeaconDistance: (params: BeaconDistanceEvent) => void;\r\n /** Fired once after a paired beacon has been continuously in range for its configured `timeoutSeconds`. */\r\n onBeaconTimeout: (params: BeaconTimeoutEvent) => void;\r\n /** Fired continuously during a live scan as each iBeacon is detected. */\r\n onBeaconFound: (params: BeaconScanResult) => void;\r\n /** Fired continuously during a live scan as each Eddystone beacon is detected. */\r\n onEddystoneFound: (params: EddystoneScanResult) => void;\r\n onEddystoneEnter: (params: EddystoneRegionEvent) => void;\r\n onEddystoneExit: (params: EddystoneRegionEvent) => void;\r\n onEddystoneDistance: (params: EddystoneDistanceEvent) => void;\r\n /** Fired once after a paired Eddystone has been continuously in range for its configured `timeoutSeconds`. */\r\n onEddystoneTimeout: (params: EddystoneTimeoutEvent) => void;\r\n /** Fired when a native monitoring or ranging failure occurs (logged to DB and forwarded to JS). */\r\n onBeaconError: (params: BeaconErrorEvent) => void;\r\n /** Fired when the device connects to a CarPlay (iOS) or Android Auto (Android) session. */\r\n onCarPlayConnected: (params: CarPlayConnectedEvent) => void;\r\n /** Fired when the device disconnects from a CarPlay (iOS) or Android Auto (Android) session. */\r\n onCarPlayDisconnected: (params: CarPlayDisconnectedEvent) => void;\r\n};\r\n\r\n/** Options for filtering event logs. */\r\nexport type EventLogQueryOptions = {\r\n /** Maximum number of log entries to return (default: 1000, max: 10000). */\r\n limit?: number;\r\n /** Filter by event type (e.g. \"onBeaconEnter\", \"onBeaconExit\"). */\r\n eventType?: string;\r\n /** Only return events with timestamp >= this value (ms since epoch). */\r\n sinceTimestamp?: number;\r\n};\r\n\r\n/** A single logged beacon event entry. */\r\nexport type EventLogEntry = {\r\n id: number;\r\n /** Timestamp in milliseconds since epoch. */\r\n timestamp: number;\r\n /** The event type that was logged (e.g. \"onBeaconEnter\"). */\r\n eventType: string;\r\n /** Beacon identifier, if available. */\r\n identifier?: string;\r\n /** The full event payload that was sent to JS. */\r\n data: Record<string, unknown>;\r\n};\r\n"]}
|
|
1
|
+
{"version":3,"file":"ExpoBeacon.types.js","sourceRoot":"","sources":["../src/ExpoBeacon.types.ts"],"names":[],"mappings":"","sourcesContent":["/** Raw beacon discovered during a scan. */\r\nexport type BeaconScanResult = {\r\n uuid: string; // iBeacon proximity UUID (uppercase, formatted)\r\n major: number; // iBeacon major value (0–65535)\r\n minor: number; // iBeacon minor value (0–65535)\r\n rssi: number; // Signal strength in dBm (negative number)\r\n distance: number; // Estimated distance in meters\r\n txPower: number; // Calibrated TX power\r\n /** BLE advertising device name. May be undefined on iOS (CoreLocation does not expose it for iBeacon). */\r\n name?: string;\r\n};\r\n\r\n/**\r\n * A beacon that has been paired/registered for monitoring.\r\n *\r\n * Note: Paired beacon data is stored unencrypted in UserDefaults (iOS) /\r\n * SharedPreferences (Android) and may be included in device backups.\r\n */\r\nexport type PairedBeacon = {\r\n identifier: string; // User-defined label (e.g. \"lobby-door\")\r\n uuid: string;\r\n major: number;\r\n minor: number;\r\n /** BLE advertising device name, if provided at pairing time. */\r\n name?: string;\r\n /**\r\n * Timeout in seconds. When set, the module fires `onBeaconTimeout` once\r\n * after the beacon has been continuously in range for this duration.\r\n * The timer resets if the beacon exits and re-enters range.\r\n *\r\n * The timeout countdown also starts if no BLE readings are received\r\n * for 60 seconds (e.g. due to Doze mode or background throttling).\r\n */\r\n timeoutSeconds?: number;\r\n};\r\n\r\n/** Payload for enter/exit region events. */\r\nexport type BeaconRegionEvent = {\r\n identifier: string; // Matches PairedBeacon.identifier\r\n uuid: string;\r\n major: number;\r\n minor: number;\r\n event: \"enter\" | \"exit\";\r\n /** Measured distance in metres at the time of the event (–1 if unavailable). */\r\n distance: number;\r\n /** Signal strength in dBm at the time of the event (0 if unavailable). */\r\n rssi?: number;\r\n};\r\n\r\n/** Payload for periodic distance update events during monitoring. */\r\nexport type BeaconDistanceEvent = {\r\n identifier: string;\r\n uuid: string;\r\n major: number;\r\n minor: number;\r\n distance: number;\r\n /** Signal strength in dBm (0 if unavailable). */\r\n rssi?: number;\r\n};\r\n\r\n/** Payload for beacon timeout events (beacon in range for configured duration). */\r\nexport type BeaconTimeoutEvent = {\r\n identifier: string;\r\n uuid: string;\r\n major: number;\r\n minor: number;\r\n /** Current distance in metres at the time the timeout fired. */\r\n distance: number;\r\n};\r\n\r\n/** Configuration for beacon enter/exit event notifications. */\r\nexport type BeaconNotificationConfig = {\r\n /** Whether to show enter/exit notifications. Default: true. */\r\n enabled?: boolean;\r\n /** Notification title on beacon enter. Default: \"Beacon Entered\". */\r\n enterTitle?: string;\r\n /** Notification title on beacon exit. Default: \"Beacon Exited\". */\r\n exitTitle?: string;\r\n /** Notification title on beacon timeout. Default: \"Beacon Timeout\". */\r\n timeoutTitle?: string;\r\n /**\r\n * Notification body template. Supports {identifier} and {event} placeholders.\r\n * Default: \"{identifier} region {event}ed\".\r\n */\r\n body?: string;\r\n /** Play a sound with the notification (iOS only). Default: true. */\r\n sound?: boolean;\r\n /** Android drawable resource name for the notification icon (e.g. \"ic_notification\"). */\r\n icon?: string;\r\n};\r\n\r\n/** Configuration for the Android foreground service notification (persistent status bar entry). */\r\nexport type ForegroundServiceConfig = {\r\n /** Title of the persistent notification. Default: \"Beacon Monitoring Active\". */\r\n title?: string;\r\n /** Body text of the persistent notification. Default: \"Monitoring for iBeacons in the background\". */\r\n text?: string;\r\n /** Android drawable resource name for the notification icon. */\r\n icon?: string;\r\n};\r\n\r\n/** Configuration for the Android notification channel. */\r\nexport type NotificationChannelConfig = {\r\n /** Channel display name shown in system settings. Default: \"Beacon Monitoring\". */\r\n name?: string;\r\n /** Channel description shown in system settings. Default: \"Used for background iBeacon region monitoring\". */\r\n description?: string;\r\n /**\r\n * Channel importance level. Default: 'low'.\r\n * Note: Android may ignore decreases in importance after first channel creation until the app is reinstalled.\r\n */\r\n importance?: \"low\" | \"default\" | \"high\";\r\n};\r\n\r\n/** Configuration for CarPlay / Android Auto connect/disconnect notifications. */\r\nexport type CarPlayNotificationConfig = {\r\n /** Whether to show CarPlay connect/disconnect notifications. Default: true. */\r\n enabled?: boolean;\r\n /** Notification title on CarPlay/Android Auto connect. Default: \"CarPlay Connected\". */\r\n connectedTitle?: string;\r\n /** Notification title on CarPlay/Android Auto disconnect. Default: \"CarPlay Disconnected\". */\r\n disconnectedTitle?: string;\r\n /**\r\n * Notification body template. Supports `{event}` (\"connected\"/\"disconnected\") and\r\n * `{transport}` (e.g. \"wired\", \"wireless\", \"projection\", \"native\", \"unknown\") placeholders.\r\n * Note: `{transport}` is only meaningful for connect events; on disconnect it is replaced with an empty string.\r\n * Default: \"CarPlay session {event}\".\r\n */\r\n body?: string;\r\n /** Play a sound with the notification (iOS only). Default: true. */\r\n sound?: boolean;\r\n /** Android drawable resource name for the notification icon (e.g. \"ic_notification\"). */\r\n icon?: string;\r\n};\r\n\r\n/** Configuration for the Android notification channel used for CarPlay events. */\r\nexport type CarPlayChannelConfig = {\r\n /** Channel display name shown in system settings. Default: \"CarPlay / Android Auto\". */\r\n name?: string;\r\n /** Channel description shown in system settings. Default: \"CarPlay and Android Auto connect/disconnect notifications\". */\r\n description?: string;\r\n /**\r\n * Channel importance level. Default: 'default' (so connect/disconnect events make a sound).\r\n * Note: Android may ignore decreases in importance after first channel creation until the app is reinstalled.\r\n */\r\n importance?: \"low\" | \"default\" | \"high\";\r\n};\r\n\r\n/** Combined notification configuration for all notification types. */\r\nexport type NotificationConfig = {\r\n /** Settings for beacon enter/exit event notifications. */\r\n beaconEvents?: BeaconNotificationConfig;\r\n /** Settings for CarPlay / Android Auto connect/disconnect notifications. */\r\n carPlayEvents?: CarPlayNotificationConfig;\r\n /** Settings for the persistent foreground service notification (Android only). */\r\n foregroundService?: ForegroundServiceConfig;\r\n /** Settings for the Android notification channel (Android only). */\r\n channel?: NotificationChannelConfig;\r\n /** Settings for the Android notification channel used for CarPlay events (Android only). */\r\n carPlayChannel?: CarPlayChannelConfig;\r\n};\r\n\r\n/** Snapshot of the current monitoring configuration and active state. */\r\nexport type MonitoringConfig = {\r\n /** Whether background monitoring is currently active. */\r\n isMonitoring: boolean;\r\n maxDistance?: number;\r\n exitDistance?: number;\r\n minRssi?: number;\r\n level?: 'all' | 'events';\r\n /** Seconds after last beacon sighting before an exit event fires. Default: 300. */\r\n exitTimeoutSeconds?: number;\r\n notifications?: NotificationConfig;\r\n};\r\n\r\n/** Current state snapshot for a paired monitored device. */\r\nexport type MonitoredDeviceState =\r\n | {\r\n kind: \"ibeacon\";\r\n identifier: string;\r\n uuid: string;\r\n major: number;\r\n minor: number;\r\n state: \"entered\" | \"exited\";\r\n /** Current distance in metres, or null when exited or no live reading is available. */\r\n distance: number | null;\r\n }\r\n | {\r\n kind: \"eddystone\";\r\n identifier: string;\r\n namespace: string;\r\n instance: string;\r\n state: \"entered\" | \"exited\";\r\n /** Current distance in metres, or null when exited or no live reading is available. */\r\n distance: number | null;\r\n };\r\n\r\n/** Options accepted by startMonitoring(). */\r\nexport type MonitoringOptions = {\r\n /**\r\n * Maximum distance in metres for distance-based enter events.\r\n * Exit events are always emitted when the region is lost.\r\n */\r\n maxDistance?: number;\r\n /**\r\n * Distance in metres at which exit events fire (must be ≥ maxDistance).\r\n * Creates a hysteresis band between enter and exit thresholds to prevent\r\n * rapid toggling near the boundary.\r\n *\r\n * Default when omitted: `maxDistance + min(maxDistance × 0.5, 2.5)`.\r\n * Only used when `maxDistance` is set.\r\n */\r\n exitDistance?: number;\r\n /**\r\n * Minimum RSSI (dBm) for a beacon reading to be considered valid.\r\n * Readings below this threshold are discarded as unreliable, preventing\r\n * false detections from reflected or distant signals.\r\n *\r\n * Default: -85. Typical range: -100 (very permissive) to -70 (strict).\r\n */\r\n minRssi?: number;\r\n /**\r\n * Controls which event types are emitted, logged, and forwarded to the API.\r\n *\r\n * - `'all'` (default): distance + enter + exit + timeout events.\r\n * - `'events'`: enter + exit + timeout only (no distance events).\r\n */\r\n level?: 'all' | 'events';\r\n /**\r\n * Seconds after last beacon sighting before an exit event fires when the beacon\r\n * disappears without moving outside the exit distance threshold.\r\n *\r\n * Default: 300 (5 minutes). Minimum: 1.\r\n */\r\n exitTimeoutSeconds?: number;\r\n /** Notification configuration overrides to apply for this monitoring session. */\r\n notifications?: NotificationConfig;\r\n};\r\n\r\n/** Eddystone frame type. */\r\nexport type EddystoneFrameType = \"uid\" | \"url\";\r\n\r\n/** Raw Eddystone beacon discovered during a scan. */\r\nexport type EddystoneScanResult = {\r\n frameType: EddystoneFrameType;\r\n /** 10-byte namespace ID as hex string (20 chars). Present for UID frames. */\r\n namespace?: string;\r\n /** 6-byte instance ID as hex string (12 chars). Present for UID frames. */\r\n instance?: string;\r\n /** Decoded URL. Present for URL frames. */\r\n url?: string;\r\n rssi: number;\r\n distance: number;\r\n txPower: number;\r\n /** BLE advertising device name. */\r\n name?: string;\r\n};\r\n\r\n/**\r\n * An Eddystone-UID beacon that has been paired/registered for monitoring.\r\n *\r\n * Note: Paired beacon data is stored unencrypted in UserDefaults (iOS) /\r\n * SharedPreferences (Android) and may be included in device backups.\r\n */\r\nexport type PairedEddystone = {\r\n identifier: string;\r\n /** 10-byte namespace ID as hex string (20 chars). */\r\n namespace: string;\r\n /** 6-byte instance ID as hex string (12 chars). */\r\n instance: string;\r\n /** BLE advertising device name, if provided at pairing time. */\r\n name?: string;\r\n /**\r\n * Timeout in seconds. When set, the module fires `onEddystoneTimeout` once\r\n * after the beacon has been continuously in range for this duration.\r\n * The timer resets if the beacon exits and re-enters range.\r\n *\r\n * The timeout countdown also starts if no BLE readings are received\r\n * for 60 seconds (e.g. due to Doze mode or background throttling).\r\n */\r\n timeoutSeconds?: number;\r\n};\r\n\r\n/** Payload for Eddystone enter/exit region events. */\r\nexport type EddystoneRegionEvent = {\r\n identifier: string;\r\n namespace: string;\r\n instance: string;\r\n event: \"enter\" | \"exit\";\r\n /** Measured distance in metres at the time of the event (–1 if unavailable). */\r\n distance: number;\r\n /** Signal strength in dBm at the time of the event (0 if unavailable). */\r\n rssi?: number;\r\n};\r\n\r\n/** Payload for periodic Eddystone distance update events during monitoring. */\r\nexport type EddystoneDistanceEvent = {\r\n identifier: string;\r\n namespace: string;\r\n instance: string;\r\n distance: number;\r\n /** Signal strength in dBm (0 if unavailable). */\r\n rssi?: number;\r\n};\r\n\r\n/** Payload for Eddystone timeout events (beacon in range for configured duration). */\r\nexport type EddystoneTimeoutEvent = {\r\n identifier: string;\r\n namespace: string;\r\n instance: string;\r\n /** Current distance in metres at the time the timeout fired. */\r\n distance: number;\r\n};\r\n\r\n/** Transport reported with CarPlay / Android Auto connection events. */\r\nexport type CarPlayTransport =\r\n | \"wired\" // iOS CarPlay over USB / Lightning\r\n | \"wireless\" // iOS CarPlay over Bluetooth + Wi-Fi\r\n | \"projection\" // Android Auto projection (phone projecting to head unit)\r\n | \"native\" // Android Automotive OS (running on the head unit)\r\n | \"unknown\";\r\n\r\n/** Payload fired when the device connects to a CarPlay or Android Auto session. */\r\nexport type CarPlayConnectedEvent = {\r\n transport: CarPlayTransport;\r\n /** Timestamp in milliseconds since epoch. */\r\n timestamp: number;\r\n /** ISO 8601 UTC representation of {@link timestamp} (e.g. \"2026-05-12T14:23:45.678Z\"). */\r\n timestampIso?: string;\r\n};\r\n\r\n/** Payload fired when the device disconnects from a CarPlay or Android Auto session. */\r\nexport type CarPlayDisconnectedEvent = {\r\n /** Timestamp in milliseconds since epoch. */\r\n timestamp: number;\r\n /** ISO 8601 UTC representation of {@link timestamp} (e.g. \"2026-05-12T14:23:45.678Z\"). */\r\n timestampIso?: string;\r\n /**\r\n * Reason this disconnect was emitted. Absent for normal real-time disconnects.\r\n * `\"reconciled\"` indicates the disconnect was synthesized after the module was\r\n * recreated in a new process and detected that the previously persisted CarPlay\r\n * state no longer matches the current connection — i.e. the disconnect happened\r\n * off-process (force-quit, OS reclaim, abrupt cable yank) and is being delivered\r\n * post-hoc. Emitted on both iOS and Android.\r\n */\r\n reason?: \"reconciled\";\r\n};\r\n\r\n/**\r\n * Snapshot of the current CarPlay / Android Auto connection state, returned by\r\n * {@link ExpoBeaconModule.getCarPlayConnectionStatus}.\r\n */\r\nexport type CarPlayConnectionStatus = {\r\n /** `true` if a CarPlay or Android Auto session is currently active. */\r\n connected: boolean;\r\n /**\r\n * Connection transport type. Present only when `connected` is `true`.\r\n * See {@link CarPlayTransport} for possible values.\r\n */\r\n transport?: CarPlayTransport;\r\n /** Unix-millisecond timestamp of last connect. Present only when `connected` is `true`. */\r\n timestamp?: number;\r\n /** ISO 8601 UTC timestamp of last connect. Present only when `connected` is `true`. */\r\n timestampIso?: string;\r\n};\r\n\r\n/**\r\n * Diagnostic snapshot for troubleshooting CarPlay / Android Auto detection.\r\n * Returned by {@link ExpoBeaconModule.getCarPlayDiagnostics}.\r\n *\r\n * The most common failure mode on Android is that the host app is not\r\n * registered as an Android Auto-aware app (missing\r\n * `com.google.android.gms.car.application` meta-data + `automotive_app_desc.xml`\r\n * resource). When that happens, Gearhead silently reports\r\n * `CONNECTION_TYPE_NOT_CONNECTED` to the app regardless of `<queries>`\r\n * declarations, so `onCarPlayConnected` events never fire.\r\n *\r\n * Inspect this object after calling `startCarPlayMonitoring()` and confirming\r\n * Android Auto is connected on the head unit. If `isCarAppMetadataPresent` or\r\n * `isCarProviderQueryable` is `false`, the consumer app needs to enable the\r\n * config plugin's `android.androidAuto.register` option (default in recent\r\n * versions) and re-run `expo prebuild`.\r\n *\r\n * On iOS the diagnostic is a best-effort stub — most fields are not applicable\r\n * because CarPlay detection uses `AVAudioSession` rather than a content\r\n * provider.\r\n */\r\nexport type CarPlayDiagnostics = {\r\n /**\r\n * Android: `true` if the host app's manifest declares the\r\n * `com.google.android.gms.car.application` meta-data tag (required for\r\n * Gearhead to expose connection state to the app). iOS: always `true`.\r\n */\r\n isCarAppMetadataPresent: boolean;\r\n /**\r\n * Android: `true` if the system can resolve at least one provider for the\r\n * `androidx.car.app.connection.action.CAR_PROVIDER` intent (requires the\r\n * `<queries>` declaration shipped by this library AND a compatible Gearhead\r\n * / AAOS install on the device). iOS: always `true`.\r\n */\r\n isCarProviderQueryable: boolean;\r\n /**\r\n * Android: most recent raw value read from `CarConnection.getType()`.\r\n * `0` = `NOT_CONNECTED`, `1` = `NATIVE` (AAOS), `2` = `PROJECTION`.\r\n * `null` if the observer has not yet received any value (or is not running).\r\n * iOS: `null`.\r\n */\r\n lastRawConnectionType: number | null;\r\n /**\r\n * `true` if the underlying connection observer is currently active.\r\n * On Android, equivalent to \"the foreground service is running AND\r\n * `CarPlayMonitor.start()` succeeded\". On iOS, the audio-session observer\r\n * is registered.\r\n */\r\n observerActive: boolean;\r\n /**\r\n * Android: `true` if the foreground service hosting the observer is alive.\r\n * iOS: always `true` (no background service involved).\r\n */\r\n serviceAlive: boolean;\r\n};\r\n\r\n/** Payload for native beacon error events (monitoring/ranging failures). */\r\nexport type BeaconErrorEvent = {\r\n /** Region or constraint identifier, empty string if unavailable. */\r\n identifier: string;\r\n /** Machine-readable error code (e.g. \"MONITORING_FAILED\", \"RANGING_FAILED\", \"SECURITY_EXCEPTION\"). */\r\n code: string;\r\n /** Human-readable error message from the native layer. */\r\n message: string;\r\n};\r\n\r\n/** Module event map. */\r\nexport type ExpoBeaconModuleEvents = {\r\n onBeaconEnter: (params: BeaconRegionEvent) => void;\r\n onBeaconExit: (params: BeaconRegionEvent) => void;\r\n onBeaconDistance: (params: BeaconDistanceEvent) => void;\r\n /** Fired once after a paired beacon has been continuously in range for its configured `timeoutSeconds`. */\r\n onBeaconTimeout: (params: BeaconTimeoutEvent) => void;\r\n /** Fired continuously during a live scan as each iBeacon is detected. */\r\n onBeaconFound: (params: BeaconScanResult) => void;\r\n /** Fired continuously during a live scan as each Eddystone beacon is detected. */\r\n onEddystoneFound: (params: EddystoneScanResult) => void;\r\n onEddystoneEnter: (params: EddystoneRegionEvent) => void;\r\n onEddystoneExit: (params: EddystoneRegionEvent) => void;\r\n onEddystoneDistance: (params: EddystoneDistanceEvent) => void;\r\n /** Fired once after a paired Eddystone has been continuously in range for its configured `timeoutSeconds`. */\r\n onEddystoneTimeout: (params: EddystoneTimeoutEvent) => void;\r\n /** Fired when a native monitoring or ranging failure occurs (logged to DB and forwarded to JS). */\r\n onBeaconError: (params: BeaconErrorEvent) => void;\r\n /** Fired when the device connects to a CarPlay (iOS) or Android Auto (Android) session. */\r\n onCarPlayConnected: (params: CarPlayConnectedEvent) => void;\r\n /** Fired when the device disconnects from a CarPlay (iOS) or Android Auto (Android) session. */\r\n onCarPlayDisconnected: (params: CarPlayDisconnectedEvent) => void;\r\n};\r\n\r\n/** Options for filtering event logs. */\r\nexport type EventLogQueryOptions = {\r\n /** Maximum number of log entries to return (default: 1000, max: 10000). */\r\n limit?: number;\r\n /** Filter by event type (e.g. \"onBeaconEnter\", \"onBeaconExit\"). */\r\n eventType?: string;\r\n /** Only return events with timestamp >= this value (ms since epoch). */\r\n sinceTimestamp?: number;\r\n};\r\n\r\n/** A single logged beacon event entry. */\r\nexport type EventLogEntry = {\r\n id: number;\r\n /** Timestamp in milliseconds since epoch. */\r\n timestamp: number;\r\n /** The event type that was logged (e.g. \"onBeaconEnter\"). */\r\n eventType: string;\r\n /** Beacon identifier, if available. */\r\n identifier?: string;\r\n /** The full event payload that was sent to JS. */\r\n data: Record<string, unknown>;\r\n};\r\n"]}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { NativeModule } from "expo";
|
|
2
|
-
import { ExpoBeaconModuleEvents, BeaconScanResult, EddystoneScanResult, PairedBeacon, PairedEddystone, NotificationConfig, MonitoringOptions, MonitoringConfig, MonitoredDeviceState, EventLogQueryOptions, EventLogEntry, CarPlayConnectionStatus } from "./ExpoBeacon.types";
|
|
2
|
+
import { ExpoBeaconModuleEvents, BeaconScanResult, EddystoneScanResult, PairedBeacon, PairedEddystone, NotificationConfig, MonitoringOptions, MonitoringConfig, MonitoredDeviceState, EventLogQueryOptions, EventLogEntry, CarPlayConnectionStatus, CarPlayDiagnostics } from "./ExpoBeacon.types";
|
|
3
3
|
declare class ExpoBeaconModule extends NativeModule<ExpoBeaconModuleEvents> {
|
|
4
4
|
/**
|
|
5
5
|
* Start a one-shot iBeacon scan. Resolves with discovered beacons after scanDuration ms.
|
|
@@ -196,6 +196,16 @@ declare class ExpoBeaconModule extends NativeModule<ExpoBeaconModuleEvents> {
|
|
|
196
196
|
* back to the persisted last-known state otherwise.
|
|
197
197
|
*/
|
|
198
198
|
getCarPlayConnectionStatus(): CarPlayConnectionStatus;
|
|
199
|
+
/**
|
|
200
|
+
* Returns diagnostic information about the CarPlay / Android Auto detection
|
|
201
|
+
* pipeline. Use this when `onCarPlayConnected` never fires despite the head
|
|
202
|
+
* unit being connected — it reveals whether the host app is correctly
|
|
203
|
+
* registered with Gearhead, whether the connection content provider is
|
|
204
|
+
* reachable, and the most recent raw value the observer received.
|
|
205
|
+
*
|
|
206
|
+
* See {@link CarPlayDiagnostics} for field-level guidance.
|
|
207
|
+
*/
|
|
208
|
+
getCarPlayDiagnostics(): CarPlayDiagnostics;
|
|
199
209
|
}
|
|
200
210
|
declare const _default: ExpoBeaconModule;
|
|
201
211
|
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,gBAAgB,EAChB,oBAAoB,EACpB,oBAAoB,EACpB,aAAa,EACb,uBAAuB,
|
|
1
|
+
{"version":3,"file":"ExpoBeaconModule.d.ts","sourceRoot":"","sources":["../src/ExpoBeaconModule.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ExpoBeaconModule.js","sourceRoot":"","sources":["../src/ExpoBeaconModule.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,mBAAmB,EAAE,MAAM,MAAM,CAAC;AAoQzD,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 MonitoringConfig,\r\n MonitoredDeviceState,\r\n EventLogQueryOptions,\r\n EventLogEntry,\r\n CarPlayConnectionStatus,\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 * Returns whether SQLite event logging is currently enabled.\r\n * Reads the persisted flag, so this stays accurate across app cold-starts.\r\n */\r\n isEventLoggingEnabled(): boolean;\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-CSFR-Token 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\n * Return the current monitoring configuration and active state.\r\n * Option fields are undefined if not explicitly set.\r\n */\r\n getMonitoringConfig(): MonitoringConfig;\r\n\r\n /**\r\n * Return the current state snapshot for a paired monitored device.\r\n * Returns null when no paired device matches the identifier.\r\n */\r\n getMonitoredDeviceState(identifier: string): MonitoredDeviceState | null;\r\n\r\n /**\r\n * Return the current state snapshot for all paired monitored devices.\r\n */\r\n getMonitoredDeviceStates(): MonitoredDeviceState[];\r\n\r\n /**\r\n * Return the current API forwarding configuration.\r\n * Each field is `null` if not set.\r\n */\r\n getApiEndpoint(): { url: string | null; apiKey: string | null; id: string | null };\r\n\r\n /**\r\n * Start observing CarPlay (iOS) / Android Auto (Android) connection state.\r\n *\r\n * Emits `onCarPlayConnected` and `onCarPlayDisconnected` JS events. Events are\r\n * also written to the SQLite event log and forwarded to the configured API\r\n * endpoint, and dispatched to native lifecycle plugins (used by the auto-\r\n * generated geolocation plugin to start/stop background-geolocation).\r\n *\r\n * **Persistent.** The enabled state is stored in native preferences and\r\n * survives app kill / device reboot. Call `stopCarPlayMonitoring()` to\r\n * disable. `startMonitoring()` also enables CarPlay observation\r\n * automatically — calling this method explicitly is only required if you\r\n * want CarPlay events without beacon monitoring.\r\n *\r\n * **Background behavior:**\r\n * - **Android**: the foreground service hosts the observer and continues to\r\n * receive `CarConnection` events even after the app process is killed and\r\n * restarted via `BootReceiver`. Guaranteed background detection.\r\n * - **iOS**: the observer auto-restarts in `OnCreate` whenever the module\r\n * is recreated, including background-launches triggered by beacon region\r\n * monitoring. **iOS cannot wake a terminated app on CarPlay alone** — for\r\n * guaranteed wake-from-suspension, also call `startMonitoring()` with at\r\n * least one paired beacon. Region wake events trigger a CarPlay state\r\n * resync to reconcile any route changes that occurred during suspension.\r\n *\r\n * - iOS: observes `AVAudioSession.routeChangeNotification` for `.carAudio` ports.\r\n * No CarPlay entitlement required.\r\n * - Android: observes `androidx.car.app.connection.CarConnection` LiveData.\r\n * No Android Auto certification required.\r\n * - Web: no-op (resolves immediately).\r\n */\r\n startCarPlayMonitoring(): Promise<void>;\r\n\r\n /**\r\n * Stop CarPlay / Android Auto connection monitoring and clear the persisted\r\n * \"enabled\" flag so the observer is not auto-restarted on next launch / boot.\r\n *\r\n * On Android, if no beacon monitoring is active, the foreground service\r\n * stops itself.\r\n */\r\n stopCarPlayMonitoring(): Promise<void>;\r\n\r\n /**\r\n * Returns whether CarPlay / Android Auto observation is currently enabled.\r\n * Reads the persisted flag, so the value survives app cold-starts and\r\n * reflects the native source of truth (foreground service on Android,\r\n * UserDefaults suite on iOS).\r\n */\r\n isCarPlayMonitoringEnabled(): boolean;\r\n\r\n /**\r\n * Returns a snapshot of the current CarPlay / Android Auto connection state\r\n * without waiting for an event. Useful on mount to immediately reflect\r\n * whether a car session is already active.\r\n *\r\n * Reads from the live observer if the foreground service is running, or falls\r\n * back to the persisted last-known state otherwise.\r\n */\r\n getCarPlayConnectionStatus(): CarPlayConnectionStatus;\r\n}\r\n\r\nexport default requireNativeModule<ExpoBeaconModule>(\"ExpoBeacon\");\r\n"]}
|
|
1
|
+
{"version":3,"file":"ExpoBeaconModule.js","sourceRoot":"","sources":["../src/ExpoBeaconModule.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,mBAAmB,EAAE,MAAM,MAAM,CAAC;AAgRzD,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 MonitoringConfig,\r\n MonitoredDeviceState,\r\n EventLogQueryOptions,\r\n EventLogEntry,\r\n CarPlayConnectionStatus,\r\n CarPlayDiagnostics,\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 * Returns whether SQLite event logging is currently enabled.\r\n * Reads the persisted flag, so this stays accurate across app cold-starts.\r\n */\r\n isEventLoggingEnabled(): boolean;\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-CSFR-Token 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\n * Return the current monitoring configuration and active state.\r\n * Option fields are undefined if not explicitly set.\r\n */\r\n getMonitoringConfig(): MonitoringConfig;\r\n\r\n /**\r\n * Return the current state snapshot for a paired monitored device.\r\n * Returns null when no paired device matches the identifier.\r\n */\r\n getMonitoredDeviceState(identifier: string): MonitoredDeviceState | null;\r\n\r\n /**\r\n * Return the current state snapshot for all paired monitored devices.\r\n */\r\n getMonitoredDeviceStates(): MonitoredDeviceState[];\r\n\r\n /**\r\n * Return the current API forwarding configuration.\r\n * Each field is `null` if not set.\r\n */\r\n getApiEndpoint(): { url: string | null; apiKey: string | null; id: string | null };\r\n\r\n /**\r\n * Start observing CarPlay (iOS) / Android Auto (Android) connection state.\r\n *\r\n * Emits `onCarPlayConnected` and `onCarPlayDisconnected` JS events. Events are\r\n * also written to the SQLite event log and forwarded to the configured API\r\n * endpoint, and dispatched to native lifecycle plugins (used by the auto-\r\n * generated geolocation plugin to start/stop background-geolocation).\r\n *\r\n * **Persistent.** The enabled state is stored in native preferences and\r\n * survives app kill / device reboot. Call `stopCarPlayMonitoring()` to\r\n * disable. `startMonitoring()` also enables CarPlay observation\r\n * automatically — calling this method explicitly is only required if you\r\n * want CarPlay events without beacon monitoring.\r\n *\r\n * **Background behavior:**\r\n * - **Android**: the foreground service hosts the observer and continues to\r\n * receive `CarConnection` events even after the app process is killed and\r\n * restarted via `BootReceiver`. Guaranteed background detection.\r\n * - **iOS**: the observer auto-restarts in `OnCreate` whenever the module\r\n * is recreated, including background-launches triggered by beacon region\r\n * monitoring. **iOS cannot wake a terminated app on CarPlay alone** — for\r\n * guaranteed wake-from-suspension, also call `startMonitoring()` with at\r\n * least one paired beacon. Region wake events trigger a CarPlay state\r\n * resync to reconcile any route changes that occurred during suspension.\r\n *\r\n * - iOS: observes `AVAudioSession.routeChangeNotification` for `.carAudio` ports.\r\n * No CarPlay entitlement required.\r\n * - Android: observes `androidx.car.app.connection.CarConnection` LiveData.\r\n * No Android Auto certification required.\r\n * - Web: no-op (resolves immediately).\r\n */\r\n startCarPlayMonitoring(): Promise<void>;\r\n\r\n /**\r\n * Stop CarPlay / Android Auto connection monitoring and clear the persisted\r\n * \"enabled\" flag so the observer is not auto-restarted on next launch / boot.\r\n *\r\n * On Android, if no beacon monitoring is active, the foreground service\r\n * stops itself.\r\n */\r\n stopCarPlayMonitoring(): Promise<void>;\r\n\r\n /**\r\n * Returns whether CarPlay / Android Auto observation is currently enabled.\r\n * Reads the persisted flag, so the value survives app cold-starts and\r\n * reflects the native source of truth (foreground service on Android,\r\n * UserDefaults suite on iOS).\r\n */\r\n isCarPlayMonitoringEnabled(): boolean;\r\n\r\n /**\r\n * Returns a snapshot of the current CarPlay / Android Auto connection state\r\n * without waiting for an event. Useful on mount to immediately reflect\r\n * whether a car session is already active.\r\n *\r\n * Reads from the live observer if the foreground service is running, or falls\r\n * back to the persisted last-known state otherwise.\r\n */\r\n getCarPlayConnectionStatus(): CarPlayConnectionStatus;\r\n\r\n /**\r\n * Returns diagnostic information about the CarPlay / Android Auto detection\r\n * pipeline. Use this when `onCarPlayConnected` never fires despite the head\r\n * unit being connected — it reveals whether the host app is correctly\r\n * registered with Gearhead, whether the connection content provider is\r\n * reachable, and the most recent raw value the observer received.\r\n *\r\n * See {@link CarPlayDiagnostics} for field-level guidance.\r\n */\r\n getCarPlayDiagnostics(): CarPlayDiagnostics;\r\n}\r\n\r\nexport default requireNativeModule<ExpoBeaconModule>(\"ExpoBeacon\");\r\n"]}
|
package/build/index.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
export { default } from "./ExpoBeaconModule.js";
|
|
2
|
-
export type { BeaconScanResult, PairedBeacon, BeaconRegionEvent, BeaconDistanceEvent, BeaconTimeoutEvent, ExpoBeaconModuleEvents, NotificationConfig, MonitoringOptions, MonitoringConfig, MonitoredDeviceState, BeaconNotificationConfig, CarPlayNotificationConfig, CarPlayChannelConfig, ForegroundServiceConfig, NotificationChannelConfig, EddystoneFrameType, EddystoneScanResult, PairedEddystone, EddystoneRegionEvent, EddystoneDistanceEvent, EddystoneTimeoutEvent, EventLogQueryOptions, EventLogEntry, CarPlayTransport, CarPlayConnectedEvent, CarPlayDisconnectedEvent, CarPlayConnectionStatus, } from "./ExpoBeacon.types";
|
|
2
|
+
export type { BeaconScanResult, PairedBeacon, BeaconRegionEvent, BeaconDistanceEvent, BeaconTimeoutEvent, ExpoBeaconModuleEvents, NotificationConfig, MonitoringOptions, MonitoringConfig, MonitoredDeviceState, BeaconNotificationConfig, CarPlayNotificationConfig, CarPlayChannelConfig, ForegroundServiceConfig, NotificationChannelConfig, EddystoneFrameType, EddystoneScanResult, PairedEddystone, EddystoneRegionEvent, EddystoneDistanceEvent, EddystoneTimeoutEvent, EventLogQueryOptions, EventLogEntry, CarPlayTransport, CarPlayConnectedEvent, CarPlayDisconnectedEvent, CarPlayConnectionStatus, CarPlayDiagnostics, } from "./ExpoBeacon.types";
|
|
3
3
|
//# sourceMappingURL=index.d.ts.map
|
package/build/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AAGhD,YAAY,EACV,gBAAgB,EAChB,YAAY,EACZ,iBAAiB,EACjB,mBAAmB,EACnB,kBAAkB,EAClB,sBAAsB,EACtB,kBAAkB,EAClB,iBAAiB,EACjB,gBAAgB,EAChB,oBAAoB,EACpB,wBAAwB,EACxB,yBAAyB,EACzB,oBAAoB,EACpB,uBAAuB,EACvB,yBAAyB,EACzB,kBAAkB,EAClB,mBAAmB,EACnB,eAAe,EACf,oBAAoB,EACpB,sBAAsB,EACtB,qBAAqB,EACrB,oBAAoB,EACpB,aAAa,EACb,gBAAgB,EAChB,qBAAqB,EACrB,wBAAwB,EACxB,uBAAuB,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AAGhD,YAAY,EACV,gBAAgB,EAChB,YAAY,EACZ,iBAAiB,EACjB,mBAAmB,EACnB,kBAAkB,EAClB,sBAAsB,EACtB,kBAAkB,EAClB,iBAAiB,EACjB,gBAAgB,EAChB,oBAAoB,EACpB,wBAAwB,EACxB,yBAAyB,EACzB,oBAAoB,EACpB,uBAAuB,EACvB,yBAAyB,EACzB,kBAAkB,EAClB,mBAAmB,EACnB,eAAe,EACf,oBAAoB,EACpB,sBAAsB,EACtB,qBAAqB,EACrB,oBAAoB,EACpB,aAAa,EACb,gBAAgB,EAChB,qBAAqB,EACrB,wBAAwB,EACxB,uBAAuB,EACvB,kBAAkB,GACnB,MAAM,oBAAoB,CAAC"}
|
package/build/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,iCAAiC;AACjC,OAAO,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC","sourcesContent":["// Native module (default export)\r\nexport { default } from \"./ExpoBeaconModule.js\";\r\n\r\n// All public types\r\nexport type {\r\n BeaconScanResult,\r\n PairedBeacon,\r\n BeaconRegionEvent,\r\n BeaconDistanceEvent,\r\n BeaconTimeoutEvent,\r\n ExpoBeaconModuleEvents,\r\n NotificationConfig,\r\n MonitoringOptions,\r\n MonitoringConfig,\r\n MonitoredDeviceState,\r\n BeaconNotificationConfig,\r\n CarPlayNotificationConfig,\r\n CarPlayChannelConfig,\r\n ForegroundServiceConfig,\r\n NotificationChannelConfig,\r\n EddystoneFrameType,\r\n EddystoneScanResult,\r\n PairedEddystone,\r\n EddystoneRegionEvent,\r\n EddystoneDistanceEvent,\r\n EddystoneTimeoutEvent,\r\n EventLogQueryOptions,\r\n EventLogEntry,\r\n CarPlayTransport,\r\n CarPlayConnectedEvent,\r\n CarPlayDisconnectedEvent,\r\n CarPlayConnectionStatus,\r\n} from \"./ExpoBeacon.types\";\r\n"]}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,iCAAiC;AACjC,OAAO,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC","sourcesContent":["// Native module (default export)\r\nexport { default } from \"./ExpoBeaconModule.js\";\r\n\r\n// All public types\r\nexport type {\r\n BeaconScanResult,\r\n PairedBeacon,\r\n BeaconRegionEvent,\r\n BeaconDistanceEvent,\r\n BeaconTimeoutEvent,\r\n ExpoBeaconModuleEvents,\r\n NotificationConfig,\r\n MonitoringOptions,\r\n MonitoringConfig,\r\n MonitoredDeviceState,\r\n BeaconNotificationConfig,\r\n CarPlayNotificationConfig,\r\n CarPlayChannelConfig,\r\n ForegroundServiceConfig,\r\n NotificationChannelConfig,\r\n EddystoneFrameType,\r\n EddystoneScanResult,\r\n PairedEddystone,\r\n EddystoneRegionEvent,\r\n EddystoneDistanceEvent,\r\n EddystoneTimeoutEvent,\r\n EventLogQueryOptions,\r\n EventLogEntry,\r\n CarPlayTransport,\r\n CarPlayConnectedEvent,\r\n CarPlayDisconnectedEvent,\r\n CarPlayConnectionStatus,\r\n CarPlayDiagnostics,\r\n} from \"./ExpoBeacon.types\";\r\n"]}
|
|
@@ -501,6 +501,31 @@ public class ExpoBeaconModule: Module {
|
|
|
501
501
|
return self.defaults.bool(forKey: CARPLAY_MONITORING_ENABLED_KEY)
|
|
502
502
|
}
|
|
503
503
|
|
|
504
|
+
Function("getCarPlayConnectionStatus") { () -> [String: Any] in
|
|
505
|
+
// Always read the live audio-route state — cheaper than persisted
|
|
506
|
+
// and accurate even when the monitor isn't running.
|
|
507
|
+
let connected = self.defaults.bool(forKey: CARPLAY_LAST_CONNECTED_KEY)
|
|
508
|
+
var out: [String: Any] = ["connected": connected]
|
|
509
|
+
if connected {
|
|
510
|
+
let now = Date()
|
|
511
|
+
out["timestamp"] = now.timeIntervalSince1970 * 1000.0
|
|
512
|
+
}
|
|
513
|
+
return out
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
Function("getCarPlayDiagnostics") { () -> [String: Any] in
|
|
517
|
+
// iOS detection is via AVAudioSession, not a content provider —
|
|
518
|
+
// most diagnostic fields aren't applicable. Returning constants
|
|
519
|
+
// keeps the cross-platform JS surface uniform.
|
|
520
|
+
return [
|
|
521
|
+
"isCarAppMetadataPresent": true,
|
|
522
|
+
"isCarProviderQueryable": true,
|
|
523
|
+
"lastRawConnectionType": NSNull(),
|
|
524
|
+
"observerActive": self.defaults.bool(forKey: CARPLAY_MONITORING_ENABLED_KEY),
|
|
525
|
+
"serviceAlive": true,
|
|
526
|
+
]
|
|
527
|
+
}
|
|
528
|
+
|
|
504
529
|
// MARK: - Continuous Scan
|
|
505
530
|
|
|
506
531
|
Function("startContinuousScan") { () -> Void in
|
package/package.json
CHANGED
package/plugin/build/index.d.ts
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { ConfigPlugin } from '@expo/config-plugins';
|
|
2
|
+
import { BeaconAndroidPluginProps } from './withBeaconAndroid';
|
|
2
3
|
import { BeaconIOSPluginProps } from './withBeaconIOS';
|
|
3
4
|
export type BeaconPluginProps = {
|
|
4
5
|
ios?: BeaconIOSPluginProps;
|
|
6
|
+
android?: BeaconAndroidPluginProps;
|
|
5
7
|
};
|
|
6
8
|
declare const _default: ConfigPlugin<void | BeaconPluginProps>;
|
|
7
9
|
export default _default;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAuB,MAAM,sBAAsB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAuB,MAAM,sBAAsB,CAAC;AACzE,OAA0B,EAAE,wBAAwB,EAAE,MAAM,qBAAqB,CAAC;AAClF,OAAsB,EAAE,oBAAoB,EAAE,MAAM,iBAAiB,CAAC;AAEtE,MAAM,MAAM,iBAAiB,GAAG;IAC9B,GAAG,CAAC,EAAE,oBAAoB,CAAC;IAC3B,OAAO,CAAC,EAAE,wBAAwB,CAAC;CACpC,CAAC;;AAqBF,wBAIE"}
|
package/plugin/build/index.js
CHANGED
|
@@ -15,7 +15,7 @@ const withBeaconBGLocation = (config, props) => {
|
|
|
15
15
|
config = (0, withBeaconIOS_1.default)(config, opts.ios);
|
|
16
16
|
}
|
|
17
17
|
if (platform !== 'ios') {
|
|
18
|
-
config = (0, withBeaconAndroid_1.default)(config);
|
|
18
|
+
config = (0, withBeaconAndroid_1.default)(config, opts.android);
|
|
19
19
|
}
|
|
20
20
|
return config;
|
|
21
21
|
};
|
|
@@ -1,5 +1,39 @@
|
|
|
1
1
|
import { ConfigPlugin } from '@expo/config-plugins';
|
|
2
|
+
/**
|
|
3
|
+
* Categories advertised in the generated `automotive_app_desc.xml` resource.
|
|
4
|
+
* - `template` — declares the app as a Car-App-Library template provider. This
|
|
5
|
+
* is the value most commonly required by Gearhead to flag the package as
|
|
6
|
+
* Android-Auto-aware and start reporting `CONNECTION_TYPE_PROJECTION` via
|
|
7
|
+
* `CarConnection.getType()`. Side effect: the app may appear in the AA
|
|
8
|
+
* launcher drawer.
|
|
9
|
+
* - `media` — media-app category (audio playback in AA).
|
|
10
|
+
* - `notification` — silent registration; no AA UI surface but still flags the
|
|
11
|
+
* package as AA-aware for connection detection. Use this when the consumer
|
|
12
|
+
* app shouldn't appear in the AA drawer at all.
|
|
13
|
+
*/
|
|
14
|
+
export type AndroidAutoUsesName = 'template' | 'media' | 'notification';
|
|
15
|
+
export type BeaconAndroidPluginProps = {
|
|
16
|
+
/**
|
|
17
|
+
* Android Auto registration. When enabled (the default), the plugin injects
|
|
18
|
+
* the `com.google.android.gms.car.application` meta-data into the consumer
|
|
19
|
+
* app's `AndroidManifest.xml` and emits a matching
|
|
20
|
+
* `res/xml/automotive_app_desc.xml` resource. This makes Gearhead recognise
|
|
21
|
+
* the app, which is a prerequisite for `CarConnection.getType()` to ever
|
|
22
|
+
* report `PROJECTION` — without it the LiveData silently stays at
|
|
23
|
+
* `NOT_CONNECTED` and `onCarPlayConnected` never fires.
|
|
24
|
+
*
|
|
25
|
+
* Defaults: `{ register: true, usesName: 'template' }`.
|
|
26
|
+
*/
|
|
27
|
+
androidAuto?: {
|
|
28
|
+
/** Set to `false` to suppress the registration entirely (e.g. when you
|
|
29
|
+
* manage `automotive_app_desc.xml` yourself). Default: `true`. */
|
|
30
|
+
register?: boolean;
|
|
31
|
+
/** Category written into the generated XML. See {@link AndroidAutoUsesName}.
|
|
32
|
+
* Default: `'template'`. */
|
|
33
|
+
usesName?: AndroidAutoUsesName;
|
|
34
|
+
};
|
|
35
|
+
};
|
|
2
36
|
export declare function getAndroidPluginKotlin(packageName: string): string;
|
|
3
|
-
declare const withBeaconAndroid: ConfigPlugin
|
|
37
|
+
declare const withBeaconAndroid: ConfigPlugin<BeaconAndroidPluginProps | void>;
|
|
4
38
|
export default withBeaconAndroid;
|
|
5
39
|
//# sourceMappingURL=withBeaconAndroid.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"withBeaconAndroid.d.ts","sourceRoot":"","sources":["../src/withBeaconAndroid.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"withBeaconAndroid.d.ts","sourceRoot":"","sources":["../src/withBeaconAndroid.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,YAAY,EAGb,MAAM,sBAAsB,CAAC;AAM9B;;;;;;;;;;;GAWG;AACH,MAAM,MAAM,mBAAmB,GAAG,UAAU,GAAG,OAAO,GAAG,cAAc,CAAC;AAExE,MAAM,MAAM,wBAAwB,GAAG;IACrC;;;;;;;;;;OAUG;IACH,WAAW,CAAC,EAAE;QACZ;2EACmE;QACnE,QAAQ,CAAC,EAAE,OAAO,CAAC;QACnB;qCAC6B;QAC7B,QAAQ,CAAC,EAAE,mBAAmB,CAAC;KAChC,CAAC;CACH,CAAC;AAIF,wBAAgB,sBAAsB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAqClE;AAqHD,QAAA,MAAM,iBAAiB,EAAE,YAAY,CAAC,wBAAwB,GAAG,IAAI,CA0EpE,CAAC;AAEF,eAAe,iBAAiB,CAAC"}
|
|
@@ -67,7 +67,72 @@ function modifyMainApplication(contents) {
|
|
|
67
67
|
return contents;
|
|
68
68
|
}
|
|
69
69
|
// ─── Plugin ───────────────────────────────────────────────────────────────────
|
|
70
|
-
const
|
|
70
|
+
const AA_META_DATA_NAME = 'com.google.android.gms.car.application';
|
|
71
|
+
const AA_META_DATA_RESOURCE = '@xml/automotive_app_desc';
|
|
72
|
+
const AA_RES_FILE = 'automotive_app_desc.xml';
|
|
73
|
+
function getAutomotiveAppDescXml(usesName) {
|
|
74
|
+
return `<?xml version="1.0" encoding="utf-8"?>
|
|
75
|
+
<!--
|
|
76
|
+
Generated by the expo-beacon config plugin. Marks this app as
|
|
77
|
+
Android-Auto-aware so Gearhead reports CarConnection.PROJECTION to the
|
|
78
|
+
process. Disable via the plugin's android.androidAuto.register: false
|
|
79
|
+
option if you want to manage this resource yourself.
|
|
80
|
+
-->
|
|
81
|
+
<automotiveApp>
|
|
82
|
+
<uses name="${usesName}"/>
|
|
83
|
+
</automotiveApp>
|
|
84
|
+
`;
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Inject the `com.google.android.gms.car.application` meta-data into the
|
|
88
|
+
* consumer app's `<application>` element. Idempotent — `addMetaDataItemToMainApplication`
|
|
89
|
+
* replaces an existing entry with the same name rather than duplicating it,
|
|
90
|
+
* so re-runs of `expo prebuild` are safe. Skipped when the manifest already
|
|
91
|
+
* declares the meta-data (presence implies the user is managing it manually).
|
|
92
|
+
*/
|
|
93
|
+
const withAndroidAutoMetaData = (config) => {
|
|
94
|
+
return (0, config_plugins_1.withAndroidManifest)(config, (config) => {
|
|
95
|
+
const app = config_plugins_1.AndroidConfig.Manifest.getMainApplicationOrThrow(config.modResults);
|
|
96
|
+
const existing = config_plugins_1.AndroidConfig.Manifest.getMainApplicationMetaDataValue(config.modResults, AA_META_DATA_NAME);
|
|
97
|
+
if (existing != null) {
|
|
98
|
+
// User-managed entry; leave it alone.
|
|
99
|
+
return config;
|
|
100
|
+
}
|
|
101
|
+
config_plugins_1.AndroidConfig.Manifest.addMetaDataItemToMainApplication(app, AA_META_DATA_NAME, AA_META_DATA_RESOURCE, 'resource');
|
|
102
|
+
return config;
|
|
103
|
+
});
|
|
104
|
+
};
|
|
105
|
+
/**
|
|
106
|
+
* Emit `android/app/src/main/res/xml/automotive_app_desc.xml`. Never
|
|
107
|
+
* overwrites an existing file — if the consumer hand-authored the resource
|
|
108
|
+
* (e.g. with multiple `<uses>` children), we respect it and log a notice.
|
|
109
|
+
*/
|
|
110
|
+
function withAndroidAutoDescriptor(usesName) {
|
|
111
|
+
return (config) => (0, config_plugins_1.withDangerousMod)(config, [
|
|
112
|
+
'android',
|
|
113
|
+
(config) => {
|
|
114
|
+
const xmlDir = path.join(config.modRequest.platformProjectRoot, 'app/src/main/res/xml');
|
|
115
|
+
const xmlPath = path.join(xmlDir, AA_RES_FILE);
|
|
116
|
+
if (fs.existsSync(xmlPath)) {
|
|
117
|
+
// Don't clobber a user-managed resource.
|
|
118
|
+
return config;
|
|
119
|
+
}
|
|
120
|
+
try {
|
|
121
|
+
fs.mkdirSync(xmlDir, { recursive: true });
|
|
122
|
+
fs.writeFileSync(xmlPath, getAutomotiveAppDescXml(usesName));
|
|
123
|
+
}
|
|
124
|
+
catch (err) {
|
|
125
|
+
console.warn(`[expo-beacon] Failed to write ${AA_RES_FILE}: ${String(err)}`);
|
|
126
|
+
}
|
|
127
|
+
return config;
|
|
128
|
+
},
|
|
129
|
+
]);
|
|
130
|
+
}
|
|
131
|
+
const withBeaconAndroid = (config, props) => {
|
|
132
|
+
var _a, _b, _c, _d;
|
|
133
|
+
const opts = props !== null && props !== void 0 ? props : {};
|
|
134
|
+
const aaRegister = (_b = (_a = opts.androidAuto) === null || _a === void 0 ? void 0 : _a.register) !== null && _b !== void 0 ? _b : true;
|
|
135
|
+
const aaUsesName = (_d = (_c = opts.androidAuto) === null || _c === void 0 ? void 0 : _c.usesName) !== null && _d !== void 0 ? _d : 'template';
|
|
71
136
|
// Step 1 – write BeaconGeoPlugin.kt into the app source tree.
|
|
72
137
|
config = (0, config_plugins_1.withDangerousMod)(config, [
|
|
73
138
|
'android',
|
|
@@ -108,6 +173,14 @@ const withBeaconAndroid = (config) => {
|
|
|
108
173
|
return config;
|
|
109
174
|
},
|
|
110
175
|
]);
|
|
176
|
+
// Step 3 – register the consumer app as Android-Auto-aware so Gearhead
|
|
177
|
+
// surfaces CarConnection.PROJECTION to our CarPlayMonitor. Opt-out via
|
|
178
|
+
// `androidAuto.register: false` for advanced consumers managing this
|
|
179
|
+
// themselves.
|
|
180
|
+
if (aaRegister) {
|
|
181
|
+
config = withAndroidAutoMetaData(config);
|
|
182
|
+
config = withAndroidAutoDescriptor(aaUsesName)(config);
|
|
183
|
+
}
|
|
111
184
|
return config;
|
|
112
185
|
};
|
|
113
186
|
exports.default = withBeaconAndroid;
|
package/src/ExpoBeacon.types.ts
CHANGED
|
@@ -364,6 +364,62 @@ export type CarPlayConnectionStatus = {
|
|
|
364
364
|
timestampIso?: string;
|
|
365
365
|
};
|
|
366
366
|
|
|
367
|
+
/**
|
|
368
|
+
* Diagnostic snapshot for troubleshooting CarPlay / Android Auto detection.
|
|
369
|
+
* Returned by {@link ExpoBeaconModule.getCarPlayDiagnostics}.
|
|
370
|
+
*
|
|
371
|
+
* The most common failure mode on Android is that the host app is not
|
|
372
|
+
* registered as an Android Auto-aware app (missing
|
|
373
|
+
* `com.google.android.gms.car.application` meta-data + `automotive_app_desc.xml`
|
|
374
|
+
* resource). When that happens, Gearhead silently reports
|
|
375
|
+
* `CONNECTION_TYPE_NOT_CONNECTED` to the app regardless of `<queries>`
|
|
376
|
+
* declarations, so `onCarPlayConnected` events never fire.
|
|
377
|
+
*
|
|
378
|
+
* Inspect this object after calling `startCarPlayMonitoring()` and confirming
|
|
379
|
+
* Android Auto is connected on the head unit. If `isCarAppMetadataPresent` or
|
|
380
|
+
* `isCarProviderQueryable` is `false`, the consumer app needs to enable the
|
|
381
|
+
* config plugin's `android.androidAuto.register` option (default in recent
|
|
382
|
+
* versions) and re-run `expo prebuild`.
|
|
383
|
+
*
|
|
384
|
+
* On iOS the diagnostic is a best-effort stub — most fields are not applicable
|
|
385
|
+
* because CarPlay detection uses `AVAudioSession` rather than a content
|
|
386
|
+
* provider.
|
|
387
|
+
*/
|
|
388
|
+
export type CarPlayDiagnostics = {
|
|
389
|
+
/**
|
|
390
|
+
* Android: `true` if the host app's manifest declares the
|
|
391
|
+
* `com.google.android.gms.car.application` meta-data tag (required for
|
|
392
|
+
* Gearhead to expose connection state to the app). iOS: always `true`.
|
|
393
|
+
*/
|
|
394
|
+
isCarAppMetadataPresent: boolean;
|
|
395
|
+
/**
|
|
396
|
+
* Android: `true` if the system can resolve at least one provider for the
|
|
397
|
+
* `androidx.car.app.connection.action.CAR_PROVIDER` intent (requires the
|
|
398
|
+
* `<queries>` declaration shipped by this library AND a compatible Gearhead
|
|
399
|
+
* / AAOS install on the device). iOS: always `true`.
|
|
400
|
+
*/
|
|
401
|
+
isCarProviderQueryable: boolean;
|
|
402
|
+
/**
|
|
403
|
+
* Android: most recent raw value read from `CarConnection.getType()`.
|
|
404
|
+
* `0` = `NOT_CONNECTED`, `1` = `NATIVE` (AAOS), `2` = `PROJECTION`.
|
|
405
|
+
* `null` if the observer has not yet received any value (or is not running).
|
|
406
|
+
* iOS: `null`.
|
|
407
|
+
*/
|
|
408
|
+
lastRawConnectionType: number | null;
|
|
409
|
+
/**
|
|
410
|
+
* `true` if the underlying connection observer is currently active.
|
|
411
|
+
* On Android, equivalent to "the foreground service is running AND
|
|
412
|
+
* `CarPlayMonitor.start()` succeeded". On iOS, the audio-session observer
|
|
413
|
+
* is registered.
|
|
414
|
+
*/
|
|
415
|
+
observerActive: boolean;
|
|
416
|
+
/**
|
|
417
|
+
* Android: `true` if the foreground service hosting the observer is alive.
|
|
418
|
+
* iOS: always `true` (no background service involved).
|
|
419
|
+
*/
|
|
420
|
+
serviceAlive: boolean;
|
|
421
|
+
};
|
|
422
|
+
|
|
367
423
|
/** Payload for native beacon error events (monitoring/ranging failures). */
|
|
368
424
|
export type BeaconErrorEvent = {
|
|
369
425
|
/** Region or constraint identifier, empty string if unavailable. */
|
package/src/ExpoBeaconModule.ts
CHANGED
|
@@ -13,6 +13,7 @@ import {
|
|
|
13
13
|
EventLogQueryOptions,
|
|
14
14
|
EventLogEntry,
|
|
15
15
|
CarPlayConnectionStatus,
|
|
16
|
+
CarPlayDiagnostics,
|
|
16
17
|
} from "./ExpoBeacon.types";
|
|
17
18
|
|
|
18
19
|
declare class ExpoBeaconModule extends NativeModule<ExpoBeaconModuleEvents> {
|
|
@@ -256,6 +257,17 @@ declare class ExpoBeaconModule extends NativeModule<ExpoBeaconModuleEvents> {
|
|
|
256
257
|
* back to the persisted last-known state otherwise.
|
|
257
258
|
*/
|
|
258
259
|
getCarPlayConnectionStatus(): CarPlayConnectionStatus;
|
|
260
|
+
|
|
261
|
+
/**
|
|
262
|
+
* Returns diagnostic information about the CarPlay / Android Auto detection
|
|
263
|
+
* pipeline. Use this when `onCarPlayConnected` never fires despite the head
|
|
264
|
+
* unit being connected — it reveals whether the host app is correctly
|
|
265
|
+
* registered with Gearhead, whether the connection content provider is
|
|
266
|
+
* reachable, and the most recent raw value the observer received.
|
|
267
|
+
*
|
|
268
|
+
* See {@link CarPlayDiagnostics} for field-level guidance.
|
|
269
|
+
*/
|
|
270
|
+
getCarPlayDiagnostics(): CarPlayDiagnostics;
|
|
259
271
|
}
|
|
260
272
|
|
|
261
273
|
export default requireNativeModule<ExpoBeaconModule>("ExpoBeacon");
|