Closed syedmumersajjad closed 2 weeks ago
@syedmumersajjad Yes it's possible. I'm currently working with this package. I had to write a plugin to let it works with EXPO.
But it's possible
Thanks for your reply how long it will take to publicly available because I need it badly
Yes, I had to create this plugin:
` / eslint-disable no-undef / const { withDangerousMod, withPlugins, } = require('@expo/config-plugins'); const { writeFileSync, existsSync, mkdirSync } = require('fs');
function addLayoutFiles(resDirectory, filename, file) {
const layoutDir = ${resDirectory}
;
const layoutDirExists = existsSync(layoutDir);
if (layoutDirExists) {
writeFileSync(${layoutDir}/${filename}
, file);
} else {
mkdirSync(layoutDir);
writeFileSync(${layoutDir}/${filename}
, file);
}
}
function withAndroidBridgeFiles(config) { return withDangerousMod(config, [ 'android', (cfg) => { const androidProjRoot = cfg.modRequest.platformProjectRoot; const navViewActivityLayoutFileName = 'mapbox_access_token.xml';
const layoutFile = `<?xml version="1.0" encoding="utf-8"?>
@syedmumersajjad Here my plugin
const {
withGradleProperties,
withAndroidManifest,
withInfoPlist,
withDangerousMod
} = require('@expo/config-plugins');
const fs = require('fs');
const path = require('path');
const withCustomWorkLibrary = (config) => {
config = withGradleProperties(config, async (config) => {
setMapboxDownloadsToken(config);
return config;
});
config = withAndroidManifest(config, async (config) => {
addMapboxAccessToken(config);
//addForegroundServiceLocationPermission(config);
return config;
});
//}
// iOS configurations
config = withInfoPlist(config, async (config) => {
addMapboxAccessTokenToInfoPlist(config);
addUIBackgroundModes(config);
return config;
});
config = withDangerousMod(config, [
'ios',
(config) => {
addNetrcFile();
modifyPodfile(config.modRequest.projectRoot);
return config;
},
]);
return config;
};
function setMapboxDownloadsToken(config) {
const { modResults } = config;
const mapboxToken = MAPBOX_DOWNLOADS_TOKEN;
const tokenKey = 'MAPBOX_DOWNLOADS_TOKEN';
if (Array.isArray(modResults)) {
const tokenIndex = modResults.findIndex((item) => item.key === tokenKey);
if (tokenIndex !== -1) {
// Replace existing token
modResults[tokenIndex].value = mapboxToken;
} else {
// Add new token
modResults.push({
type: 'property',
key: tokenKey,
value: mapboxToken,
});
}
} else {
throw new Error('gradleProperties is not an array');
}
}
function addMapboxAccessTokenToInfoPlist(config) {
const { modResults } = config;
const mapboxAccessToken = MAPBOX_ACCESS_TOKEN;
modResults['MBXAccessToken'] = mapboxAccessToken;
}
function addUIBackgroundModes(config) {
const { modResults } = config;
if (!modResults.UIBackgroundModes) {
modResults.UIBackgroundModes = [];
}
if (!modResults.UIBackgroundModes.includes('audio')) {
modResults.UIBackgroundModes.push('audio');
}
if (!modResults.UIBackgroundModes.includes('location')) {
modResults.UIBackgroundModes.push('location');
}
}
function addNetrcFile() {
const homeDir = require('os').homedir();
const netrcPath = path.join(homeDir, '.netrc');
const secretToken = MAPBOX_DOWNLOADS_TOKEN;
const netrcContent = `machine api.mapbox.com\nlogin mapbox\npassword ${secretToken}\n`;
fs.writeFileSync(netrcPath, netrcContent, { mode: 0o600 });
}
function modifyPodfile(projectRoot) {
const podfilePath = path.join(projectRoot, 'ios', 'Podfile');
if (fs.existsSync(podfilePath)) {
let podfileContent = fs.readFileSync(podfilePath, 'utf8');
// Ensure the correct version of MapboxMaps is specified
const mapboxVersion = '10.18.2';
const regex = /pod 'MapboxMaps', '.*'/;
if (regex.test(podfileContent)) {
podfileContent = podfileContent.replace(regex, `pod 'MapboxMaps', '~> ${mapboxVersion}'`);
} else {
// Add the MapboxMaps dependency if not present
podfileContent += `\npod 'MapboxMaps', '~> ${mapboxVersion}'\n`;
}
fs.writeFileSync(podfilePath, podfileContent, 'utf8');
} else {
throw new Error('Podfile not found');
}
}
function addMapboxAccessToken(config) {
const { modResults } = config;
const mapboxAccessToken = MAPBOX_ACCESS_TOKEN;
const application = modResults.manifest.application[0];
if (!application.hasOwnProperty('meta-data')) {
application['meta-data'] = [];
}
const metaDataItem = application['meta-data'].find((item) => item['$']['android:name'] === 'MAPBOX_ACCESS_TOKEN');
if (metaDataItem) {
// If the meta-data item exists, update its value and add the attributes
metaDataItem['$']['android:value'] = mapboxAccessToken;
metaDataItem['$']['translatable'] = 'false';
metaDataItem['$']['tools:ignore'] = 'UnusedResources';
} else {
// If the meta-data item does not exist, add it with the attributes
application['meta-data'].push({
$: {
'android:name': 'MAPBOX_ACCESS_TOKEN',
'android:value': mapboxAccessToken,
'translatable': 'false',
'tools:ignore': 'UnusedResources'
}
});
}
}
module.exports = withCustomWorkLibrary;
Inside the App.json => pluggin add ["./plugins/withCustomWorkLibrary.js",{}],
I can see it's better than my plugin, in fact you added to iOS. Congratulations my friend, I'm going to use.
We should add this plugin to the library
@jacquesngomeheffa thanks for sharing but still getting errors can you share your project it will helps a lot for newbie like me
@jacquesngomeheffa please i need it badly nothing working for me can you give me in separate project
@syedmumersajjad Share your error, I will take a look at it?
Incident Identifier: BAD0009B-86D5-4761-898E-42942AA1EF8D CrashReporter Key: 91FE9550-7974-8D4E-BC06-971601F52573 Hardware Model: MacBookPro16,2
Coalition: com.apple.CoreSimulator.SimDevice.B8C8F3B3-9BAA-4799-9EDD-A2FD5439F7AC [24256] Responsible Process: SimulatorTrampoline [51232]
Date/Time: 2024-08-25 14:46:31.2490 +0500 Launch Time: 2024-08-25 14:46:31.1987 +0500 OS Version: macOS 14.6.1 (23G93) Release Type: User Report Version: 104
Exception Type: EXC_CRASH (SIGABRT) Exception Codes: 0x0000000000000000, 0x0000000000000000 Termination Reason: DYLD 1 Library missing Library not loaded: @rpath/MapboxCommon.framework/MapboxCommon Referenced from: <6645BACD-586B-3B2C-A884-09B701040564> /Users/USER/Library/Developer/CoreSimulator/Devices/B8C8F3B3-9BAA-4799-9EDD-A2FD5439F7AC/data/Containers/Bundle/Application/8AFF4689-0E88-4190-85AE-614DC219379F/YurDrivers.app/YurDrivers Reason: tried: '/Library/Developer/CoreSimulator/Volumes/iOS_21F79/Library/Developer/CoreSimulator/Profiles/Runtimes/iOS 17.5.simruntime/Contents/Resources/RuntimeRoot/usr/lib/swift/MapboxCommon.framework/MapboxCommon' (no such file), '/usr/lib/swift/MapboxCommon.framework/MapboxCommon' (no such file, not in dyld cache), '/Users/mac/Library/Developer/CoreSimulator/Devices/B8C8F3B3-9BAA-4799-9EDD-A2FD5439F7AC/data/Containers/Bundle/Application/8AFF4689-0E88-4190-85AE-614DC219379F/YurDrivers.app/Frameworks/MapboxCommon.framework/MapboxCommon' (no such file), '/Users/mac/Library/Developer/CoreSimulator/Devices/B8C8F3B3-9BAA-4799-9EDD-A2FD5439F7AC/data/Containers/Bundle/Application/8AFF4689-0E88-4190-85AE-614 (terminated at launch; ignore backtrace)
@syedmumersajjad I think you have this problem because you're not using this package as a static Frameworks
Make sure you have passed a Mapbox key who has download rights, otherwise it won't work
Try the same below (My whole configuration)
Here is how my app.json looks like
Where my plugin is located at
How my plugin looks like
const {
withGradleProperties,
withAndroidManifest,
withInfoPlist,
withDangerousMod
} = require('@expo/config-plugins');
const fs = require('fs');
const path = require('path');
const { MAPBOX_ACCESS_TOKEN, MAPBOX_DOWNLOADS_TOKEN } = require('../constants/constants');
const withCustomWorkLibrary = (config) => {
// Android configurations
config = withGradleProperties(config, async (config) => {
setMapboxDownloadsToken(config);
return config;
});
config = withAndroidManifest(config, async (config) => {
addMapboxAccessToken(config);
//addForegroundServiceLocationPermission(config);
return config;
});
//}
// iOS configurations
config = withInfoPlist(config, async (config) => {
addMapboxAccessTokenToInfoPlist(config);
addUIBackgroundModes(config);
return config;
});
config = withDangerousMod(config, [
'ios',
(config) => {
addNetrcFile();
modifyPodfile(config.modRequest.projectRoot);
return config;
},
]);
return config;
};
function setMapboxDownloadsToken(config) {
const { modResults } = config;
const mapboxToken = MAPBOX_DOWNLOADS_TOKEN;
const tokenKey = 'MAPBOX_DOWNLOADS_TOKEN';
if (Array.isArray(modResults)) {
const tokenIndex = modResults.findIndex((item) => item.key === tokenKey);
if (tokenIndex !== -1) {
// Replace existing token
modResults[tokenIndex].value = mapboxToken;
} else {
// Add new token
modResults.push({
type: 'property',
key: tokenKey,
value: mapboxToken,
});
}
} else {
throw new Error('gradleProperties is not an array');
}
}
function addMapboxAccessTokenToInfoPlist(config) {
const { modResults } = config;
const mapboxAccessToken = MAPBOX_ACCESS_TOKEN;
modResults['MBXAccessToken'] = mapboxAccessToken;
}
function addUIBackgroundModes(config) {
const { modResults } = config;
if (!modResults.UIBackgroundModes) {
modResults.UIBackgroundModes = [];
}
if (!modResults.UIBackgroundModes.includes('audio')) {
modResults.UIBackgroundModes.push('audio');
}
if (!modResults.UIBackgroundModes.includes('location')) {
modResults.UIBackgroundModes.push('location');
}
}
function addNetrcFile() {
const homeDir = require('os').homedir();
const netrcPath = path.join(homeDir, '.netrc');
const secretToken = MAPBOX_DOWNLOADS_TOKEN;
const netrcContent = `machine api.mapbox.com\nlogin mapbox\npassword ${secretToken}\n`;
fs.writeFileSync(netrcPath, netrcContent, { mode: 0o600 });
}
function modifyPodfile(projectRoot) {
const podfilePath = path.join(projectRoot, 'ios', 'Podfile');
if (fs.existsSync(podfilePath)) {
let podfileContent = fs.readFileSync(podfilePath, 'utf8');
// Ensure the correct version of MapboxMaps is specified
const mapboxVersion = '10.18.2';
const regex = /pod 'MapboxMaps', '.*'/;
if (regex.test(podfileContent)) {
podfileContent = podfileContent.replace(regex, `pod 'MapboxMaps', '~> ${mapboxVersion}'`);
} else {
// Add the MapboxMaps dependency if not present
podfileContent += `\npod 'MapboxMaps', '~> ${mapboxVersion}'\n`;
}
// Ensure that other Mapbox-related pods are compatible
const otherPods = [
{
name: 'MapboxNavigation',
version: '2.18.3' // This version should be compatible with MapboxMaps 10.18.2
}
];
otherPods.forEach(pod => {
const podRegex = new RegExp(`pod '${pod.name}', '.*'`);
if (podRegex.test(podfileContent)) {
podfileContent = podfileContent.replace(podRegex, `pod '${pod.name}', '~> ${pod.version}'`);
} else {
podfileContent += `\npod '${pod.name}', '~> ${pod.version}'\n`;
}
});
fs.writeFileSync(podfilePath, podfileContent, 'utf8');
} else {
throw new Error('Podfile not found');
}
}
function addMapboxAccessToken(config) {
const { modResults } = config;
const mapboxAccessToken = MAPBOX_ACCESS_TOKEN;
const application = modResults.manifest.application[0];
if (!application.hasOwnProperty('meta-data')) {
application['meta-data'] = [];
}
const metaDataItem = application['meta-data'].find((item) => item['$']['android:name'] === 'MAPBOX_ACCESS_TOKEN');
if (metaDataItem) {
// If the meta-data item exists, update its value and add the attributes
metaDataItem['$']['android:value'] = mapboxAccessToken;
metaDataItem['$']['translatable'] = 'false';
metaDataItem['$']['tools:ignore'] = 'UnusedResources';
} else {
// If the meta-data item does not exist, add it with the attributes
application['meta-data'].push({
$: {
'android:name': 'MAPBOX_ACCESS_TOKEN',
'android:value': mapboxAccessToken,
'translatable': 'false',
'tools:ignore': 'UnusedResources'
}
});
}
}
module.exports = withCustomWorkLibrary;
This is the way I'm using this package. Additional configuration is not necessary.
My last expo build
@jacquesngomeheffa thanks for your response after setting up the project according to instructions provided above the error has gone but one more error i faced on development build to expo error: Multiple commands produce '/Users/expo/Library/Developer/Xcode/DerivedData/YurDrivers-dlhpehndovsedtakeolqvsvkwbkp/Build/Intermediates.noindex/ArchiveIntermediates/YurDrivers/InstallationBuildProductsLocation/Applications/YurDrivers.app/PrivacyInfo.xcprivacy'
duplicate output file '/Users/expo/Library/Developer/Xcode/DerivedData/YurDrivers-dlhpehndovsedtakeolqvsvkwbkp/Build/Intermediates.noindex/ArchiveIntermediates/YurDrivers/InstallationBuildProductsLocation/Applications/YurDrivers.app/PrivacyInfo.xcprivacy' on task: PhaseScriptExecution [CP] Copy Pods Resources /Users/expo/Library/Developer/Xcode/DerivedData/YurDrivers-dlhpehndovsedtakeolqvsvkwbkp/Build/Intermediates.noindex/ArchiveIntermediates/YurDrivers/IntermediateBuildFilesPath/YurDrivers.build/Debug-iphoneos/YurDrivers.build/Script-7CCF5F63BEAB1AFF30F0C986.sh (in target 'YurDrivers' from project 'YurDrivers')
@syedmumersajjad did you tried this https://docs.expo.dev/build-reference/simulators/ I guess you're using a simulator right?
Better use Expo Enviroment to build the development.
If you're not using the @rnmapbox/maps doesn't install it, otherwise you'll probably facing errors
@jacquesngomeheffa Yes I have used it and yes using a simulator
@syedmumersajjad If you're not using the @rnmapbox/maps doesn't install it, otherwise you'll probably facing errors
any errors logs from expo environment?
@jacquesngomeheffa can you share settings for android I mean which gradle you are using for it
any errors logs from expo environment?
eas build --profile development --platform ios i am using development build
@syedmumersajjad I'm using Expo SDK 50, which might be why. However, I've also tested this package, and it works too. It might be helpful to you. Check it out: https://github.com/YoussefHenna/expo-mapbox-navigation.
This package is for Expo and works on SDK 50 and 51. I've tested it, and it works well.
I hope this helps you guys. I've been in your place before.
Let me know if you'd like any further changes!
any errors logs from expo environment?
eas build --profile development --platform ios i am using development build
Try this one, I have changed something (Mapbox version)
const {
withGradleProperties,
withAndroidManifest,
withInfoPlist,
withDangerousMod
} = require('@expo/config-plugins');
const fs = require('fs');
const path = require('path');
const { MAPBOX_ACCESS_TOKEN, MAPBOX_DOWNLOADS_TOKEN } = require('../constants/constants');
const withCustomWorkLibrary = (config) => {
// Android configurations
config = withGradleProperties(config, async (config) => {
setMapboxDownloadsToken(config);
return config;
});
config = withAndroidManifest(config, async (config) => {
addMapboxAccessToken(config);
//addForegroundServiceLocationPermission(config);
return config;
});
//}
// iOS configurations
config = withInfoPlist(config, async (config) => {
addMapboxAccessTokenToInfoPlist(config);
addUIBackgroundModes(config);
return config;
});
config = withDangerousMod(config, [
'ios',
(config) => {
addNetrcFile();
return config;
},
]);
return config;
};
function setMapboxDownloadsToken(config) {
const { modResults } = config;
const mapboxToken = MAPBOX_DOWNLOADS_TOKEN;
const tokenKey = 'MAPBOX_DOWNLOADS_TOKEN';
if (Array.isArray(modResults)) {
const tokenIndex = modResults.findIndex((item) => item.key === tokenKey);
if (tokenIndex !== -1) {
// Replace existing token
modResults[tokenIndex].value = mapboxToken;
} else {
// Add new token
modResults.push({
type: 'property',
key: tokenKey,
value: mapboxToken,
});
}
} else {
throw new Error('gradleProperties is not an array');
}
}
function addMapboxAccessTokenToInfoPlist(config) {
const { modResults } = config;
const mapboxAccessToken = MAPBOX_ACCESS_TOKEN;
modResults['MBXAccessToken'] = mapboxAccessToken;
}
function addUIBackgroundModes(config) {
const { modResults } = config;
if (!modResults.UIBackgroundModes) {
modResults.UIBackgroundModes = [];
}
if (!modResults.UIBackgroundModes.includes('audio')) {
modResults.UIBackgroundModes.push('audio');
}
if (!modResults.UIBackgroundModes.includes('location')) {
modResults.UIBackgroundModes.push('location');
}
}
function addNetrcFile() {
const homeDir = require('os').homedir();
const netrcPath = path.join(homeDir, '.netrc');
const secretToken = MAPBOX_DOWNLOADS_TOKEN;
const netrcContent = `machine api.mapbox.com\nlogin mapbox\npassword ${secretToken}\n`;
fs.writeFileSync(netrcPath, netrcContent, { mode: 0o600 });
}
function addMapboxAccessToken(config) {
const { modResults } = config;
const mapboxAccessToken = MAPBOX_ACCESS_TOKEN;
const application = modResults.manifest.application[0];
if (!application.hasOwnProperty('meta-data')) {
application['meta-data'] = [];
}
const metaDataItem = application['meta-data'].find((item) => item['$']['android:name'] === 'MAPBOX_ACCESS_TOKEN');
if (metaDataItem) {
// If the meta-data item exists, update its value and add the attributes
metaDataItem['$']['android:value'] = mapboxAccessToken;
metaDataItem['$']['translatable'] = 'false';
metaDataItem['$']['tools:ignore'] = 'UnusedResources';
} else {
// If the meta-data item does not exist, add it with the attributes
application['meta-data'].push({
$: {
'android:name': 'MAPBOX_ACCESS_TOKEN',
'android:value': mapboxAccessToken,
'translatable': 'false',
'tools:ignore': 'UnusedResources'
}
});
}
}
module.exports = withCustomWorkLibrary;
Hope this one helps.
And If you're using @rnmapbox/maps use version RNMapboxMapsVersion: 10.17.0 (IOS ONLY) and for Android use Version 11.4.0
Doesn't work try this one easy to use: https://github.com/YoussefHenna/expo-mapbox-navigation.
@syedmumersajjad Good luck my friend
@jacquesngomeheffa thank you so much i really appreciate your work hope we will have library for managed workflow soon. Appreciated 👍
@jacquesngomeheffa one last question if I use this library https://github.com/YoussefHenna/expo-mapbox-navigation do we need to add config module for that or just need to install and use it with expo prebuilt
@syedmumersajjad Not necessary, just follow his instructions, it will be enough 👍
@jacquesngomeheffa okay thanks
Thank you @jacquesngomeheffa for your resolution regarding the Expo managed project. I'm closing this issue on behalf of Comment-2311160292.
Hi thanks for sharing this library can we use this library in managed workflow.