expo-beacon 0.8.2 → 0.8.3

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.
@@ -19,6 +19,7 @@ import org.altbeacon.beacon.*
19
19
  import org.json.JSONArray
20
20
 
21
21
  private const val CHANNEL_ID = "expo_beacon_channel"
22
+ private const val CARPLAY_CHANNEL_ID = "expo_beacon_carplay_channel"
22
23
  internal const val FOREGROUND_NOTIF_ID = 1001
23
24
  /**
24
25
  * Base ID for per-beacon enter/exit notifications; incremented per unique region.
@@ -26,6 +27,14 @@ internal const val FOREGROUND_NOTIF_ID = 1001
26
27
  * before ID collision. Sufficient for real-world beacon deployments.
27
28
  */
28
29
  private const val ENTER_EXIT_NOTIF_BASE_ID = 2000
30
+ /**
31
+ * Fixed notification IDs for CarPlay connect / disconnect events. Each event
32
+ * type uses a single ID so repeated events of the same type replace the prior
33
+ * notification rather than stacking, while connect and disconnect remain
34
+ * independently visible.
35
+ */
36
+ private const val CARPLAY_CONNECTED_NOTIF_ID = 3000
37
+ private const val CARPLAY_DISCONNECTED_NOTIF_ID = 3001
29
38
 
