@mentra/crust 3.2.0-dev.137 → 3.2.0-dev.154
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/ios/Crust.podspec +2 -2
- package/package.json +3 -2
- package/plugin/build/index.d.ts +2 -1
- package/plugin/build/index.js +8 -2
- package/plugin/build/withMapboxNavCrustLink.d.ts +3 -0
- package/plugin/build/withMapboxNavCrustLink.js +163 -0
- package/plugin/build/withMapboxNavIos.d.ts +3 -0
- package/plugin/build/withMapboxNavIos.js +151 -0
package/ios/Crust.podspec
CHANGED
|
@@ -24,7 +24,7 @@ Pod::Spec.new do |s|
|
|
|
24
24
|
# CocoaPods dependency — Mapbox Nav v3 dropped reliable CocoaPods support, so
|
|
25
25
|
# `pod install` cannot resolve 'MapboxNavigationCore' ("Unable to find a
|
|
26
26
|
# specification"). The SPM package is wired into the Xcode project by
|
|
27
|
-
#
|
|
27
|
+
# @mentra/crust/plugin/src/withMapboxNavIos.ts at prebuild, and its MapboxMaps dependency
|
|
28
28
|
# + Downloads-token auth come from the @rnmapbox/maps config plugin. So there
|
|
29
29
|
# is intentionally NO `s.dependency 'MapboxNavigationCore'` here.
|
|
30
30
|
|
|
@@ -34,7 +34,7 @@ Pod::Spec.new do |s|
|
|
|
34
34
|
# Swift/Objective-C compatibility + Mapbox SPM module visibility.
|
|
35
35
|
#
|
|
36
36
|
# MapboxNavigationCore / MapboxMaps / MapboxDirections are linked into the
|
|
37
|
-
# Crust target as Swift Package products (see
|
|
37
|
+
# Crust target as Swift Package products (see plugin/src/withMapboxNavCrustLink.ts).
|
|
38
38
|
# MapboxDirections builds as a STATIC LIBRARY, so SPM emits it as a bare
|
|
39
39
|
# `MapboxDirections.swiftmodule` in the build-products dir rather than a
|
|
40
40
|
# `.framework`. For `import MapboxDirections` to resolve from this CocoaPods
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mentra/crust",
|
|
3
|
-
"version": "3.2.0-dev.
|
|
3
|
+
"version": "3.2.0-dev.154",
|
|
4
4
|
"description": "Mentra Native Module",
|
|
5
5
|
"main": "build/index.js",
|
|
6
6
|
"types": "build/index.d.ts",
|
|
@@ -35,10 +35,11 @@
|
|
|
35
35
|
"license": "Apache-2.0",
|
|
36
36
|
"homepage": "https://github.com/Mentra-Community/MentraOS/tree/dev/mobile/modules/crust#readme",
|
|
37
37
|
"dependencies": {
|
|
38
|
-
"@mentra/jspolyfill": "3.2.0-dev.
|
|
38
|
+
"@mentra/jspolyfill": "3.2.0-dev.154"
|
|
39
39
|
},
|
|
40
40
|
"devDependencies": {
|
|
41
41
|
"@expo/config-plugins": ">=8.0.0",
|
|
42
|
+
"@types/node": "^25.9.3",
|
|
42
43
|
"expo-module-scripts": "^55.0.2",
|
|
43
44
|
"typescript": "~5.9.2"
|
|
44
45
|
},
|
package/plugin/build/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { type ConfigPlugin } from "expo/config-plugins";
|
|
2
2
|
/**
|
|
3
|
-
* @mentra/crust config plugin — the module's
|
|
3
|
+
* @mentra/crust config plugin — the module's native build contract, so
|
|
4
4
|
* every host that embeds crust (the Mentra app, the example OEM app, real OEM
|
|
5
5
|
* hosts) inherits it by listing "@mentra/crust" in `app.json` plugins instead
|
|
6
6
|
* of hand-mirroring gradle edits:
|
|
@@ -16,6 +16,7 @@ import { type ConfigPlugin } from "expo/config-plugins";
|
|
|
16
16
|
* apps — the Nav SDK uses newer core libs)
|
|
17
17
|
* - a generated MainApplication process guard so the notification-listener
|
|
18
18
|
* process never initializes React Native
|
|
19
|
+
* - iOS Mapbox Swift Package products and the Crust build-order dependency
|
|
19
20
|
*/
|
|
20
21
|
declare const withCrust: ConfigPlugin;
|
|
21
22
|
export default withCrust;
|
package/plugin/build/index.js
CHANGED
|
@@ -1,8 +1,13 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
2
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
6
|
const withAndroid_1 = require("./withAndroid");
|
|
7
|
+
const withMapboxNavCrustLink_1 = __importDefault(require("./withMapboxNavCrustLink"));
|
|
8
|
+
const withMapboxNavIos_1 = __importDefault(require("./withMapboxNavIos"));
|
|
4
9
|
/**
|
|
5
|
-
* @mentra/crust config plugin — the module's
|
|
10
|
+
* @mentra/crust config plugin — the module's native build contract, so
|
|
6
11
|
* every host that embeds crust (the Mentra app, the example OEM app, real OEM
|
|
7
12
|
* hosts) inherits it by listing "@mentra/crust" in `app.json` plugins instead
|
|
8
13
|
* of hand-mirroring gradle edits:
|
|
@@ -18,8 +23,9 @@ const withAndroid_1 = require("./withAndroid");
|
|
|
18
23
|
* apps — the Nav SDK uses newer core libs)
|
|
19
24
|
* - a generated MainApplication process guard so the notification-listener
|
|
20
25
|
* process never initializes React Native
|
|
26
|
+
* - iOS Mapbox Swift Package products and the Crust build-order dependency
|
|
21
27
|
*/
|
|
22
28
|
const withCrust = (config) => {
|
|
23
|
-
return (0, withAndroid_1.withCrustAndroidBuildContract)(config);
|
|
29
|
+
return (0, withMapboxNavCrustLink_1.default)((0, withMapboxNavIos_1.default)((0, withAndroid_1.withCrustAndroidBuildContract)(config)));
|
|
24
30
|
};
|
|
25
31
|
exports.default = withCrust;
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const fs_1 = __importDefault(require("fs"));
|
|
7
|
+
const path_1 = __importDefault(require("path"));
|
|
8
|
+
const config_plugins_1 = require("expo/config-plugins");
|
|
9
|
+
/**
|
|
10
|
+
* Expo Config Plugin — make the Mapbox Navigation SPM modules importable from
|
|
11
|
+
* the `Crust` CocoaPods target WITHOUT statically linking them into libCrust.a,
|
|
12
|
+
* AND guarantee they are built BEFORE Crust compiles.
|
|
13
|
+
*
|
|
14
|
+
* The problem: `Crust` is a CocoaPods static-library target (in Pods.xcodeproj),
|
|
15
|
+
* and the Mapbox SPM products (MapboxNavigationCore / MapboxDirections /
|
|
16
|
+
* MapboxMaps) are added to the APP target in the app project (withMapboxNavIos.ts).
|
|
17
|
+
* Crust's Swift needs to `import MapboxNavigationCore` etc.
|
|
18
|
+
*
|
|
19
|
+
* IMPORTANT — why we do NOT add package_product_dependencies to Crust:
|
|
20
|
+
* adding an XCSwiftPackageProductDependency to a *static library* target makes
|
|
21
|
+
* Xcode bake that product's object code straight into `libCrust.a`. The app
|
|
22
|
+
* target then links `libCrust.a` (Mapbox baked in) AND the same SPM products
|
|
23
|
+
* again → "duplicate symbol" link errors for every Mapbox symbol. (Confirmed:
|
|
24
|
+
* MapboxNavigationCore / MapboxDirections / MapboxMaps all build as STATIC
|
|
25
|
+
* swiftmodules + .o, not dynamic frameworks, so the collision is real.) A static
|
|
26
|
+
* library does not need its external symbols resolved at archive time; it only
|
|
27
|
+
* needs the modules to be VISIBLE at compile time so `import` typechecks. That
|
|
28
|
+
* visibility is provided entirely by the search paths in Crust.podspec
|
|
29
|
+
* (SWIFT_INCLUDE_PATHS / FRAMEWORK_SEARCH_PATHS / OTHER_SWIFT_FLAGS -I pointing
|
|
30
|
+
* at ${PODS_CONFIGURATION_BUILD_DIR}, where SPM drops the .swiftmodule /
|
|
31
|
+
* .framework). The actual Mapbox object code is linked exactly once, by the app
|
|
32
|
+
* target.
|
|
33
|
+
*
|
|
34
|
+
* THE BUILD-ORDER RACE (why a previous version of this plugin was insufficient):
|
|
35
|
+
* a clean `xcodebuild archive` builds targets in parallel against a fresh
|
|
36
|
+
* ArchiveIntermediates dir. Crust only sees the Mapbox swiftmodules via search
|
|
37
|
+
* paths into the shared build-products dir — but NOTHING forced those modules to
|
|
38
|
+
* exist there before Crust compiled. The app target's own SPM product deps make
|
|
39
|
+
* Xcode emit them, but that emission is NOT ordered relative to Crust (a target
|
|
40
|
+
* in a *different* project). In practice MapboxNavigationCore.swiftmodule lands
|
|
41
|
+
* in the products dir AFTER Crust compiles → `error: no such module
|
|
42
|
+
* 'MapboxNavigationCore'` → ARCHIVE FAILED (exit 65), DETERMINISTICALLY on a
|
|
43
|
+
* clean build. The release-ios.mjs archive-retry can't recover it: every fresh
|
|
44
|
+
* clean archive re-races identically and the failed partial build never copies
|
|
45
|
+
* NavigationCore's swiftmodule into the products dir for the next attempt.
|
|
46
|
+
*
|
|
47
|
+
* THE FIX — a build-order-only target dependency:
|
|
48
|
+
* 1. Create a tiny throwaway static-library "host" target (MapboxNavOrder) in
|
|
49
|
+
* Pods.xcodeproj that carries the Mapbox SPM product dependencies. Building
|
|
50
|
+
* it forces SPM to emit MapboxNavigationCore/Directions/Maps.swiftmodule
|
|
51
|
+
* into the shared build-products dir. Its own libMapboxNavOrder.a is never
|
|
52
|
+
* linked by anyone, so the Mapbox objects baked into it are harmless (no
|
|
53
|
+
* duplicate symbols — the app still links Mapbox exactly once via its own
|
|
54
|
+
* SPM deps).
|
|
55
|
+
* 2. Add a PBXTargetDependency from Crust → MapboxNavOrder. This is a pure
|
|
56
|
+
* BUILD-ORDER edge (not a link dep), so Xcode schedules the host (and thus
|
|
57
|
+
* the Mapbox swiftmodules) before Crust compiles. Verified: a clean archive
|
|
58
|
+
* now logs "Explicit dependency on target 'MapboxNavOrder'" and succeeds on
|
|
59
|
+
* the first try with no missing-module error.
|
|
60
|
+
* 3. SCRUB any stale Mapbox package_product_dependencies that an older version
|
|
61
|
+
* of this plugin (or a manual edit) may have added directly to Crust, which
|
|
62
|
+
* would re-introduce the duplicate-symbol error.
|
|
63
|
+
*
|
|
64
|
+
* Runs as a Podfile post_install hook (not a file patch) so it executes AFTER
|
|
65
|
+
* `pod install` has generated Pods.xcodeproj with the Crust target.
|
|
66
|
+
*/
|
|
67
|
+
const MARKER_BEGIN = "# @generated begin mapbox-nav-crust-link";
|
|
68
|
+
const MARKER_END = "# @generated end mapbox-nav-crust-link";
|
|
69
|
+
const PRODUCTS = ["MapboxNavigationCore", "MapboxDirections", "MapboxMaps"];
|
|
70
|
+
const CRUST_TARGET = "Crust";
|
|
71
|
+
const HOST_TARGET = "MapboxNavOrder";
|
|
72
|
+
// Must match the repo + version pinned in plugin/src/withMapboxNavIos.ts so the host
|
|
73
|
+
// target resolves the SAME package the app target uses (one Mapbox provider).
|
|
74
|
+
const NAV_REPO = "https://github.com/mapbox/mapbox-navigation-ios.git";
|
|
75
|
+
const NAV_MIN_VERSION = "3.0.0";
|
|
76
|
+
function crustLinkRuby() {
|
|
77
|
+
const rubyList = PRODUCTS.map((p) => `'${p}'`).join(", ");
|
|
78
|
+
return [
|
|
79
|
+
` ${MARKER_BEGIN} (DO NOT MODIFY — plugin/src/withMapboxNavCrustLink.ts)`,
|
|
80
|
+
` # Guarantee the Mapbox SPM swiftmodules are built BEFORE Crust compiles,`,
|
|
81
|
+
` # without linking them into libCrust.a (which would duplicate-symbol against`,
|
|
82
|
+
` # the app target's own copy). See plugin/src/withMapboxNavCrustLink.ts header.`,
|
|
83
|
+
` __mb_products = [${rubyList}]`,
|
|
84
|
+
` __mb_host_name = '${HOST_TARGET}'`,
|
|
85
|
+
` __mb_repo = '${NAV_REPO}'`,
|
|
86
|
+
` __mb_min_ver = '${NAV_MIN_VERSION}'`,
|
|
87
|
+
` __mb_proj = installer.pods_project`,
|
|
88
|
+
` __mb_crust = __mb_proj.targets.find { |t| t.name == '${CRUST_TARGET}' }`,
|
|
89
|
+
` if __mb_crust.nil?`,
|
|
90
|
+
` Pod::UI.warn "[mapbox-nav-crust-link] ${CRUST_TARGET} target not found — skipping"`,
|
|
91
|
+
` else`,
|
|
92
|
+
` # CocoaPods stabilizes target UUIDs before post_install, resetting its`,
|
|
93
|
+
` # sequential allocator bookkeeping. Adding this host can then reuse`,
|
|
94
|
+
` # existing IDs, including rootObject. Use Xcodeproj's collision-checked`,
|
|
95
|
+
` # allocator for any new objects in this project after that reset.`,
|
|
96
|
+
` def __mb_proj.generate_available_uuid_list(count = 100)`,
|
|
97
|
+
` Xcodeproj::Project.instance_method(:generate_available_uuid_list).bind(self).call(count)`,
|
|
98
|
+
` end`,
|
|
99
|
+
``,
|
|
100
|
+
` # 1) SCRUB any stale Mapbox link-deps from Crust (duplicate-symbol guard).`,
|
|
101
|
+
` __removed = __mb_crust.package_product_dependencies.select { |d| __mb_products.include?(d.product_name) }`,
|
|
102
|
+
` unless __removed.empty?`,
|
|
103
|
+
` __mb_crust.package_product_dependencies.reject! { |d| __mb_products.include?(d.product_name) }`,
|
|
104
|
+
` Pod::UI.puts "[mapbox-nav-crust-link] removed stale Mapbox link-deps from ${CRUST_TARGET}: #{__removed.map(&:product_name).join(', ')}"`,
|
|
105
|
+
` end`,
|
|
106
|
+
``,
|
|
107
|
+
` # 2) Ensure a remote SPM package reference for the Nav repo exists in the`,
|
|
108
|
+
` # Pods project (the host target's product deps point at it).`,
|
|
109
|
+
` __mb_pkg = __mb_proj.root_object.package_references.find { |r| (r.repositoryURL rescue nil) == __mb_repo }`,
|
|
110
|
+
` unless __mb_pkg`,
|
|
111
|
+
` __mb_pkg = __mb_proj.new(Xcodeproj::Project::Object::XCRemoteSwiftPackageReference)`,
|
|
112
|
+
` __mb_pkg.repositoryURL = __mb_repo`,
|
|
113
|
+
` __mb_pkg.requirement = { 'kind' => 'upToNextMajorVersion', 'minimumVersion' => __mb_min_ver }`,
|
|
114
|
+
` __mb_proj.root_object.package_references << __mb_pkg`,
|
|
115
|
+
` end`,
|
|
116
|
+
``,
|
|
117
|
+
` # 3) (Re)create the throwaway host static-lib target carrying the Mapbox`,
|
|
118
|
+
` # SPM product deps. Building it emits the swiftmodules into the shared`,
|
|
119
|
+
` # products dir; its .a is never linked, so no duplicate symbols.`,
|
|
120
|
+
` __mb_crust.dependencies.reject! { |d| d.target&.name == __mb_host_name }`,
|
|
121
|
+
` __mb_proj.targets.reject! { |t| t.name == __mb_host_name }`,
|
|
122
|
+
` __mb_host = __mb_proj.new_target(:static_library, __mb_host_name, :ios, '15.1')`,
|
|
123
|
+
` __mb_products.each do |p|`,
|
|
124
|
+
` __mb_dep = __mb_proj.new(Xcodeproj::Project::Object::XCSwiftPackageProductDependency)`,
|
|
125
|
+
` __mb_dep.package = __mb_pkg`,
|
|
126
|
+
` __mb_dep.product_name = p`,
|
|
127
|
+
` __mb_host.package_product_dependencies << __mb_dep`,
|
|
128
|
+
` end`,
|
|
129
|
+
``,
|
|
130
|
+
` # 4) Build-order edge: Crust depends on the host (NOT a link dep).`,
|
|
131
|
+
` __mb_crust.add_dependency(__mb_host)`,
|
|
132
|
+
` __mb_proj.save`,
|
|
133
|
+
` Pod::UI.puts "[mapbox-nav-crust-link] ${CRUST_TARGET} now build-order-depends on #{__mb_host_name} (#{__mb_products.join(', ')})"`,
|
|
134
|
+
` end`,
|
|
135
|
+
` ${MARKER_END}`,
|
|
136
|
+
].join("\n");
|
|
137
|
+
}
|
|
138
|
+
const withMapboxNavCrustLink = (config) => {
|
|
139
|
+
return (0, config_plugins_1.withDangerousMod)(config, [
|
|
140
|
+
"ios",
|
|
141
|
+
async (cfg) => {
|
|
142
|
+
const podfilePath = path_1.default.join(cfg.modRequest.platformProjectRoot, "Podfile");
|
|
143
|
+
if (!fs_1.default.existsSync(podfilePath)) {
|
|
144
|
+
throw new Error(`[mapbox-nav-crust-link] Podfile not found at ${podfilePath}`);
|
|
145
|
+
}
|
|
146
|
+
let contents = fs_1.default.readFileSync(podfilePath, "utf8");
|
|
147
|
+
if (contents.includes(MARKER_BEGIN)) {
|
|
148
|
+
const re = new RegExp(`\\n? *${MARKER_BEGIN}[\\s\\S]*?${MARKER_END}\\n?`, "g");
|
|
149
|
+
contents = contents.replace(re, "\n");
|
|
150
|
+
}
|
|
151
|
+
const anchor = /post_install do \|installer\|\n/;
|
|
152
|
+
if (!anchor.test(contents)) {
|
|
153
|
+
throw new Error(`[mapbox-nav-crust-link] no 'post_install do |installer|' in Podfile`);
|
|
154
|
+
}
|
|
155
|
+
contents = contents.replace(anchor, (m) => `${m}${crustLinkRuby()}\n`);
|
|
156
|
+
fs_1.default.writeFileSync(podfilePath, contents, "utf8");
|
|
157
|
+
// eslint-disable-next-line no-console
|
|
158
|
+
console.log("[mapbox-nav-crust-link] injected post_install hook (build-order host target + link-dep scrub)");
|
|
159
|
+
return cfg;
|
|
160
|
+
},
|
|
161
|
+
]);
|
|
162
|
+
};
|
|
163
|
+
exports.default = withMapboxNavCrustLink;
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const child_process_1 = require("child_process");
|
|
7
|
+
const fs_1 = __importDefault(require("fs"));
|
|
8
|
+
const path_1 = __importDefault(require("path"));
|
|
9
|
+
const config_plugins_1 = require("expo/config-plugins");
|
|
10
|
+
/**
|
|
11
|
+
* Expo Config Plugin — add the Mapbox Navigation SDK for iOS (v3) as a Swift
|
|
12
|
+
* Package to the generated Xcode project so the `crust` native module can
|
|
13
|
+
* `import MapboxNavigationCore`.
|
|
14
|
+
*
|
|
15
|
+
* Why a Swift Package and not CocoaPods: Mapbox Navigation v3 dropped reliable
|
|
16
|
+
* CocoaPods support — `pod install` cannot resolve `MapboxNavigationCore`
|
|
17
|
+
* (that's the "Unable to find a specification" error). v3 is SPM-first, so we
|
|
18
|
+
* add it via SPM here, including its MapboxMaps dependency, and link the
|
|
19
|
+
* products to the app target. The host supplies Downloads-token authentication.
|
|
20
|
+
*
|
|
21
|
+
* Implementation: a dangerous mod that drives the `xcodeproj` Ruby gem (always
|
|
22
|
+
* present on a Mac with CocoaPods) to add the remote SPM package + product.
|
|
23
|
+
* The legacy JS `xcode` pbxproj lib predates SPM and can't express package
|
|
24
|
+
* references, so Ruby is the reliable path.
|
|
25
|
+
*
|
|
26
|
+
* Requirements at build time:
|
|
27
|
+
* • ~/.netrc with `machine api.mapbox.com / login mapbox / password sk.…`
|
|
28
|
+
* (the secret Downloads:Read token) so SPM can fetch the binaries.
|
|
29
|
+
* • Use SPM as the single Mapbox provider; do not also install MapboxMaps
|
|
30
|
+
* through CocoaPods.
|
|
31
|
+
*/
|
|
32
|
+
// Mapbox Navigation v3 resolves the matching MapboxMaps dependency through SPM.
|
|
33
|
+
const NAV_REPO = "https://github.com/mapbox/mapbox-navigation-ios.git";
|
|
34
|
+
const NAV_MIN_VERSION = "3.0.0";
|
|
35
|
+
// Products to link into the app target:
|
|
36
|
+
// • MapboxNavigationCore — the headless engine the crust module imports.
|
|
37
|
+
// • MapboxDirections — Waypoint / RouteStep / ManeuverType / etc.
|
|
38
|
+
// (NavigationManager.swift + NavPayloads.swift use these).
|
|
39
|
+
// • MapboxMaps — peer Maps SDK / runtime-token consumer.
|
|
40
|
+
// Linking all three from the SAME package makes SPM the single Mapbox provider
|
|
41
|
+
// for the whole app.
|
|
42
|
+
const NAV_PRODUCTS = ["MapboxNavigationCore", "MapboxDirections", "MapboxMaps"];
|
|
43
|
+
/**
|
|
44
|
+
* Find CocoaPods' private GEM_HOME (which contains the `xcodeproj` gem) by
|
|
45
|
+
* reading it out of the `pod` launcher wrapper. Homebrew's `pod` is a bash
|
|
46
|
+
* shim that does `GEM_HOME="…/libexec" exec "…/bin/pod"`. We grep that path so
|
|
47
|
+
* our Ruby invocation can `require 'xcodeproj'` using the same gems CocoaPods
|
|
48
|
+
* uses. Returns {} when it can't be determined (caller falls back to bare ruby).
|
|
49
|
+
*/
|
|
50
|
+
function cocoapodsGemEnv() {
|
|
51
|
+
try {
|
|
52
|
+
const podPath = (0, child_process_1.execSync)("command -v pod", { encoding: "utf8" }).trim();
|
|
53
|
+
if (!podPath || !fs_1.default.existsSync(podPath))
|
|
54
|
+
return {};
|
|
55
|
+
const contents = fs_1.default.readFileSync(podPath, "utf8");
|
|
56
|
+
const m = contents.match(/GEM_HOME=["']?([^"'\s]+)["']?/);
|
|
57
|
+
if (m?.[1])
|
|
58
|
+
return { GEM_HOME: m[1] };
|
|
59
|
+
}
|
|
60
|
+
catch {
|
|
61
|
+
/* ignore — fall back to bare ruby */
|
|
62
|
+
}
|
|
63
|
+
return {};
|
|
64
|
+
}
|
|
65
|
+
const withMapboxNavIos = (config) => {
|
|
66
|
+
return (0, config_plugins_1.withDangerousMod)(config, [
|
|
67
|
+
"ios",
|
|
68
|
+
async (cfg) => {
|
|
69
|
+
const iosRoot = cfg.modRequest.platformProjectRoot; // .../ios
|
|
70
|
+
const projName = cfg.modRequest.projectName; // e.g. "Mentra"
|
|
71
|
+
const pbxproj = path_1.default.join(iosRoot, `${projName}.xcodeproj`, "project.pbxproj");
|
|
72
|
+
if (!fs_1.default.existsSync(pbxproj)) {
|
|
73
|
+
throw new Error(`[mapbox-nav-ios] project.pbxproj not found at ${pbxproj}`);
|
|
74
|
+
}
|
|
75
|
+
// Ruby script: idempotently add the SPM remote package + product, and
|
|
76
|
+
// link the product to the FIRST application target (the app, not the
|
|
77
|
+
// test/extension targets).
|
|
78
|
+
//
|
|
79
|
+
// Written to a TEMP FILE and run as `ruby <file>` rather than inlined via
|
|
80
|
+
// `ruby -e "..."` — inlining a multi-line script through the shell mangles
|
|
81
|
+
// the newlines into literal backslash-n and Ruby errors with
|
|
82
|
+
// "unexpected backslash". Config values are injected as JSON literals so
|
|
83
|
+
// there's no string-escaping ambiguity.
|
|
84
|
+
const ruby = [
|
|
85
|
+
`require 'xcodeproj'`,
|
|
86
|
+
`proj = Xcodeproj::Project.open(${JSON.stringify(`${projName}.xcodeproj`)})`,
|
|
87
|
+
`target = proj.targets.find { |t| t.product_type == 'com.apple.product-type.application' }`,
|
|
88
|
+
`abort('[mapbox-nav-ios] no application target found') unless target`,
|
|
89
|
+
``,
|
|
90
|
+
`repo = ${JSON.stringify(NAV_REPO)}`,
|
|
91
|
+
`products = ${JSON.stringify(NAV_PRODUCTS)}`,
|
|
92
|
+
`min_version = ${JSON.stringify(NAV_MIN_VERSION)}`,
|
|
93
|
+
``,
|
|
94
|
+
`# Reuse an existing package reference for this repo if present (idempotent).`,
|
|
95
|
+
`pkg = proj.root_object.package_references.find { |r| r.respond_to?(:repositoryURL) && r.repositoryURL == repo }`,
|
|
96
|
+
`unless pkg`,
|
|
97
|
+
` pkg = proj.new(Xcodeproj::Project::Object::XCRemoteSwiftPackageReference)`,
|
|
98
|
+
` pkg.repositoryURL = repo`,
|
|
99
|
+
` pkg.requirement = { 'kind' => 'upToNextMajorVersion', 'minimumVersion' => min_version }`,
|
|
100
|
+
` proj.root_object.package_references << pkg`,
|
|
101
|
+
`end`,
|
|
102
|
+
``,
|
|
103
|
+
`# Link each product to the target if not already linked.`,
|
|
104
|
+
`products.each do |product|`,
|
|
105
|
+
` already = target.package_product_dependencies.any? { |d| d.product_name == product }`,
|
|
106
|
+
` next if already`,
|
|
107
|
+
` dep = proj.new(Xcodeproj::Project::Object::XCSwiftPackageProductDependency)`,
|
|
108
|
+
` dep.package = pkg`,
|
|
109
|
+
` dep.product_name = product`,
|
|
110
|
+
` target.package_product_dependencies << dep`,
|
|
111
|
+
`end`,
|
|
112
|
+
``,
|
|
113
|
+
`proj.save`,
|
|
114
|
+
`puts "[mapbox-nav-ios] ensured #{products.join(', ')} (>= #{min_version}) from #{repo}"`,
|
|
115
|
+
].join("\n");
|
|
116
|
+
const scriptPath = path_1.default.join(iosRoot, ".mapbox-nav-ios-spm.rb");
|
|
117
|
+
try {
|
|
118
|
+
fs_1.default.writeFileSync(scriptPath, ruby, "utf8");
|
|
119
|
+
// The `xcodeproj` gem isn't in the system Ruby — it ships INSIDE
|
|
120
|
+
// CocoaPods' private GEM_HOME. Reuse CocoaPods' own environment so the
|
|
121
|
+
// require works regardless of which Ruby the user has on PATH. We read
|
|
122
|
+
// GEM_HOME out of the `pod` launcher wrapper (it sets it before exec),
|
|
123
|
+
// falling back to a bare `ruby` (which works if the user happens to
|
|
124
|
+
// have xcodeproj installed globally).
|
|
125
|
+
const env = { ...process.env, ...cocoapodsGemEnv() };
|
|
126
|
+
(0, child_process_1.execSync)(`ruby ${JSON.stringify(scriptPath)}`, {
|
|
127
|
+
cwd: iosRoot,
|
|
128
|
+
stdio: "inherit",
|
|
129
|
+
env,
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
catch (e) {
|
|
133
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
134
|
+
throw new Error(`[mapbox-nav-ios] failed to add the Mapbox Navigation SPM package. ` +
|
|
135
|
+
`Ensure the 'xcodeproj' Ruby gem is available (it ships with CocoaPods). ` +
|
|
136
|
+
`Underlying error: ${msg}`);
|
|
137
|
+
}
|
|
138
|
+
finally {
|
|
139
|
+
// Clean up the temp script so it doesn't linger in the generated ios/.
|
|
140
|
+
try {
|
|
141
|
+
fs_1.default.unlinkSync(scriptPath);
|
|
142
|
+
}
|
|
143
|
+
catch {
|
|
144
|
+
/* ignore */
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
return cfg;
|
|
148
|
+
},
|
|
149
|
+
]);
|
|
150
|
+
};
|
|
151
|
+
exports.default = withMapboxNavIos;
|