expo-location 19.0.9-canary-20260105-6b962e6 → 19.1.0-canary-20260113-0ce2b9c

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.
Files changed (51) hide show
  1. package/CHANGELOG.md +3 -0
  2. package/android/build.gradle +2 -2
  3. package/android/src/main/java/expo/modules/location/services/LocationTaskService.kt +20 -1
  4. package/android/src/main/java/expo/modules/location/taskConsumers/LocationTaskConsumer.kt +49 -8
  5. package/expo-module.config.json +1 -1
  6. package/ios/Requesters/EXBaseLocationRequester.m +2 -1
  7. package/local-maven-repo/host/exp/exponent/expo.modules.location/{19.0.9-canary-20260105-6b962e6/expo.modules.location-19.0.9-canary-20260105-6b962e6-sources.jar → 19.1.0-canary-20260113-0ce2b9c/expo.modules.location-19.1.0-canary-20260113-0ce2b9c-sources.jar} +0 -0
  8. package/local-maven-repo/host/exp/exponent/expo.modules.location/19.1.0-canary-20260113-0ce2b9c/expo.modules.location-19.1.0-canary-20260113-0ce2b9c-sources.jar.md5 +1 -0
  9. package/local-maven-repo/host/exp/exponent/expo.modules.location/19.1.0-canary-20260113-0ce2b9c/expo.modules.location-19.1.0-canary-20260113-0ce2b9c-sources.jar.sha1 +1 -0
  10. package/local-maven-repo/host/exp/exponent/expo.modules.location/19.1.0-canary-20260113-0ce2b9c/expo.modules.location-19.1.0-canary-20260113-0ce2b9c-sources.jar.sha256 +1 -0
  11. package/local-maven-repo/host/exp/exponent/expo.modules.location/19.1.0-canary-20260113-0ce2b9c/expo.modules.location-19.1.0-canary-20260113-0ce2b9c-sources.jar.sha512 +1 -0
  12. package/local-maven-repo/host/exp/exponent/expo.modules.location/{19.0.9-canary-20260105-6b962e6/expo.modules.location-19.0.9-canary-20260105-6b962e6.aar → 19.1.0-canary-20260113-0ce2b9c/expo.modules.location-19.1.0-canary-20260113-0ce2b9c.aar} +0 -0
  13. package/local-maven-repo/host/exp/exponent/expo.modules.location/19.1.0-canary-20260113-0ce2b9c/expo.modules.location-19.1.0-canary-20260113-0ce2b9c.aar.md5 +1 -0
  14. package/local-maven-repo/host/exp/exponent/expo.modules.location/19.1.0-canary-20260113-0ce2b9c/expo.modules.location-19.1.0-canary-20260113-0ce2b9c.aar.sha1 +1 -0
  15. package/local-maven-repo/host/exp/exponent/expo.modules.location/19.1.0-canary-20260113-0ce2b9c/expo.modules.location-19.1.0-canary-20260113-0ce2b9c.aar.sha256 +1 -0
  16. package/local-maven-repo/host/exp/exponent/expo.modules.location/19.1.0-canary-20260113-0ce2b9c/expo.modules.location-19.1.0-canary-20260113-0ce2b9c.aar.sha512 +1 -0
  17. package/local-maven-repo/host/exp/exponent/expo.modules.location/{19.0.9-canary-20260105-6b962e6/expo.modules.location-19.0.9-canary-20260105-6b962e6.module → 19.1.0-canary-20260113-0ce2b9c/expo.modules.location-19.1.0-canary-20260113-0ce2b9c.module} +22 -22
  18. package/local-maven-repo/host/exp/exponent/expo.modules.location/19.1.0-canary-20260113-0ce2b9c/expo.modules.location-19.1.0-canary-20260113-0ce2b9c.module.md5 +1 -0
  19. package/local-maven-repo/host/exp/exponent/expo.modules.location/19.1.0-canary-20260113-0ce2b9c/expo.modules.location-19.1.0-canary-20260113-0ce2b9c.module.sha1 +1 -0
  20. package/local-maven-repo/host/exp/exponent/expo.modules.location/19.1.0-canary-20260113-0ce2b9c/expo.modules.location-19.1.0-canary-20260113-0ce2b9c.module.sha256 +1 -0
  21. package/local-maven-repo/host/exp/exponent/expo.modules.location/19.1.0-canary-20260113-0ce2b9c/expo.modules.location-19.1.0-canary-20260113-0ce2b9c.module.sha512 +1 -0
  22. package/local-maven-repo/host/exp/exponent/expo.modules.location/{19.0.9-canary-20260105-6b962e6/expo.modules.location-19.0.9-canary-20260105-6b962e6.pom → 19.1.0-canary-20260113-0ce2b9c/expo.modules.location-19.1.0-canary-20260113-0ce2b9c.pom} +1 -1
  23. package/local-maven-repo/host/exp/exponent/expo.modules.location/19.1.0-canary-20260113-0ce2b9c/expo.modules.location-19.1.0-canary-20260113-0ce2b9c.pom.md5 +1 -0
  24. package/local-maven-repo/host/exp/exponent/expo.modules.location/19.1.0-canary-20260113-0ce2b9c/expo.modules.location-19.1.0-canary-20260113-0ce2b9c.pom.sha1 +1 -0
  25. package/local-maven-repo/host/exp/exponent/expo.modules.location/19.1.0-canary-20260113-0ce2b9c/expo.modules.location-19.1.0-canary-20260113-0ce2b9c.pom.sha256 +1 -0
  26. package/local-maven-repo/host/exp/exponent/expo.modules.location/19.1.0-canary-20260113-0ce2b9c/expo.modules.location-19.1.0-canary-20260113-0ce2b9c.pom.sha512 +1 -0
  27. package/local-maven-repo/host/exp/exponent/expo.modules.location/maven-metadata.xml +4 -4
  28. package/local-maven-repo/host/exp/exponent/expo.modules.location/maven-metadata.xml.md5 +1 -1
  29. package/local-maven-repo/host/exp/exponent/expo.modules.location/maven-metadata.xml.sha1 +1 -1
  30. package/local-maven-repo/host/exp/exponent/expo.modules.location/maven-metadata.xml.sha256 +1 -1
  31. package/local-maven-repo/host/exp/exponent/expo.modules.location/maven-metadata.xml.sha512 +1 -1
  32. package/package.json +6 -3
  33. package/plugin/build/withLocation.d.ts +18 -0
  34. package/plugin/build/withLocation.js +89 -1
  35. package/plugin/src/withLocation.ts +121 -0
  36. package/local-maven-repo/host/exp/exponent/expo.modules.location/19.0.9-canary-20260105-6b962e6/expo.modules.location-19.0.9-canary-20260105-6b962e6-sources.jar.md5 +0 -1
  37. package/local-maven-repo/host/exp/exponent/expo.modules.location/19.0.9-canary-20260105-6b962e6/expo.modules.location-19.0.9-canary-20260105-6b962e6-sources.jar.sha1 +0 -1
  38. package/local-maven-repo/host/exp/exponent/expo.modules.location/19.0.9-canary-20260105-6b962e6/expo.modules.location-19.0.9-canary-20260105-6b962e6-sources.jar.sha256 +0 -1
  39. package/local-maven-repo/host/exp/exponent/expo.modules.location/19.0.9-canary-20260105-6b962e6/expo.modules.location-19.0.9-canary-20260105-6b962e6-sources.jar.sha512 +0 -1
  40. package/local-maven-repo/host/exp/exponent/expo.modules.location/19.0.9-canary-20260105-6b962e6/expo.modules.location-19.0.9-canary-20260105-6b962e6.aar.md5 +0 -1
  41. package/local-maven-repo/host/exp/exponent/expo.modules.location/19.0.9-canary-20260105-6b962e6/expo.modules.location-19.0.9-canary-20260105-6b962e6.aar.sha1 +0 -1
  42. package/local-maven-repo/host/exp/exponent/expo.modules.location/19.0.9-canary-20260105-6b962e6/expo.modules.location-19.0.9-canary-20260105-6b962e6.aar.sha256 +0 -1
  43. package/local-maven-repo/host/exp/exponent/expo.modules.location/19.0.9-canary-20260105-6b962e6/expo.modules.location-19.0.9-canary-20260105-6b962e6.aar.sha512 +0 -1
  44. package/local-maven-repo/host/exp/exponent/expo.modules.location/19.0.9-canary-20260105-6b962e6/expo.modules.location-19.0.9-canary-20260105-6b962e6.module.md5 +0 -1
  45. package/local-maven-repo/host/exp/exponent/expo.modules.location/19.0.9-canary-20260105-6b962e6/expo.modules.location-19.0.9-canary-20260105-6b962e6.module.sha1 +0 -1
  46. package/local-maven-repo/host/exp/exponent/expo.modules.location/19.0.9-canary-20260105-6b962e6/expo.modules.location-19.0.9-canary-20260105-6b962e6.module.sha256 +0 -1
  47. package/local-maven-repo/host/exp/exponent/expo.modules.location/19.0.9-canary-20260105-6b962e6/expo.modules.location-19.0.9-canary-20260105-6b962e6.module.sha512 +0 -1
  48. package/local-maven-repo/host/exp/exponent/expo.modules.location/19.0.9-canary-20260105-6b962e6/expo.modules.location-19.0.9-canary-20260105-6b962e6.pom.md5 +0 -1
  49. package/local-maven-repo/host/exp/exponent/expo.modules.location/19.0.9-canary-20260105-6b962e6/expo.modules.location-19.0.9-canary-20260105-6b962e6.pom.sha1 +0 -1
  50. package/local-maven-repo/host/exp/exponent/expo.modules.location/19.0.9-canary-20260105-6b962e6/expo.modules.location-19.0.9-canary-20260105-6b962e6.pom.sha256 +0 -1
  51. package/local-maven-repo/host/exp/exponent/expo.modules.location/19.0.9-canary-20260105-6b962e6/expo.modules.location-19.0.9-canary-20260105-6b962e6.pom.sha512 +0 -1
