-
Notifications
You must be signed in to change notification settings - Fork 312
Make crust's Mapbox Navigation dependency opt-in (default off) #3372
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: dev
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -98,7 +98,13 @@ dependencies { | |
| // banner/maneuver formatting used to label turns. | ||
| // Version pinned to 3.25.0 — re-check https://docs.mapbox.com/android/navigation/releases/ | ||
| def isChinaBuild = System.getenv("EXPO_PUBLIC_DEPLOYMENT_REGION") == "china" | ||
| if (isChinaBuild) { | ||
| // Host opt-in via the @mentra/crust config plugin (default false). China has | ||
| // always excluded the Nav SDK from the APK; a non-navigating host does the | ||
| // same, so it needs no MAPBOX_DOWNLOADS_TOKEN to build. Either way crust still | ||
| // compiles against the SDK — the classes are just absent at runtime, and | ||
| // CrustModule's navAvailable guard returns a clean error if nav is invoked. | ||
| def navigationEnabled = (findProperty("mentraCrustNavigation") ?: "false").toString() == "true" | ||
| if (isChinaBuild || !navigationEnabled) { | ||
| compileOnly 'com.mapbox.navigationcore:navigation:3.25.0' | ||
| compileOnly 'com.mapbox.navigationcore:tripdata:3.25.0' | ||
|
Comment on lines
108
to
109
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
When Useful? React with 👍 / 👎. |
||
| } else { | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -13,6 +13,26 @@ import com.mentra.crust.jsc.InstalledMiniappManifest | |
| import com.mentra.crust.jsc.JSCPolyfillBridge | ||
|
|
||
| class CrustModule : Module() { | ||
| // Whether the Mapbox Navigation SDK is compiled into this APK. crust's config | ||
| // plugin defaults navigation off (compileOnly deps → classes absent at | ||
| // runtime) so non-navigating hosts build without a Mapbox credential; when | ||
| // off, the nav commands below return a clean error instead of crashing with | ||
| // NoClassDefFoundError. Resolved once, lazily (never during class init, which | ||
| // must not touch NavigationManager). Catches Throwable — a missing class | ||
| // surfaces as an Error, not an Exception. | ||
| private val navAvailable: Boolean by lazy { | ||
| try { | ||
| Class.forName("com.mapbox.navigation.core.MapboxNavigation") | ||
| true | ||
| } catch (t: Throwable) { | ||
| Log.i(TAG, "Mapbox Navigation SDK not compiled in — navigation commands disabled") | ||
| false | ||
| } | ||
| } | ||
|
|
||
| private val navUnavailableResult: Map<String, Any> = | ||
| mapOf("ok" to false, "error" to "navigation not available in this build") | ||
|
|
||
| companion object { | ||
| private const val TAG = "CrustModule" | ||
|
|
||
|
|
@@ -640,6 +660,7 @@ class CrustModule : Module() { | |
| // MARK: - Navigation Commands (Google Navigation SDK) | ||
|
|
||
| AsyncFunction("startNavigation") { lat: Double, lng: Double, options: Map<String, Any?>? -> | ||
| if (!navAvailable) return@AsyncFunction navUnavailableResult | ||
| val activity = appContext.currentActivity | ||
| ?: return@AsyncFunction mapOf("ok" to false, "error" to "no current activity (app backgrounded?)") | ||
| val simulate = (options?.get("simulate") as? Boolean) ?: false | ||
|
|
@@ -785,6 +806,10 @@ class CrustModule : Module() { | |
| // friction-free. Idempotent — resolves immediately when the user has | ||
| // already accepted (in-process flag, on-disk pref, or SDK state). | ||
| AsyncFunction("requestNavigationPermission") { promise: expo.modules.kotlin.Promise -> | ||
| if (!navAvailable) { | ||
| promise.resolve(navUnavailableResult) | ||
| return@AsyncFunction | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Permission response missing acceptedLow Severity When navigation is unavailable, Reviewed by Cursor Bugbot for commit 9f6602b. Configure here. |
||
| } | ||
| val activity = appContext.currentActivity | ||
| if (activity == null) { | ||
| promise.resolve(mapOf("ok" to false, "accepted" to false, "error" to "no current activity")) | ||
|
|
@@ -801,6 +826,10 @@ class CrustModule : Module() { | |
| // pref + in-process) so the next requestNavigationPermission() call | ||
| // re-shows the dialog. Used by the dev-settings re-trigger button. | ||
| AsyncFunction("resetNavigationPermission") { promise: expo.modules.kotlin.Promise -> | ||
| if (!navAvailable) { | ||
| promise.resolve(navUnavailableResult) | ||
| return@AsyncFunction | ||
| } | ||
| val activity = appContext.currentActivity | ||
| if (activity == null) { | ||
| promise.resolve(mapOf("ok" to false, "error" to "no current activity")) | ||
|
|
@@ -818,6 +847,7 @@ class CrustModule : Module() { | |
| } | ||
|
|
||
| AsyncFunction("stopNavigation") { | ||
| if (!navAvailable) return@AsyncFunction navUnavailableResult | ||
| try { | ||
| NavigationManager.stop() | ||
| mapOf("ok" to true) | ||
|
|
@@ -831,6 +861,7 @@ class CrustModule : Module() { | |
| // exercise the Nav SDK's onRerouting() pipeline without having to | ||
| // physically walk off the planned path. No-op on real GPS fixes. | ||
| AsyncFunction("simulateDeviation") { offsetMeters: Double? -> | ||
| if (!navAvailable) return@AsyncFunction navUnavailableResult | ||
| try { | ||
| NavigationManager.simulateDeviation(offsetMeters ?: 20.0) | ||
| mapOf("ok" to true) | ||
|
|
@@ -841,6 +872,7 @@ class CrustModule : Module() { | |
| } | ||
|
|
||
| AsyncFunction("setWrongSidewalkOffset") { enabled: Boolean -> | ||
| if (!navAvailable) return@AsyncFunction navUnavailableResult | ||
| try { | ||
| NavigationManager.setWrongSidewalkOffset(enabled) | ||
| mapOf("ok" to true) | ||
|
|
@@ -851,6 +883,7 @@ class CrustModule : Module() { | |
| } | ||
|
|
||
| AsyncFunction("setSkipCrossings") { enabled: Boolean -> | ||
| if (!navAvailable) return@AsyncFunction navUnavailableResult | ||
| try { | ||
| NavigationManager.setSkipCrossings(enabled) | ||
| mapOf("ok" to true) | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -6,11 +6,11 @@ | |
| "types": "build/index.d.ts", | ||
| "app.plugin": "app.plugin.js", | ||
| "scripts": { | ||
| "build": "expo-module build && expo-module build plugin", | ||
| "build": "expo-module build", | ||
| "clean": "expo-module clean", | ||
| "lint": "expo-module lint", | ||
| "test": "expo-module test", | ||
| "prepare": "expo-module prepare && expo-module build plugin", | ||
| "prepare": "expo-module prepare", | ||
|
Comment on lines
+9
to
+13
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Useful? React with 👍 / 👎. |
||
| "prepublishOnly": "expo-module prepublishOnly", | ||
| "expo-module": "expo-module", | ||
| "open:ios": "xed example/ios", | ||
|
|
||


There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nav-off compile needs Mapbox repo
High Severity
When
navigationis off, the crust plugin stops injecting the Mapbox Downloads Maven repo, but:mentra-cruststill declarescompileOnlyMapbox Navigation SDK dependencies. Gradle must still resolve those artifacts to compileNavigationManager.kt, which only exists in Mapbox’s private registry—so credential-free OEM builds fail on a clean cache.Additional Locations (1)
mobile/modules/crust/plugin/src/withAndroid.ts#L37-L38Reviewed by Cursor Bugbot for commit 9f6602b. Configure here.