"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.bundleAssetsAsync = bundleAssetsAsync; exports.prepareDetachedBuildAsync = prepareDetachedBuildAsync; function _config() { const data = require("@expo/config"); _config = function () { return data; }; return data; } function _jsonFile() { const data = _interopRequireDefault(require("@expo/json-file")); _jsonFile = function () { return data; }; return data; } function _fsExtra() { const data = _interopRequireDefault(require("fs-extra")); _fsExtra = function () { return data; }; return data; } function _glob() { const data = require("glob"); _glob = function () { return data; }; return data; } function _path() { const data = _interopRequireDefault(require("path")); _path = function () { return data; }; return data; } function _internal() { const data = require("../internal"); _internal = function () { return data; }; return data; } function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } const SERVICE_CONTEXT_PROJECT_NAME = 'exponent-view-template'; async function ensureBuildConstantsExistsIOSAsync(configFilePath) { // EXBuildConstants is included in newer ExpoKit projects. // create it if it doesn't exist. const doesBuildConstantsExist = _fsExtra().default.existsSync(_path().default.join(configFilePath, 'EXBuildConstants.plist')); if (!doesBuildConstantsExist) { await _internal().IosPlist.createBlankAsync(configFilePath, 'EXBuildConstants'); _internal().LoggerDetach.info('Created `EXBuildConstants.plist` because it did not exist yet'); } } async function _getIosExpoKitVersionThrowErrorAsync(iosProjectDirectory) { let expoKitVersion = ''; const podfileLockPath = _path().default.join(iosProjectDirectory, 'Podfile.lock'); try { const podfileLock = await _fsExtra().default.readFile(podfileLockPath, 'utf8'); const expoKitVersionRegex = /ExpoKit\/Core\W?\(([0-9.]+)\)/gi; const match = expoKitVersionRegex.exec(podfileLock); if (!match) { throw new Error('ExpoKit/Core not found'); } expoKitVersion = match[1]; } catch (e) { throw new Error(`Unable to read ExpoKit version from Podfile.lock. Make sure your project depends on ExpoKit. (${e})`); } return expoKitVersion; } async function readNullableConfigJsonAsync(projectDir) { try { return (0, _config().getConfig)(projectDir); } catch { return null; } } async function prepareDetachedBuildIosAsync(projectDir, args) { const config = await readNullableConfigJsonAsync(projectDir); if (config && config.exp.name !== SERVICE_CONTEXT_PROJECT_NAME) { return prepareDetachedUserContextIosAsync(projectDir, config.exp, args); } else { return prepareDetachedServiceContextIosAsync(projectDir, args); } } async function prepareDetachedServiceContextIosAsync(projectDir, args) { // service context // TODO: very brittle hack: the paths here are hard coded to match the single workspace // path generated inside IosShellApp. When we support more than one path, this needs to // be smarter. const expoRootDir = _path().default.join(projectDir, '..', '..'); const workspaceSourcePath = _path().default.join(projectDir, 'ios'); const buildFlags = _internal().StandaloneBuildFlags.createIos('Release', { workspaceSourcePath }); // @ts-ignore missing 9th argument const context = _internal().StandaloneContext.createServiceContext(expoRootDir, null, null, null, /* testEnvironment */'none', buildFlags, null, null); const { iosProjectDirectory, supportingDirectory } = _internal().IosWorkspace.getPaths(context); const expoKitVersion = await _getIosExpoKitVersionThrowErrorAsync(iosProjectDirectory); // use prod api keys if available const prodApiKeys = await _readDefaultApiKeysAsync(_path().default.join(context.data.expoSourcePath, '__internal__', 'keys.json')); const { exp } = (0, _config().getConfig)(expoRootDir, { skipSDKVersionRequirement: true }); await _internal().IosPlist.modifyAsync(supportingDirectory, 'EXBuildConstants', constantsConfig => { // verify that we are actually in a service context and not a misconfigured project const contextType = constantsConfig.STANDALONE_CONTEXT_TYPE; if (contextType !== 'service') { throw new Error('Unable to configure a project which has no app.json and also no STANDALONE_CONTEXT_TYPE.'); } constantsConfig.EXPO_RUNTIME_VERSION = expoKitVersion; constantsConfig.API_SERVER_ENDPOINT = process.env.ENVIRONMENT === 'staging' ? 'https://staging.exp.host/--/api/v2/' : 'https://exp.host/--/api/v2/'; if (prodApiKeys) { constantsConfig.DEFAULT_API_KEYS = prodApiKeys; } if (exp && exp.sdkVersion) { constantsConfig.TEMPORARY_SDK_VERSION = exp.sdkVersion; } return constantsConfig; }); } async function _readDefaultApiKeysAsync(jsonFilePath) { if (_fsExtra().default.existsSync(jsonFilePath)) { const keys = {}; const allKeys = await new (_jsonFile().default)(jsonFilePath).readAsync(); const validKeys = ['AMPLITUDE_KEY', 'GOOGLE_MAPS_IOS_API_KEY']; for (const key in allKeys) { if (allKeys.hasOwnProperty(key) && validKeys.includes(key)) { keys[key] = allKeys[key]; } } return keys; } return null; } async function prepareDetachedUserContextIosAsync(projectDir, exp, args) { const context = _internal().StandaloneContext.createUserContext(projectDir, exp); const { iosProjectDirectory, supportingDirectory } = _internal().IosWorkspace.getPaths(context); _internal().LoggerDetach.info(`Preparing iOS build at ${iosProjectDirectory}...`); // These files cause @providesModule naming collisions // but are not available until after `pod install` has run. const podsDirectory = _path().default.join(iosProjectDirectory, 'Pods'); if (!_internal().ExponentTools.isDirectory(podsDirectory)) { throw new Error(`Can't find directory ${podsDirectory}, make sure you've run pod install.`); } const rnPodDirectory = _path().default.join(podsDirectory, 'React'); if (_internal().ExponentTools.isDirectory(rnPodDirectory)) { const rnFilesToDelete = (0, _glob().sync)('**/*.@(js|json)', { absolute: true, cwd: rnPodDirectory }); if (rnFilesToDelete) { for (let i = 0; i < rnFilesToDelete.length; i++) { await _fsExtra().default.unlink(rnFilesToDelete[i]); } } } // insert expo development url into iOS config if (!args.skipXcodeConfig) { // populate EXPO_RUNTIME_VERSION from ExpoKit pod version const expoKitVersion = await _getIosExpoKitVersionThrowErrorAsync(iosProjectDirectory); // populate development url const devUrl = await _internal().UrlUtils.constructManifestUrlAsync(projectDir); // populate default api keys const defaultApiKeys = await _readDefaultApiKeysAsync(_path().default.join(podsDirectory, 'ExpoKit', 'template-files', 'keys.json')); await ensureBuildConstantsExistsIOSAsync(supportingDirectory); await _internal().IosPlist.modifyAsync(supportingDirectory, 'EXBuildConstants', constantsConfig => { constantsConfig.developmentUrl = devUrl; constantsConfig.EXPO_RUNTIME_VERSION = expoKitVersion; if (defaultApiKeys) { constantsConfig.DEFAULT_API_KEYS = defaultApiKeys; } if (exp.sdkVersion) { constantsConfig.TEMPORARY_SDK_VERSION = exp.sdkVersion; } return constantsConfig; }); } } async function prepareDetachedBuildAsync(projectDir, args) { if (args.platform === 'ios') { await prepareDetachedBuildIosAsync(projectDir, args); } else { const expoBuildConstantsMatches = (0, _glob().sync)('android/**/DetachBuildConstants.java', { absolute: true, cwd: projectDir }); if (expoBuildConstantsMatches && expoBuildConstantsMatches.length) { const expoBuildConstants = expoBuildConstantsMatches[0]; const devUrl = await _internal().UrlUtils.constructManifestUrlAsync(projectDir); await _internal().ExponentTools.regexFileAsync(/DEVELOPMENT_URL = "[^"]*";/, `DEVELOPMENT_URL = "${devUrl}";`, expoBuildConstants); } } } // args.dest: string, // This is the path where assets will be copied to. It should be // `$CONFIGURATION_BUILD_DIR/$UNLOCALIZED_RESOURCES_FOLDER_PATH` on iOS // (see `exponent-view-template.xcodeproj/project.pbxproj` for an example) // and `$buildDir/intermediates/assets/$targetPath` on Android (see // `android/app/expo.gradle` for an example). async function bundleAssetsAsync(projectDir, args) { const options = await readNullableConfigJsonAsync(projectDir); if (!options || options.exp.name === SERVICE_CONTEXT_PROJECT_NAME) { // Don't run assets bundling for the service context. return; } const { exp } = options; const bundledManifestPath = _internal().EmbeddedAssets.getEmbeddedManifestPath(args.platform, projectDir, exp); if (!bundledManifestPath) { _internal().LoggerDetach.warn(`Skipped assets bundling because the '${args.platform}.publishManifestPath' key is not specified in the app manifest.`); return; } let manifest; try { manifest = JSON.parse(await _fsExtra().default.readFile(bundledManifestPath, 'utf8')); } catch (ex) { throw new Error(`Error reading the manifest file. Make sure the path '${bundledManifestPath}' is correct.\n\nError: ${ex.message}`); } if (!manifest || !Object.keys(manifest).length) { throw new Error(`The manifest at '${bundledManifestPath}' was empty or invalid.`); } await _internal().AssetBundle.bundleAsync(null, manifest.bundledAssets, args.dest, getExportUrl(manifest)); } /** * This function extracts the exported public URL that is set in the manifest * when the developer runs `expo export --public-url x`. We use this to ensure * that we fetch the resources from the appropriate place when doing builds * against self-hosted apps. */ function getExportUrl(manifest) { const { bundleUrl } = manifest; if (bundleUrl.includes(_internal().AssetBundle.DEFAULT_CDN_HOST)) { return null; } try { const bundleUrlParts = bundleUrl.split('/'); return bundleUrlParts.slice(0, bundleUrlParts.length - 2).join('/'); } catch { throw Error(`Expected bundleUrl to be of the format https://domain/bundles/bundle-hash-id, ${bundleUrl} does not follow this format.`); } } //# sourceMappingURL=Detach.js.map