30
39
  class BeaconForegroundService : Service(), BeaconConsumer {
31
40
 
@@ -94,6 +103,7 @@ class BeaconForegroundService : Service(), BeaconConsumer {
94
103
  super.onCreate()
95
104
  activeService = this
96
105
  createNotificationChannel()
106
+ createCarPlayNotificationChannel()
97
107
  apiForwarder = BeaconApiForwarder(this)
98
108
  beaconManager = BeaconManager.getInstanceForApplication(this).also { manager ->
99
109
  BeaconParsers.ensureRegistered(manager)
@@ -856,6 +866,60 @@ class BeaconForegroundService : Service(), BeaconConsumer {
856
866
  }
857
867
  // Best-effort delivery to the live JS bridge if a module instance is bound.
858
868
  try { boundModule?.get()?.forwardCarPlayEventFromService(eventName, payload) } catch (_: Throwable) {}
869
+ // Local notification for connect/disconnect (config-gated).
870
+ try {
871
+ when (eventName) {
872
+ "onCarPlayConnected" -> showCarPlayNotification(
873
+ "connected",
874
+ payload["transport"] as? String,
875
+ )
876
+ "onCarPlayDisconnected" -> showCarPlayNotification("disconnected", null)
877
+ }
878
+ } catch (e: Throwable) {
879
+ Log.w(TAG, "CarPlay notification post failed", e)
880
+ }
881
+ }
882
+
883
+ private fun showCarPlayNotification(eventType: String, transport: String?) {
884
+ val config = readNotificationConfig()
885
+ val eventsConfig = config.optJSONObject("carPlayEvents")
886
+
887
+ // Respect the enabled flag (defaults to true)
888
+ if (eventsConfig != null && !eventsConfig.optBoolean("enabled", true)) return
889
+
890
+ val defaultTitle = if (eventType == "connected") "CarPlay Connected" else "CarPlay Disconnected"
891
+ val title = when (eventType) {
892
+ "connected" -> eventsConfig?.optString("connectedTitle")?.takeIf { it.isNotEmpty() } ?: defaultTitle
893
+ else -> eventsConfig?.optString("disconnectedTitle")?.takeIf { it.isNotEmpty() } ?: defaultTitle
894
+ }
895
+
896
+ val bodyTemplate = eventsConfig?.optString("body")?.takeIf { it.isNotEmpty() }
897
+ ?: "CarPlay session {event}"
898
+ val message = bodyTemplate
899
+ .replace("{event}", eventType)
900
+ .replace("{transport}", transport ?: "")
901
+
902
+ val iconName = eventsConfig?.optString("icon")?.takeIf { it.isNotEmpty() }
903
+ val iconResId = iconName?.let { name ->
904
+ try { resources.getIdentifier(name, "drawable", packageName).takeIf { it != 0 } }
905
+ catch (_: Exception) { null }
906
+ } ?: android.R.drawable.ic_dialog_info
907
+
908
+ val notification = NotificationCompat.Builder(this, CARPLAY_CHANNEL_ID)
909
+ .setSmallIcon(iconResId)
910
+ .setContentTitle(title)
911
+ .setContentText(message)
912
+ .setPriority(NotificationCompat.PRIORITY_DEFAULT)
913
+ .setAutoCancel(true)
914
+ .build()
915
+
916
+ val notifId = if (eventType == "connected") CARPLAY_CONNECTED_NOTIF_ID
917
+ else CARPLAY_DISCONNECTED_NOTIF_ID
918
+ try {
919
+ NotificationManagerCompat.from(this).notify(notifId, notification)
920
+ } catch (_: SecurityException) {
921
+ // POST_NOTIFICATIONS not granted — silently skip notification
922
+ }
859
923
  }
860
924
 
861
925
  private fun createNotificationChannel() {
@@ -884,6 +948,31 @@ class BeaconForegroundService : Service(), BeaconConsumer {
884
948
  }
885
949
  }
886
950
 
951
+ private fun createCarPlayNotificationChannel() {
952
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
953
+ val config = readNotificationConfig()
954
+ val channelConfig = config.optJSONObject("carPlayChannel")
955
+
956
+ val channelName = channelConfig?.optString("name")?.takeIf { it.isNotEmpty() }
957
+ ?: "CarPlay / Android Auto"
958
+ val channelDesc = channelConfig?.optString("description")?.takeIf { it.isNotEmpty() }
959
+ ?: "CarPlay and Android Auto connect/disconnect notifications"
960
+ val importance = when (channelConfig?.optString("importance")) {
961
+ "high" -> NotificationManager.IMPORTANCE_HIGH
962
+ "low" -> NotificationManager.IMPORTANCE_LOW
963
+ else -> NotificationManager.IMPORTANCE_DEFAULT
964
+ }
965
+
966
+ val notifMgr = getSystemService(NotificationManager::class.java)
967
+ if (notifMgr?.getNotificationChannel(CARPLAY_CHANNEL_ID) == null) {
968
+ val channel = NotificationChannel(CARPLAY_CHANNEL_ID, channelName, importance).apply {
969
+ description = channelDesc
970
+ }
971
+ notifMgr?.createNotificationChannel(channel)
972
+ }
973
+ }
974
+ }
975
+
887
976
  private fun buildForegroundNotification(): Notification {
888
977
  return Companion.buildForegroundNotification(this)
889
978
  }
@@ -926,6 +1015,7 @@ class BeaconForegroundService : Service(), BeaconConsumer {
926
1015
  context.getSharedPreferences(PREF_IS_MONITORING, Context.MODE_PRIVATE)
927
1016
  .edit().putBoolean("active", true).apply()
928
1017
  ensureNotificationChannel(context)
1018
+ ensureCarPlayNotificationChannel(context)
929
1019
  val intent = Intent(context, BeaconForegroundService::class.java)
930
1020
  if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
931
1021
  context.startForegroundService(intent)
@@ -976,6 +1066,7 @@ class BeaconForegroundService : Service(), BeaconConsumer {
976
1066
  fun enableCarPlay(context: Context) {
977
1067
  setCarPlayEnabled(context, true)
978
1068
  ensureNotificationChannel(context)
1069
+ ensureCarPlayNotificationChannel(context)
979
1070
  val intent = Intent(context, BeaconForegroundService::class.java)
980
1071
  .setAction(ACTION_ENABLE_CARPLAY)
981
1072
  if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
@@ -1050,6 +1141,38 @@ class BeaconForegroundService : Service(), BeaconConsumer {
1050
1141
  }
1051
1142
  }
1052
1143
 
1144
+ /**
1145
+ * Ensure the CarPlay notification channel exists. Mirrors
1146
+ * [ensureNotificationChannel] for the dedicated CarPlay channel so that
1147
+ * users can mute CarPlay notifications independently in system settings.
1148
+ */
1149
+ fun ensureCarPlayNotificationChannel(context: Context) {
1150
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
1151
+ val json = context.getSharedPreferences(NOTIFICATION_CONFIG_PREFS, Context.MODE_PRIVATE)
1152
+ .getString("config", null)
1153
+ val config = try { org.json.JSONObject(json ?: "") } catch (_: Exception) { org.json.JSONObject() }
1154
+ val channelConfig = config.optJSONObject("carPlayChannel")
1155
+
1156
+ val channelName = channelConfig?.optString("name")?.takeIf { it.isNotEmpty() }
1157
+ ?: "CarPlay / Android Auto"
1158
+ val channelDesc = channelConfig?.optString("description")?.takeIf { it.isNotEmpty() }
1159
+ ?: "CarPlay and Android Auto connect/disconnect notifications"
1160
+ val importance = when (channelConfig?.optString("importance")) {
1161
+ "high" -> NotificationManager.IMPORTANCE_HIGH
1162
+ "low" -> NotificationManager.IMPORTANCE_LOW
1163
+ else -> NotificationManager.IMPORTANCE_DEFAULT
1164
+ }
1165
+
1166
+ val notifMgr = context.getSystemService(NotificationManager::class.java)
1167
+ if (notifMgr?.getNotificationChannel(CARPLAY_CHANNEL_ID) == null) {
1168
+ val channel = NotificationChannel(CARPLAY_CHANNEL_ID, channelName, importance).apply {
1169
+ description = channelDesc
1170
+ }
1171
+ notifMgr?.createNotificationChannel(channel)
1172
+ }
1173
+ }
1174
+ }
1175
+
1053
1176
  /**
1054
1177
  * Build the foreground notification from any Context (service or module).
1055
1178
  * Shared so that ExpoBeaconModule can pass the same notification to
@@ -7,6 +7,10 @@ import android.util.Log
7
7
  import androidx.car.app.connection.CarConnection
8
8
  import androidx.lifecycle.LiveData
9
9
  import androidx.lifecycle.Observer
10
+ import java.text.SimpleDateFormat
11
+ import java.util.Date
12
+ import java.util.Locale
13
+ import java.util.TimeZone
10
14
 
11
15
  /**
12
16
  * Wraps [CarConnection] LiveData to surface Android Auto / Automotive OS
@@ -72,6 +76,8 @@ internal class CarPlayMonitor(private val context: Context) {
72
76
  if (lastConnected == connected) return
73
77
  lastConnected = connected
74
78
  val callback = emit ?: return
79
+ val now = System.currentTimeMillis()
80
+ val nowIso = formatIso(now)
75
81
  if (connected) {
76
82
  val transport = when (type) {
77
83
  CarConnection.CONNECTION_TYPE_PROJECTION -> "projection"
@@ -80,15 +86,24 @@ internal class CarPlayMonitor(private val context: Context) {
80
86
  }
81
87
  callback("onCarPlayConnected", mapOf(
82
88
  "transport" to transport,
83
- "timestamp" to System.currentTimeMillis(),
89
+ "timestamp" to now,
90
+ "timestampIso" to nowIso,
84
91
  ))
85
92
  } else {
86
93
  callback("onCarPlayDisconnected", mapOf(
87
- "timestamp" to System.currentTimeMillis(),
94
+ "timestamp" to now,
95
+ "timestampIso" to nowIso,
88
96
  ))
89
97
  }
90
98
  }
91
99
 
100
+ private fun formatIso(millis: Long): String {
101
+ // SimpleDateFormat is not thread-safe — synchronize on the shared instance.
102
+ synchronized(ISO_FORMAT) {
103
+ return ISO_FORMAT.format(Date(millis))
104
+ }
105
+ }
106
+
92
107
  private fun runOnMain(block: () -> Unit) {
93
108
  if (Looper.myLooper() == Looper.getMainLooper()) {
94
109
  block()
@@ -99,5 +114,9 @@ internal class CarPlayMonitor(private val context: Context) {
99
114
 
100
115
  private companion object {
101
116
  const val TAG = "CarPlayMonitor"
117
+ // ISO 8601 UTC with millisecond precision. Safe for all supported APIs (minSdk 23).
118
+ private val ISO_FORMAT = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", Locale.US).apply {
119
+ timeZone = TimeZone.getTimeZone("UTC")
120
+ }
102
121
  }
103
122
  }
@@ -104,14 +104,50 @@ export type NotificationChannelConfig = {
104
104
  */
105
105
  importance?: "low" | "default" | "high";
106
106
  };
107
+ /** Configuration for CarPlay / Android Auto connect/disconnect notifications. */
108
+ export type CarPlayNotificationConfig = {
109
+ /** Whether to show CarPlay connect/disconnect notifications. Default: true. */
110
+ enabled?: boolean;
111
+ /** Notification title on CarPlay/Android Auto connect. Default: "CarPlay Connected". */
112
+ connectedTitle?: string;
113
+ /** Notification title on CarPlay/Android Auto disconnect. Default: "CarPlay Disconnected". */
114
+ disconnectedTitle?: string;
115
+ /**
116
+ * Notification body template. Supports `{event}` ("connected"/"disconnected") and
117
+ * `{transport}` (e.g. "wired", "wireless", "projection", "native", "unknown") placeholders.
118
+ * Note: `{transport}` is only meaningful for connect events; on disconnect it is replaced with an empty string.
119
+ * Default: "CarPlay session {event}".
120
+ */
121
+ body?: string;
122
+ /** Play a sound with the notification (iOS only). Default: true. */
123
+ sound?: boolean;
124
+ /** Android drawable resource name for the notification icon (e.g. "ic_notification"). */
125
+ icon?: string;
126
+ };
127
+ /** Configuration for the Android notification channel used for CarPlay events. */
128
+ export type CarPlayChannelConfig = {
129
+ /** Channel display name shown in system settings. Default: "CarPlay / Android Auto". */
130
+ name?: string;
131
+ /** Channel description shown in system settings. Default: "CarPlay and Android Auto connect/disconnect notifications". */
132
+ description?: string;
133
+ /**
134
+ * Channel importance level. Default: 'default' (so connect/disconnect events make a sound).
135
+ * Note: Android may ignore decreases in importance after first channel creation until the app is reinstalled.
136
+ */
137
+ importance?: "low" | "default" | "high";
138
+ };
107
139
  /** Combined notification configuration for all notification types. */
108
140
  export type NotificationConfig = {
109
141
  /** Settings for beacon enter/exit event notifications. */
110
142
  beaconEvents?: BeaconNotificationConfig;
143
+ /** Settings for CarPlay / Android Auto connect/disconnect notifications. */
144
+ carPlayEvents?: CarPlayNotificationConfig;
111
145
  /** Settings for the persistent foreground service notification (Android only). */
112
146
  foregroundService?: ForegroundServiceConfig;
113
147
  /** Settings for the Android notification channel (Android only). */
114
148
  channel?: NotificationChannelConfig;
149
+ /** Settings for the Android notification channel used for CarPlay events (Android only). */
150
+ carPlayChannel?: CarPlayChannelConfig;
115
151
  };
116
152
  /** Snapshot of the current monitoring configuration and active state. */
117
153
  export type MonitoringConfig = {
@@ -261,11 +297,15 @@ export type CarPlayConnectedEvent = {
261
297
  transport: CarPlayTransport;
262
298
  /** Timestamp in milliseconds since epoch. */
263
299
  timestamp: number;
300
+ /** ISO 8601 UTC representation of {@link timestamp} (e.g. "2026-05-12T14:23:45.678Z"). */
301
+ timestampIso?: string;
264
302
  };
265
303
  /** Payload fired when the device disconnects from a CarPlay or Android Auto session. */
266
304
  export type CarPlayDisconnectedEvent = {
267
305
  /** Timestamp in milliseconds since epoch. */
268
306
  timestamp: number;
307
+ /** ISO 8601 UTC representation of {@link timestamp} (e.g. "2026-05-12T14:23:45.678Z"). */
308
+ timestampIso?: string;
269
309
  };
270
310
  /** Payload for native beacon error events (monitoring/ranging failures). */
271
311
  export type BeaconErrorEvent = {
@@ -1 +1 @@
1
- {"version":3,"file":"ExpoBeacon.types.d.ts","sourceRoot":"","sources":["../src/ExpoBeacon.types.ts"],"names":[],"mappings":"AAAA,2CAA2C;AAC3C,MAAM,MAAM,gBAAgB,GAAG;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,0GAA0G;IAC1G,IAAI,CAAC,EAAE,MAAM,CAAC;CACf,CAAC;AAEF;;;;;GAKG;AACH,MAAM,MAAM,YAAY,GAAG;IACzB,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,gEAAgE;IAChE,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;;;;;;;OAOG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB,CAAC;AAEF,4CAA4C;AAC5C,MAAM,MAAM,iBAAiB,GAAG;IAC9B,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,OAAO,GAAG,MAAM,CAAC;IACxB,gFAAgF;IAChF,QAAQ,EAAE,MAAM,CAAC;IACjB,0EAA0E;IAC1E,IAAI,CAAC,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,qEAAqE;AACrE,MAAM,MAAM,mBAAmB,GAAG;IAChC,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,iDAAiD;IACjD,IAAI,CAAC,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,mFAAmF;AACnF,MAAM,MAAM,kBAAkB,GAAG;IAC/B,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,gEAAgE;IAChE,QAAQ,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF,+DAA+D;AAC/D,MAAM,MAAM,wBAAwB,GAAG;IACrC,+DAA+D;IAC/D,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,qEAAqE;IACrE,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,mEAAmE;IACnE,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,uEAAuE;IACvE,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;;OAGG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,oEAAoE;IACpE,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,yFAAyF;IACzF,IAAI,CAAC,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,mGAAmG;AACnG,MAAM,MAAM,uBAAuB,GAAG;IACpC,iFAAiF;IACjF,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,sGAAsG;IACtG,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,gEAAgE;IAChE,IAAI,CAAC,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,0DAA0D;AAC1D,MAAM,MAAM,yBAAyB,GAAG;IACtC,mFAAmF;IACnF,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,8GAA8G;IAC9G,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;OAGG;IACH,UAAU,CAAC,EAAE,KAAK,GAAG,SAAS,GAAG,MAAM,CAAC;CACzC,CAAC;AAEF,sEAAsE;AACtE,MAAM,MAAM,kBAAkB,GAAG;IAC/B,0DAA0D;IAC1D,YAAY,CAAC,EAAE,wBAAwB,CAAC;IACxC,kFAAkF;IAClF,iBAAiB,CAAC,EAAE,uBAAuB,CAAC;IAC5C,oEAAoE;IACpE,OAAO,CAAC,EAAE,yBAAyB,CAAC;CACrC,CAAC;AAEF,yEAAyE;AACzE,MAAM,MAAM,gBAAgB,GAAG;IAC7B,yDAAyD;IACzD,YAAY,EAAE,OAAO,CAAC;IACtB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,KAAK,GAAG,QAAQ,CAAC;IACzB,mFAAmF;IACnF,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,aAAa,CAAC,EAAE,kBAAkB,CAAC;CACpC,CAAC;AAEF,4DAA4D;AAC5D,MAAM,MAAM,oBAAoB,GAC5B;IACE,IAAI,EAAE,SAAS,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,SAAS,GAAG,QAAQ,CAAC;IAC5B,uFAAuF;IACvF,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;CACzB,GACD;IACE,IAAI,EAAE,WAAW,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,SAAS,GAAG,QAAQ,CAAC;IAC5B,uFAAuF;IACvF,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;CACzB,CAAC;AAEN,6CAA6C;AAC7C,MAAM,MAAM,iBAAiB,GAAG;IAC9B;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;;;;;OAOG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;;;;;OAMG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;;;OAKG;IACH,KAAK,CAAC,EAAE,KAAK,GAAG,QAAQ,CAAC;IACzB;;;;;OAKG;IACH,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,iFAAiF;IACjF,aAAa,CAAC,EAAE,kBAAkB,CAAC;CACpC,CAAC;AAEF,4BAA4B;AAC5B,MAAM,MAAM,kBAAkB,GAAG,KAAK,GAAG,KAAK,CAAC;AAE/C,qDAAqD;AACrD,MAAM,MAAM,mBAAmB,GAAG;IAChC,SAAS,EAAE,kBAAkB,CAAC;IAC9B,6EAA6E;IAC7E,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,2EAA2E;IAC3E,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,2CAA2C;IAC3C,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,mCAAmC;IACnC,IAAI,CAAC,EAAE,MAAM,CAAC;CACf,CAAC;AAEF;;;;;GAKG;AACH,MAAM,MAAM,eAAe,GAAG;IAC5B,UAAU,EAAE,MAAM,CAAC;IACnB,qDAAqD;IACrD,SAAS,EAAE,MAAM,CAAC;IAClB,mDAAmD;IACnD,QAAQ,EAAE,MAAM,CAAC;IACjB,gEAAgE;IAChE,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;;;;;;;OAOG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB,CAAC;AAEF,sDAAsD;AACtD,MAAM,MAAM,oBAAoB,GAAG;IACjC,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,OAAO,GAAG,MAAM,CAAC;IACxB,gFAAgF;IAChF,QAAQ,EAAE,MAAM,CAAC;IACjB,0EAA0E;IAC1E,IAAI,CAAC,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,+EAA+E;AAC/E,MAAM,MAAM,sBAAsB,GAAG;IACnC,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,iDAAiD;IACjD,IAAI,CAAC,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,sFAAsF;AACtF,MAAM,MAAM,qBAAqB,GAAG;IAClC,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,gEAAgE;IAChE,QAAQ,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF,wEAAwE;AACxE,MAAM,MAAM,gBAAgB,GACxB,OAAO,GACP,UAAU,GACV,YAAY,GACZ,QAAQ,GACR,SAAS,CAAC;AAEd,mFAAmF;AACnF,MAAM,MAAM,qBAAqB,GAAG;IAClC,SAAS,EAAE,gBAAgB,CAAC;IAC5B,6CAA6C;IAC7C,SAAS,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF,wFAAwF;AACxF,MAAM,MAAM,wBAAwB,GAAG;IACrC,6CAA6C;IAC7C,SAAS,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF,4EAA4E;AAC5E,MAAM,MAAM,gBAAgB,GAAG;IAC7B,oEAAoE;IACpE,UAAU,EAAE,MAAM,CAAC;IACnB,sGAAsG;IACtG,IAAI,EAAE,MAAM,CAAC;IACb,0DAA0D;IAC1D,OAAO,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF,wBAAwB;AACxB,MAAM,MAAM,sBAAsB,GAAG;IACnC,aAAa,EAAE,CAAC,MAAM,EAAE,iBAAiB,KAAK,IAAI,CAAC;IACnD,YAAY,EAAE,CAAC,MAAM,EAAE,iBAAiB,KAAK,IAAI,CAAC;IAClD,gBAAgB,EAAE,CAAC,MAAM,EAAE,mBAAmB,KAAK,IAAI,CAAC;IACxD,2GAA2G;IAC3G,eAAe,EAAE,CAAC,MAAM,EAAE,kBAAkB,KAAK,IAAI,CAAC;IACtD,yEAAyE;IACzE,aAAa,EAAE,CAAC,MAAM,EAAE,gBAAgB,KAAK,IAAI,CAAC;IAClD,kFAAkF;IAClF,gBAAgB,EAAE,CAAC,MAAM,EAAE,mBAAmB,KAAK,IAAI,CAAC;IACxD,gBAAgB,EAAE,CAAC,MAAM,EAAE,oBAAoB,KAAK,IAAI,CAAC;IACzD,eAAe,EAAE,CAAC,MAAM,EAAE,oBAAoB,KAAK,IAAI,CAAC;IACxD,mBAAmB,EAAE,CAAC,MAAM,EAAE,sBAAsB,KAAK,IAAI,CAAC;IAC9D,8GAA8G;IAC9G,kBAAkB,EAAE,CAAC,MAAM,EAAE,qBAAqB,KAAK,IAAI,CAAC;IAC5D,mGAAmG;IACnG,aAAa,EAAE,CAAC,MAAM,EAAE,gBAAgB,KAAK,IAAI,CAAC;IAClD,2FAA2F;IAC3F,kBAAkB,EAAE,CAAC,MAAM,EAAE,qBAAqB,KAAK,IAAI,CAAC;IAC5D,gGAAgG;IAChG,qBAAqB,EAAE,CAAC,MAAM,EAAE,wBAAwB,KAAK,IAAI,CAAC;CACnE,CAAC;AAEF,wCAAwC;AACxC,MAAM,MAAM,oBAAoB,GAAG;IACjC,2EAA2E;IAC3E,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,mEAAmE;IACnE,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,wEAAwE;IACxE,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB,CAAC;AAEF,0CAA0C;AAC1C,MAAM,MAAM,aAAa,GAAG;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,6CAA6C;IAC7C,SAAS,EAAE,MAAM,CAAC;IAClB,6DAA6D;IAC7D,SAAS,EAAE,MAAM,CAAC;IAClB,uCAAuC;IACvC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,kDAAkD;IAClD,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAC/B,CAAC"}
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/** 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 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};\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};\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};\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\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"]}
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, ForegroundServiceConfig, NotificationChannelConfig, EddystoneFrameType, EddystoneScanResult, PairedEddystone, EddystoneRegionEvent, EddystoneDistanceEvent, EddystoneTimeoutEvent, EventLogQueryOptions, EventLogEntry, CarPlayTransport, CarPlayConnectedEvent, CarPlayDisconnectedEvent, } 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, } from "./ExpoBeacon.types";
3
3
  //# sourceMappingURL=index.d.ts.map
@@ -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,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,GACzB,MAAM,oBAAoB,CAAC"}
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,GACzB,MAAM,oBAAoB,CAAC"}
@@ -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 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} 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} from \"./ExpoBeacon.types\";\r\n"]}
@@ -20,6 +20,16 @@ final class CarPlayMonitor {
20
20
  private let log = OSLog(subsystem: "expo.modules.beacon", category: "CarPlayMonitor")
21
21
  private let queue = DispatchQueue.main
22
22
 
23
+ /// Cached ISO8601 formatter (UTC, fractional seconds). Reused across emits
24
+ /// to avoid per-event allocation. `ISO8601DateFormatter` is documented as
25
+ /// thread-safe.
26
+ private static let isoFormatter: ISO8601DateFormatter = {
27
+ let f = ISO8601DateFormatter()
28
+ f.formatOptions = [.withInternetDateTime, .withFractionalSeconds]
29
+ f.timeZone = TimeZone(identifier: "UTC")
30
+ return f
31
+ }()
32
+
23
33
  private var observer: NSObjectProtocol?
24
34
  private var emit: Emit?
25
35
  private var isConnected: Bool = false
@@ -170,16 +180,20 @@ final class CarPlayMonitor {
170
180
  }
171
181
 
172
182
  private func emitConnected(transport: String) {
183
+ let now = Date()
173
184
  let payload: [String: Any] = [
174
185
  "transport": transport,
175
- "timestamp": Date().timeIntervalSince1970 * 1000.0,
186
+ "timestamp": now.timeIntervalSince1970 * 1000.0,
187
+ "timestampIso": Self.isoFormatter.string(from: now),
176
188
  ]
177
189
  emit?("onCarPlayConnected", payload)
178
190
  }
179
191
 
180
192
  private func emitDisconnected() {
193
+ let now = Date()
181
194
  let payload: [String: Any] = [
182
- "timestamp": Date().timeIntervalSince1970 * 1000.0,
195
+ "timestamp": now.timeIntervalSince1970 * 1000.0,
196
+ "timestampIso": Self.isoFormatter.string(from: now),
183
197
  ]
184
198
  emit?("onCarPlayDisconnected", payload)
185
199
  }
@@ -7,7 +7,19 @@ extension ExpoBeaconModule {
7
7
  /// (see `CarPlayMonitor.start(emit:)` semantics).
8
8
  func startCarPlayMonitoringInternal() {
9
9
  CarPlayMonitor.shared.start { [weak self] eventName, payload in
10
- self?.sendLoggedEvent(eventName, payload)
10
+ guard let self = self else { return }
11
+ self.sendLoggedEvent(eventName, payload)
12
+ switch eventName {
13
+ case "onCarPlayConnected":
14
+ self.postCarPlayNotification(
15
+ eventType: "connected",
16
+ transport: payload["transport"] as? String
17
+ )
18
+ case "onCarPlayDisconnected":
19
+ self.postCarPlayNotification(eventType: "disconnected", transport: nil)
20
+ default:
21
+ break
22
+ }
11
23
  }
12
24
  // Tier 2 fallback: subscribe to background-wake signals so suspended
13
25
  // apps still notice CarPlay route changes that happened off-process.
@@ -46,6 +46,48 @@ extension ExpoBeaconModule {
46
46
  UNUserNotificationCenter.current().add(request, withCompletionHandler: nil)
47
47
  }
48
48
 
49
+ /// Post a local notification when a CarPlay session connects or disconnects.
50
+ /// `eventType` is `"connected"` or `"disconnected"`. `transport` is the
51
+ /// transport string from the connect payload (e.g. "wired", "wireless");
52
+ /// pass `nil` on disconnect — the `{transport}` body placeholder is then
53
+ /// substituted with an empty string.
54
+ func postCarPlayNotification(eventType: String, transport: String?) {
55
+ let cfg = loadNotificationConfig()
56
+ let eventsCfg = cfg["carPlayEvents"] as? [String: Any]
57
+
58
+ // Respect the enabled flag (defaults to true)
59
+ if let enabled = eventsCfg?["enabled"] as? Bool, !enabled { return }
60
+
61
+ let defaultTitle = eventType == "connected" ? "CarPlay Connected" : "CarPlay Disconnected"
62
+ let title: String
63
+ switch eventType {
64
+ case "connected":
65
+ title = (eventsCfg?["connectedTitle"] as? String).flatMap { $0.isEmpty ? nil : $0 } ?? defaultTitle
66
+ default:
67
+ title = (eventsCfg?["disconnectedTitle"] as? String).flatMap { $0.isEmpty ? nil : $0 } ?? defaultTitle
68
+ }
69
+
70
+ let bodyTemplate = (eventsCfg?["body"] as? String).flatMap { $0.isEmpty ? nil : $0 }
71
+ ?? "CarPlay session {event}"
72
+ let body = bodyTemplate
73
+ .replacingOccurrences(of: "{event}", with: eventType)
74
+ .replacingOccurrences(of: "{transport}", with: transport ?? "")
75
+
76
+ let content = UNMutableNotificationContent()
77
+ content.title = title
78
+ content.body = body
79
+
80
+ let playSound = eventsCfg?["sound"] as? Bool ?? true
81
+ if playSound { content.sound = .default }
82
+
83
+ let request = UNNotificationRequest(
84
+ identifier: "carplay_\(eventType)_\(Date().timeIntervalSince1970)",
85
+ content: content,
86
+ trigger: nil
87
+ )
88
+ UNUserNotificationCenter.current().add(request, withCompletionHandler: nil)
89
+ }
90
+
49
91
  func loadNotificationConfig() -> [String: Any] {
50
92
  guard let json = self.defaults.string(forKey: NOTIFICATION_CONFIG_KEY),
51
93
  let data = json.data(using: .utf8) else { return [:] }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "expo-beacon",
3
- "version": "0.8.2",
3
+ "version": "0.8.3",
4
4
  "description": "Expo module for scanning, pairing, and monitoring iBeacons on Android and iOS",
5
5
  "main": "build/index.js",
6
6
  "types": "build/index.d.ts",
@@ -112,14 +112,52 @@ export type NotificationChannelConfig = {
112
112
  importance?: "low" | "default" | "high";
113
113
  };
114
114
 
115
+ /** Configuration for CarPlay / Android Auto connect/disconnect notifications. */
116
+ export type CarPlayNotificationConfig = {
117
+ /** Whether to show CarPlay connect/disconnect notifications. Default: true. */
118
+ enabled?: boolean;
119
+ /** Notification title on CarPlay/Android Auto connect. Default: "CarPlay Connected". */
120
+ connectedTitle?: string;
121
+ /** Notification title on CarPlay/Android Auto disconnect. Default: "CarPlay Disconnected". */
122
+ disconnectedTitle?: string;
123
+ /**
124
+ * Notification body template. Supports `{event}` ("connected"/"disconnected") and
125
+ * `{transport}` (e.g. "wired", "wireless", "projection", "native", "unknown") placeholders.
126
+ * Note: `{transport}` is only meaningful for connect events; on disconnect it is replaced with an empty string.
127
+ * Default: "CarPlay session {event}".
128
+ */
129
+ body?: string;
130
+ /** Play a sound with the notification (iOS only). Default: true. */
131
+ sound?: boolean;
132
+ /** Android drawable resource name for the notification icon (e.g. "ic_notification"). */
133
+ icon?: string;
134
+ };
135
+
136
+ /** Configuration for the Android notification channel used for CarPlay events. */
137
+ export type CarPlayChannelConfig = {
138
+ /** Channel display name shown in system settings. Default: "CarPlay / Android Auto". */
139
+ name?: string;
140
+ /** Channel description shown in system settings. Default: "CarPlay and Android Auto connect/disconnect notifications". */
141
+ description?: string;
142
+ /**
143
+ * Channel importance level. Default: 'default' (so connect/disconnect events make a sound).
144
+ * Note: Android may ignore decreases in importance after first channel creation until the app is reinstalled.
145
+ */
146
+ importance?: "low" | "default" | "high";
147
+ };
148
+
115
149
  /** Combined notification configuration for all notification types. */
116
150
  export type NotificationConfig = {
117
151
  /** Settings for beacon enter/exit event notifications. */
118
152
  beaconEvents?: BeaconNotificationConfig;
153
+ /** Settings for CarPlay / Android Auto connect/disconnect notifications. */
154
+ carPlayEvents?: CarPlayNotificationConfig;
119
155
  /** Settings for the persistent foreground service notification (Android only). */
120
156
  foregroundService?: ForegroundServiceConfig;
121
157
  /** Settings for the Android notification channel (Android only). */
122
158
  channel?: NotificationChannelConfig;
159
+ /** Settings for the Android notification channel used for CarPlay events (Android only). */
160
+ carPlayChannel?: CarPlayChannelConfig;
123
161
  };
124
162
 
125
163
  /** Snapshot of the current monitoring configuration and active state. */
@@ -287,12 +325,16 @@ export type CarPlayConnectedEvent = {
287
325
  transport: CarPlayTransport;
288
326
  /** Timestamp in milliseconds since epoch. */
289
327
  timestamp: number;
328
+ /** ISO 8601 UTC representation of {@link timestamp} (e.g. "2026-05-12T14:23:45.678Z"). */
329
+ timestampIso?: string;
290
330
  };
291
331
 
292
332
  /** Payload fired when the device disconnects from a CarPlay or Android Auto session. */
293
333
  export type CarPlayDisconnectedEvent = {
294
334
  /** Timestamp in milliseconds since epoch. */
295
335
  timestamp: number;
336
+ /** ISO 8601 UTC representation of {@link timestamp} (e.g. "2026-05-12T14:23:45.678Z"). */
337
+ timestampIso?: string;
296
338
  };
297
339
 
298
340
  /** Payload for native beacon error events (monitoring/ranging failures). */
package/src/index.ts CHANGED
@@ -14,6 +14,8 @@ export type {
14
14
  MonitoringConfig,
15
15
  MonitoredDeviceState,
16
16
  BeaconNotificationConfig,
17
+ CarPlayNotificationConfig,
18
+ CarPlayChannelConfig,
17
19
  ForegroundServiceConfig,
18
20
  NotificationChannelConfig,
19
21
  EddystoneFrameType,