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.
400 lines
19 KiB
400 lines
19 KiB
"use strict";
|
|
|
|
Object.defineProperty(exports, "__esModule", {
|
|
value: true
|
|
});
|
|
exports.configureAsync = configureAsync;
|
|
exports.getEmbeddedManifestPath = getEmbeddedManifestPath;
|
|
exports.getIOSPaths = getIOSPaths;
|
|
exports.shouldEmbedAssetsForExpoUpdates = shouldEmbedAssetsForExpoUpdates;
|
|
function _config() {
|
|
const data = require("@expo/config");
|
|
_config = function () {
|
|
return data;
|
|
};
|
|
return data;
|
|
}
|
|
function _configPlugins() {
|
|
const data = require("@expo/config-plugins");
|
|
_configPlugins = function () {
|
|
return data;
|
|
};
|
|
return data;
|
|
}
|
|
function _plist() {
|
|
const data = _interopRequireDefault(require("@expo/plist"));
|
|
_plist = function () {
|
|
return data;
|
|
};
|
|
return data;
|
|
}
|
|
function _fsExtra() {
|
|
const data = _interopRequireDefault(require("fs-extra"));
|
|
_fsExtra = function () {
|
|
return data;
|
|
};
|
|
return data;
|
|
}
|
|
function _path() {
|
|
const data = _interopRequireDefault(require("path"));
|
|
_path = function () {
|
|
return data;
|
|
};
|
|
return data;
|
|
}
|
|
function _semver() {
|
|
const data = _interopRequireDefault(require("semver"));
|
|
_semver = 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 PLACEHOLDER_URL = 'YOUR-APP-URL-HERE';
|
|
const FYI_URL = 'https://expo.fyi/expo-updates-config';
|
|
async function configureAsync(config) {
|
|
await _maybeWriteArtifactsToDiskAsync(config);
|
|
await _maybeConfigureExpoKitEmbeddedAssetsAsync(config);
|
|
await _maybeRunModifiedExpoUpdatesPluginAsync(config);
|
|
}
|
|
function getEmbeddedManifestPath(platform, projectRoot, exp) {
|
|
if (platform === 'ios') {
|
|
return exp.ios && exp.ios.publishManifestPath ? exp.ios.publishManifestPath : _getDefaultEmbeddedManifestPath(platform, projectRoot, exp);
|
|
} else if (platform === 'android') {
|
|
return exp.android && exp.android.publishManifestPath ? exp.android.publishManifestPath : _getDefaultEmbeddedManifestPath(platform, projectRoot, exp);
|
|
}
|
|
return _getDefaultEmbeddedManifestPath(platform, projectRoot, exp);
|
|
}
|
|
function _getDefaultEmbeddedManifestPath(platform, projectRoot, exp) {
|
|
return _path().default.join(_getDefaultEmbeddedAssetDir(platform, projectRoot, exp), 'app.manifest');
|
|
}
|
|
function _getDefaultEmbeddedBundlePath(platform, projectRoot, exp) {
|
|
return _path().default.join(_getDefaultEmbeddedAssetDir(platform, projectRoot, exp), 'app.bundle');
|
|
}
|
|
function _getDefaultEmbeddedAssetDir(platform, projectRoot, exp) {
|
|
if (platform === 'ios') {
|
|
const {
|
|
iosSupportingDirectory
|
|
} = getIOSPaths(projectRoot);
|
|
return iosSupportingDirectory;
|
|
} else if (platform === 'android') {
|
|
return _path().default.join(projectRoot, 'android', 'app', 'src', 'main', 'assets');
|
|
} else {
|
|
throw new Error('Embedding assets is not supported for platform ' + platform);
|
|
}
|
|
}
|
|
function shouldEmbedAssetsForExpoUpdates(projectRoot, exp, pkg, target) {
|
|
var _pkg$dependencies;
|
|
if (!((_pkg$dependencies = pkg.dependencies) !== null && _pkg$dependencies !== void 0 && _pkg$dependencies['expo-updates']) || target !== 'bare') {
|
|
return false;
|
|
}
|
|
|
|
// semver.coerce can return null
|
|
const expoUpdatesVersion = _semver().default.coerce(pkg.dependencies['expo-updates']);
|
|
|
|
// expo-updates 0.1.x relies on expo-cli automatically embedding the manifest and bundle
|
|
if (expoUpdatesVersion && _semver().default.satisfies(expoUpdatesVersion, '~0.1.0')) {
|
|
return true;
|
|
}
|
|
|
|
// We also want to support developers who had expo-updates 0.1.x and upgraded but still rely on
|
|
// expo-cli's automatic embedding. If the files already exist we can assume we need to update them
|
|
if (_fsExtra().default.existsSync(_getDefaultEmbeddedBundlePath('android', projectRoot, exp)) || _fsExtra().default.existsSync(_getDefaultEmbeddedManifestPath('android', projectRoot, exp)) || _fsExtra().default.existsSync(_getDefaultEmbeddedBundlePath('ios', projectRoot, exp)) || _fsExtra().default.existsSync(_getDefaultEmbeddedManifestPath('ios', projectRoot, exp))) {
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
async function _maybeWriteArtifactsToDiskAsync(config) {
|
|
var _exp$android, _exp$android2, _exp$ios, _exp$ios2;
|
|
const {
|
|
projectRoot,
|
|
pkg,
|
|
exp,
|
|
iosManifest,
|
|
iosBundle,
|
|
androidManifest,
|
|
androidBundle,
|
|
target
|
|
} = config;
|
|
let androidBundlePath;
|
|
let androidManifestPath;
|
|
let iosBundlePath;
|
|
let iosManifestPath;
|
|
if (shouldEmbedAssetsForExpoUpdates(projectRoot, exp, pkg, target)) {
|
|
const defaultAndroidDir = _getDefaultEmbeddedAssetDir('android', projectRoot, exp);
|
|
const defaultIosDir = _getDefaultEmbeddedAssetDir('ios', projectRoot, exp);
|
|
await _fsExtra().default.ensureDir(defaultIosDir);
|
|
await _fsExtra().default.ensureDir(defaultAndroidDir);
|
|
androidBundlePath = _getDefaultEmbeddedBundlePath('android', projectRoot, exp);
|
|
androidManifestPath = _getDefaultEmbeddedManifestPath('android', projectRoot, exp);
|
|
iosBundlePath = _getDefaultEmbeddedBundlePath('ios', projectRoot, exp);
|
|
iosManifestPath = _getDefaultEmbeddedManifestPath('ios', projectRoot, exp);
|
|
if (!_fsExtra().default.existsSync(iosBundlePath) || !_fsExtra().default.existsSync(iosManifestPath)) {
|
|
_internal().Logger.global.warn('Creating app.manifest and app.bundle inside of your ios/<project>/Supporting directory.\nBe sure to add these files to your Xcode project. More info at https://expo.fyi/embedded-assets');
|
|
}
|
|
}
|
|
|
|
// allow custom overrides
|
|
if ((_exp$android = exp.android) !== null && _exp$android !== void 0 && _exp$android.publishBundlePath) {
|
|
androidBundlePath = exp.android.publishBundlePath;
|
|
}
|
|
if ((_exp$android2 = exp.android) !== null && _exp$android2 !== void 0 && _exp$android2.publishManifestPath) {
|
|
androidManifestPath = exp.android.publishManifestPath;
|
|
}
|
|
if ((_exp$ios = exp.ios) !== null && _exp$ios !== void 0 && _exp$ios.publishBundlePath) {
|
|
iosBundlePath = exp.ios.publishBundlePath;
|
|
}
|
|
if ((_exp$ios2 = exp.ios) !== null && _exp$ios2 !== void 0 && _exp$ios2.publishManifestPath) {
|
|
iosManifestPath = exp.ios.publishManifestPath;
|
|
}
|
|
if (androidBundlePath) {
|
|
await (0, _internal().writeArtifactSafelyAsync)(projectRoot, 'android.publishBundlePath', androidBundlePath, androidBundle);
|
|
}
|
|
if (androidManifestPath) {
|
|
await (0, _internal().writeArtifactSafelyAsync)(projectRoot, 'android.publishManifestPath', androidManifestPath, JSON.stringify(androidManifest));
|
|
}
|
|
if (iosBundlePath) {
|
|
await (0, _internal().writeArtifactSafelyAsync)(projectRoot, 'ios.publishBundlePath', iosBundlePath, iosBundle);
|
|
}
|
|
if (iosManifestPath) {
|
|
await (0, _internal().writeArtifactSafelyAsync)(projectRoot, 'ios.publishManifestPath', iosManifestPath, JSON.stringify(iosManifest));
|
|
}
|
|
}
|
|
async function _maybeConfigureExpoKitEmbeddedAssetsAsync(config) {
|
|
const {
|
|
projectRoot,
|
|
exp,
|
|
releaseChannel,
|
|
androidManifestUrl,
|
|
androidManifest
|
|
} = config;
|
|
const context = _internal().StandaloneContext.createUserContext(projectRoot, exp);
|
|
const {
|
|
supportingDirectory
|
|
} = _internal().IosWorkspace.getPaths(context);
|
|
|
|
// iOS ExpoKit
|
|
if (releaseChannel && _fsExtra().default.existsSync(_path().default.join(supportingDirectory, 'EXShell.plist'))) {
|
|
// This is an ExpoKit app, set properties in EXShell.plist
|
|
await _internal().IosPlist.modifyAsync(supportingDirectory, 'EXShell', shellPlist => {
|
|
shellPlist.releaseChannel = releaseChannel;
|
|
return shellPlist;
|
|
});
|
|
}
|
|
|
|
// Android ExpoKit
|
|
const constantsPath = _path().default.join(projectRoot, 'android', 'app', 'src', 'main', 'java', 'host', 'exp', 'exponent', 'generated', 'AppConstants.java');
|
|
if (_fsExtra().default.existsSync(constantsPath)) {
|
|
// This is an ExpoKit app
|
|
// We need to add EmbeddedResponse instances on Android to tell the runtime
|
|
// that the shell app manifest and bundle is packaged.
|
|
await _internal().ExponentTools.deleteLinesInFileAsync(`START EMBEDDED RESPONSES`, `END EMBEDDED RESPONSES`, constantsPath);
|
|
await _internal().ExponentTools.regexFileAsync('// ADD EMBEDDED RESPONSES HERE', `
|
|
// ADD EMBEDDED RESPONSES HERE
|
|
// START EMBEDDED RESPONSES
|
|
embeddedResponses.add(new Constants.EmbeddedResponse("${androidManifestUrl}", "assets://shell-app-manifest.json", "application/json"));
|
|
embeddedResponses.add(new Constants.EmbeddedResponse("${androidManifest.bundleUrl}", "assets://shell-app.bundle", "application/javascript"));
|
|
// END EMBEDDED RESPONSES`, constantsPath);
|
|
if (releaseChannel) {
|
|
await _internal().ExponentTools.regexFileAsync(/RELEASE_CHANNEL = "[^"]*"/, `RELEASE_CHANNEL = "${releaseChannel}"`, constantsPath);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Guess if this is a user's first publish and run a slightly modified expo-updates plugin.
|
|
* If it is not their first publish and a config mismatch is noticed, log warnings.
|
|
*/
|
|
async function _maybeRunModifiedExpoUpdatesPluginAsync(config) {
|
|
var _config$pkg$dependenc;
|
|
if (!((_config$pkg$dependenc = config.pkg.dependencies) !== null && _config$pkg$dependenc !== void 0 && _config$pkg$dependenc['expo-updates']) || config.target === 'managed') {
|
|
return;
|
|
}
|
|
const {
|
|
projectRoot,
|
|
exp,
|
|
releaseChannel,
|
|
iosManifestUrl,
|
|
androidManifestUrl
|
|
} = config;
|
|
const {
|
|
iosSupportingDirectory: supportingDirectory
|
|
} = getIOSPaths(projectRoot);
|
|
|
|
// iOS expo-updates
|
|
let isLikelyFirstIOSPublish = false;
|
|
const expoPlistPath = _path().default.join(supportingDirectory, 'Expo.plist');
|
|
if (_fsExtra().default.existsSync(expoPlistPath)) {
|
|
let expoPlistForProject = _plist().default.parse(await _fsExtra().default.readFileSync(expoPlistPath, 'utf8'));
|
|
const currentlyConfiguredExpoPlist = {
|
|
...expoPlistForProject
|
|
};
|
|
|
|
// The username is only used for defining a default updates URL.
|
|
// Since we overwrite the URL below the username is superfluous.
|
|
expoPlistForProject = _configPlugins().IOSConfig.Updates.setUpdatesConfig(projectRoot, exp, expoPlistForProject, /*expoUsername*/null);
|
|
|
|
// overwrite the URL defined in IOSConfig.Updates.setUpdatesConfig
|
|
expoPlistForProject[_configPlugins().IOSConfig.Updates.Config.UPDATE_URL] = iosManifestUrl;
|
|
// set a release channel (not done in updates plugin)
|
|
if (releaseChannel) {
|
|
expoPlistForProject[_configPlugins().IOSConfig.Updates.Config.RELEASE_CHANNEL] = releaseChannel;
|
|
}
|
|
|
|
// If we guess that this is a users first publish, modify the native code to match
|
|
// what is configured.
|
|
const configuredIOSUpdatesURL = currentlyConfiguredExpoPlist[_configPlugins().IOSConfig.Updates.Config.UPDATE_URL];
|
|
if (configuredIOSUpdatesURL === PLACEHOLDER_URL) {
|
|
isLikelyFirstIOSPublish = true;
|
|
_fsExtra().default.writeFileSync(expoPlistPath, _plist().default.build(expoPlistForProject));
|
|
} else {
|
|
// Log warnings if this is not the first publish and critical properties seem misconfigured
|
|
const {
|
|
UPDATE_URL,
|
|
SDK_VERSION,
|
|
RUNTIME_VERSION,
|
|
RELEASE_CHANNEL
|
|
} = _configPlugins().IOSConfig.Updates.Config;
|
|
for (const key of [UPDATE_URL, SDK_VERSION, RUNTIME_VERSION, RELEASE_CHANNEL]) {
|
|
let currentlyConfiguredValue = currentlyConfiguredExpoPlist[key];
|
|
const inferredValue = expoPlistForProject[key];
|
|
if (key === RELEASE_CHANNEL && inferredValue) {
|
|
var _currentlyConfiguredV;
|
|
// A client with an undefined release channel is mapped to
|
|
// 'default' in the server, so avoid logging an unneccessary warning.
|
|
currentlyConfiguredValue = (_currentlyConfiguredV = currentlyConfiguredValue) !== null && _currentlyConfiguredV !== void 0 ? _currentlyConfiguredV : 'default';
|
|
}
|
|
if (currentlyConfiguredValue !== inferredValue) {
|
|
let message;
|
|
switch (key) {
|
|
case RELEASE_CHANNEL:
|
|
{
|
|
message = `The value passed to the --release-channel flag is to "${inferredValue}", but it is set to "${currentlyConfiguredValue}".`;
|
|
break;
|
|
}
|
|
case UPDATE_URL:
|
|
case SDK_VERSION:
|
|
case RUNTIME_VERSION:
|
|
default:
|
|
message = `${key} is inferred to be "${inferredValue}", but it is set to "${currentlyConfiguredValue}".`;
|
|
}
|
|
_configPlugins().WarningAggregator.addWarningIOS(`Expo.plist key: "${key}"`, message, FYI_URL);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Android expo-updates
|
|
let isLikelyFirstAndroidPublish = false;
|
|
const androidManifestXmlPath = _path().default.join(projectRoot, 'android', 'app', 'src', 'main', 'AndroidManifest.xml');
|
|
const AndroidManifestKeyForUpdateURL = _configPlugins().AndroidConfig.Updates.Config.UPDATE_URL;
|
|
if (_fsExtra().default.existsSync(androidManifestXmlPath)) {
|
|
var _currentConfiguredMan, _currentConfiguredMan2, _currentlyConfiguredM;
|
|
const currentlyConfiguredAndroidManifest = await _configPlugins().AndroidConfig.Manifest.readAndroidManifestAsync(androidManifestXmlPath);
|
|
const currentConfiguredManifestApplication = _configPlugins().AndroidConfig.Manifest.getMainApplicationOrThrow(currentlyConfiguredAndroidManifest);
|
|
const currentlyConfiguredMetaDataAttributes = (_currentConfiguredMan = (_currentConfiguredMan2 = currentConfiguredManifestApplication['meta-data']) === null || _currentConfiguredMan2 === void 0 ? void 0 : _currentConfiguredMan2.map(md => md['$'])) !== null && _currentConfiguredMan !== void 0 ? _currentConfiguredMan : [];
|
|
|
|
// The username is only used for defining a default updates URL.
|
|
// Since we overwrite the URL below the username is superfluous.
|
|
const inferredAndroidManifest = _configPlugins().AndroidConfig.Updates.setUpdatesConfig(projectRoot, exp, currentlyConfiguredAndroidManifest, /*username*/null);
|
|
const inferredMainApplication = _configPlugins().AndroidConfig.Manifest.getMainApplicationOrThrow(inferredAndroidManifest);
|
|
// overwrite the URL defined in AndroidConfig.Updates.setUpdatesConfig
|
|
_configPlugins().AndroidConfig.Manifest.addMetaDataItemToMainApplication(inferredMainApplication, AndroidManifestKeyForUpdateURL, androidManifestUrl);
|
|
// set a release channel (not done in updates plugin)
|
|
if (releaseChannel) {
|
|
_configPlugins().AndroidConfig.Manifest.addMetaDataItemToMainApplication(inferredMainApplication, _configPlugins().AndroidConfig.Updates.Config.RELEASE_CHANNEL, releaseChannel);
|
|
}
|
|
|
|
// If we guess that this is a users first publish, modify the native code to match
|
|
// what is configured.
|
|
const currentlyConfiguredAndroidUpdateURL = (_currentlyConfiguredM = currentlyConfiguredMetaDataAttributes.find(x => x['android:name'] === _configPlugins().AndroidConfig.Updates.Config.UPDATE_URL)) === null || _currentlyConfiguredM === void 0 ? void 0 : _currentlyConfiguredM['android:value'];
|
|
if (currentlyConfiguredAndroidUpdateURL === PLACEHOLDER_URL) {
|
|
isLikelyFirstAndroidPublish = true;
|
|
await _configPlugins().AndroidConfig.Manifest.writeAndroidManifestAsync(androidManifestXmlPath, inferredAndroidManifest);
|
|
} else {
|
|
var _inferredMainApplicat;
|
|
// Log warnings if this is not the first publish and critical properties seem misconfigured
|
|
const inferredMainApplication = _configPlugins().AndroidConfig.Manifest.getMainApplicationOrThrow(inferredAndroidManifest);
|
|
const inferredMetaDataAttributes = (_inferredMainApplicat = inferredMainApplication['meta-data']) === null || _inferredMainApplicat === void 0 ? void 0 : _inferredMainApplicat.map(md => md['$']);
|
|
const {
|
|
UPDATE_URL,
|
|
SDK_VERSION,
|
|
RUNTIME_VERSION,
|
|
RELEASE_CHANNEL
|
|
} = _configPlugins().AndroidConfig.Updates.Config;
|
|
for (const key of [UPDATE_URL, SDK_VERSION, RUNTIME_VERSION, RELEASE_CHANNEL]) {
|
|
var _inferredMetaDataAttr, _currentlyConfiguredM2;
|
|
const inferredValue = (_inferredMetaDataAttr = inferredMetaDataAttributes.find(x => x['android:name'] === key)) === null || _inferredMetaDataAttr === void 0 ? void 0 : _inferredMetaDataAttr['android:value'];
|
|
let currentlyConfiguredValue = (_currentlyConfiguredM2 = currentlyConfiguredMetaDataAttributes.find(x => x['android:name'] === key)) === null || _currentlyConfiguredM2 === void 0 ? void 0 : _currentlyConfiguredM2['android:value'];
|
|
if (key === RELEASE_CHANNEL && inferredValue) {
|
|
var _currentlyConfiguredV2;
|
|
// A client with an undefined release channel is mapped to
|
|
// 'default' in the server, so avoid logging an unneccessary warning.
|
|
currentlyConfiguredValue = (_currentlyConfiguredV2 = currentlyConfiguredValue) !== null && _currentlyConfiguredV2 !== void 0 ? _currentlyConfiguredV2 : 'default';
|
|
}
|
|
if (inferredValue !== currentlyConfiguredValue) {
|
|
let message;
|
|
switch (key) {
|
|
case RELEASE_CHANNEL:
|
|
{
|
|
message = `The value passed to the --release-channel flag is "${inferredValue}", but it is set to "${currentlyConfiguredValue}".`;
|
|
break;
|
|
}
|
|
case UPDATE_URL:
|
|
case SDK_VERSION:
|
|
case RUNTIME_VERSION:
|
|
default:
|
|
message = `The inferred value is "${inferredValue}", but it is set to "${currentlyConfiguredValue}".`;
|
|
}
|
|
_configPlugins().WarningAggregator.addWarningAndroid(`AndroidManifest.xml key "${key}"`, message, FYI_URL);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (isLikelyFirstIOSPublish || isLikelyFirstAndroidPublish) {
|
|
let platformSpecificMessage;
|
|
if (isLikelyFirstIOSPublish && !isLikelyFirstAndroidPublish) {
|
|
platformSpecificMessage = '🚀 It looks like this your first iOS publish for this project! ' + `We've automatically set some configuration values in Expo.plist. `;
|
|
} else if (!isLikelyFirstIOSPublish && isLikelyFirstAndroidPublish) {
|
|
platformSpecificMessage = '🚀 It looks like this your first Android publish for this project! ' + `We've automatically set some configuration values in AndroidManifest.xml. `;
|
|
} else {
|
|
platformSpecificMessage = '🚀 It looks like this your first publish for this project! ' + `We've automatically set some configuration values in Expo.plist and AndroidManifest.xml. `;
|
|
}
|
|
_internal().Logger.global.warn(platformSpecificMessage + `You'll need to make and release a new build before your users can download the update ` + 'you just published.');
|
|
}
|
|
}
|
|
|
|
/** The code below here is duplicated from expo-cli currently **/
|
|
|
|
// TODO: it's silly and kind of fragile that we look at app config to determine
|
|
// the ios project paths. Overall this function needs to be revamped, just a
|
|
// placeholder for now! Make this more robust when we support applying config
|
|
// at any time (currently it's only applied on eject).
|
|
function getIOSPaths(projectRoot) {
|
|
const {
|
|
exp
|
|
} = (0, _config().getConfig)(projectRoot, {
|
|
skipSDKVersionRequirement: true
|
|
});
|
|
const projectName = exp.name;
|
|
if (!projectName) {
|
|
throw new Error('Your project needs a name in app.json/app.config.js.');
|
|
}
|
|
const iosProjectDirectory = _path().default.join(projectRoot, 'ios', _configPlugins().IOSConfig.XcodeUtils.sanitizedName(projectName));
|
|
const iosSupportingDirectory = _path().default.join(projectRoot, 'ios', _configPlugins().IOSConfig.XcodeUtils.sanitizedName(projectName), 'Supporting');
|
|
const iconPath = _path().default.join(iosProjectDirectory, 'Assets.xcassets', 'AppIcon.appiconset');
|
|
return {
|
|
projectName,
|
|
iosProjectDirectory,
|
|
iosSupportingDirectory,
|
|
iconPath
|
|
};
|
|
}
|
|
//# sourceMappingURL=EmbeddedAssets.js.map
|