1"use strict"; 2 3Object.defineProperty(exports, "__esModule", { 4 value: true 5}); 6exports.getBundleIdentifier = getBundleIdentifier; 7exports.getBundleIdentifierFromPbxproj = getBundleIdentifierFromPbxproj; 8exports.resetAllPlistBundleIdentifiers = resetAllPlistBundleIdentifiers; 9exports.resetPlistBundleIdentifier = resetPlistBundleIdentifier; 10exports.setBundleIdentifier = setBundleIdentifier; 11exports.setBundleIdentifierForPbxproj = setBundleIdentifierForPbxproj; 12exports.updateBundleIdentifierForPbxproj = updateBundleIdentifierForPbxproj; 13exports.withBundleIdentifier = void 0; 14function _plist() { 15 const data = _interopRequireDefault(require("@expo/plist")); 16 _plist = function () { 17 return data; 18 }; 19 return data; 20} 21function _assert() { 22 const data = _interopRequireDefault(require("assert")); 23 _assert = function () { 24 return data; 25 }; 26 return data; 27} 28function _fs() { 29 const data = _interopRequireDefault(require("fs")); 30 _fs = function () { 31 return data; 32 }; 33 return data; 34} 35function _xcode() { 36 const data = _interopRequireDefault(require("xcode")); 37 _xcode = function () { 38 return data; 39 }; 40 return data; 41} 42function _Paths() { 43 const data = require("./Paths"); 44 _Paths = function () { 45 return data; 46 }; 47 return data; 48} 49function _Target() { 50 const data = require("./Target"); 51 _Target = function () { 52 return data; 53 }; 54 return data; 55} 56function _Xcodeproj() { 57 const data = require("./utils/Xcodeproj"); 58 _Xcodeproj = function () { 59 return data; 60 }; 61 return data; 62} 63function _string() { 64 const data = require("./utils/string"); 65 _string = function () { 66 return data; 67 }; 68 return data; 69} 70function _withDangerousMod() { 71 const data = require("../plugins/withDangerousMod"); 72 _withDangerousMod = function () { 73 return data; 74 }; 75 return data; 76} 77function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 78const withBundleIdentifier = (config, { 79 bundleIdentifier 80}) => { 81 return (0, _withDangerousMod().withDangerousMod)(config, ['ios', async config => { 82 var _config$ios; 83 const bundleId = bundleIdentifier !== null && bundleIdentifier !== void 0 ? bundleIdentifier : (_config$ios = config.ios) === null || _config$ios === void 0 ? void 0 : _config$ios.bundleIdentifier; 84 (0, _assert().default)(bundleId, '`bundleIdentifier` must be defined in the app config (`expo.ios.bundleIdentifier`) or passed to the plugin `withBundleIdentifier`.'); 85 await setBundleIdentifierForPbxproj(config.modRequest.projectRoot, bundleId); 86 return config; 87 }]); 88}; 89exports.withBundleIdentifier = withBundleIdentifier; 90function getBundleIdentifier(config) { 91 var _config$ios$bundleIde, _config$ios2; 92 return (_config$ios$bundleIde = (_config$ios2 = config.ios) === null || _config$ios2 === void 0 ? void 0 : _config$ios2.bundleIdentifier) !== null && _config$ios$bundleIde !== void 0 ? _config$ios$bundleIde : null; 93} 94 95/** 96 * In Turtle v1 we set the bundleIdentifier directly on Info.plist rather 97 * than in pbxproj 98 */ 99function setBundleIdentifier(config, infoPlist) { 100 const bundleIdentifier = getBundleIdentifier(config); 101 if (!bundleIdentifier) { 102 return infoPlist; 103 } 104 return { 105 ...infoPlist, 106 CFBundleIdentifier: bundleIdentifier 107 }; 108} 109 110/** 111 * Gets the bundle identifier defined in the Xcode project found in the project directory. 112 * 113 * A bundle identifier is stored as a value in XCBuildConfiguration entry. 114 * Those entries exist for every pair (build target, build configuration). 115 * Unless target name is passed, the first target defined in the pbxproj is used 116 * (to keep compatibility with the inaccurate legacy implementation of this function). 117 * The build configuration is usually 'Release' or 'Debug'. However, it could be any arbitrary string. 118 * Defaults to 'Release'. 119 * 120 * @param {string} projectRoot Path to project root containing the ios directory 121 * @param {string} targetName Target name 122 * @param {string} buildConfiguration Build configuration. Defaults to 'Release'. 123 * @returns {string | null} bundle identifier of the Xcode project or null if the project is not configured 124 */ 125function getBundleIdentifierFromPbxproj(projectRoot, { 126 targetName, 127 buildConfiguration = 'Release' 128} = {}) { 129 let pbxprojPath; 130 try { 131 pbxprojPath = (0, _Paths().getPBXProjectPath)(projectRoot); 132 } catch { 133 return null; 134 } 135 const project = _xcode().default.project(pbxprojPath); 136 project.parseSync(); 137 const xcBuildConfiguration = (0, _Target().getXCBuildConfigurationFromPbxproj)(project, { 138 targetName, 139 buildConfiguration 140 }); 141 if (!xcBuildConfiguration) { 142 return null; 143 } 144 return getProductBundleIdentifierFromBuildConfiguration(xcBuildConfiguration); 145} 146function getProductBundleIdentifierFromBuildConfiguration(xcBuildConfiguration) { 147 const bundleIdentifierRaw = xcBuildConfiguration.buildSettings.PRODUCT_BUNDLE_IDENTIFIER; 148 if (bundleIdentifierRaw) { 149 const bundleIdentifier = (0, _string().trimQuotes)(bundleIdentifierRaw); 150 // it's possible to use interpolation for the bundle identifier 151 // the most common case is when the last part of the id is set to `$(PRODUCT_NAME:rfc1034identifier)` 152 // in this case, PRODUCT_NAME should be replaced with its value 153 // the `rfc1034identifier` modifier replaces all non-alphanumeric characters with dashes 154 const bundleIdentifierParts = bundleIdentifier.split('.'); 155 if (bundleIdentifierParts[bundleIdentifierParts.length - 1] === '$(PRODUCT_NAME:rfc1034identifier)' && xcBuildConfiguration.buildSettings.PRODUCT_NAME) { 156 bundleIdentifierParts[bundleIdentifierParts.length - 1] = xcBuildConfiguration.buildSettings.PRODUCT_NAME.replace(/[^a-zA-Z0-9]/g, '-'); 157 } 158 return bundleIdentifierParts.join('.'); 159 } else { 160 return null; 161 } 162} 163 164/** 165 * Updates the bundle identifier for a given pbxproj 166 * 167 * @param {string} pbxprojPath Path to pbxproj file 168 * @param {string} bundleIdentifier Bundle identifier to set in the pbxproj 169 * @param {boolean} [updateProductName=true] Whether to update PRODUCT_NAME 170 */ 171function updateBundleIdentifierForPbxproj(pbxprojPath, bundleIdentifier, updateProductName = true) { 172 const project = _xcode().default.project(pbxprojPath); 173 project.parseSync(); 174 const [, nativeTarget] = (0, _Target().findFirstNativeTarget)(project); 175 (0, _Xcodeproj().getBuildConfigurationsForListId)(project, nativeTarget.buildConfigurationList).forEach(([, item]) => { 176 if (item.buildSettings.PRODUCT_BUNDLE_IDENTIFIER === bundleIdentifier) { 177 return; 178 } 179 item.buildSettings.PRODUCT_BUNDLE_IDENTIFIER = `"${bundleIdentifier}"`; 180 if (updateProductName) { 181 const productName = bundleIdentifier.split('.').pop(); 182 if (!(productName !== null && productName !== void 0 && productName.includes('$'))) { 183 item.buildSettings.PRODUCT_NAME = productName; 184 } 185 } 186 }); 187 _fs().default.writeFileSync(pbxprojPath, project.writeSync()); 188} 189 190/** 191 * Updates the bundle identifier for pbx projects inside the ios directory of the given project root 192 * 193 * @param {string} projectRoot Path to project root containing the ios directory 194 * @param {string} bundleIdentifier Desired bundle identifier 195 * @param {boolean} [updateProductName=true] Whether to update PRODUCT_NAME 196 */ 197function setBundleIdentifierForPbxproj(projectRoot, bundleIdentifier, updateProductName = true) { 198 // Get all pbx projects in the ${projectRoot}/ios directory 199 let pbxprojPaths = []; 200 try { 201 pbxprojPaths = (0, _Paths().getAllPBXProjectPaths)(projectRoot); 202 } catch {} 203 for (const pbxprojPath of pbxprojPaths) { 204 updateBundleIdentifierForPbxproj(pbxprojPath, bundleIdentifier, updateProductName); 205 } 206} 207 208/** 209 * Reset bundle identifier field in Info.plist to use PRODUCT_BUNDLE_IDENTIFIER, as recommended by Apple. 210 */ 211 212const defaultBundleId = '$(PRODUCT_BUNDLE_IDENTIFIER)'; 213function resetAllPlistBundleIdentifiers(projectRoot) { 214 const infoPlistPaths = (0, _Paths().getAllInfoPlistPaths)(projectRoot); 215 for (const plistPath of infoPlistPaths) { 216 resetPlistBundleIdentifier(plistPath); 217 } 218} 219function resetPlistBundleIdentifier(plistPath) { 220 const rawPlist = _fs().default.readFileSync(plistPath, 'utf8'); 221 const plistObject = _plist().default.parse(rawPlist); 222 if (plistObject.CFBundleIdentifier) { 223 if (plistObject.CFBundleIdentifier === defaultBundleId) return; 224 225 // attempt to match default Info.plist format 226 const format = { 227 pretty: true, 228 indent: `\t` 229 }; 230 const xml = _plist().default.build({ 231 ...plistObject, 232 CFBundleIdentifier: defaultBundleId 233 }, format); 234 if (xml !== rawPlist) { 235 _fs().default.writeFileSync(plistPath, xml); 236 } 237 } 238} 239//# sourceMappingURL=BundleIdentifier.js.map