@glassly/crust 0.4.0 → 0.4.1-beta.1138
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/android/build.gradle +9 -9
- package/android/src/main/java/com/glassly/crust/jsc/JSCPolyfillBridge.kt +11 -2
- package/build/CrustModule.d.ts +1 -0
- package/build/CrustModule.d.ts.map +1 -1
- package/build/CrustModule.js.map +1 -1
- package/ios/CrustModule.swift +11 -0
- package/ios/Resources/startup.js +3 -1
- package/ios/navigation/NavigationManager.swift +140 -112
- package/package.json +2 -2
- package/src/CrustModule.ts +1 -0
package/android/build.gradle
CHANGED
|
@@ -101,11 +101,11 @@ dependencies {
|
|
|
101
101
|
// Version pinned to 3.25.0 — re-check https://docs.mapbox.com/android/navigation/releases/
|
|
102
102
|
def isChinaBuild = System.getenv("EXPO_PUBLIC_DEPLOYMENT_REGION") == "china"
|
|
103
103
|
if (isChinaBuild) {
|
|
104
|
-
compileOnly 'com.mapbox.navigationcore:navigation-ndk27:3.
|
|
105
|
-
compileOnly 'com.mapbox.navigationcore:tripdata-ndk27:3.
|
|
104
|
+
compileOnly 'com.mapbox.navigationcore:navigation-ndk27:3.34.2'
|
|
105
|
+
compileOnly 'com.mapbox.navigationcore:tripdata-ndk27:3.34.2'
|
|
106
106
|
} else {
|
|
107
|
-
implementation 'com.mapbox.navigationcore:navigation-ndk27:3.
|
|
108
|
-
implementation 'com.mapbox.navigationcore:tripdata-ndk27:3.
|
|
107
|
+
implementation 'com.mapbox.navigationcore:navigation-ndk27:3.34.2'
|
|
108
|
+
implementation 'com.mapbox.navigationcore:tripdata-ndk27:3.34.2'
|
|
109
109
|
}
|
|
110
110
|
|
|
111
111
|
// Required for Java 8+ APIs on minSdk < 26 (was needed by Google Nav SDK;
|
|
@@ -114,8 +114,8 @@ dependencies {
|
|
|
114
114
|
}
|
|
115
115
|
|
|
116
116
|
dependencies {
|
|
117
|
-
implementation 'com.google.android.gms:play-services-location:21.0
|
|
118
|
-
implementation 'com.google.android.gms:play-services-base:18.
|
|
117
|
+
implementation 'com.google.android.gms:play-services-location:21.4.0'
|
|
118
|
+
implementation 'com.google.android.gms:play-services-base:18.11.1'
|
|
119
119
|
}
|
|
120
120
|
|
|
121
121
|
dependencies {
|
|
@@ -137,10 +137,10 @@ dependencies {
|
|
|
137
137
|
// Tink for X25519 (Android stdlib X25519 is API 33+ only; minSdk is 24).
|
|
138
138
|
// ~1.2 MB AAR. Crypto.subtle's SHA / AES-GCM / HMAC stay on javax.crypto
|
|
139
139
|
// which ships on the platform.
|
|
140
|
-
implementation 'com.google.crypto.tink:tink-android:1.
|
|
140
|
+
implementation 'com.google.crypto.tink:tink-android:1.24.0'
|
|
141
141
|
|
|
142
142
|
// Kotlin coroutines: dokar3's `evaluate()` is suspend; we bridge it via
|
|
143
143
|
// `runBlocking(dispatcher)` from the per-miniapp single-thread executor.
|
|
144
|
-
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.
|
|
145
|
-
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.
|
|
144
|
+
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.11.0'
|
|
145
|
+
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.11.0'
|
|
146
146
|
}
|
|
@@ -179,13 +179,22 @@ object JSCPolyfillBridge {
|
|
|
179
179
|
val sid = req["sid"] as? String
|
|
180
180
|
?: return@register JSCDispatchOutcome.Error("INVALID_ARGS", "ws.close: missing sid")
|
|
181
181
|
val rec = sockets[sid] ?: return@register JSCDispatchOutcome.Sync("null")
|
|
182
|
-
val
|
|
182
|
+
val rawCode = (req["code"] as? Number)?.toInt() ?: 1000
|
|
183
183
|
val reason = (req["reason"] as? String) ?: ""
|
|
184
|
-
rec.socket.close(
|
|
184
|
+
rec.socket.close(if (isSendableCloseCode(rawCode)) rawCode else 1001, reason)
|
|
185
|
+
if (!rec.closedSent) {
|
|
186
|
+
rec.closedSent = true
|
|
187
|
+
sockets.remove(sid)
|
|
188
|
+
deliverEvent(runtime, rec.packageName, sid, "close", mapOf("code" to rawCode, "reason" to reason))
|
|
189
|
+
}
|
|
185
190
|
JSCDispatchOutcome.Sync("null")
|
|
186
191
|
}
|
|
187
192
|
}
|
|
188
193
|
|
|
194
|
+
// Mirrors OkHttp's close-code validation, which throws instead of sending.
|
|
195
|
+
private fun isSendableCloseCode(code: Int): Boolean =
|
|
196
|
+
code in 1000..4999 && code !in 1004..1006 && code !in 1015..2999
|
|
197
|
+
|
|
189
198
|
private fun deliverEvent(
|
|
190
199
|
runtime: JSCRuntime,
|
|
191
200
|
packageName: String,
|
package/build/CrustModule.d.ts
CHANGED
|
@@ -2,6 +2,7 @@ import { NativeModule } from "expo";
|
|
|
2
2
|
import type { CrustModuleEvents, InstalledApp, PhoneLockState, ReservedRegion, WebViewCookie } from "./Crust.types";
|
|
3
3
|
declare class CrustModule extends NativeModule<CrustModuleEvents> {
|
|
4
4
|
PI: number;
|
|
5
|
+
arrangementViewAvailable?: boolean;
|
|
5
6
|
hello(): string;
|
|
6
7
|
/**
|
|
7
8
|
* iOS 27.1+: the regions the system currently occludes in the app window (the
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CrustModule.d.ts","sourceRoot":"","sources":["../src/CrustModule.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"CrustModule.d.ts","sourceRoot":"","sources":["../src/CrustModule.ts"],"names":[],"mappings":"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"}
|
package/build/CrustModule.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CrustModule.js","sourceRoot":"","sources":["../src/CrustModule.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,YAAY,EAAE,mBAAmB,EAAC,MAAM,MAAM,CAAA;
|
|
1
|
+
{"version":3,"file":"CrustModule.js","sourceRoot":"","sources":["../src/CrustModule.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,YAAY,EAAE,mBAAmB,EAAC,MAAM,MAAM,CAAA;AAiNtD,yDAAyD;AACzD,eAAe,mBAAmB,CAAc,OAAO,CAAC,CAAA","sourcesContent":["import {NativeModule, requireNativeModule} from \"expo\"\n\nimport type {CrustModuleEvents, InstalledApp, PhoneLockState, ReservedRegion, WebViewCookie} from \"./Crust.types\"\n\ndeclare class CrustModule extends NativeModule<CrustModuleEvents> {\n PI: number\n arrangementViewAvailable?: boolean\n hello(): string\n /**\n * iOS 27.1+: the regions the system currently occludes in the app window (the\n * Dynamic Island; on an iPhone Duo the status column down its rail, which grows\n * while the island holds a Live Activity). Empty elsewhere.\n */\n reservedRegions(): Promise<ReservedRegion[]>\n setValueAsync(value: string): Promise<void>\n nativeHttpRequest(\n method: string,\n url: string,\n headers: Record<string, string>,\n body?: string | null,\n ): Promise<{status: number; statusText: string; headers: Record<string, string>; body: string}>\n showAVRoutePicker(tintColor?: string | null): void\n\n /**\n * iOS: configure `preferredScreenEdgesDeferringSystemGestures`. When an\n * edge is deferred, the first swipe across that edge is consumed by the\n * app and the system gesture (Control Center, Notification Center, Home\n * indicator) only fires on a second swipe — i.e. a two-swipe-to-exit UX.\n *\n * Pass `[]` to restore default behavior. Android: no-op (Android has no\n * per-app equivalent; system gestures are configured at the OS level).\n */\n setDeferredSystemGestures(edges: Array<\"top\" | \"bottom\" | \"left\" | \"right\" | \"all\">): Promise<void>\n\n // Glassly Notification Commands\n setNotificationConfig(listenerEnabled: boolean, blocklist: string[]): Promise<void>\n getInstalledApps(): Promise<InstalledApp[]>\n getInstalledAppsForNotifications(): Promise<InstalledApp[]>\n hasNotificationListenerPermission(): Promise<boolean>\n refreshNotificationListener(): Promise<boolean>\n openNotificationListenerSettings(): Promise<boolean>\n /** Current lock state; changes arrive as `phone_lock_state` events. */\n getPhoneLockState(): Promise<PhoneLockState>\n isBetaBuild(): Promise<boolean>\n // location services commands\n showLocationServicesDialog(): Promise<boolean>\n isLocationServicesEnabled(): Promise<boolean>\n openLocationSettings(): Promise<boolean>\n openAppSettings(): Promise<boolean>\n openBluetoothSettings(): Promise<boolean>\n\n /**\n * Cookies the app's WebViews hold for `url`'s host, HttpOnly ones included\n * (a page's own JS cannot read those). Backs `session.system.webLogin`.\n */\n getWebViewCookies(url: string): Promise<WebViewCookie[]>\n /** Deletes those cookies, best effort; resolves with how many it removed. */\n clearWebViewCookies(url: string): Promise<number>\n\n // Image Processing Commands\n processGalleryImage(\n inputPath: string,\n outputPath: string,\n options: {\n lensCorrection?: boolean\n colorCorrection?: boolean\n },\n ): Promise<{\n success: boolean\n outputPath?: string\n processingTimeMs?: number\n error?: string\n }>\n\n mergeHdrBrackets(\n underPath: string,\n normalPath: string,\n overPath: string,\n outputPath: string,\n ): Promise<{\n success: boolean\n outputPath?: string\n processingTimeMs?: number\n error?: string\n }>\n\n stabilizeVideo(\n inputPath: string,\n imuPath: string,\n outputPath: string,\n ): Promise<{\n success: boolean\n outputPath?: string\n processingTimeMs?: number\n error?: string\n }>\n\n // Media Library Commands\n saveToGalleryWithDate(\n filePath: string,\n captureTimeMillis?: number,\n displayName?: string,\n ): Promise<{\n success: boolean\n uri?: string\n identifier?: string\n existing?: boolean\n error?: string\n }>\n\n // Navigation (both platforms via Mapbox; the dev toggles below are Android-only)\n /**\n * Override the Mapbox access token the native Navigation SDK\n * authenticates with. A non-empty token wins over the one baked at build\n * time (AndroidManifest `com.mapbox.token` / Info.plist `MBXAccessToken`);\n * \"\" clears the override and restores the baked token. Call before\n * `startNavigation` — the engine pushes the user's Settings > Keys token\n * here per trip start.\n */\n setMapboxAccessToken(token: string): Promise<{ok: boolean; error?: string}>\n startNavigation(\n lat: number,\n lng: number,\n options?: {\n simulate?: boolean\n speedMultiplier?: number\n /** Optional multi-stop list. When present takes precedence over lat/lng. Last entry is the final destination. */\n stops?: Array<{lat: number; lng: number}>\n /** \"walking\" | \"driving\" | \"cycling\" | \"two_wheeler\". Defaults walking. */\n mode?: string\n avoid?: {highways?: boolean; tolls?: boolean; ferries?: boolean}\n /** Force a reroute when the user is more than N meters past a pivot they didn't take. */\n missedTurnRerouteMeters?: number\n },\n ): Promise<{ok: boolean; error?: string}>\n stopNavigation(): Promise<{ok: boolean; error?: string}>\n\n /**\n * Kept for API parity with the Google-era contract. Mapbox has no\n * Terms & Conditions dialog, so no dialog is shown; resolves with\n * `{accepted: true}` once permission handling completes. Idempotent —\n * still safe (and intended) to call eagerly.\n */\n requestNavigationPermission(): Promise<{ok: boolean; accepted: boolean; error?: string}>\n\n /**\n * Dev-only: push the simulated user position off-route so the Nav SDK\n * reroutes. Only meaningful in simulate mode. Both platforms;\n * `offsetMeters` tunes the jump on Android and is ignored on iOS.\n */\n simulateDeviation(offsetMeters?: number): Promise<{ok: boolean; error?: string}>\n\n /**\n * Dev toggle. When enabled, the native NavigationManager shifts every\n * reported location ~8m perpendicular to the route bearing, simulating\n * a pedestrian walking on the wrong sidewalk. Only meaningful in\n * simulate mode; lets us verify the SDK's along-path pivot trigger\n * fires even when the user never crosses the 7m pivot point radius.\n * Android-only today; iOS is a no-op stub.\n */\n setWrongSidewalkOffset(enabled: boolean): Promise<{ok: boolean; error?: string}>\n\n /**\n * Dev toggle. When enabled, the native NavigationManager takes over\n * from the Mapbox simulator and walks the user along a modified\n * polyline that omits crossing micro-steps — reproducing the\n * wrong-sidewalk-then-missed-the-turn scenario. Android-only today;\n * iOS is a no-op stub.\n */\n setSkipCrossings(enabled: boolean): Promise<{ok: boolean; error?: string}>\n\n // Heading / compass (both platforms)\n startHeading(): Promise<{ok: boolean; error?: string}>\n stopHeading(): Promise<{ok: boolean; error?: string}>\n\n // JS Runtime — per-miniapp JSContext lifecycle.\n /**\n * Spawn a per-miniapp JS context. Re-spawn is allowed: a live context\n * with the same packageName is killed first. Returns true if the\n * polyfill bundle + miniapp source evaluated without throwing.\n *\n * The polyfill bundle is `mobile/modules/jspolyfill/dist/startup.js`\n * (shipped inside the host binary). It installs window-style globals\n * (console, timers, fetch, localStorage, crypto) atop the JSC runtime.\n */\n jsSpawn(packageName: string, polyfillBundle: string, miniappJs: string): Promise<boolean>\n jsEvaluate(packageName: string, source: string): Promise<unknown>\n jsKill(packageName: string): Promise<void>\n /**\n * Push a `{kind: \"event\"|\"response\", …}` envelope into the named\n * context's globalThis.__deliver. Returns when the underlying\n * evaluateScript completes (the JS handler runs synchronously on the\n * context's queue).\n */\n jsDispatchToJs(packageName: string, envelope: Record<string, unknown>): Promise<void>\n jsSetManifest(packageName: string, permissions: string[]): Promise<void>\n /** Diagnostic — returns the packageNames of every live JSContext. */\n jsAlivePackages(): string[]\n /** Diagnostic — force a GC cycle on the named context. */\n jsDebugForceGC(packageName: string): Promise<boolean>\n /**\n * Read the bundled JSRuntime polyfill (startup.js) shipped inside the\n * host binary. Synchronous — host RN code calls this once on app boot\n * and caches the string, then passes it to every jsSpawn so\n * every JSContext starts with the same polyfill ABI.\n */\n jsLoadPolyfillBundle(): string\n}\n\n// This call loads the native module object from the JSI.\nexport default requireNativeModule<CrustModule>(\"Crust\")\n"]}
|
package/ios/CrustModule.swift
CHANGED
|
@@ -112,6 +112,17 @@ public class CrustModule: Module {
|
|
|
112
112
|
Double.pi
|
|
113
113
|
}
|
|
114
114
|
|
|
115
|
+
// SwiftUI's ArrangementView exists only in binaries linked against the
|
|
116
|
+
// iOS 27.1 SDK and running on 27.1; anything else lays home out in JS.
|
|
117
|
+
Constant("arrangementViewAvailable") { () -> Bool in
|
|
118
|
+
#if canImport(SwiftUICore, _version: 8.0.85)
|
|
119
|
+
if #available(iOS 27.1, *) {
|
|
120
|
+
return true
|
|
121
|
+
}
|
|
122
|
+
#endif
|
|
123
|
+
return false
|
|
124
|
+
}
|
|
125
|
+
|
|
115
126
|
Events(
|
|
116
127
|
"onChange",
|
|
117
128
|
"phone_notification",
|
package/ios/Resources/startup.js
CHANGED
|
@@ -605,7 +605,9 @@
|
|
|
605
605
|
}
|
|
606
606
|
}
|
|
607
607
|
const sendRequest = g.__sendRequest;
|
|
608
|
-
const result = await sendRequest("fetch", "request", [
|
|
608
|
+
const result = await sendRequest("fetch", "request", [
|
|
609
|
+
{ url, method, headers, body: bodyString, bodyBase64 }
|
|
610
|
+
]);
|
|
609
611
|
const bodyText = typeof result.body === "string" ? result.body : "";
|
|
610
612
|
const responseHeaders = new Map(Object.entries(result.headers ?? {}));
|
|
611
613
|
class ResponseLike {
|
|
@@ -24,10 +24,8 @@ import MapboxNavigationCore
|
|
|
24
24
|
/// - iOS v3 is **Combine publisher-based**, not observer-based. We hold
|
|
25
25
|
/// `AnyCancellable`s instead of registering observer objects.
|
|
26
26
|
/// - Routing is `async`: `routingProvider().calculateRoutes(options:)`.
|
|
27
|
-
/// - Simulation is a
|
|
28
|
-
/// provider
|
|
29
|
-
/// the source is fixed when the provider is built, switching sim on/off
|
|
30
|
-
/// rebuilds the provider (see `makeProvider`).
|
|
27
|
+
/// - Simulation is a CoreConfig location source. Reconfigure the one retained
|
|
28
|
+
/// provider between trips; Mapbox forbids simultaneous provider instances.
|
|
31
29
|
/// - Mapbox owns off-route detection + auto-reroute on iOS too, same as
|
|
32
30
|
/// Android — we observe, we don't re-derive.
|
|
33
31
|
///
|
|
@@ -55,19 +53,23 @@ final class NavigationManager: NSObject {
|
|
|
55
53
|
private var onLocation: LocationCallback?
|
|
56
54
|
private var onRoute: RouteCallback?
|
|
57
55
|
|
|
58
|
-
//
|
|
59
|
-
//
|
|
56
|
+
// Mapbox permits exactly one provider, including while old async work unwinds.
|
|
57
|
+
// Keep it for this singleton's lifetime and reconfigure it between trips.
|
|
58
|
+
private var tripGeneration = UUID()
|
|
59
|
+
private var startCompletion: StartCompletion?
|
|
60
60
|
private var provider: MapboxNavigationProvider?
|
|
61
|
-
private var mapboxNavigation: MapboxNavigation? {
|
|
61
|
+
private var mapboxNavigation: MapboxNavigation? {
|
|
62
|
+
provider?.mapboxNavigation
|
|
63
|
+
}
|
|
62
64
|
|
|
63
|
-
|
|
65
|
+
/// Combine subscriptions — torn down on stop().
|
|
64
66
|
private var cancellables = Set<AnyCancellable>()
|
|
65
67
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
68
|
+
/// First-fix gate. Mapbox has no synchronous "current location" getter; the
|
|
69
|
+
/// device position arrives only via the locationMatching publisher AFTER the
|
|
70
|
+
/// session starts. So we start the session, capture the first fix, THEN
|
|
71
|
+
/// request the route from that real origin. Mirrors Android's
|
|
72
|
+
/// `pendingRouteRequest`. nil once fired (one-shot).
|
|
71
73
|
private var pendingRouteRequest: ((_ originLat: Double, _ originLng: Double) -> Void)?
|
|
72
74
|
|
|
73
75
|
// Per-trip config captured from start().
|
|
@@ -76,18 +78,18 @@ final class NavigationManager: NSObject {
|
|
|
76
78
|
private var simulating: Bool = false
|
|
77
79
|
private var simulationSpeed: Double = 1.0
|
|
78
80
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
81
|
+
/// Dedup the maneuver emission to ~1m granularity (matches Android's
|
|
82
|
+
/// emitManeuverIfChanged so the "In X m" countdown updates ~1 Hz and stays in
|
|
83
|
+
/// lockstep with the trip distance). Key = "type|distM|tripM".
|
|
82
84
|
private var lastEmittedManeuverKey: String?
|
|
83
85
|
|
|
84
|
-
|
|
86
|
+
/// Arrival is reported once; the SDK keeps ticking COMPLETE afterwards.
|
|
85
87
|
private var arrivedHandled = false
|
|
86
|
-
|
|
88
|
+
/// Off-route emitted once per episode (reset on reroute), same as Android.
|
|
87
89
|
private var offRouteEmitted = false
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
90
|
+
/// The navigationRoutes publisher fires once with the INITIAL route (already
|
|
91
|
+
/// emitted by requestAndStartRoute). We skip that first emission and treat
|
|
92
|
+
/// every subsequent one as a reroute redraw. false until the first fires.
|
|
91
93
|
private var didEmitInitialRoute = false
|
|
92
94
|
|
|
93
95
|
// Last two forwarded coords — the Deviate dev walker derives its bearing
|
|
@@ -99,9 +101,9 @@ final class NavigationManager: NSObject {
|
|
|
99
101
|
|
|
100
102
|
// MARK: - Access token
|
|
101
103
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
104
|
+
/// User-supplied Mapbox token (Settings > Keys), pushed from JS via
|
|
105
|
+
/// CrustModule.setMapboxAccessToken. Non-empty wins over the Info.plist
|
|
106
|
+
/// MBXAccessToken the SDK reads at boot; "" means "no override".
|
|
105
107
|
private var accessTokenOverride: String = ""
|
|
106
108
|
|
|
107
109
|
/// Set (or with "" clear) the runtime token override. Applied to the
|
|
@@ -115,7 +117,9 @@ final class NavigationManager: NSObject {
|
|
|
115
117
|
/// The token the next provider build must use: the override when set, else
|
|
116
118
|
/// the baked Info.plist token, else "" (nothing to authenticate with).
|
|
117
119
|
private func resolvedAccessToken() -> String {
|
|
118
|
-
if !accessTokenOverride.isEmpty {
|
|
120
|
+
if !accessTokenOverride.isEmpty {
|
|
121
|
+
return accessTokenOverride
|
|
122
|
+
}
|
|
119
123
|
if let baked = Bundle.main.object(forInfoDictionaryKey: "MBXAccessToken") as? String, !baked.isEmpty {
|
|
120
124
|
return baked
|
|
121
125
|
}
|
|
@@ -127,7 +131,9 @@ final class NavigationManager: NSObject {
|
|
|
127
131
|
/// components read it, so keep it in step.
|
|
128
132
|
private func applyAccessToken() {
|
|
129
133
|
let token = resolvedAccessToken()
|
|
130
|
-
if !token.isEmpty {
|
|
134
|
+
if !token.isEmpty {
|
|
135
|
+
MapboxOptions.accessToken = token
|
|
136
|
+
}
|
|
131
137
|
}
|
|
132
138
|
|
|
133
139
|
// MARK: - Permissions
|
|
@@ -162,73 +168,71 @@ final class NavigationManager: NSObject {
|
|
|
162
168
|
return
|
|
163
169
|
}
|
|
164
170
|
|
|
171
|
+
startCompletion = completion
|
|
172
|
+
let completion: StartCompletion = { [weak self] success, error in
|
|
173
|
+
self?.finishStart(success, error)
|
|
174
|
+
}
|
|
165
175
|
self.onEvent = onEvent
|
|
166
176
|
self.onLocation = onLocation
|
|
167
177
|
self.onRoute = onRoute
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
178
|
+
tripStops = stops
|
|
179
|
+
travelMode = mode
|
|
180
|
+
simulating = simulate
|
|
181
|
+
simulationSpeed = max(0.5, min(speedMultiplier, 50))
|
|
182
|
+
arrivedHandled = false
|
|
183
|
+
offRouteEmitted = false
|
|
184
|
+
didEmitInitialRoute = false
|
|
185
|
+
lastEmittedManeuverKey = nil
|
|
176
186
|
// (missedTurnRerouteMeters is intentionally unused on the Mapbox path —
|
|
177
187
|
// Mapbox owns reroute natively, same decision as Android. Kept in the
|
|
178
188
|
// signature for contract parity with CrustModule.)
|
|
179
189
|
_ = missedTurnRerouteMeters
|
|
180
190
|
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
// when set, else the baked Info.plist token.
|
|
186
|
-
self.applyAccessToken()
|
|
187
|
-
|
|
188
|
-
// Build the provider with the right location source. Simulation is a
|
|
189
|
-
// CoreConfig choice; `.simulation` drives a synthetic puck along the
|
|
190
|
-
// active route once one is set.
|
|
191
|
-
let provider = self.makeProvider(simulate: simulate)
|
|
192
|
-
self.provider = provider
|
|
193
|
-
|
|
194
|
-
// `mapboxNavigation` is non-optional on the provider.
|
|
195
|
-
let nav = provider.mapboxNavigation
|
|
196
|
-
|
|
197
|
-
// Subscribe to the publishers BEFORE starting the session so we don't
|
|
198
|
-
// miss the first ticks.
|
|
199
|
-
self.subscribe(nav)
|
|
200
|
-
|
|
201
|
-
// Start a free-drive (passive) session so location starts flowing; the
|
|
202
|
-
// first fix satisfies the gate below, then we request the route and
|
|
203
|
-
// switch to active guidance.
|
|
204
|
-
// VERIFY-IN-XCODE: free-drive start method name. v3 examples show
|
|
205
|
-
// `nav.tripSession().startFreeDrive()`.
|
|
206
|
-
nav.tripSession().startFreeDrive()
|
|
207
|
-
|
|
208
|
-
// First-fix gate: request the route from the device's real origin.
|
|
209
|
-
self.pendingRouteRequest = { [weak self] originLat, originLng in
|
|
210
|
-
self?.requestAndStartRoute(
|
|
211
|
-
nav: nav,
|
|
212
|
-
originLat: originLat,
|
|
213
|
-
originLng: originLng,
|
|
214
|
-
completion: completion
|
|
215
|
-
)
|
|
216
|
-
}
|
|
191
|
+
// Already on the main actor: do not enqueue a second, overlapping start.
|
|
192
|
+
// Token precedence must hold for THIS provider build: user override
|
|
193
|
+
// when set, else the baked Info.plist token.
|
|
194
|
+
applyAccessToken()
|
|
217
195
|
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
196
|
+
// Reconfigure the shared provider for live or simulated locations.
|
|
197
|
+
let provider = makeProvider(simulate: simulate)
|
|
198
|
+
self.provider = provider
|
|
199
|
+
|
|
200
|
+
// `mapboxNavigation` is non-optional on the provider.
|
|
201
|
+
let nav = provider.mapboxNavigation
|
|
202
|
+
|
|
203
|
+
// Subscribe to the publishers BEFORE starting the session so we don't
|
|
204
|
+
// miss the first ticks.
|
|
205
|
+
subscribe(nav)
|
|
206
|
+
|
|
207
|
+
// Start a free-drive (passive) session so location starts flowing; the
|
|
208
|
+
// first fix satisfies the gate below, then we request the route and
|
|
209
|
+
// switch to active guidance.
|
|
210
|
+
// VERIFY-IN-XCODE: free-drive start method name. v3 examples show
|
|
211
|
+
// `nav.tripSession().startFreeDrive()`.
|
|
212
|
+
nav.tripSession().startFreeDrive()
|
|
213
|
+
|
|
214
|
+
// First-fix gate: request the route from the device's real origin.
|
|
215
|
+
pendingRouteRequest = { [weak self] originLat, originLng in
|
|
216
|
+
self?.requestAndStartRoute(
|
|
217
|
+
nav: nav,
|
|
218
|
+
originLat: originLat,
|
|
219
|
+
originLng: originLng,
|
|
220
|
+
completion: completion
|
|
221
|
+
)
|
|
227
222
|
}
|
|
223
|
+
|
|
224
|
+
// First-fix TIMEOUT (live AND sim). The gate above waits for Mapbox's
|
|
225
|
+
// locationMatching publisher to emit the first fix before requesting the
|
|
226
|
+
// route. On a COLD APP LAUNCH that first fix can be slow or never arrive
|
|
227
|
+
// until the CLLocationManager fully spins up — which is exactly the
|
|
228
|
+
// "first nav after launch hangs at Starting…, works on the 2nd try" bug
|
|
229
|
+
// (the 2nd try has a warm location manager). So we ALWAYS arm a timeout:
|
|
230
|
+
// if no fix satisfies the gate in time, request the route from a one-shot
|
|
231
|
+
// CoreLocation fix / last known location so we never hang.
|
|
232
|
+
armFirstFixTimeout(nav: nav, completion: completion)
|
|
228
233
|
}
|
|
229
234
|
|
|
230
|
-
///
|
|
231
|
-
/// at construction, which is why a sim toggle rebuilds the provider.
|
|
235
|
+
/// Reuse the provider even when a previous trip still has routing work in flight.
|
|
232
236
|
private func makeProvider(simulate: Bool) -> MapboxNavigationProvider {
|
|
233
237
|
// Explicit reroute config: native off-route detection + auto-reroute ON
|
|
234
238
|
// (this is the SDK default — detectsReroute defaults to true — but we set it
|
|
@@ -254,6 +258,10 @@ final class NavigationManager: NSObject {
|
|
|
254
258
|
routingConfig: routingConfig,
|
|
255
259
|
locationSource: simulate ? .simulation(initialLocation: nil) : .live
|
|
256
260
|
)
|
|
261
|
+
if let provider {
|
|
262
|
+
provider.apply(coreConfig: coreConfig)
|
|
263
|
+
return provider
|
|
264
|
+
}
|
|
257
265
|
return MapboxNavigationProvider(coreConfig: coreConfig)
|
|
258
266
|
}
|
|
259
267
|
|
|
@@ -364,10 +372,11 @@ final class NavigationManager: NSObject {
|
|
|
364
372
|
completion: @escaping StartCompletion,
|
|
365
373
|
attempt: Int = 0
|
|
366
374
|
) {
|
|
367
|
-
let maxAttempts = 8
|
|
375
|
+
let maxAttempts = 8 // ~8 × 0.75s ≈ 6s total before giving up
|
|
368
376
|
let interval: TimeInterval = 0.75
|
|
377
|
+
let generation = tripGeneration
|
|
369
378
|
DispatchQueue.main.asyncAfter(deadline: .now() + interval) { [weak self] in
|
|
370
|
-
guard let self else { return }
|
|
379
|
+
guard let self, self.tripGeneration == generation else { return }
|
|
371
380
|
// Gate already fired (a real fix arrived) — nothing to do.
|
|
372
381
|
guard let pending = self.pendingRouteRequest else { return }
|
|
373
382
|
|
|
@@ -416,24 +425,22 @@ final class NavigationManager: NSObject {
|
|
|
416
425
|
|
|
417
426
|
// VERIFY-IN-XCODE: `routingProvider().calculateRoutes(options:)` returns a
|
|
418
427
|
// Task whose `.result` is `Result<NavigationRoutes, Error>` (v3 example).
|
|
428
|
+
let generation = tripGeneration
|
|
419
429
|
let task = nav.routingProvider().calculateRoutes(options: options)
|
|
420
430
|
Task { [weak self] in
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
await MainActor.run {
|
|
435
|
-
completion(false, "route request failed: \(error.localizedDescription)")
|
|
436
|
-
}
|
|
431
|
+
let result = await task.result
|
|
432
|
+
guard let self, self.tripGeneration == generation else { return }
|
|
433
|
+
switch result {
|
|
434
|
+
case let .success(navigationRoutes):
|
|
435
|
+
// v3 SessionController: startActiveGuidance(with:startLegIndex:).
|
|
436
|
+
// Off-route detection + auto-reroute only run in ACTIVE GUIDANCE — so
|
|
437
|
+
// this call (not the earlier free-drive) is what arms rerouting.
|
|
438
|
+
print("[NavMgr] startActiveGuidance — \(navigationRoutes.mainRoute.route.legs.count) legs, profile=\(self.travelMode)")
|
|
439
|
+
nav.tripSession().startActiveGuidance(with: navigationRoutes, startLegIndex: 0)
|
|
440
|
+
self.emitRoute(navigationRoutes)
|
|
441
|
+
completion(true, nil)
|
|
442
|
+
case let .failure(error):
|
|
443
|
+
completion(false, "route request failed: \(error.localizedDescription)")
|
|
437
444
|
}
|
|
438
445
|
}
|
|
439
446
|
}
|
|
@@ -453,12 +460,18 @@ final class NavigationManager: NSObject {
|
|
|
453
460
|
// MARK: - Stop
|
|
454
461
|
|
|
455
462
|
func stop() {
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
463
|
+
stopInternal()
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
private func finishStart(_ success: Bool, _ error: String?) {
|
|
467
|
+
let completion = startCompletion
|
|
468
|
+
startCompletion = nil
|
|
469
|
+
completion?(success, error)
|
|
459
470
|
}
|
|
460
471
|
|
|
461
472
|
private func stopInternal() {
|
|
473
|
+
tripGeneration = UUID()
|
|
474
|
+
finishStart(false, "navigation stopped")
|
|
462
475
|
deviateTimer?.invalidate()
|
|
463
476
|
deviateTimer = nil
|
|
464
477
|
cancellables.forEach { $0.cancel() }
|
|
@@ -466,7 +479,6 @@ final class NavigationManager: NSObject {
|
|
|
466
479
|
// Trip-session stop: SessionController.setToIdle(). `mapboxNavigation` is
|
|
467
480
|
// non-optional, so only `provider?` carries the optional chain.
|
|
468
481
|
provider?.mapboxNavigation.tripSession().setToIdle()
|
|
469
|
-
provider = nil
|
|
470
482
|
onEvent = nil
|
|
471
483
|
onLocation = nil
|
|
472
484
|
onRoute = nil
|
|
@@ -522,7 +534,7 @@ final class NavigationManager: NSObject {
|
|
|
522
534
|
if simulating {
|
|
523
535
|
// In sim the puck is parked at the destination; nothing more to do
|
|
524
536
|
// on iOS (no replay session to tear back to live). The next start()
|
|
525
|
-
//
|
|
537
|
+
// reconfigures the shared provider.
|
|
526
538
|
}
|
|
527
539
|
}
|
|
528
540
|
return
|
|
@@ -592,7 +604,9 @@ final class NavigationManager: NSObject {
|
|
|
592
604
|
let distBucket = distanceMeters >= 0 ? distanceMeters : -1
|
|
593
605
|
let tripBucket = distanceToDestinationMeters >= 0 ? distanceToDestinationMeters : -1
|
|
594
606
|
let key = "\(maneuverType)|\(distBucket)|\(tripBucket)"
|
|
595
|
-
if key == lastEmittedManeuverKey {
|
|
607
|
+
if key == lastEmittedManeuverKey {
|
|
608
|
+
return
|
|
609
|
+
}
|
|
596
610
|
lastEmittedManeuverKey = key
|
|
597
611
|
|
|
598
612
|
var payload: [String: Any] = [
|
|
@@ -602,9 +616,15 @@ final class NavigationManager: NSObject {
|
|
|
602
616
|
"distanceToDestinationMeters": distanceToDestinationMeters,
|
|
603
617
|
"timeToDestinationSeconds": timeToDestinationSeconds,
|
|
604
618
|
]
|
|
605
|
-
if let fromRoad {
|
|
606
|
-
|
|
607
|
-
|
|
619
|
+
if let fromRoad {
|
|
620
|
+
payload["fromRoad"] = fromRoad; payload["toRoad"] = fromRoad
|
|
621
|
+
}
|
|
622
|
+
if let nextStepRoad {
|
|
623
|
+
payload["nextStepRoad"] = nextStepRoad
|
|
624
|
+
}
|
|
625
|
+
if let instruction {
|
|
626
|
+
payload["instruction"] = instruction
|
|
627
|
+
}
|
|
608
628
|
onEvent?(payload)
|
|
609
629
|
}
|
|
610
630
|
|
|
@@ -647,11 +667,15 @@ final class NavigationManager: NSObject {
|
|
|
647
667
|
"maneuver": maneuverString(type: step.maneuverType, direction: step.maneuverDirection),
|
|
648
668
|
"distanceMeters": Int(step.distance.rounded()),
|
|
649
669
|
]
|
|
650
|
-
if let road = step.names?.first?.nonBlank {
|
|
670
|
+
if let road = step.names?.first?.nonBlank {
|
|
671
|
+
entry["road"] = road
|
|
672
|
+
}
|
|
651
673
|
steps.append(entry)
|
|
652
674
|
}
|
|
653
675
|
}
|
|
654
|
-
if !steps.isEmpty {
|
|
676
|
+
if !steps.isEmpty {
|
|
677
|
+
payload["steps"] = steps
|
|
678
|
+
}
|
|
655
679
|
|
|
656
680
|
onRoute?(payload)
|
|
657
681
|
}
|
|
@@ -663,7 +687,9 @@ final class NavigationManager: NSObject {
|
|
|
663
687
|
let dx = (p["lat"] ?? 0) - lat
|
|
664
688
|
let dy = (p["lng"] ?? 0) - lng
|
|
665
689
|
let d = dx * dx + dy * dy
|
|
666
|
-
if d < bestD {
|
|
690
|
+
if d < bestD {
|
|
691
|
+
bestD = d; best = i
|
|
692
|
+
}
|
|
667
693
|
}
|
|
668
694
|
return best
|
|
669
695
|
}
|
|
@@ -685,7 +711,9 @@ final class NavigationManager: NSObject {
|
|
|
685
711
|
let bearing: Double = {
|
|
686
712
|
if let prev = self.prevReportedCoord, let last = self.lastReportedCoord {
|
|
687
713
|
let d = self.haversineMeters(prev, last)
|
|
688
|
-
if d > 0.5 {
|
|
714
|
+
if d > 0.5 {
|
|
715
|
+
return self.bearingDegrees(from: prev, to: last)
|
|
716
|
+
}
|
|
689
717
|
}
|
|
690
718
|
return .nan
|
|
691
719
|
}()
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@glassly/crust",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.1-beta.1138",
|
|
4
4
|
"description": "Glassly Native Module",
|
|
5
5
|
"main": "build/index.js",
|
|
6
6
|
"types": "build/index.d.ts",
|
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
"license": "MIT",
|
|
36
36
|
"homepage": "https://github.com/fossephate/crust#readme",
|
|
37
37
|
"dependencies": {
|
|
38
|
-
"@glassly/jspolyfill": "0.4.
|
|
38
|
+
"@glassly/jspolyfill": "0.4.1-beta.1138"
|
|
39
39
|
},
|
|
40
40
|
"devDependencies": {
|
|
41
41
|
"@expo/config-plugins": ">=8.0.0",
|
package/src/CrustModule.ts
CHANGED
|
@@ -4,6 +4,7 @@ import type {CrustModuleEvents, InstalledApp, PhoneLockState, ReservedRegion, We
|
|
|
4
4
|
|
|
5
5
|
declare class CrustModule extends NativeModule<CrustModuleEvents> {
|
|
6
6
|
PI: number
|
|
7
|
+
arrangementViewAvailable?: boolean
|
|
7
8
|
hello(): string
|
|
8
9
|
/**
|
|
9
10
|
* iOS 27.1+: the regions the system currently occludes in the app window (the
|