therms-device-tracker 1.0.0-rc.2 → 1.0.0-rc.4

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/CHANGELOG.md CHANGED
@@ -7,6 +7,24 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [1.0.0-rc.4] - 2026-06-19
11
+
12
+ ### Fixed
13
+ - **Critical crash on Android 14+ (API 34+)**: `SecurityException: One of the RECEIVER_EXPORTED or RECEIVER_NOT_EXPORTED should be specified...`
14
+ - All dynamic `context.registerReceiver(...)` calls (5 sites in `ThermsDeviceTrackerModule.kt`) updated to use `ContextCompat.registerReceiver(..., ContextCompat.RECEIVER_NOT_EXPORTED)`.
15
+ - These are internal app-private receivers for custom actions (bg location, provider changes, geofence, sync, activity).
16
+ - Added `setPackage(...)` to the corresponding `sendBroadcast` calls for explicit delivery (ThermsLocationService, SyncProvider, GeofenceTransitionReceiver).
17
+ - Declared `GeofenceTransitionReceiver` statically in AndroidManifest.xml with `android:exported="false"` for modern compatibility.
18
+ - ContextCompat was already a dependency/import; change is backward compatible.
19
+
20
+ ## [1.0.0-rc.3] - 2026-06-19
21
+
22
+ ### Fixed
23
+ - **Critical Android build failure**: Compilation errors in `compileDebugKotlin`.
24
+ - `ThermsDeviceTrackerModule.kt:464`: Removed stray Swift `nil` literal in `sendEvent` for `onMotionChange` (was `location to nil`, now `null`). Other call sites already used `null` or `toLocationDict(...)`.
25
+ - `LocationProvider.kt`: Removed `fun getClient()` which caused JVM signature clash with the Kotlin-generated getter for the private `val client` property (`getClient(): FusedLocationProviderClient`). The constructor injection seam (`fusedClient` param) and internal `client` usage remain; no external callers depended on `getClient()`.
26
+ - Updated deprecated `lintOptions` to modern `lint { abortOnError = false }` in `android/build.gradle`.
27
+
10
28
  ## [1.0.0-rc.2] - 2026-06-18
11
29
 
12
30
  ### Fixed
@@ -4,16 +4,16 @@ plugins {
4
4
  }
5
5
 
6
6
  group = 'expo.modules.thermsdevicetracker'
7
- version = '1.0.0-rc.2'
7
+ version = '1.0.0-rc.4'
8
8
 
9
9
  android {
10
10
  namespace "expo.modules.thermsdevicetracker"
11
11
  defaultConfig {
12
12
  versionCode 1
13
- versionName "1.0.0-rc.2"
13
+ versionName "1.0.0-rc.4"
14
14
  }
15
- lintOptions {
16
- abortOnError false
15
+ lint {
16
+ abortOnError = false
17
17
  }
18
18
  }
19
19
 
@@ -19,5 +19,13 @@
19
19
  android:name="expo.modules.thermsdevicetracker.ThermsLocationService"
20
20
  android:foregroundServiceType="location"
21
21
  android:exported="false" />
22
+
23
+ <!--
24
+ Geofence transition receiver. Used via explicit PendingIntent from GeofencingClient.
25
+ Declared explicitly with exported=false for API 34+ compatibility (even though intent targets class).
26
+ -->
27
+ <receiver
28
+ android:name="expo.modules.thermsdevicetracker.GeofenceTransitionReceiver"
29
+ android:exported="false" />
22
30
  </application>
23
31
  </manifest>
@@ -29,6 +29,7 @@ class GeofenceTransitionReceiver : BroadcastReceiver() {
29
29
  putExtra(EXTRA_TRANSITION, transition)
30
30
  putStringArrayListExtra(EXTRA_IDS, ids)
31
31
  }
32
+ outIntent.setPackage(context.packageName)
32
33
  context.sendBroadcast(outIntent)
33
34
  }
34
35
  }
@@ -21,7 +21,7 @@ import com.google.android.gms.location.*
21
21
  * Seam: module wires `onNewLocation` callback (or consumes via start).
22
22
  * No direct sendEvent here; module owns event + state + sync trigger (keeps provider thin).
23
23
  *
24
- * Test seam precedent: callers can inject a mock FusedLocationProviderClient.
24
+ * Test seam precedent: callers can inject a mock FusedLocationProviderClient via the constructor parameter.
25
25
  */
26
26
  class LocationProvider(
27
27
  private val context: Context,
@@ -79,6 +79,4 @@ class LocationProvider(
79
79
  }
80
80
  currentCallback = null
81
81
  }
82
-
83
- fun getClient(): FusedLocationProviderClient = client
84
82
  }
@@ -286,6 +286,7 @@ class SyncProvider(
286
286
  putExtra(EXTRA_COUNT, count)
287
287
  message?.let { putExtra(EXTRA_MESSAGE, it) }
288
288
  }
