You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
266 lines
10 KiB
266 lines
10 KiB
"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
|