package/CHANGELOG.md CHANGED
@@ -6,8 +6,11 @@
6
6
 
7
7
  ### 🎉 New features
8
8
 
9
+ - [Android] Add option `androidForegroundServiceIcon` for controlling the icon for the foreground service. ([#41132](https://github.com/expo/expo/pull/41132) by [@jeppester](https://github.com/jeppester))
10
+
9
11
  ### 🐛 Bug fixes
10
12
 
13
+ - [Android] Fixed deferred location updates being applied in foreground due to incorrect `mIsHostPaused` initialization. Location updates are now delivered immediately when app is in foreground, matching iOS behavior. ([#41659](https://github.com/expo/expo/pull/41659) by [@tyrauber](https://github.com/tyrauber))
11
14
  - use WGS 84 as reference for altitude on iOS ([#41318](https://github.com/expo/expo/pull/41318) by [@vonovak](https://github.com/vonovak))
12
15
  - fix position of the `scope` field in a permissions request result ([#41328](https://github.com/expo/expo/pull/41328) by [@vonovak](https://github.com/vonovak))
13
16
  - [Web] Stop using legacy event emitter. ([#41680](https://github.com/expo/expo/pull/41680) by [@alanjhughes](https://github.com/alanjhughes))
@@ -4,13 +4,13 @@ plugins {
4
4
  }
5
5
 
6
6
  group = 'host.exp.exponent'
7
- version = '19.0.9-canary-20260105-6b962e6'
7
+ version = '19.1.0-canary-20260113-0ce2b9c'
8
8
 
9
9
  android {
10
10
  namespace "expo.modules.location"
11
11
  defaultConfig {
12
12
  versionCode 29
13
- versionName "19.0.9-canary-20260105-6b962e6"
13
+ versionName "19.1.0-canary-20260113-0ce2b9c"
14
14
  consumerProguardFiles("proguard-rules.pro")
15
15
  }
16
16
  }
@@ -8,6 +8,7 @@ import android.app.PendingIntent
8
8
  import android.app.Service
9
9
  import android.content.Context
10
10
  import android.content.Intent
11
+ import android.content.pm.PackageManager
11
12
  import android.graphics.Color
12
13
  import android.os.Binder
13
14
  import android.os.Build
@@ -88,8 +89,24 @@ class LocationTaskService : Service() {
88
89
  builder.setContentIntent(contentIntent)
89
90
  }
90
91
 
92
+ val iconsResId = try {
93
+ val packageManager = mParentContext.packageManager
94
+ val ai = packageManager.getApplicationInfo(
95
+ mParentContext.packageName,
96
+ android.content.pm.PackageManager.GET_META_DATA
97
+ )
98
+ if (ai.metaData?.containsKey(META_DATA_FOREGROUND_SERVICE_ICON_KEY) == true) {
99
+ ai.metaData.getInt(META_DATA_FOREGROUND_SERVICE_ICON_KEY)
100
+ } else {
101
+ applicationInfo.icon
102
+ }
103
+ } catch (e: Exception) {
104
+ android.util.Log.e("expo-location", "Could not fetch default notification icon.", e)
105
+ applicationInfo.icon
106
+ }
107
+
91
108
  return builder.setCategory(Notification.CATEGORY_SERVICE)
92
- .setSmallIcon(applicationInfo.icon)
109
+ .setSmallIcon(iconsResId)
93
110
  .build()
94
111
  }
95
112
 
@@ -116,5 +133,7 @@ class LocationTaskService : Service() {
116
133
 
117
134
  companion object {
118
135
  private var sServiceId = 481756
136
+ const val META_DATA_FOREGROUND_SERVICE_ICON_KEY: String =
137
+ "expo.modules.location.foreground_service_icon"
119
138
  }
120
139
  }
@@ -43,7 +43,9 @@ class LocationTaskConsumer(context: Context, taskManagerUtils: TaskManagerUtilsI
43
43
  private var mLastReportedLocation: Location? = null
44
44
  private var mDeferredDistance = 0.0
45
45
  private val mDeferredLocations: MutableList<Location> = ArrayList()
46
- private var mIsHostPaused = true
46
+
47
+ // Apps start in foreground state; lifecycle callbacks update this after initialization
48
+ private var mIsHostPaused = false
47
49
  private val mLocationClient: FusedLocationProviderClient by lazy {
48
50
  LocationServices.getFusedLocationProviderClient(context)
49
51
  }
@@ -82,16 +84,11 @@ class LocationTaskConsumer(context: Context, taskManagerUtils: TaskManagerUtilsI
82
84
  mTask ?: return
83
85
  val result = LocationResult.extractResult(intent)
84
86
  if (result != null) {
85
- val locations = result.locations
86
- deferLocations(locations)
87
- maybeReportDeferredLocations()
87
+ handleLocationUpdate(result.locations)
88
88
  } else {
89
89
  try {
90
90
  mLocationClient.lastLocation.addOnCompleteListener { task ->
91
- task.result?.let {
92
- deferLocations(listOf(it))
93
- maybeReportDeferredLocations()
94
- }
91
+ task.result?.let { handleLocationUpdate(listOf(it)) }
95
92
  }
96
93
  } catch (e: SecurityException) {
97
94
  Log.e(TAG, "Cannot get last location: " + e.message)
@@ -99,6 +96,24 @@ class LocationTaskConsumer(context: Context, taskManagerUtils: TaskManagerUtilsI
99
96
  }
100
97
  }
101
98
 
99
+ /**
100
+ * Handles incoming location updates by either reporting immediately (foreground)
101
+ * or deferring for battery optimization (background).
102
+ */
103
+ private fun handleLocationUpdate(locations: List<Location>) {
104
+ if (locations.isEmpty()) return
105
+
106
+ // Foreground: report immediately for responsive UI (matches iOS behavior)
107
+ if (!mIsHostPaused) {
108
+ reportLocationsImmediately(locations)
109
+ return
110
+ }
111
+
112
+ // Background: use deferred buffer for battery optimization
113
+ deferLocations(locations)
114
+ maybeReportDeferredLocations()
115
+ }
116
+
102
117
  override fun didExecuteJob(jobService: JobService, params: JobParameters): Boolean {
103
118
  val data = taskManagerUtils.extractDataFromJobParams(params)
104
119
  val locationBundles = ArrayList<Bundle>()
@@ -227,6 +242,32 @@ class LocationTaskConsumer(context: Context, taskManagerUtils: TaskManagerUtilsI
227
242
  mService?.stop()
228
243
  }
229
244
 
245
+ /**
246
+ * Reports locations immediately without deferred batching.
247
+ * Used in foreground mode to provide responsive location updates (matches iOS behavior).
248
+ */
249
+ private fun reportLocationsImmediately(locations: List<Location>) {
250
+ if (locations.isEmpty()) return
251
+ val context = context.applicationContext
252
+ val data: MutableList<PersistableBundle> = ArrayList()
253
+ var lastReported: Location? = null
254
+ for (location in locations) {
255
+ val timestamp = location.time
256
+ // Some devices may broadcast the same location multiple times (mostly twice)
257
+ // so we're filtering out these locations.
258
+ if (timestamp > sLastTimestamp) {
259
+ val bundle = LocationResponse(location).toBundle(PersistableBundle::class.java)
260
+ data.add(bundle)
261
+ sLastTimestamp = timestamp
262
+ lastReported = location
263
+ }
264
+ }
265
+ if (data.isNotEmpty()) {
266
+ mLastReportedLocation = lastReported
267
+ taskManagerUtils.scheduleJob(context, mTask, data)
268
+ }
269
+ }
270
+
230
271
  private fun deferLocations(locations: List<Location>) {
231
272
  val size = mDeferredLocations.size
232
273
  var lastLocation = if (size > 0) mDeferredLocations[size - 1] else mLastReportedLocation
@@ -8,7 +8,7 @@
8
8
  "publication": {
9
9
  "groupId": "host.exp.exponent",
10
10
  "artifactId": "expo.modules.location",
11
- "version": "19.0.9-canary-20260105-6b962e6",
11
+ "version": "19.1.0-canary-20260113-0ce2b9c",
12
12
  "repository": "local-maven-repo"
13
13
  }
14
14
  }
@@ -2,6 +2,7 @@
2
2
 
3
3
  #import <ExpoLocation/EXBaseLocationRequester.h>
4
4
  #import <ExpoModulesCore/EXUtilities.h>
5
+ #import <React/RCTLog.h>
5
6
 
6
7
  #import <objc/message.h>
7
8
 
@@ -36,7 +37,7 @@
36
37
 
37
38
  CLAuthorizationStatus systemStatus;
38
39
  if (![EXBaseLocationRequester isConfiguredForAlwaysAuthorization] && ![EXBaseLocationRequester isConfiguredForWhenInUseAuthorization]) {
39
- EXFatal(EXErrorWithMessage(@"This app is missing usage descriptions, so location services will fail. Add one of the `NSLocation*UsageDescription` keys to your bundle's Info.plist. See https://bit.ly/3iLqy6S (https://docs.expo.dev/distribution/app-stores/#system-permissions-dialogs-on-ios) for more information."));
40
+ RCTFatal(RCTErrorWithMessage(@"This app is missing usage descriptions, so location services will fail. Add one of the `NSLocation*UsageDescription` keys to your bundle's Info.plist. See https://bit.ly/3iLqy6S (https://docs.expo.dev/distribution/app-stores/#system-permissions-dialogs-on-ios) for more information."));
40
41
  systemStatus = kCLAuthorizationStatusDenied;
41
42
  } else {
42
43
  systemStatus = [CLLocationManager authorizationStatus];
@@ -0,0 +1 @@
1
+ e642dfffd88dbc11a410a5256ff054c2dd1d1c26771bb207e20564ae5a0a63412b00507ba48e6a27a316b4bcd1567f2971a3c2c3ad6651d7a7e203a7c96d76d9
@@ -0,0 +1 @@
1
+ 51df8f119233a55149a1976161c36ce6910adde4a21e6e76c39aefc43b2d540b946f82810d244787774dc07f8520c64a21498ec59060f5f1b9de92f52721b2c9
@@ -3,7 +3,7 @@
3
3
  "component": {
4
4
  "group": "host.exp.exponent",
5
5
  "module": "expo.modules.location",
6
- "version": "19.0.9-canary-20260105-6b962e6",
6
+ "version": "19.1.0-canary-20260113-0ce2b9c",
7
7
  "attributes": {
8
8
  "org.gradle.status": "release"
9
9
  }
@@ -33,13 +33,13 @@
33
33
  ],
34
34
  "files": [
35
35
  {
36
- "name": "expo.modules.location-19.0.9-canary-20260105-6b962e6.aar",
37
- "url": "expo.modules.location-19.0.9-canary-20260105-6b962e6.aar",
38
- "size": 186400,
39
- "sha512": "b699d0267e159d2b0a895e82bca3c24c7539ae867fc0b28eff247d12a063dcffcbc9a14fadf9b282eb21092a4ee6dd259ca007a2bccaa4d0137c430150a236d1",
40
- "sha256": "19ee2f7e42942c7818a69b9d6f7904f5f48e6d2266d7ab72f50edd55d7af1a30",
41
- "sha1": "ca419929221b6cdb7615a3e353af45de46ff2048",
42
- "md5": "36fba766c0b62c1f9f0eeabd0064fd6c"
36
+ "name": "expo.modules.location-19.1.0-canary-20260113-0ce2b9c.aar",
37
+ "url": "expo.modules.location-19.1.0-canary-20260113-0ce2b9c.aar",
38
+ "size": 187200,
39
+ "sha512": "51df8f119233a55149a1976161c36ce6910adde4a21e6e76c39aefc43b2d540b946f82810d244787774dc07f8520c64a21498ec59060f5f1b9de92f52721b2c9",
40
+ "sha256": "0215cb22002d32409d9fbb1b55acda0b45f4f2156e50c6a74d2b1f9663e093d7",
41
+ "sha1": "d3fec6455f5226448e5c54328f913866faa8d723",
42
+ "md5": "28452903a9e73dbac06d878c497bc7d9"
43
43
  }
44
44
  ]
45
45
  },
@@ -69,13 +69,13 @@
69
69
  ],
70
70
  "files": [
71
71
  {
72
- "name": "expo.modules.location-19.0.9-canary-20260105-6b962e6.aar",
73
- "url": "expo.modules.location-19.0.9-canary-20260105-6b962e6.aar",
74
- "size": 186400,
75
- "sha512": "b699d0267e159d2b0a895e82bca3c24c7539ae867fc0b28eff247d12a063dcffcbc9a14fadf9b282eb21092a4ee6dd259ca007a2bccaa4d0137c430150a236d1",
76
- "sha256": "19ee2f7e42942c7818a69b9d6f7904f5f48e6d2266d7ab72f50edd55d7af1a30",
77
- "sha1": "ca419929221b6cdb7615a3e353af45de46ff2048",
78
- "md5": "36fba766c0b62c1f9f0eeabd0064fd6c"
72
+ "name": "expo.modules.location-19.1.0-canary-20260113-0ce2b9c.aar",
73
+ "url": "expo.modules.location-19.1.0-canary-20260113-0ce2b9c.aar",
74
+ "size": 187200,
75
+ "sha512": "51df8f119233a55149a1976161c36ce6910adde4a21e6e76c39aefc43b2d540b946f82810d244787774dc07f8520c64a21498ec59060f5f1b9de92f52721b2c9",
76
+ "sha256": "0215cb22002d32409d9fbb1b55acda0b45f4f2156e50c6a74d2b1f9663e093d7",
77
+ "sha1": "d3fec6455f5226448e5c54328f913866faa8d723",
78
+ "md5": "28452903a9e73dbac06d878c497bc7d9"
79
79
  }
80
80
  ]
81
81
  },
@@ -89,13 +89,13 @@
89
89
  },
90
90
  "files": [
91
91
  {
92
- "name": "expo.modules.location-19.0.9-canary-20260105-6b962e6-sources.jar",
93
- "url": "expo.modules.location-19.0.9-canary-20260105-6b962e6-sources.jar",
94
- "size": 22881,
95
- "sha512": "d2866075faf8ccb0b18a3e2fce7039bc6eebf226cf552924adb749fbfaf32d6daf73ee1de8bc33dee2d7c2ff8f3fd3ba86d02f2a65e5e9dc6432316148aec2e2",
96
- "sha256": "44632f521d20b7de97e7093313f5cdbc9d57166256f97235ce0c85a4f83287cd",
97
- "sha1": "3f1ebf2caa695bb5ca9c0d4e2952210ee0463a20",
98
- "md5": "e61b5988298567160d57c9a2d7e89e3a"
92
+ "name": "expo.modules.location-19.1.0-canary-20260113-0ce2b9c-sources.jar",
93
+ "url": "expo.modules.location-19.1.0-canary-20260113-0ce2b9c-sources.jar",
94
+ "size": 23402,
95
+ "sha512": "e642dfffd88dbc11a410a5256ff054c2dd1d1c26771bb207e20564ae5a0a63412b00507ba48e6a27a316b4bcd1567f2971a3c2c3ad6651d7a7e203a7c96d76d9",
96
+ "sha256": "1be3e6c53d661851f9a16186229e3215b370c7cb102c794828326996ef624fb0",
97
+ "sha1": "ce1099475e3095dce5560cd3efb5e3d16021be1a",
98
+ "md5": "f0e208560e60938fe5c8bed104a13b7c"
99
99
  }
100
100
  ]
101
101
  }
@@ -0,0 +1 @@
1
+ 700a91df1d0bd33d8a5aabf192c5c8f19364d458bd8bf085818b4f1c403d3268582f42532ec8a24246f0858a6a3cc3336faa1e89b9e11fb8fa9cad5bc77aeb3a
@@ -9,7 +9,7 @@
9
9
  <modelVersion>4.0.0</modelVersion>
10
10
  <groupId>host.exp.exponent</groupId>
11
11
  <artifactId>expo.modules.location</artifactId>
12
- <version>19.0.9-canary-20260105-6b962e6</version>
12
+ <version>19.1.0-canary-20260113-0ce2b9c</version>
13
13
  <packaging>aar</packaging>
14
14
  <name>expo.modules.location</name>
15
15
  <url>https://github.com/expo/expo</url>
@@ -0,0 +1 @@
1
+ 3de56592bf19d395ff48d1ae402b3c4c8cdde149fa4e17657579eba397dde434c4f5ed60e70263e52e9ae9b57bc18e6c4f974c61b62e109128516e678fb74471
@@ -3,11 +3,11 @@
3
3
  <groupId>host.exp.exponent</groupId>
4
4
  <artifactId>expo.modules.location</artifactId>
5
5
  <versioning>
6
- <latest>19.0.9-canary-20260105-6b962e6</latest>
7
- <release>19.0.9-canary-20260105-6b962e6</release>
6
+ <latest>19.1.0-canary-20260113-0ce2b9c</latest>
7
+ <release>19.1.0-canary-20260113-0ce2b9c</release>
8
8
  <versions>
9
- <version>19.0.9-canary-20260105-6b962e6</version>
9
+ <version>19.1.0-canary-20260113-0ce2b9c</version>
10
10
  </versions>
11
- <lastUpdated>20260105102107</lastUpdated>
11
+ <lastUpdated>20260113181603</lastUpdated>
12
12
  </versioning>
13
13
  </metadata>
@@ -1 +1 @@
1
- b309aaa92baf38319f108ac054eb4317
1
+ 77cb024a019bef377438361d5c73ef15
@@ -1 +1 @@
1
- cd4a7eac17850643677f58ddde814e4f06248f15
1
+ a11c86e225b44ec5c16a4bcd04ede3f17f5628a3
@@ -1 +1 @@
1
- 8fe806ebc1d150267d1a6d577bbeef3df6f987cc9205154450ab07ee8462241f
1
+ 82245d9162f804cd1949e821e6cc673fdbb1c351dab107977a0338b2e086c060
@@ -1 +1 @@
1
- 53417e54d48a1f6e862568163f21abbaee28a2608437d7e539ae98a217c4e648487c7957cd788b2cc8d3fb32df9332b9c4a8451144efab408d3537e4a7bde406
1
+ d76d3ad6962cce9191b0388dcb3921b78186b447044036428da62e2fd4bbaa39a62107e2c4ff48cbba8f5f6024ae98e3d65df706e78524a6c3c548e6e81316ce
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "expo-location",
3
- "version": "19.0.9-canary-20260105-6b962e6",
3
+ "version": "19.1.0-canary-20260113-0ce2b9c",
4
4
  "description": "Allows reading geolocation information from the device. Your app can poll for the current location or subscribe to location update events.",
5
5
  "main": "build/index.js",
6
6
  "types": "build/index.d.ts",
@@ -38,10 +38,13 @@
38
38
  "jest": {
39
39
  "preset": "expo-module-scripts"
40
40
  },
41
+ "dependencies": {
42
+ "@expo/image-utils": "0.8.9-canary-20260113-0ce2b9c"
43
+ },
41
44
  "devDependencies": {
42
- "expo-module-scripts": "5.1.0-canary-20260105-6b962e6"
45
+ "expo-module-scripts": "5.1.0-canary-20260113-0ce2b9c"
43
46
  },
44
47
  "peerDependencies": {
45
- "expo": "55.0.0-canary-20260105-6b962e6"
48
+ "expo": "55.0.0-canary-20260113-0ce2b9c"
46
49
  }
47
50
  }
@@ -1,4 +1,21 @@
1
1
  import { ConfigPlugin } from 'expo/config-plugins';
2
+ type DPIString = 'mdpi' | 'hdpi' | 'xhdpi' | 'xxhdpi' | 'xxxhdpi';
3
+ type dpiMap = Record<DPIString, {
4
+ folderName: string;
5
+ scale: number;
6
+ }>;
7
+ export declare const ANDROID_RES_PATH = "android/app/src/main/res/";
8
+ export declare const dpiValues: dpiMap;
9
+ export declare const FOREGROUND_SERVICE_ICON = "location_foreground_service_icon";
10
+ export declare const FOREGROUND_SERVICE_ICON_RESOURCE = "@drawable/location_foreground_service_icon";
11
+ export declare const META_DATA_FOREGROUND_SERVICE_ICON = "expo.modules.location.foreground_service_icon";
12
+ export declare const withForegroundServiceIcon: ConfigPlugin<{
13
+ icon: string | null;
14
+ }>;
15
+ /**
16
+ * Applies foreground service icon configuration for expo-location
17
+ */
18
+ export declare function setForegroundServiceIconAsync(projectRoot: string, icon: string | null): Promise<void>;
2
19
  declare const _default: ConfigPlugin<void | {
3
20
  locationAlwaysAndWhenInUsePermission?: string | false;
4
21
  locationAlwaysPermission?: string | false;
@@ -6,5 +23,6 @@ declare const _default: ConfigPlugin<void | {
6
23
  isIosBackgroundLocationEnabled?: boolean;
7
24
  isAndroidBackgroundLocationEnabled?: boolean;
8
25
  isAndroidForegroundServiceEnabled?: boolean;
26
+ androidForegroundServiceIcon?: string;
9
27
  }>;
10
28
  export default _default;
@@ -1,8 +1,27 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.withForegroundServiceIcon = exports.META_DATA_FOREGROUND_SERVICE_ICON = exports.FOREGROUND_SERVICE_ICON_RESOURCE = exports.FOREGROUND_SERVICE_ICON = exports.dpiValues = exports.ANDROID_RES_PATH = void 0;
4
+ exports.setForegroundServiceIconAsync = setForegroundServiceIconAsync;
5
+ const image_utils_1 = require("@expo/image-utils");
3
6
  const config_plugins_1 = require("expo/config-plugins");
7
+ const fs_1 = require("fs");
8
+ const path_1 = require("path");
4
9
  const pkg = require('expo-location/package.json');
5
10
  const LOCATION_USAGE = 'Allow $(PRODUCT_NAME) to access your location';
11
+ exports.ANDROID_RES_PATH = 'android/app/src/main/res/';
12
+ exports.dpiValues = {
13
+ mdpi: { folderName: 'mipmap-mdpi', scale: 1 },
14
+ hdpi: { folderName: 'mipmap-hdpi', scale: 1.5 },
15
+ xhdpi: { folderName: 'mipmap-xhdpi', scale: 2 },
16
+ xxhdpi: { folderName: 'mipmap-xxhdpi', scale: 3 },
17
+ xxxhdpi: { folderName: 'mipmap-xxxhdpi', scale: 4 },
18
+ };
19
+ const { addMetaDataItemToMainApplication, getMainApplicationOrThrow, removeMetaDataItemFromMainApplication, } = config_plugins_1.AndroidConfig.Manifest;
20
+ const BASELINE_PIXEL_SIZE = 24;
21
+ const ERROR_MSG_PREFIX = 'An error occurred while configuring Android location. ';
22
+ exports.FOREGROUND_SERVICE_ICON = 'location_foreground_service_icon';
23
+ exports.FOREGROUND_SERVICE_ICON_RESOURCE = `@drawable/${exports.FOREGROUND_SERVICE_ICON}`;
24
+ exports.META_DATA_FOREGROUND_SERVICE_ICON = 'expo.modules.location.foreground_service_icon';
6
25
  const withBackgroundLocation = (config) => {
7
26
  return (0, config_plugins_1.withInfoPlist)(config, (config) => {
8
27
  if (!Array.isArray(config.modResults.UIBackgroundModes)) {
@@ -14,10 +33,79 @@ const withBackgroundLocation = (config) => {
14
33
  return config;
15
34
  });
16
35
  };
17
- const withLocation = (config, { locationAlwaysAndWhenInUsePermission, locationAlwaysPermission, locationWhenInUsePermission, isIosBackgroundLocationEnabled, isAndroidBackgroundLocationEnabled, isAndroidForegroundServiceEnabled, } = {}) => {
36
+ const withForegroundServiceIcon = (config, { icon }) => {
37
+ // Update icon assets
38
+ const configWithIconAssets = (0, config_plugins_1.withDangerousMod)(config, [
39
+ 'android',
40
+ async (config) => {
41
+ await setForegroundServiceIconAsync(config.modRequest.projectRoot, icon);
42
+ return config;
43
+ },
44
+ ]);
45
+ // Update assets Android manifest
46
+ return (0, config_plugins_1.withAndroidManifest)(configWithIconAssets, (config) => {
47
+ const manifest = config.modResults;
48
+ const mainApplication = getMainApplicationOrThrow(manifest);
49
+ if (icon) {
50
+ addMetaDataItemToMainApplication(mainApplication, exports.META_DATA_FOREGROUND_SERVICE_ICON, exports.FOREGROUND_SERVICE_ICON_RESOURCE, 'resource');
51
+ }
52
+ else {
53
+ removeMetaDataItemFromMainApplication(mainApplication, exports.META_DATA_FOREGROUND_SERVICE_ICON);
54
+ }
55
+ config.modResults = manifest;
56
+ return config;
57
+ });
58
+ };
59
+ exports.withForegroundServiceIcon = withForegroundServiceIcon;
60
+ /**
61
+ * Applies foreground service icon configuration for expo-location
62
+ */
63
+ async function setForegroundServiceIconAsync(projectRoot, icon) {
64
+ if (icon) {
65
+ await writeForegroundServiceIconImageFilesAsync(icon, projectRoot);
66
+ }
67
+ else {
68
+ removeForegroundServiceIconImageFiles(projectRoot);
69
+ }
70
+ }
71
+ async function writeForegroundServiceIconImageFilesAsync(icon, projectRoot) {
72
+ await Promise.all(Object.values(exports.dpiValues).map(async ({ folderName, scale }) => {
73
+ const drawableFolderName = folderName.replace('mipmap', 'drawable');
74
+ const dpiFolderPath = (0, path_1.resolve)(projectRoot, exports.ANDROID_RES_PATH, drawableFolderName);
75
+ if (!(0, fs_1.existsSync)(dpiFolderPath)) {
76
+ (0, fs_1.mkdirSync)(dpiFolderPath, { recursive: true });
77
+ }
78
+ const iconSizePx = BASELINE_PIXEL_SIZE * scale;
79
+ try {
80
+ const resizedIcon = (await (0, image_utils_1.generateImageAsync)({ projectRoot, cacheType: 'android-location' }, {
81
+ src: icon,
82
+ width: iconSizePx,
83
+ height: iconSizePx,
84
+ resizeMode: 'cover',
85
+ backgroundColor: 'transparent',
86
+ })).source;
87
+ (0, fs_1.writeFileSync)((0, path_1.resolve)(dpiFolderPath, exports.FOREGROUND_SERVICE_ICON + '.png'), resizedIcon);
88
+ }
89
+ catch (e) {
90
+ throw new Error(ERROR_MSG_PREFIX + 'Encountered an issue resizing Android foreground service icon: ' + e);
91
+ }
92
+ }));
93
+ }
94
+ function removeForegroundServiceIconImageFiles(projectRoot) {
95
+ Object.values(exports.dpiValues).forEach(async ({ folderName }) => {
96
+ const drawableFolderName = folderName.replace('mipmap', 'drawable');
97
+ const dpiFolderPath = (0, path_1.resolve)(projectRoot, exports.ANDROID_RES_PATH, drawableFolderName);
98
+ const iconFile = (0, path_1.resolve)(dpiFolderPath, exports.FOREGROUND_SERVICE_ICON + '.png');
99
+ if ((0, fs_1.existsSync)(iconFile)) {
100
+ (0, fs_1.unlinkSync)(iconFile);
101
+ }
102
+ });
103
+ }
104
+ const withLocation = (config, { locationAlwaysAndWhenInUsePermission, locationAlwaysPermission, locationWhenInUsePermission, isIosBackgroundLocationEnabled, isAndroidBackgroundLocationEnabled, isAndroidForegroundServiceEnabled, androidForegroundServiceIcon, } = {}) => {
18
105
  if (isIosBackgroundLocationEnabled) {
19
106
  config = withBackgroundLocation(config);
20
107
  }
108
+ config = (0, exports.withForegroundServiceIcon)(config, { icon: androidForegroundServiceIcon ?? null });
21
109
  config_plugins_1.IOSConfig.Permissions.createPermissionsPlugin({
22
110
  NSLocationAlwaysAndWhenInUseUsageDescription: LOCATION_USAGE,
23
111
  NSLocationAlwaysUsageDescription: LOCATION_USAGE,
@@ -1,14 +1,42 @@
1
+ import { generateImageAsync } from '@expo/image-utils';
1
2
  import {
2
3
  AndroidConfig,
3
4
  ConfigPlugin,
4
5
  IOSConfig,
5
6
  createRunOncePlugin,
6
7
  withInfoPlist,
8
+ withDangerousMod,
9
+ withAndroidManifest,
7
10
  } from 'expo/config-plugins';
11
+ import { writeFileSync, unlinkSync, existsSync, mkdirSync } from 'fs';
12
+ import { resolve } from 'path';
8
13
 
9
14
  const pkg = require('expo-location/package.json');
10
15
  const LOCATION_USAGE = 'Allow $(PRODUCT_NAME) to access your location';
11
16
 
17
+ type DPIString = 'mdpi' | 'hdpi' | 'xhdpi' | 'xxhdpi' | 'xxxhdpi';
18
+ type dpiMap = Record<DPIString, { folderName: string; scale: number }>;
19
+
20
+ export const ANDROID_RES_PATH = 'android/app/src/main/res/';
21
+ export const dpiValues: dpiMap = {
22
+ mdpi: { folderName: 'mipmap-mdpi', scale: 1 },
23
+ hdpi: { folderName: 'mipmap-hdpi', scale: 1.5 },
24
+ xhdpi: { folderName: 'mipmap-xhdpi', scale: 2 },
25
+ xxhdpi: { folderName: 'mipmap-xxhdpi', scale: 3 },
26
+ xxxhdpi: { folderName: 'mipmap-xxxhdpi', scale: 4 },
27
+ };
28
+ const {
29
+ addMetaDataItemToMainApplication,
30
+ getMainApplicationOrThrow,
31
+ removeMetaDataItemFromMainApplication,
32
+ } = AndroidConfig.Manifest;
33
+ const BASELINE_PIXEL_SIZE = 24;
34
+ const ERROR_MSG_PREFIX = 'An error occurred while configuring Android location. ';
35
+
36
+ export const FOREGROUND_SERVICE_ICON = 'location_foreground_service_icon';
37
+ export const FOREGROUND_SERVICE_ICON_RESOURCE = `@drawable/${FOREGROUND_SERVICE_ICON}`;
38
+ export const META_DATA_FOREGROUND_SERVICE_ICON = 'expo.modules.location.foreground_service_icon';
39
+
12
40
  const withBackgroundLocation: ConfigPlugin = (config) => {
13
41
  return withInfoPlist(config, (config) => {
14
42
  if (!Array.isArray(config.modResults.UIBackgroundModes)) {
@@ -21,6 +49,95 @@ const withBackgroundLocation: ConfigPlugin = (config) => {
21
49
  });
22
50
  };
23
51
 
52
+ export const withForegroundServiceIcon: ConfigPlugin<{ icon: string | null }> = (
53
+ config,
54
+ { icon }
55
+ ) => {
56
+ // Update icon assets
57
+ const configWithIconAssets = withDangerousMod(config, [
58
+ 'android',
59
+ async (config) => {
60
+ await setForegroundServiceIconAsync(config.modRequest.projectRoot, icon);
61
+ return config;
62
+ },
63
+ ]);
64
+
65
+ // Update assets Android manifest
66
+ return withAndroidManifest(configWithIconAssets, (config) => {
67
+ const manifest = config.modResults;
68
+ const mainApplication = getMainApplicationOrThrow(manifest);
69
+
70
+ if (icon) {
71
+ addMetaDataItemToMainApplication(
72
+ mainApplication,
73
+ META_DATA_FOREGROUND_SERVICE_ICON,
74
+ FOREGROUND_SERVICE_ICON_RESOURCE,
75
+ 'resource'
76
+ );
77
+ } else {
78
+ removeMetaDataItemFromMainApplication(mainApplication, META_DATA_FOREGROUND_SERVICE_ICON);
79
+ }
80
+
81
+ config.modResults = manifest;
82
+ return config;
83
+ });
84
+ };
85
+
86
+ /**
87
+ * Applies foreground service icon configuration for expo-location
88
+ */
89
+ export async function setForegroundServiceIconAsync(projectRoot: string, icon: string | null) {
90
+ if (icon) {
91
+ await writeForegroundServiceIconImageFilesAsync(icon, projectRoot);
92
+ } else {
93
+ removeForegroundServiceIconImageFiles(projectRoot);
94
+ }
95
+ }
96
+
97
+ async function writeForegroundServiceIconImageFilesAsync(icon: string, projectRoot: string) {
98
+ await Promise.all(
99
+ Object.values(dpiValues).map(async ({ folderName, scale }) => {
100
+ const drawableFolderName = folderName.replace('mipmap', 'drawable');
101
+ const dpiFolderPath = resolve(projectRoot, ANDROID_RES_PATH, drawableFolderName);
102
+ if (!existsSync(dpiFolderPath)) {
103
+ mkdirSync(dpiFolderPath, { recursive: true });
104
+ }
105
+ const iconSizePx = BASELINE_PIXEL_SIZE * scale;
106
+
107
+ try {
108
+ const resizedIcon = (
109
+ await generateImageAsync(
110
+ { projectRoot, cacheType: 'android-location' },
111
+ {
112
+ src: icon,
113
+ width: iconSizePx,
114
+ height: iconSizePx,
115
+ resizeMode: 'cover',
116
+ backgroundColor: 'transparent',
117
+ }
118
+ )
119
+ ).source;
120
+ writeFileSync(resolve(dpiFolderPath, FOREGROUND_SERVICE_ICON + '.png'), resizedIcon);
121
+ } catch (e) {
122
+ throw new Error(
123
+ ERROR_MSG_PREFIX + 'Encountered an issue resizing Android foreground service icon: ' + e
124
+ );
125
+ }
126
+ })
127
+ );
128
+ }
129
+
130
+ function removeForegroundServiceIconImageFiles(projectRoot: string) {
131
+ Object.values(dpiValues).forEach(async ({ folderName }) => {
132
+ const drawableFolderName = folderName.replace('mipmap', 'drawable');
133
+ const dpiFolderPath = resolve(projectRoot, ANDROID_RES_PATH, drawableFolderName);
134
+ const iconFile = resolve(dpiFolderPath, FOREGROUND_SERVICE_ICON + '.png');
135
+ if (existsSync(iconFile)) {
136
+ unlinkSync(iconFile);
137
+ }
138
+ });
139
+ }
140
+
24
141
  const withLocation: ConfigPlugin<
25
142
  {
26
143
  locationAlwaysAndWhenInUsePermission?: string | false;
@@ -29,6 +146,7 @@ const withLocation: ConfigPlugin<
29
146
  isIosBackgroundLocationEnabled?: boolean;
30
147
  isAndroidBackgroundLocationEnabled?: boolean;
31
148
  isAndroidForegroundServiceEnabled?: boolean;
149
+ androidForegroundServiceIcon?: string;
32
150
  } | void
33
151
  > = (
34
152
  config,
@@ -39,12 +157,15 @@ const withLocation: ConfigPlugin<
39
157
  isIosBackgroundLocationEnabled,
40
158
  isAndroidBackgroundLocationEnabled,
41
159
  isAndroidForegroundServiceEnabled,
160
+ androidForegroundServiceIcon,
42
161
  } = {}
43
162
  ) => {
44
163
  if (isIosBackgroundLocationEnabled) {
45
164
  config = withBackgroundLocation(config);
46
165
  }
47
166
 
167
+ config = withForegroundServiceIcon(config, { icon: androidForegroundServiceIcon ?? null });
168
+
48
169
  IOSConfig.Permissions.createPermissionsPlugin({
49
170
  NSLocationAlwaysAndWhenInUseUsageDescription: LOCATION_USAGE,
50
171
  NSLocationAlwaysUsageDescription: LOCATION_USAGE,
@@ -1 +0,0 @@
1
- d2866075faf8ccb0b18a3e2fce7039bc6eebf226cf552924adb749fbfaf32d6daf73ee1de8bc33dee2d7c2ff8f3fd3ba86d02f2a65e5e9dc6432316148aec2e2
@@ -1 +0,0 @@
1
- b699d0267e159d2b0a895e82bca3c24c7539ae867fc0b28eff247d12a063dcffcbc9a14fadf9b282eb21092a4ee6dd259ca007a2bccaa4d0137c430150a236d1
@@ -1 +0,0 @@
1
- 6a82a6d9e5dc87a0d10b5be8ad1c668d22cad58f539f391ae1ff58f2810431ccf890fd8f5e2994b4e5de6ddfe37812ba32def2380635c002e836526d66f410e0
@@ -1 +0,0 @@
1
- 85861dfc9085942a793fba7ccd08197b8eccc045892b2e1764bc4c01c3828b17daf3404cd281072551e91afb7089e3a79fc72829282ef1e4978ed60bab98bc76