289
+ intent.setPackage(applicationContext.packageName)
289
290
  applicationContext.sendBroadcast(intent)
290
291
  }
291
292
  }
@@ -461,7 +461,7 @@ class ThermsDeviceTrackerModule : Module() {
461
461
 
462
462
  syncProvider.stop()
463
463
  lastSyncConfig = null
464
- sendEvent("onMotionChange", mapOf("isMoving" to false, "location" to nil))
464
+ sendEvent("onMotionChange", mapOf("isMoving" to false, "location" to null))
465
465
  // Note: schedule lifecycle independent (no auto stopSchedule on stopTracking; call explicitly if needed)
466
466
  }
467
467
 
@@ -496,7 +496,7 @@ class ThermsDeviceTrackerModule : Module() {
496
496
  }
497
497
  }
498
498
  val filter = IntentFilter(ThermsLocationService.BROADCAST_ACTION)
499
- context.registerReceiver(bgReceiver, filter)
499
+ ContextCompat.registerReceiver(context, bgReceiver, filter, ContextCompat.RECEIVER_NOT_EXPORTED)
500
500
  }
501
501
 
502
502
  private fun unregisterBgReceiver() {
@@ -516,7 +516,7 @@ class ThermsDeviceTrackerModule : Module() {
516
516
  }
517
517
  }
518
518
  val filter = IntentFilter(android.location.LocationManager.PROVIDERS_CHANGED_ACTION)
519
- context.registerReceiver(providerReceiver, filter)
519
+ ContextCompat.registerReceiver(context, providerReceiver, filter, ContextCompat.RECEIVER_NOT_EXPORTED)
520
520
  }
521
521
 
522
522
  private fun unregisterProviderReceiver() {
@@ -654,7 +654,7 @@ class ThermsDeviceTrackerModule : Module() {
654
654
  geofenceProvider.handleTransition(transition, ids)
655
655
  }
656
656
  }
657
- context.registerReceiver(geofenceReceiver, IntentFilter(GeofenceTransitionReceiver.ACTION))
657
+ ContextCompat.registerReceiver(context, geofenceReceiver, IntentFilter(GeofenceTransitionReceiver.ACTION), ContextCompat.RECEIVER_NOT_EXPORTED)
658
658
  }
659
659
 
660
660
  private fun unregisterGeofenceReceiver() {
@@ -674,7 +674,7 @@ class ThermsDeviceTrackerModule : Module() {
674
674
  syncProvider.handleSyncResult(intent)
675
675
  }
676
676
  }
677
- context.registerReceiver(syncReceiver, IntentFilter(SyncProvider.SYNC_RESULT_ACTION))
677
+ ContextCompat.registerReceiver(context, syncReceiver, IntentFilter(SyncProvider.SYNC_RESULT_ACTION), ContextCompat.RECEIVER_NOT_EXPORTED)
678
678
  }
679
679
 
680
680
  private fun unregisterSyncReceiver() {
@@ -697,7 +697,7 @@ class ThermsDeviceTrackerModule : Module() {
697
697
  }
698
698
  }
699
699
  val filter = IntentFilter(ActivityRecognitionProvider.ACTION_ACTIVITY_UPDATE)
700
- context.registerReceiver(activityReceiver, filter)
700
+ ContextCompat.registerReceiver(context, activityReceiver, filter, ContextCompat.RECEIVER_NOT_EXPORTED)
701
701
  }
702
702
 
703
703
  private fun unregisterActivityReceiver() {
@@ -71,6 +71,7 @@ class ThermsLocationService : Service() {
71
71
  putExtra(EXTRA_SPEED, if (loc.hasSpeed()) loc.speed else -1f)
72
72
  putExtra(EXTRA_TIMESTAMP, loc.time)
73
73
  }
74
+ i.setPackage(packageName)
74
75
  sendBroadcast(i)
75
76
  }
76
77
  }
@@ -1,6 +1,6 @@
1
1
  Pod::Spec.new do |s|
2
2
  s.name = 'ThermsDeviceTracker'
3
- s.version = '1.0.0-rc.2'
3
+ s.version = '1.0.0-rc.4'
4
4
  s.summary = 'Device physical activity and geolocation tracking for THERMS'
5
5
  s.description = 'Expo native module providing unified access to location updates, physical activity recognition (walking/running/etc), and pedometer data with foreground and background support.'
6
6
  s.author = 'Cory Robinson <cory@therms.io>'
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "therms-device-tracker",
3
- "version": "1.0.0-rc.2",
3
+ "version": "1.0.0-rc.4",
4
4
  "description": "THERMS software expo app device physical activity and geo location tracking",
5
5
  "main": "build/index.js",
6
6
  "types": "build/index.d.ts",