UNPKG

@expo/xdl

Version:
432 lines (327 loc) 16.1 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.configureAsync = configureAsync; exports.getEmbeddedManifestPath = getEmbeddedManifestPath; exports.shouldEmbedAssetsForExpoUpdates = shouldEmbedAssetsForExpoUpdates; exports.getIOSPaths = getIOSPaths; function _config() { const data = require("@expo/config"); _config = 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 _Logger() { const data = _interopRequireDefault(require("./Logger")); _Logger = function () { return data; }; return data; } function ExponentTools() { const data = _interopRequireWildcard(require("./detach/ExponentTools")); ExponentTools = function () { return data; }; return data; } function IosPlist() { const data = _interopRequireWildcard(require("./detach/IosPlist")); IosPlist = function () { return data; }; return data; } function IosWorkspace() { const data = _interopRequireWildcard(require("./detach/IosWorkspace")); IosWorkspace = function () { return data; }; return data; } function _StandaloneContext() { const data = _interopRequireDefault(require("./detach/StandaloneContext")); _StandaloneContext = function () { return data; }; return data; } function _ArtifactUtils() { const data = require("./tools/ArtifactUtils"); _ArtifactUtils = function () { return data; }; return data; } function _getRequireWildcardCache() { if (typeof WeakMap !== "function") return null; var cache = new WeakMap(); _getRequireWildcardCache = function () { return cache; }; return cache; } function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; } function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } // @ts-ignore IosWorkspace not yet converted to TypeScript async function configureAsync(config) { await _maybeWriteArtifactsToDiskAsync(config); await _maybeConfigureExpoKitEmbeddedAssetsAsync(config); await _maybeConfigureExpoUpdatesEmbeddedAssetsAsync(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 ? 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$android3, _exp$ios, _exp$ios2, _exp$ios3; const { projectRoot, pkg, exp, iosManifest, iosBundle, iosSourceMap, androidManifest, androidBundle, androidSourceMap, target } = config; let androidBundlePath; let androidManifestPath; let androidSourceMapPath; let iosBundlePath; let iosManifestPath; let iosSourceMapPath; 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)) { _Logger().default.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 ? void 0 : _exp$android.publishBundlePath) { androidBundlePath = exp.android.publishBundlePath; } if ((_exp$android2 = exp.android) === null || _exp$android2 === void 0 ? void 0 : _exp$android2.publishManifestPath) { androidManifestPath = exp.android.publishManifestPath; } if ((_exp$android3 = exp.android) === null || _exp$android3 === void 0 ? void 0 : _exp$android3.publishSourceMapPath) { androidSourceMapPath = exp.android.publishSourceMapPath; } if ((_exp$ios = exp.ios) === null || _exp$ios === void 0 ? void 0 : _exp$ios.publishBundlePath) { iosBundlePath = exp.ios.publishBundlePath; } if ((_exp$ios2 = exp.ios) === null || _exp$ios2 === void 0 ? void 0 : _exp$ios2.publishManifestPath) { iosManifestPath = exp.ios.publishManifestPath; } if ((_exp$ios3 = exp.ios) === null || _exp$ios3 === void 0 ? void 0 : _exp$ios3.publishSourceMapPath) { iosSourceMapPath = exp.ios.publishSourceMapPath; } if (androidBundlePath) { await (0, _ArtifactUtils().writeArtifactSafelyAsync)(projectRoot, 'android.publishBundlePath', androidBundlePath, androidBundle); } if (androidManifestPath) { await (0, _ArtifactUtils().writeArtifactSafelyAsync)(projectRoot, 'android.publishManifestPath', androidManifestPath, JSON.stringify(androidManifest)); } if (androidSourceMapPath && androidSourceMap) { await (0, _ArtifactUtils().writeArtifactSafelyAsync)(projectRoot, 'android.publishSourceMapPath', androidSourceMapPath, androidSourceMap); } if (iosBundlePath) { await (0, _ArtifactUtils().writeArtifactSafelyAsync)(projectRoot, 'ios.publishBundlePath', iosBundlePath, iosBundle); } if (iosManifestPath) { await (0, _ArtifactUtils().writeArtifactSafelyAsync)(projectRoot, 'ios.publishManifestPath', iosManifestPath, JSON.stringify(iosManifest)); } if (iosSourceMapPath && iosSourceMap) { await (0, _ArtifactUtils().writeArtifactSafelyAsync)(projectRoot, 'ios.publishSourceMapPath', iosSourceMapPath, iosSourceMap); } } async function _maybeConfigureExpoKitEmbeddedAssetsAsync(config) { const { projectRoot, exp, releaseChannel, androidManifestUrl, androidManifest } = config; const context = _StandaloneContext().default.createUserContext(projectRoot, exp); const { supportingDirectory } = 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 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 ExponentTools().deleteLinesInFileAsync(`START EMBEDDED RESPONSES`, `END EMBEDDED RESPONSES`, constantsPath); await 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 ExponentTools().regexFileAsync(/RELEASE_CHANNEL = "[^"]*"/, `RELEASE_CHANNEL = "${releaseChannel}"`, constantsPath); } } } async function _maybeConfigureExpoUpdatesEmbeddedAssetsAsync(config) { var _config$pkg$dependenc; if (!((_config$pkg$dependenc = config.pkg.dependencies) === null || _config$pkg$dependenc === void 0 ? void 0 : _config$pkg$dependenc['expo-updates']) || config.target === 'managed') { return; } let isLikelyFirstPublish = false; const { projectRoot, exp, releaseChannel, iosManifestUrl, androidManifestUrl } = config; const { iosSupportingDirectory: supportingDirectory } = getIOSPaths(projectRoot); // iOS expo-updates if (_fsExtra().default.existsSync(_path().default.join(supportingDirectory, 'Expo.plist'))) { // This is an app with expo-updates installed, set properties in Expo.plist await IosPlist().modifyAsync(supportingDirectory, 'Expo', configPlist => { if (configPlist.EXUpdatesURL === 'YOUR-APP-URL-HERE') { isLikelyFirstPublish = true; } configPlist.EXUpdatesURL = iosManifestUrl; configPlist.EXUpdatesSDKVersion = exp.sdkVersion; if (releaseChannel) { configPlist.EXUpdatesReleaseChannel = releaseChannel; } return configPlist; }); await IosPlist().cleanBackupAsync(supportingDirectory, 'Expo', false); } // Android expo-updates const androidManifestXmlPath = _path().default.join(projectRoot, 'android', 'app', 'src', 'main', 'AndroidManifest.xml'); const androidManifestXmlFile = _fsExtra().default.readFileSync(androidManifestXmlPath, 'utf8'); const expoUpdateUrlRegex = /<meta-data[^>]+"expo.modules.updates.EXPO_UPDATE_URL"[^>]+\/>/; const expoSdkVersionRegex = /<meta-data[^>]+"expo.modules.updates.EXPO_SDK_VERSION"[^>]+\/>/; const expoReleaseChannelRegex = /<meta-data[^>]+"expo.modules.updates.EXPO_RELEASE_CHANNEL"[^>]+\/>/; const expoUpdateUrlTag = `<meta-data android:name="expo.modules.updates.EXPO_UPDATE_URL" android:value="${androidManifestUrl}" />`; const expoSdkVersionTag = `<meta-data android:name="expo.modules.updates.EXPO_SDK_VERSION" android:value="${exp.sdkVersion}" />`; const expoReleaseChannelTag = `<meta-data android:name="expo.modules.updates.EXPO_RELEASE_CHANNEL" android:value="${releaseChannel}" />`; const tagsToInsert = []; if (androidManifestXmlFile.search(expoUpdateUrlRegex) < 0) { tagsToInsert.push(expoUpdateUrlTag); } if (androidManifestXmlFile.search(expoSdkVersionRegex) < 0) { tagsToInsert.push(expoSdkVersionTag); } if (releaseChannel && androidManifestXmlFile.search(expoReleaseChannelRegex) < 0) { tagsToInsert.push(expoReleaseChannelTag); } if (tagsToInsert.length) { // try to insert the meta-data tags that aren't found await ExponentTools().regexFileAsync(/<activity\s+android:name=".MainActivity"/, `${tagsToInsert.join('\n ')} <activity android:name=".MainActivity"`, androidManifestXmlPath); } await ExponentTools().regexFileAsync(expoUpdateUrlRegex, expoUpdateUrlTag, androidManifestXmlPath); await ExponentTools().regexFileAsync(expoSdkVersionRegex, expoSdkVersionTag, androidManifestXmlPath); if (releaseChannel) { await ExponentTools().regexFileAsync(expoReleaseChannelRegex, expoReleaseChannelTag, androidManifestXmlPath); } if (isLikelyFirstPublish) { _Logger().default.global.warn('🚀 It looks like this your first publish for this project! ' + "We've automatically set some configuration values in Expo.plist and AndroidManifest.xml. " + "You'll need to make a new build with these changes before you can download the update " + 'you just published.'); } } /** The code below here is duplicated from expo-cli currently **/ // TODO: come up with a better solution for using app.json expo.name in various places function sanitizedName(name) { return name.replace(/[\W_]+/g, '').normalize('NFD').replace(/[\u0300-\u036f]/g, ''); } // 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', sanitizedName(projectName)); const iosSupportingDirectory = _path().default.join(projectRoot, 'ios', sanitizedName(projectName), 'Supporting'); const iconPath = _path().default.join(iosProjectDirectory, 'Assets.xcassets', 'AppIcon.appiconset'); return { projectName, iosProjectDirectory, iosSupportingDirectory, iconPath }; } //# sourceMappingURL=__sourcemaps__/EmbeddedAssets.js.map