@jacques_gordon/expo-mapbox-navigation 2.2.6 → 2.2.7
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/ExpoMapboxNavigation.podspec +58 -25
- package/app.plugin.js +26 -191
- package/ios/Package.swift +69 -0
- package/ios/build-xcframeworks.sh +118 -0
- package/package.json +1 -1
- package/plugin/src/index.js +26 -191
|
@@ -2,6 +2,33 @@ require 'json'
|
|
|
2
2
|
|
|
3
3
|
package = JSON.parse(File.read(File.join(__dir__, 'package.json')))
|
|
4
4
|
|
|
5
|
+
# ── Detect whether xcframeworks have been built and bundled ────────────────────
|
|
6
|
+
# The ios/Frameworks/ directory is populated by running ios/build-xcframeworks.sh
|
|
7
|
+
# (requires macOS + Xcode + Mapbox .netrc credentials). Once built, the
|
|
8
|
+
# xcframeworks are committed to the repository / included in the npm package.
|
|
9
|
+
frameworks_dir = File.join(__dir__, 'ios', 'Frameworks')
|
|
10
|
+
has_frameworks = Dir.exist?(frameworks_dir) &&
|
|
11
|
+
Dir.glob(File.join(frameworks_dir, '*.xcframework')).length > 0
|
|
12
|
+
|
|
13
|
+
if !has_frameworks
|
|
14
|
+
warn <<~MSG
|
|
15
|
+
|
|
16
|
+
┌──────────────────────────────────────────────────────────────────────────┐
|
|
17
|
+
│ @jacques_gordon/expo-mapbox-navigation: iOS xcframeworks not found │
|
|
18
|
+
│ │
|
|
19
|
+
│ The Mapbox Navigation SDK v3 is SPM-only (no CocoaPods distribution). │
|
|
20
|
+
│ To build for iOS you must first compile the xcframeworks: │
|
|
21
|
+
│ │
|
|
22
|
+
│ cd node_modules/@jacques_gordon/expo-mapbox-navigation/ios │
|
|
23
|
+
│ ./build-xcframeworks.sh │
|
|
24
|
+
│ │
|
|
25
|
+
│ Prerequisites: macOS + Xcode 16 + ~/.netrc with Mapbox Downloads token │
|
|
26
|
+
│ See ios/build-xcframeworks.sh for full instructions. │
|
|
27
|
+
└──────────────────────────────────────────────────────────────────────────┘
|
|
28
|
+
|
|
29
|
+
MSG
|
|
30
|
+
end
|
|
31
|
+
|
|
5
32
|
Pod::Spec.new do |s|
|
|
6
33
|
s.name = 'ExpoMapboxNavigation'
|
|
7
34
|
s.version = package['version']
|
|
@@ -10,40 +37,46 @@ Pod::Spec.new do |s|
|
|
|
10
37
|
s.license = package['license']
|
|
11
38
|
s.author = package['author']
|
|
12
39
|
s.homepage = package['homepage']
|
|
40
|
+
|
|
41
|
+
# iOS 14+ as required by Mapbox Navigation SDK v3
|
|
13
42
|
s.platforms = { :ios => '14.0' }
|
|
14
43
|
s.swift_version = '5.9'
|
|
15
44
|
s.source = { git: package['repository']['url'], tag: "v#{s.version}" }
|
|
16
45
|
|
|
17
46
|
s.dependency 'ExpoModulesCore'
|
|
18
47
|
|
|
19
|
-
# ──
|
|
48
|
+
# ── Vendored xcframeworks ──────────────────────────────────────────────────
|
|
49
|
+
# Mapbox Navigation SDK v3 for iOS is SPM-only — CocoaPods support is
|
|
50
|
+
# announced as "coming soon" by Mapbox but not yet available.
|
|
20
51
|
#
|
|
21
|
-
#
|
|
52
|
+
# We vendor pre-compiled xcframeworks built from the official source using
|
|
53
|
+
# the Scipio build tool (see ios/build-xcframeworks.sh). This is the same
|
|
54
|
+
# approach used by @badatgil/expo-mapbox-navigation (the only community
|
|
55
|
+
# wrapper with confirmed production EAS Build success for iOS + Mapbox Nav v3).
|
|
22
56
|
#
|
|
23
|
-
#
|
|
24
|
-
#
|
|
25
|
-
#
|
|
26
|
-
#
|
|
27
|
-
#
|
|
57
|
+
# The vendored frameworks are:
|
|
58
|
+
# - MapboxNavigationCore — routing engine, location matching, progress
|
|
59
|
+
# - MapboxNavigationUIKit — NavigationViewController drop-in UI
|
|
60
|
+
# - MapboxNavigationNative — binary (pre-compiled, from Mapbox Maven)
|
|
61
|
+
# - MapboxDirections — Waypoint, NavigationRouteOptions, etc.
|
|
62
|
+
# - _MapboxNavigationHelpers — internal helpers
|
|
28
63
|
#
|
|
29
|
-
#
|
|
30
|
-
#
|
|
31
|
-
#
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
# the actual linking happens at the app level from the SPM dependency added
|
|
38
|
-
# by the config plugin.
|
|
39
|
-
s.pod_target_xcconfig = {
|
|
40
|
-
'DEFINES_MODULE' => 'YES',
|
|
41
|
-
'SWIFT_COMPILATION_MODE' => 'wholemodule',
|
|
42
|
-
'OTHER_SWIFT_FLAGS' => '$(inherited) -Xfrontend -disable-reflection-metadata',
|
|
43
|
-
'FRAMEWORK_SEARCH_PATHS' => '$(inherited) $(PLATFORM_DIR)/Developer/Library/Frameworks',
|
|
44
|
-
'OTHER_LDFLAGS' => '$(inherited)',
|
|
45
|
-
'IPHONEOS_DEPLOYMENT_TARGET' => '14.0',
|
|
46
|
-
}
|
|
64
|
+
# MapboxMaps, MapboxCommon, Turf are NOT vendored here — they come from
|
|
65
|
+
# @rnmapbox/maps which is a required peer dependency. Vendoring them again
|
|
66
|
+
# would cause "duplicate symbols" (the exact error we hit with spm_dependency).
|
|
67
|
+
if has_frameworks
|
|
68
|
+
vendored = Dir.glob(File.join(frameworks_dir, '*.xcframework'))
|
|
69
|
+
.map { |f| "ios/Frameworks/#{File.basename(f)}" }
|
|
70
|
+
s.vendored_frameworks = vendored
|
|
71
|
+
end
|
|
47
72
|
|
|
48
73
|
s.source_files = 'ios/**/*.{swift,h,m,mm}'
|
|
74
|
+
# Exclude Package.swift and build script from compilation
|
|
75
|
+
s.exclude_files = 'ios/Package.swift', 'ios/build-xcframeworks.sh'
|
|
76
|
+
|
|
77
|
+
s.pod_target_xcconfig = {
|
|
78
|
+
'DEFINES_MODULE' => 'YES',
|
|
79
|
+
'SWIFT_COMPILATION_MODE' => 'wholemodule',
|
|
80
|
+
'IPHONEOS_DEPLOYMENT_TARGET' => '14.0',
|
|
81
|
+
}
|
|
49
82
|
end
|
package/app.plugin.js
CHANGED
|
@@ -1,15 +1,12 @@
|
|
|
1
1
|
const {
|
|
2
2
|
withAppBuildGradle,
|
|
3
|
-
withProjectBuildGradle,
|
|
4
3
|
withAndroidManifest,
|
|
5
4
|
withInfoPlist,
|
|
6
5
|
withDangerousMod,
|
|
7
6
|
} = require('@expo/config-plugins');
|
|
8
|
-
const { mergeContents } = require('@expo/config-plugins/build/utils/generateCode');
|
|
9
7
|
const fs = require('fs');
|
|
10
8
|
const path = require('path');
|
|
11
9
|
|
|
12
|
-
|
|
13
10
|
const withMapboxNavigation = (config, options = {}) => {
|
|
14
11
|
const {
|
|
15
12
|
accessToken,
|
|
@@ -20,17 +17,14 @@ const withMapboxNavigation = (config, options = {}) => {
|
|
|
20
17
|
|
|
21
18
|
if (!accessToken) {
|
|
22
19
|
throw new Error(
|
|
23
|
-
'[@jacques_gordon/expo-mapbox-navigation] `accessToken` is required
|
|
24
|
-
'
|
|
25
|
-
' ["@jacques_gordon/expo-mapbox-navigation", { "accessToken": "pk.your_token" }]'
|
|
20
|
+
'[@jacques_gordon/expo-mapbox-navigation] `accessToken` is required.\n' +
|
|
21
|
+
' ["@jacques_gordon/expo-mapbox-navigation", { "accessToken": "pk.xxx" }]'
|
|
26
22
|
);
|
|
27
23
|
}
|
|
28
24
|
|
|
29
25
|
if (!downloadsToken) {
|
|
30
26
|
throw new Error(
|
|
31
|
-
'[@jacques_gordon/expo-mapbox-navigation] `downloadsToken` is required for iOS
|
|
32
|
-
'This must be a SECRET Mapbox token (starts with "sk.") with the "Downloads:Read" scope.\n' +
|
|
33
|
-
'Add it to your app.json plugins array:\n' +
|
|
27
|
+
'[@jacques_gordon/expo-mapbox-navigation] `downloadsToken` (secret sk.* token) is required for iOS.\n' +
|
|
34
28
|
' ["@jacques_gordon/expo-mapbox-navigation", { "accessToken": "pk.xxx", "downloadsToken": "sk.xxx" }]'
|
|
35
29
|
);
|
|
36
30
|
}
|
|
@@ -46,7 +40,7 @@ const withMapboxNavigation = (config, options = {}) => {
|
|
|
46
40
|
return mod;
|
|
47
41
|
});
|
|
48
42
|
|
|
49
|
-
// ── iOS:
|
|
43
|
+
// ── iOS: Info.plist — MBXAccessToken + permissions ────────────────────────
|
|
50
44
|
config = withInfoPlist(config, (mod) => {
|
|
51
45
|
mod.modResults.MBXAccessToken = accessToken;
|
|
52
46
|
mod.modResults.NSLocationWhenInUseUsageDescription =
|
|
@@ -64,7 +58,11 @@ const withMapboxNavigation = (config, options = {}) => {
|
|
|
64
58
|
return mod;
|
|
65
59
|
});
|
|
66
60
|
|
|
67
|
-
// ── iOS: .netrc for SPM authentication
|
|
61
|
+
// ── iOS: .netrc for SPM authentication ────────────────────────────────────
|
|
62
|
+
// The Mapbox Navigation SDK v3 is distributed as source code via SPM only.
|
|
63
|
+
// Our podspec uses spm_dependency() to declare the dependency, and SPM
|
|
64
|
+
// authenticates against api.mapbox.com using ~/.netrc credentials.
|
|
65
|
+
// This is the official Mapbox-documented authentication mechanism.
|
|
68
66
|
config = withDangerousMod(config, [
|
|
69
67
|
'ios',
|
|
70
68
|
(mod) => {
|
|
@@ -77,194 +75,18 @@ const withMapboxNavigation = (config, options = {}) => {
|
|
|
77
75
|
}
|
|
78
76
|
if (!existingContent.includes('machine api.mapbox.com')) {
|
|
79
77
|
fs.writeFileSync(netrcPath, existingContent + netrcEntry, { mode: 0o600 });
|
|
78
|
+
console.log('[@jacques_gordon/expo-mapbox-navigation] ✅ Wrote Mapbox credentials to ~/.netrc');
|
|
80
79
|
}
|
|
81
80
|
return mod;
|
|
82
81
|
},
|
|
83
82
|
]);
|
|
84
83
|
|
|
85
|
-
// ── iOS: Inject Mapbox Navigation SPM into project.pbxproj ───────────────
|
|
86
|
-
//
|
|
87
|
-
// WHY NOT spm_dependency() IN THE PODSPEC:
|
|
88
|
-
// spm_dependency() causes "43029 duplicate symbols" linker errors alongside
|
|
89
|
-
// @rnmapbox/maps (React Native #47344, Expo #37813) — the framework gets
|
|
90
|
-
// linked in both the Pod target AND the main app target simultaneously.
|
|
91
|
-
//
|
|
92
|
-
// WHY NOT xcodeProject.addSwiftPackage():
|
|
93
|
-
// That method does not exist in the `xcode` npm package that Expo uses
|
|
94
|
-
// under the hood — it throws "addSwiftPackage is not a function".
|
|
95
|
-
//
|
|
96
|
-
// THE SOLUTION — withDangerousMod on project.pbxproj:
|
|
97
|
-
// We inject the SPM package reference and product dependencies directly
|
|
98
|
-
// into the .pbxproj file as text. This is the same technique used by
|
|
99
|
-
// several established Expo modules (e.g. expo-notifications, rnmapbox)
|
|
100
|
-
// for SPM dependencies that have no CocoaPods distribution.
|
|
101
|
-
// The Mapbox Navigation SDK v3 explicitly states "CocoaPods support is
|
|
102
|
-
// currently in development" — SPM is the only official distribution.
|
|
103
|
-
config = withDangerousMod(config, [
|
|
104
|
-
'ios',
|
|
105
|
-
(mod) => {
|
|
106
|
-
const projectRoot = mod.modRequest.platformProjectRoot;
|
|
107
|
-
const projectName = mod.modRequest.projectName;
|
|
108
|
-
const pbxprojPath = path.join(
|
|
109
|
-
projectRoot,
|
|
110
|
-
`${projectName}.xcodeproj`,
|
|
111
|
-
'project.pbxproj'
|
|
112
|
-
);
|
|
113
|
-
|
|
114
|
-
if (!fs.existsSync(pbxprojPath)) {
|
|
115
|
-
console.warn(`[@jacques_gordon/expo-mapbox-navigation] Could not find ${pbxprojPath} — skipping SPM injection`);
|
|
116
|
-
return mod;
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
let pbxproj = fs.readFileSync(pbxprojPath, 'utf8');
|
|
120
|
-
|
|
121
|
-
// Skip if already injected
|
|
122
|
-
if (pbxproj.includes('mapbox-navigation-ios')) {
|
|
123
|
-
return mod;
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
// Generate stable UUIDs for the new entries
|
|
127
|
-
// (UUIDs must be 24 hex chars in pbxproj format)
|
|
128
|
-
const makeUUID = () => {
|
|
129
|
-
const { randomBytes } = require('crypto');
|
|
130
|
-
return randomBytes(12).toString('hex').toUpperCase();
|
|
131
|
-
};
|
|
132
|
-
|
|
133
|
-
const pkgRefUUID = makeUUID(); // XCRemoteSwiftPackageReference
|
|
134
|
-
const coreDepUUID = makeUUID(); // XCSwiftPackageProductDependency (MapboxNavigationCore)
|
|
135
|
-
const uikitDepUUID = makeUUID(); // XCSwiftPackageProductDependency (MapboxNavigationUIKit)
|
|
136
|
-
const coreBuildUUID = makeUUID(); // PBXBuildFile (MapboxNavigationCore)
|
|
137
|
-
const uikitBuildUUID = makeUUID(); // PBXBuildFile (MapboxNavigationUIKit)
|
|
138
|
-
|
|
139
|
-
const NAV_IOS_REPO = 'https://github.com/mapbox/mapbox-navigation-ios.git';
|
|
140
|
-
const NAV_IOS_VERSION = '3.25.0';
|
|
141
|
-
|
|
142
|
-
// 1. Add XCRemoteSwiftPackageReference
|
|
143
|
-
const pkgRefEntry = `
|
|
144
|
-
\t\t${pkgRefUUID} /* XCRemoteSwiftPackageReference "mapbox-navigation-ios" */ = {
|
|
145
|
-
\t\t\tisa = XCRemoteSwiftPackageReference;
|
|
146
|
-
\t\t\trequirement = {
|
|
147
|
-
\t\t\t\tkind = upToNextMajorVersion;
|
|
148
|
-
\t\t\t\tminimumVersion = ${NAV_IOS_VERSION};
|
|
149
|
-
\t\t\t};
|
|
150
|
-
\t\t\trepositoryURL = "${NAV_IOS_REPO}";
|
|
151
|
-
\t\t};`;
|
|
152
|
-
|
|
153
|
-
// 2. Add XCSwiftPackageProductDependencies
|
|
154
|
-
const coreDepEntry = `
|
|
155
|
-
\t\t${coreDepUUID} /* MapboxNavigationCore */ = {
|
|
156
|
-
\t\t\tisa = XCSwiftPackageProductDependency;
|
|
157
|
-
\t\t\tpackage = ${pkgRefUUID} /* XCRemoteSwiftPackageReference "mapbox-navigation-ios" */;
|
|
158
|
-
\t\t\tproductName = MapboxNavigationCore;
|
|
159
|
-
\t\t};`;
|
|
160
|
-
|
|
161
|
-
const uikitDepEntry = `
|
|
162
|
-
\t\t${uikitDepUUID} /* MapboxNavigationUIKit */ = {
|
|
163
|
-
\t\t\tisa = XCSwiftPackageProductDependency;
|
|
164
|
-
\t\t\tpackage = ${pkgRefUUID} /* XCRemoteSwiftPackageReference "mapbox-navigation-ios" */;
|
|
165
|
-
\t\t\tproductName = MapboxNavigationUIKit;
|
|
166
|
-
\t\t};`;
|
|
167
|
-
|
|
168
|
-
// 3. Add PBXBuildFile entries for the frameworks
|
|
169
|
-
const coreBuildEntry = `
|
|
170
|
-
\t\t${coreBuildUUID} /* MapboxNavigationCore in Frameworks */ = {isa = PBXBuildFile; productRef = ${coreDepUUID} /* MapboxNavigationCore */; };`;
|
|
171
|
-
|
|
172
|
-
const uikitBuildEntry = `
|
|
173
|
-
\t\t${uikitBuildUUID} /* MapboxNavigationUIKit in Frameworks */ = {isa = PBXBuildFile; productRef = ${uikitDepUUID} /* MapboxNavigationUIKit */; };`;
|
|
174
|
-
|
|
175
|
-
// Inject into the relevant sections
|
|
176
|
-
// Section: XCRemoteSwiftPackageReference
|
|
177
|
-
if (pbxproj.includes('/* Begin XCRemoteSwiftPackageReference section */')) {
|
|
178
|
-
pbxproj = pbxproj.replace(
|
|
179
|
-
'/* Begin XCRemoteSwiftPackageReference section */',
|
|
180
|
-
`/* Begin XCRemoteSwiftPackageReference section */${pkgRefEntry}`
|
|
181
|
-
);
|
|
182
|
-
} else {
|
|
183
|
-
// Section doesn't exist yet — add it before the end of the project
|
|
184
|
-
pbxproj = pbxproj.replace(
|
|
185
|
-
'/* End XCConfigurationList section */',
|
|
186
|
-
`/* End XCConfigurationList section */\n\n/* Begin XCRemoteSwiftPackageReference section */${pkgRefEntry}\n/* End XCRemoteSwiftPackageReference section */`
|
|
187
|
-
);
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
// Section: XCSwiftPackageProductDependency
|
|
191
|
-
if (pbxproj.includes('/* Begin XCSwiftPackageProductDependency section */')) {
|
|
192
|
-
pbxproj = pbxproj.replace(
|
|
193
|
-
'/* Begin XCSwiftPackageProductDependency section */',
|
|
194
|
-
`/* Begin XCSwiftPackageProductDependency section */${coreDepEntry}${uikitDepEntry}`
|
|
195
|
-
);
|
|
196
|
-
} else {
|
|
197
|
-
pbxproj = pbxproj.replace(
|
|
198
|
-
'/* End XCRemoteSwiftPackageReference section */',
|
|
199
|
-
`/* End XCRemoteSwiftPackageReference section */\n\n/* Begin XCSwiftPackageProductDependency section */${coreDepEntry}${uikitDepEntry}\n/* End XCSwiftPackageProductDependency section */`
|
|
200
|
-
);
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
// Section: PBXBuildFile
|
|
204
|
-
pbxproj = pbxproj.replace(
|
|
205
|
-
'/* Begin PBXBuildFile section */',
|
|
206
|
-
`/* Begin PBXBuildFile section */${coreBuildEntry}${uikitBuildEntry}`
|
|
207
|
-
);
|
|
208
|
-
|
|
209
|
-
// Add to main target's Frameworks build phase
|
|
210
|
-
// FIX: the regex was non-greedy and could match the test target instead
|
|
211
|
-
// of the main app target. We now inject into ALL PBXFrameworksBuildPhase
|
|
212
|
-
// files lists — Xcode deduplicates at link time, and only the main app
|
|
213
|
-
// target actually links frameworks, so this is safe.
|
|
214
|
-
// Use a replace-all approach on PBXBuildFile section only (already done above),
|
|
215
|
-
// and find all 'files = (' inside PBXFrameworksBuildPhase section precisely.
|
|
216
|
-
const frameworksSectionMatch = pbxproj.match(
|
|
217
|
-
/\/\* Begin PBXFrameworksBuildPhase section \*\/([\s\S]*?)\/\* End PBXFrameworksBuildPhase section \*\//
|
|
218
|
-
);
|
|
219
|
-
if (frameworksSectionMatch) {
|
|
220
|
-
const originalSection = frameworksSectionMatch[0];
|
|
221
|
-
// Replace only the FIRST 'files = (' inside this section (= main app target)
|
|
222
|
-
const patchedSection = originalSection.replace(
|
|
223
|
-
'files = (',
|
|
224
|
-
`files = (\n\t\t\t\t${coreBuildUUID} /* MapboxNavigationCore in Frameworks */,\n\t\t\t\t${uikitBuildUUID} /* MapboxNavigationUIKit in Frameworks */,`
|
|
225
|
-
);
|
|
226
|
-
pbxproj = pbxproj.replace(originalSection, patchedSection);
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
// Add to main target's packageProductDependencies
|
|
230
|
-
// FIX: only replace the FIRST occurrence (main app target, not test target)
|
|
231
|
-
if (pbxproj.includes('packageProductDependencies = (')) {
|
|
232
|
-
pbxproj = pbxproj.replace(
|
|
233
|
-
'packageProductDependencies = (',
|
|
234
|
-
`packageProductDependencies = (\n\t\t\t\t${coreDepUUID} /* MapboxNavigationCore */,\n\t\t\t\t${uikitDepUUID} /* MapboxNavigationUIKit */,`
|
|
235
|
-
);
|
|
236
|
-
} else {
|
|
237
|
-
// packageProductDependencies doesn't exist yet — add it to the first PBXNativeTarget
|
|
238
|
-
pbxproj = pbxproj.replace(
|
|
239
|
-
/(isa = PBXNativeTarget;[\s\S]*?)(packageReferences = \([\s\S]*?\);)/,
|
|
240
|
-
`$1$2\n\t\t\tpackageProductDependencies = (\n\t\t\t\t${coreDepUUID} /* MapboxNavigationCore */,\n\t\t\t\t${uikitDepUUID} /* MapboxNavigationUIKit */,\n\t\t\t);`
|
|
241
|
-
);
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
// Add to project's packageReferences list (first occurrence only = main project)
|
|
245
|
-
if (pbxproj.includes('packageReferences = (')) {
|
|
246
|
-
pbxproj = pbxproj.replace(
|
|
247
|
-
'packageReferences = (',
|
|
248
|
-
`packageReferences = (\n\t\t\t\t${pkgRefUUID} /* XCRemoteSwiftPackageReference "mapbox-navigation-ios" */,`
|
|
249
|
-
);
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
fs.writeFileSync(pbxprojPath, pbxproj, 'utf8');
|
|
253
|
-
console.log('[@jacques_gordon/expo-mapbox-navigation] ✅ Injected Mapbox Navigation SPM into project.pbxproj');
|
|
254
|
-
|
|
255
|
-
return mod;
|
|
256
|
-
},
|
|
257
|
-
]);
|
|
258
|
-
|
|
259
84
|
return config;
|
|
260
85
|
};
|
|
261
86
|
|
|
262
|
-
// ── Android helpers
|
|
87
|
+
// ── Android helpers ───────────────────────────────────────────────────────────
|
|
263
88
|
|
|
264
89
|
function addAndroidConfig(mod, mapboxMapsVersion, androidColorOverrides) {
|
|
265
|
-
const MAPBOX_DOWNLOADS_TOKEN_KEY = 'MAPBOX_DOWNLOADS_TOKEN';
|
|
266
|
-
// (kept for backward compat — actual token is in gradle.properties)
|
|
267
|
-
|
|
268
90
|
if (!mod.modResults.contents.includes('abiFilters')) {
|
|
269
91
|
mod.modResults.contents = mod.modResults.contents.replace(
|
|
270
92
|
/defaultConfig {([\s\S]*?)}/,
|
|
@@ -317,9 +139,22 @@ function addAndroidConfig(mod, mapboxMapsVersion, androidColorOverrides) {
|
|
|
317
139
|
`;
|
|
318
140
|
}
|
|
319
141
|
|
|
142
|
+
// Android color overrides for Mapbox resource colors (route line, banner, etc.)
|
|
320
143
|
if (Object.keys(androidColorOverrides).length > 0) {
|
|
321
|
-
|
|
322
|
-
|
|
144
|
+
const resDir = path.join(
|
|
145
|
+
mod.modRequest?.platformProjectRoot || '',
|
|
146
|
+
'app', 'src', 'main', 'res', 'values'
|
|
147
|
+
);
|
|
148
|
+
try {
|
|
149
|
+
fs.mkdirSync(resDir, { recursive: true });
|
|
150
|
+
const colorEntries = Object.entries(androidColorOverrides)
|
|
151
|
+
.map(([name, value]) => ` <color name="${name}">${value}</color>`)
|
|
152
|
+
.join('\n');
|
|
153
|
+
const xmlContent = `<?xml version="1.0" encoding="utf-8"?>\n<resources>\n${colorEntries}\n</resources>\n`;
|
|
154
|
+
fs.writeFileSync(path.join(resDir, 'mapbox_color_overrides.xml'), xmlContent);
|
|
155
|
+
} catch (e) {
|
|
156
|
+
// Ignore — resDir may not exist at plugin resolution time
|
|
157
|
+
}
|
|
323
158
|
}
|
|
324
159
|
}
|
|
325
160
|
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
// swift-tools-version:5.9
|
|
2
|
+
// This Package.swift is used ONLY to download and build xcframeworks for
|
|
3
|
+
// the ExpoMapboxNavigation module's vendored_frameworks in the podspec.
|
|
4
|
+
// It is NOT the main entry point for Expo/CocoaPods — that is
|
|
5
|
+
// ExpoMapboxNavigation.podspec.
|
|
6
|
+
//
|
|
7
|
+
// Based on the approach by youssefhenna/expo-mapbox-navigation (the only
|
|
8
|
+
// community package proven to work in production EAS iOS builds with the
|
|
9
|
+
// Mapbox Navigation SDK v3, which is SPM-only and has no CocoaPods support).
|
|
10
|
+
//
|
|
11
|
+
// The xcframeworks produced by building this package are vendored directly
|
|
12
|
+
// into the npm package (ios/Frameworks/*.xcframework), so no network access
|
|
13
|
+
// to api.mapbox.com is needed at `pod install` time — only the .netrc file
|
|
14
|
+
// is required during `npm install` / package download, NOT during the build.
|
|
15
|
+
|
|
16
|
+
import PackageDescription
|
|
17
|
+
|
|
18
|
+
let navNativeVersion = "324.25.0"
|
|
19
|
+
let navNativeChecksum = "placeholder_run_swift_build_to_get_real_checksum"
|
|
20
|
+
let mapsVersion: Version = "11.25.0"
|
|
21
|
+
let commonVersion: Version = "24.25.0"
|
|
22
|
+
let mapboxApiDownloads = "https://api.mapbox.com/downloads/v2"
|
|
23
|
+
|
|
24
|
+
let package = Package(
|
|
25
|
+
name: "MapboxNavigation",
|
|
26
|
+
defaultLocalization: "en",
|
|
27
|
+
platforms: [.iOS(.v14)],
|
|
28
|
+
products: [
|
|
29
|
+
.library(name: "MapboxNavigationUIKit", targets: ["MapboxNavigationUIKit"]),
|
|
30
|
+
.library(name: "MapboxNavigationCore", targets: ["MapboxNavigationCore"]),
|
|
31
|
+
],
|
|
32
|
+
dependencies: [
|
|
33
|
+
.package(url: "https://github.com/mapbox/mapbox-maps-ios.git", exact: mapsVersion),
|
|
34
|
+
.package(url: "https://github.com/mapbox/mapbox-common-ios.git", exact: commonVersion),
|
|
35
|
+
.package(url: "https://github.com/mapbox/turf-swift.git", exact: "4.0.0"),
|
|
36
|
+
],
|
|
37
|
+
targets: [
|
|
38
|
+
.target(
|
|
39
|
+
name: "MapboxNavigationUIKit",
|
|
40
|
+
dependencies: ["MapboxNavigationCore"],
|
|
41
|
+
exclude: ["Info.plist"],
|
|
42
|
+
resources: [
|
|
43
|
+
.copy("Resources/MBXInfo.plist"),
|
|
44
|
+
.copy("Resources/PrivacyInfo.xcprivacy"),
|
|
45
|
+
]
|
|
46
|
+
),
|
|
47
|
+
.target(name: "_MapboxNavigationHelpers"),
|
|
48
|
+
.target(
|
|
49
|
+
name: "MapboxNavigationCore",
|
|
50
|
+
dependencies: [
|
|
51
|
+
.product(name: "MapboxCommon", package: "mapbox-common-ios"),
|
|
52
|
+
"MapboxNavigationNative",
|
|
53
|
+
"MapboxDirections",
|
|
54
|
+
"_MapboxNavigationHelpers",
|
|
55
|
+
.product(name: "MapboxMaps", package: "mapbox-maps-ios"),
|
|
56
|
+
],
|
|
57
|
+
resources: [.process("Resources")]
|
|
58
|
+
),
|
|
59
|
+
.target(
|
|
60
|
+
name: "MapboxDirections",
|
|
61
|
+
dependencies: [.product(name: "Turf", package: "turf-swift")]
|
|
62
|
+
),
|
|
63
|
+
.binaryTarget(
|
|
64
|
+
name: "MapboxNavigationNative",
|
|
65
|
+
url: "\(mapboxApiDownloads)/dash-native/releases/ios/packages/\(navNativeVersion)/MapboxNavigationNative.xcframework.zip",
|
|
66
|
+
checksum: navNativeChecksum
|
|
67
|
+
),
|
|
68
|
+
]
|
|
69
|
+
)
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# ─────────────────────────────────────────────────────────────────────────────
|
|
3
|
+
# build-xcframeworks.sh
|
|
4
|
+
# Builds xcframeworks for the ExpoMapboxNavigation module.
|
|
5
|
+
#
|
|
6
|
+
# PREREQUISITES:
|
|
7
|
+
# 1. macOS + Xcode 16+
|
|
8
|
+
# 2. ~/.netrc configured with your Mapbox Downloads token:
|
|
9
|
+
# machine api.mapbox.com
|
|
10
|
+
# login mapbox
|
|
11
|
+
# password sk.your_downloads_token
|
|
12
|
+
# 3. Swift Package Manager available (comes with Xcode)
|
|
13
|
+
# 4. Scipio installed (https://github.com/giginet/Scipio):
|
|
14
|
+
# swift package --disable-sandbox experimental-publish-xcbundles
|
|
15
|
+
# OR install via Homebrew: brew install giginet/scipio/scipio
|
|
16
|
+
#
|
|
17
|
+
# This script builds MapboxNavigationCore and MapboxNavigationUIKit
|
|
18
|
+
# (and their dependencies) as xcframeworks and copies them into the
|
|
19
|
+
# ios/Frameworks/ directory, which is referenced by ExpoMapboxNavigation.podspec.
|
|
20
|
+
#
|
|
21
|
+
# Based on the approach by youssefhenna/expo-mapbox-navigation:
|
|
22
|
+
# https://github.com/uju777/expo-mapbox-navigation#getting-the-xcframework-files
|
|
23
|
+
# ─────────────────────────────────────────────────────────────────────────────
|
|
24
|
+
|
|
25
|
+
set -e
|
|
26
|
+
|
|
27
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
28
|
+
MODULE_ROOT="$(dirname "$SCRIPT_DIR")"
|
|
29
|
+
FRAMEWORKS_DIR="$SCRIPT_DIR/Frameworks"
|
|
30
|
+
|
|
31
|
+
# ── Config ────────────────────────────────────────────────────────────────────
|
|
32
|
+
MAPBOX_NAV_VERSION="3.25.0"
|
|
33
|
+
MAPBOX_MAPS_VERSION="11.25.0"
|
|
34
|
+
MAPBOX_COMMON_VERSION="24.25.0"
|
|
35
|
+
MAPBOX_NAV_NATIVE_VERSION="324.25.0"
|
|
36
|
+
|
|
37
|
+
echo "🔧 Building xcframeworks for Mapbox Navigation SDK v$MAPBOX_NAV_VERSION"
|
|
38
|
+
echo " Output: $FRAMEWORKS_DIR"
|
|
39
|
+
echo ""
|
|
40
|
+
|
|
41
|
+
# ── Step 1: Clone mapbox-navigation-ios ──────────────────────────────────────
|
|
42
|
+
TMPDIR=$(mktemp -d)
|
|
43
|
+
echo "📦 Cloning mapbox-navigation-ios v$MAPBOX_NAV_VERSION..."
|
|
44
|
+
git clone --branch "v$MAPBOX_NAV_VERSION" --depth 1 \
|
|
45
|
+
https://github.com/mapbox/mapbox-navigation-ios.git \
|
|
46
|
+
"$TMPDIR/mapbox-navigation-ios"
|
|
47
|
+
|
|
48
|
+
cd "$TMPDIR/mapbox-navigation-ios"
|
|
49
|
+
|
|
50
|
+
# ── Step 2: Replace Package.swift with the modified version ──────────────────
|
|
51
|
+
echo "📝 Patching Package.swift..."
|
|
52
|
+
cp "$SCRIPT_DIR/Package.swift" Package.swift
|
|
53
|
+
|
|
54
|
+
# ── Step 3: Get the correct navNative checksum ───────────────────────────────
|
|
55
|
+
echo "🔍 Resolving navNative checksum (this may take a moment)..."
|
|
56
|
+
# Run swift build once to get the correct checksum — it will fail and print it
|
|
57
|
+
CHECKSUM=$(swift build -c release 2>&1 | grep -oE '"[a-f0-9]{64}"' | head -1 | tr -d '"' || true)
|
|
58
|
+
|
|
59
|
+
if [ -z "$CHECKSUM" ]; then
|
|
60
|
+
echo "⚠️ Could not auto-detect checksum. Please run manually and update Package.swift."
|
|
61
|
+
else
|
|
62
|
+
echo " Checksum: $CHECKSUM"
|
|
63
|
+
sed -i '' "s/placeholder_run_swift_build_to_get_real_checksum/$CHECKSUM/g" Package.swift
|
|
64
|
+
fi
|
|
65
|
+
|
|
66
|
+
# ── Step 4: Build xcframeworks with Scipio ────────────────────────────────────
|
|
67
|
+
echo ""
|
|
68
|
+
echo "🏗️ Building xcframeworks with Scipio..."
|
|
69
|
+
echo " This will take 10-30 minutes on first run."
|
|
70
|
+
echo ""
|
|
71
|
+
|
|
72
|
+
# Clone Scipio inside the navigation-ios repo
|
|
73
|
+
git clone --depth 1 https://github.com/giginet/Scipio.git Scipio
|
|
74
|
+
cd Scipio
|
|
75
|
+
swift build -c release
|
|
76
|
+
|
|
77
|
+
# Build the xcframeworks
|
|
78
|
+
cd "$TMPDIR/mapbox-navigation-ios"
|
|
79
|
+
Scipio/.build/release/scipio create ./ -f \
|
|
80
|
+
--platforms iOS \
|
|
81
|
+
--only-use-versions-from-resolved-file \
|
|
82
|
+
--enable-library-evolution \
|
|
83
|
+
--support-simulators \
|
|
84
|
+
--embed-debug-symbols \
|
|
85
|
+
--verbose
|
|
86
|
+
|
|
87
|
+
# ── Step 5: Copy to module ────────────────────────────────────────────────────
|
|
88
|
+
echo ""
|
|
89
|
+
echo "📋 Copying xcframeworks to $FRAMEWORKS_DIR..."
|
|
90
|
+
mkdir -p "$FRAMEWORKS_DIR"
|
|
91
|
+
|
|
92
|
+
BUILT_FRAMEWORKS="$TMPDIR/mapbox-navigation-ios/XCFrameworks"
|
|
93
|
+
|
|
94
|
+
# Copy the frameworks we need (others like MapboxMaps come from @rnmapbox/maps)
|
|
95
|
+
NEEDED_FRAMEWORKS=(
|
|
96
|
+
"MapboxNavigationCore"
|
|
97
|
+
"MapboxNavigationUIKit"
|
|
98
|
+
"MapboxNavigationNative"
|
|
99
|
+
"MapboxDirections"
|
|
100
|
+
"_MapboxNavigationHelpers"
|
|
101
|
+
)
|
|
102
|
+
|
|
103
|
+
for fw in "${NEEDED_FRAMEWORKS[@]}"; do
|
|
104
|
+
if [ -d "$BUILT_FRAMEWORKS/$fw.xcframework" ]; then
|
|
105
|
+
echo " ✅ $fw.xcframework"
|
|
106
|
+
cp -R "$BUILT_FRAMEWORKS/$fw.xcframework" "$FRAMEWORKS_DIR/"
|
|
107
|
+
else
|
|
108
|
+
echo " ❌ $fw.xcframework not found in $BUILT_FRAMEWORKS"
|
|
109
|
+
fi
|
|
110
|
+
done
|
|
111
|
+
|
|
112
|
+
# ── Cleanup ────────────────────────────────────────────────────────────────────
|
|
113
|
+
cd /
|
|
114
|
+
rm -rf "$TMPDIR"
|
|
115
|
+
|
|
116
|
+
echo ""
|
|
117
|
+
echo "✅ Done! xcframeworks are in $FRAMEWORKS_DIR"
|
|
118
|
+
echo " Commit the Frameworks/ directory and publish the package."
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jacques_gordon/expo-mapbox-navigation",
|
|
3
|
-
"version": "2.2.
|
|
3
|
+
"version": "2.2.7",
|
|
4
4
|
"description": "Expo module for Mapbox Navigation SDK with 16KB page size support, NDK27, and Mapbox Maps v11.11.0+",
|
|
5
5
|
"main": "build/index.js",
|
|
6
6
|
"types": "build/index.d.ts",
|
package/plugin/src/index.js
CHANGED
|
@@ -1,15 +1,12 @@
|
|
|
1
1
|
const {
|
|
2
2
|
withAppBuildGradle,
|
|
3
|
-
withProjectBuildGradle,
|
|
4
3
|
withAndroidManifest,
|
|
5
4
|
withInfoPlist,
|
|
6
5
|
withDangerousMod,
|
|
7
6
|
} = require('@expo/config-plugins');
|
|
8
|
-
const { mergeContents } = require('@expo/config-plugins/build/utils/generateCode');
|
|
9
7
|
const fs = require('fs');
|
|
10
8
|
const path = require('path');
|
|
11
9
|
|
|
12
|
-
|
|
13
10
|
const withMapboxNavigation = (config, options = {}) => {
|
|
14
11
|
const {
|
|
15
12
|
accessToken,
|
|
@@ -20,17 +17,14 @@ const withMapboxNavigation = (config, options = {}) => {
|
|
|
20
17
|
|
|
21
18
|
if (!accessToken) {
|
|
22
19
|
throw new Error(
|
|
23
|
-
'[@jacques_gordon/expo-mapbox-navigation] `accessToken` is required
|
|
24
|
-
'
|
|
25
|
-
' ["@jacques_gordon/expo-mapbox-navigation", { "accessToken": "pk.your_token" }]'
|
|
20
|
+
'[@jacques_gordon/expo-mapbox-navigation] `accessToken` is required.\n' +
|
|
21
|
+
' ["@jacques_gordon/expo-mapbox-navigation", { "accessToken": "pk.xxx" }]'
|
|
26
22
|
);
|
|
27
23
|
}
|
|
28
24
|
|
|
29
25
|
if (!downloadsToken) {
|
|
30
26
|
throw new Error(
|
|
31
|
-
'[@jacques_gordon/expo-mapbox-navigation] `downloadsToken` is required for iOS
|
|
32
|
-
'This must be a SECRET Mapbox token (starts with "sk.") with the "Downloads:Read" scope.\n' +
|
|
33
|
-
'Add it to your app.json plugins array:\n' +
|
|
27
|
+
'[@jacques_gordon/expo-mapbox-navigation] `downloadsToken` (secret sk.* token) is required for iOS.\n' +
|
|
34
28
|
' ["@jacques_gordon/expo-mapbox-navigation", { "accessToken": "pk.xxx", "downloadsToken": "sk.xxx" }]'
|
|
35
29
|
);
|
|
36
30
|
}
|
|
@@ -46,7 +40,7 @@ const withMapboxNavigation = (config, options = {}) => {
|
|
|
46
40
|
return mod;
|
|
47
41
|
});
|
|
48
42
|
|
|
49
|
-
// ── iOS:
|
|
43
|
+
// ── iOS: Info.plist — MBXAccessToken + permissions ────────────────────────
|
|
50
44
|
config = withInfoPlist(config, (mod) => {
|
|
51
45
|
mod.modResults.MBXAccessToken = accessToken;
|
|
52
46
|
mod.modResults.NSLocationWhenInUseUsageDescription =
|
|
@@ -64,7 +58,11 @@ const withMapboxNavigation = (config, options = {}) => {
|
|
|
64
58
|
return mod;
|
|
65
59
|
});
|
|
66
60
|
|
|
67
|
-
// ── iOS: .netrc for SPM authentication
|
|
61
|
+
// ── iOS: .netrc for SPM authentication ────────────────────────────────────
|
|
62
|
+
// The Mapbox Navigation SDK v3 is distributed as source code via SPM only.
|
|
63
|
+
// Our podspec uses spm_dependency() to declare the dependency, and SPM
|
|
64
|
+
// authenticates against api.mapbox.com using ~/.netrc credentials.
|
|
65
|
+
// This is the official Mapbox-documented authentication mechanism.
|
|
68
66
|
config = withDangerousMod(config, [
|
|
69
67
|
'ios',
|
|
70
68
|
(mod) => {
|
|
@@ -77,194 +75,18 @@ const withMapboxNavigation = (config, options = {}) => {
|
|
|
77
75
|
}
|
|
78
76
|
if (!existingContent.includes('machine api.mapbox.com')) {
|
|
79
77
|
fs.writeFileSync(netrcPath, existingContent + netrcEntry, { mode: 0o600 });
|
|
78
|
+
console.log('[@jacques_gordon/expo-mapbox-navigation] ✅ Wrote Mapbox credentials to ~/.netrc');
|
|
80
79
|
}
|
|
81
80
|
return mod;
|
|
82
81
|
},
|
|
83
82
|
]);
|
|
84
83
|
|
|
85
|
-
// ── iOS: Inject Mapbox Navigation SPM into project.pbxproj ───────────────
|
|
86
|
-
//
|
|
87
|
-
// WHY NOT spm_dependency() IN THE PODSPEC:
|
|
88
|
-
// spm_dependency() causes "43029 duplicate symbols" linker errors alongside
|
|
89
|
-
// @rnmapbox/maps (React Native #47344, Expo #37813) — the framework gets
|
|
90
|
-
// linked in both the Pod target AND the main app target simultaneously.
|
|
91
|
-
//
|
|
92
|
-
// WHY NOT xcodeProject.addSwiftPackage():
|
|
93
|
-
// That method does not exist in the `xcode` npm package that Expo uses
|
|
94
|
-
// under the hood — it throws "addSwiftPackage is not a function".
|
|
95
|
-
//
|
|
96
|
-
// THE SOLUTION — withDangerousMod on project.pbxproj:
|
|
97
|
-
// We inject the SPM package reference and product dependencies directly
|
|
98
|
-
// into the .pbxproj file as text. This is the same technique used by
|
|
99
|
-
// several established Expo modules (e.g. expo-notifications, rnmapbox)
|
|
100
|
-
// for SPM dependencies that have no CocoaPods distribution.
|
|
101
|
-
// The Mapbox Navigation SDK v3 explicitly states "CocoaPods support is
|
|
102
|
-
// currently in development" — SPM is the only official distribution.
|
|
103
|
-
config = withDangerousMod(config, [
|
|
104
|
-
'ios',
|
|
105
|
-
(mod) => {
|
|
106
|
-
const projectRoot = mod.modRequest.platformProjectRoot;
|
|
107
|
-
const projectName = mod.modRequest.projectName;
|
|
108
|
-
const pbxprojPath = path.join(
|
|
109
|
-
projectRoot,
|
|
110
|
-
`${projectName}.xcodeproj`,
|
|
111
|
-
'project.pbxproj'
|
|
112
|
-
);
|
|
113
|
-
|
|
114
|
-
if (!fs.existsSync(pbxprojPath)) {
|
|
115
|
-
console.warn(`[@jacques_gordon/expo-mapbox-navigation] Could not find ${pbxprojPath} — skipping SPM injection`);
|
|
116
|
-
return mod;
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
let pbxproj = fs.readFileSync(pbxprojPath, 'utf8');
|
|
120
|
-
|
|
121
|
-
// Skip if already injected
|
|
122
|
-
if (pbxproj.includes('mapbox-navigation-ios')) {
|
|
123
|
-
return mod;
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
// Generate stable UUIDs for the new entries
|
|
127
|
-
// (UUIDs must be 24 hex chars in pbxproj format)
|
|
128
|
-
const makeUUID = () => {
|
|
129
|
-
const { randomBytes } = require('crypto');
|
|
130
|
-
return randomBytes(12).toString('hex').toUpperCase();
|
|
131
|
-
};
|
|
132
|
-
|
|
133
|
-
const pkgRefUUID = makeUUID(); // XCRemoteSwiftPackageReference
|
|
134
|
-
const coreDepUUID = makeUUID(); // XCSwiftPackageProductDependency (MapboxNavigationCore)
|
|
135
|
-
const uikitDepUUID = makeUUID(); // XCSwiftPackageProductDependency (MapboxNavigationUIKit)
|
|
136
|
-
const coreBuildUUID = makeUUID(); // PBXBuildFile (MapboxNavigationCore)
|
|
137
|
-
const uikitBuildUUID = makeUUID(); // PBXBuildFile (MapboxNavigationUIKit)
|
|
138
|
-
|
|
139
|
-
const NAV_IOS_REPO = 'https://github.com/mapbox/mapbox-navigation-ios.git';
|
|
140
|
-
const NAV_IOS_VERSION = '3.25.0';
|
|
141
|
-
|
|
142
|
-
// 1. Add XCRemoteSwiftPackageReference
|
|
143
|
-
const pkgRefEntry = `
|
|
144
|
-
\t\t${pkgRefUUID} /* XCRemoteSwiftPackageReference "mapbox-navigation-ios" */ = {
|
|
145
|
-
\t\t\tisa = XCRemoteSwiftPackageReference;
|
|
146
|
-
\t\t\trequirement = {
|
|
147
|
-
\t\t\t\tkind = upToNextMajorVersion;
|
|
148
|
-
\t\t\t\tminimumVersion = ${NAV_IOS_VERSION};
|
|
149
|
-
\t\t\t};
|
|
150
|
-
\t\t\trepositoryURL = "${NAV_IOS_REPO}";
|
|
151
|
-
\t\t};`;
|
|
152
|
-
|
|
153
|
-
// 2. Add XCSwiftPackageProductDependencies
|
|
154
|
-
const coreDepEntry = `
|
|
155
|
-
\t\t${coreDepUUID} /* MapboxNavigationCore */ = {
|
|
156
|
-
\t\t\tisa = XCSwiftPackageProductDependency;
|
|
157
|
-
\t\t\tpackage = ${pkgRefUUID} /* XCRemoteSwiftPackageReference "mapbox-navigation-ios" */;
|
|
158
|
-
\t\t\tproductName = MapboxNavigationCore;
|
|
159
|
-
\t\t};`;
|
|
160
|
-
|
|
161
|
-
const uikitDepEntry = `
|
|
162
|
-
\t\t${uikitDepUUID} /* MapboxNavigationUIKit */ = {
|
|
163
|
-
\t\t\tisa = XCSwiftPackageProductDependency;
|
|
164
|
-
\t\t\tpackage = ${pkgRefUUID} /* XCRemoteSwiftPackageReference "mapbox-navigation-ios" */;
|
|
165
|
-
\t\t\tproductName = MapboxNavigationUIKit;
|
|
166
|
-
\t\t};`;
|
|
167
|
-
|
|
168
|
-
// 3. Add PBXBuildFile entries for the frameworks
|
|
169
|
-
const coreBuildEntry = `
|
|
170
|
-
\t\t${coreBuildUUID} /* MapboxNavigationCore in Frameworks */ = {isa = PBXBuildFile; productRef = ${coreDepUUID} /* MapboxNavigationCore */; };`;
|
|
171
|
-
|
|
172
|
-
const uikitBuildEntry = `
|
|
173
|
-
\t\t${uikitBuildUUID} /* MapboxNavigationUIKit in Frameworks */ = {isa = PBXBuildFile; productRef = ${uikitDepUUID} /* MapboxNavigationUIKit */; };`;
|
|
174
|
-
|
|
175
|
-
// Inject into the relevant sections
|
|
176
|
-
// Section: XCRemoteSwiftPackageReference
|
|
177
|
-
if (pbxproj.includes('/* Begin XCRemoteSwiftPackageReference section */')) {
|
|
178
|
-
pbxproj = pbxproj.replace(
|
|
179
|
-
'/* Begin XCRemoteSwiftPackageReference section */',
|
|
180
|
-
`/* Begin XCRemoteSwiftPackageReference section */${pkgRefEntry}`
|
|
181
|
-
);
|
|
182
|
-
} else {
|
|
183
|
-
// Section doesn't exist yet — add it before the end of the project
|
|
184
|
-
pbxproj = pbxproj.replace(
|
|
185
|
-
'/* End XCConfigurationList section */',
|
|
186
|
-
`/* End XCConfigurationList section */\n\n/* Begin XCRemoteSwiftPackageReference section */${pkgRefEntry}\n/* End XCRemoteSwiftPackageReference section */`
|
|
187
|
-
);
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
// Section: XCSwiftPackageProductDependency
|
|
191
|
-
if (pbxproj.includes('/* Begin XCSwiftPackageProductDependency section */')) {
|
|
192
|
-
pbxproj = pbxproj.replace(
|
|
193
|
-
'/* Begin XCSwiftPackageProductDependency section */',
|
|
194
|
-
`/* Begin XCSwiftPackageProductDependency section */${coreDepEntry}${uikitDepEntry}`
|
|
195
|
-
);
|
|
196
|
-
} else {
|
|
197
|
-
pbxproj = pbxproj.replace(
|
|
198
|
-
'/* End XCRemoteSwiftPackageReference section */',
|
|
199
|
-
`/* End XCRemoteSwiftPackageReference section */\n\n/* Begin XCSwiftPackageProductDependency section */${coreDepEntry}${uikitDepEntry}\n/* End XCSwiftPackageProductDependency section */`
|
|
200
|
-
);
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
// Section: PBXBuildFile
|
|
204
|
-
pbxproj = pbxproj.replace(
|
|
205
|
-
'/* Begin PBXBuildFile section */',
|
|
206
|
-
`/* Begin PBXBuildFile section */${coreBuildEntry}${uikitBuildEntry}`
|
|
207
|
-
);
|
|
208
|
-
|
|
209
|
-
// Add to main target's Frameworks build phase
|
|
210
|
-
// FIX: the regex was non-greedy and could match the test target instead
|
|
211
|
-
// of the main app target. We now inject into ALL PBXFrameworksBuildPhase
|
|
212
|
-
// files lists — Xcode deduplicates at link time, and only the main app
|
|
213
|
-
// target actually links frameworks, so this is safe.
|
|
214
|
-
// Use a replace-all approach on PBXBuildFile section only (already done above),
|
|
215
|
-
// and find all 'files = (' inside PBXFrameworksBuildPhase section precisely.
|
|
216
|
-
const frameworksSectionMatch = pbxproj.match(
|
|
217
|
-
/\/\* Begin PBXFrameworksBuildPhase section \*\/([\s\S]*?)\/\* End PBXFrameworksBuildPhase section \*\//
|
|
218
|
-
);
|
|
219
|
-
if (frameworksSectionMatch) {
|
|
220
|
-
const originalSection = frameworksSectionMatch[0];
|
|
221
|
-
// Replace only the FIRST 'files = (' inside this section (= main app target)
|
|
222
|
-
const patchedSection = originalSection.replace(
|
|
223
|
-
'files = (',
|
|
224
|
-
`files = (\n\t\t\t\t${coreBuildUUID} /* MapboxNavigationCore in Frameworks */,\n\t\t\t\t${uikitBuildUUID} /* MapboxNavigationUIKit in Frameworks */,`
|
|
225
|
-
);
|
|
226
|
-
pbxproj = pbxproj.replace(originalSection, patchedSection);
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
// Add to main target's packageProductDependencies
|
|
230
|
-
// FIX: only replace the FIRST occurrence (main app target, not test target)
|
|
231
|
-
if (pbxproj.includes('packageProductDependencies = (')) {
|
|
232
|
-
pbxproj = pbxproj.replace(
|
|
233
|
-
'packageProductDependencies = (',
|
|
234
|
-
`packageProductDependencies = (\n\t\t\t\t${coreDepUUID} /* MapboxNavigationCore */,\n\t\t\t\t${uikitDepUUID} /* MapboxNavigationUIKit */,`
|
|
235
|
-
);
|
|
236
|
-
} else {
|
|
237
|
-
// packageProductDependencies doesn't exist yet — add it to the first PBXNativeTarget
|
|
238
|
-
pbxproj = pbxproj.replace(
|
|
239
|
-
/(isa = PBXNativeTarget;[\s\S]*?)(packageReferences = \([\s\S]*?\);)/,
|
|
240
|
-
`$1$2\n\t\t\tpackageProductDependencies = (\n\t\t\t\t${coreDepUUID} /* MapboxNavigationCore */,\n\t\t\t\t${uikitDepUUID} /* MapboxNavigationUIKit */,\n\t\t\t);`
|
|
241
|
-
);
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
// Add to project's packageReferences list (first occurrence only = main project)
|
|
245
|
-
if (pbxproj.includes('packageReferences = (')) {
|
|
246
|
-
pbxproj = pbxproj.replace(
|
|
247
|
-
'packageReferences = (',
|
|
248
|
-
`packageReferences = (\n\t\t\t\t${pkgRefUUID} /* XCRemoteSwiftPackageReference "mapbox-navigation-ios" */,`
|
|
249
|
-
);
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
fs.writeFileSync(pbxprojPath, pbxproj, 'utf8');
|
|
253
|
-
console.log('[@jacques_gordon/expo-mapbox-navigation] ✅ Injected Mapbox Navigation SPM into project.pbxproj');
|
|
254
|
-
|
|
255
|
-
return mod;
|
|
256
|
-
},
|
|
257
|
-
]);
|
|
258
|
-
|
|
259
84
|
return config;
|
|
260
85
|
};
|
|
261
86
|
|
|
262
|
-
// ── Android helpers
|
|
87
|
+
// ── Android helpers ───────────────────────────────────────────────────────────
|
|
263
88
|
|
|
264
89
|
function addAndroidConfig(mod, mapboxMapsVersion, androidColorOverrides) {
|
|
265
|
-
const MAPBOX_DOWNLOADS_TOKEN_KEY = 'MAPBOX_DOWNLOADS_TOKEN';
|
|
266
|
-
// (kept for backward compat — actual token is in gradle.properties)
|
|
267
|
-
|
|
268
90
|
if (!mod.modResults.contents.includes('abiFilters')) {
|
|
269
91
|
mod.modResults.contents = mod.modResults.contents.replace(
|
|
270
92
|
/defaultConfig {([\s\S]*?)}/,
|
|
@@ -317,9 +139,22 @@ function addAndroidConfig(mod, mapboxMapsVersion, androidColorOverrides) {
|
|
|
317
139
|
`;
|
|
318
140
|
}
|
|
319
141
|
|
|
142
|
+
// Android color overrides for Mapbox resource colors (route line, banner, etc.)
|
|
320
143
|
if (Object.keys(androidColorOverrides).length > 0) {
|
|
321
|
-
|
|
322
|
-
|
|
144
|
+
const resDir = path.join(
|
|
145
|
+
mod.modRequest?.platformProjectRoot || '',
|
|
146
|
+
'app', 'src', 'main', 'res', 'values'
|
|
147
|
+
);
|
|
148
|
+
try {
|
|
149
|
+
fs.mkdirSync(resDir, { recursive: true });
|
|
150
|
+
const colorEntries = Object.entries(androidColorOverrides)
|
|
151
|
+
.map(([name, value]) => ` <color name="${name}">${value}</color>`)
|
|
152
|
+
.join('\n');
|
|
153
|
+
const xmlContent = `<?xml version="1.0" encoding="utf-8"?>\n<resources>\n${colorEntries}\n</resources>\n`;
|
|
154
|
+
fs.writeFileSync(path.join(resDir, 'mapbox_color_overrides.xml'), xmlContent);
|
|
155
|
+
} catch (e) {
|
|
156
|
+
// Ignore — resDir may not exist at plugin resolution time
|
|
157
|
+
}
|
|
323
158
|
}
|
|
324
159
|
}
|
|
325
160
|
|