GT2/GT2-Android/node_modules/xdl/build/detach/AndroidShellApp.js

740 lines
31 KiB
JavaScript
Raw Normal View History

// Copyright 2015-present 650 Industries. All rights reserved.
'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.runShellAppModificationsAsync = exports.copyInitialShellAppFilesAsync = undefined;
let regexFileAsync = (() => {
var _ref = _asyncToGenerator(function* (regex, replace, filename) {
let file = yield fs.readFile(filename);
let fileString = file.toString();
yield fs.writeFile(filename, fileString.replace(regex, replace));
});
return function regexFileAsync(_x, _x2, _x3) {
return _ref.apply(this, arguments);
};
})();
// Matches sed /d behavior
let deleteLinesInFileAsync = (() => {
var _ref2 = _asyncToGenerator(function* (startRegex, endRegex, filename) {
let file = yield fs.readFile(filename);
let fileString = file.toString();
let lines = fileString.split(/\r?\n/);
let filteredLines = [];
let inDeleteRange = false;
for (let i = 0; i < lines.length; i++) {
if (lines[i].match(startRegex)) {
inDeleteRange = true;
}
if (!inDeleteRange) {
filteredLines.push(lines[i]);
}
if (inDeleteRange && lines[i].match(endRegex)) {
inDeleteRange = false;
}
}
yield fs.writeFile(filename, filteredLines.join('\n'));
});
return function deleteLinesInFileAsync(_x4, _x5, _x6) {
return _ref2.apply(this, arguments);
};
})();
let copyInitialShellAppFilesAsync = exports.copyInitialShellAppFilesAsync = (() => {
var _ref4 = _asyncToGenerator(function* (androidSrcPath, shellPath, isDetached = false) {
let _exponentDirectory = exponentDirectory();
if (_exponentDirectory) {
yield spawnAsync(`../../tools-public/generate-dynamic-macros-android.sh`, [], {
stdio: 'inherit',
cwd: path.join(_exponentDirectory, 'android', 'app')
}); // populate android template files now since we take out the prebuild step later on
}
let copyToShellApp = (() => {
var _ref5 = _asyncToGenerator(function* (fileName) {
try {
yield fs.copy(path.join(androidSrcPath, fileName), path.join(shellPath, fileName));
} catch (e) {
// android.iml is only available locally, not on the builders, so don't crash when this happens
console.warn(`Warning: Could not copy ${fileName} to shell app directory.`);
}
});
return function copyToShellApp(_x10) {
return _ref5.apply(this, arguments);
};
})();
if (!isDetached) {
yield copyToShellApp('expoview');
yield copyToShellApp('ReactCommon');
yield copyToShellApp('ReactAndroid');
}
yield copyToShellApp('android.iml');
yield copyToShellApp('app');
yield copyToShellApp('build.gradle');
yield copyToShellApp('gradle');
yield copyToShellApp('gradle.properties');
yield copyToShellApp('gradlew');
yield copyToShellApp('settings.gradle');
yield copyToShellApp('maven');
yield copyToShellApp('debug.keystore');
yield copyToShellApp('run.sh');
yield copyToShellApp('detach-scripts');
});
return function copyInitialShellAppFilesAsync(_x8, _x9) {
return _ref4.apply(this, arguments);
};
})();
let copyIconsToResSubfolders = (() => {
var _ref7 = _asyncToGenerator(function* (resDirPath, folderPrefix, fileName, iconUrl, isLocalUrl) {
return Promise.all(imageKeys.map((() => {
var _ref8 = _asyncToGenerator(function* (key) {
try {
const dirPath = path.join(resDirPath, `${folderPrefix}-${key}`);
fs.accessSync(dirPath, fs.constants.F_OK);
if (isLocalUrl) {
return fs.copyFileSync(iconUrl, path.join(dirPath, fileName));
}
return yield saveUrlToPathAsync(iconUrl, path.join(dirPath, fileName));
} catch (e) {
// directory does not exist, so ignore
}
});
return function (_x17) {
return _ref8.apply(this, arguments);
};
})()));
});
return function copyIconsToResSubfolders(_x12, _x13, _x14, _x15, _x16) {
return _ref7.apply(this, arguments);
};
})();
let runShellAppModificationsAsync = exports.runShellAppModificationsAsync = (() => {
var _ref9 = _asyncToGenerator(function* (context, isDetached = false) {
let shellPath = shellPathForContext(context);
let url = context.published.url;
let manifest = context.config; // manifest or app.json
let releaseChannel = context.published.releaseChannel;
if (!context.data.privateConfig) {
console.warn('Warning: No config file specified.');
}
let fullManifestUrl = `${url.replace('exp://', 'https://')}/index.exp`;
let versionCode = 1;
let javaPackage = manifest.android.package;
if (manifest.android.versionCode) {
versionCode = manifest.android.versionCode;
}
if (!javaPackage) {
throw new Error('Must specify androidPackage option (either from manifest or on command line).');
}
let name = manifest.name;
let iconUrl = manifest.android && manifest.android.iconUrl ? manifest.android.iconUrl : manifest.iconUrl;
let scheme = manifest.scheme || manifest.detach && manifest.detach.scheme;
let bundleUrl = manifest.bundleUrl;
let isFullManifest = !!bundleUrl;
let notificationIconUrl = manifest.notification ? manifest.notification.iconUrl : null;
let version = manifest.version ? manifest.version : '0.0.0';
let backgroundImages = backgroundImagesForApp(shellPath, manifest);
let splashBackgroundColor = getSplashScreenBackgroundColor(manifest);
if (isDetached) {
// manifest is actually just app.json in this case, so iconUrl fields don't exist
iconUrl = manifest.android && manifest.android.icon ? manifest.android.icon : manifest.icon;
notificationIconUrl = manifest.notification ? manifest.notification.icon : null;
}
// Clean build directories
yield fs.remove(path.join(shellPath, 'app', 'build'));
yield fs.remove(path.join(shellPath, 'ReactAndroid', 'build'));
yield fs.remove(path.join(shellPath, 'expoview', 'build'));
yield fs.remove(path.join(shellPath, 'app', 'src', 'androidTest'));
if (isDetached) {
let appBuildGradle = path.join(shellPath, 'app', 'build.gradle');
yield regexFileAsync(/\/\* UNCOMMENT WHEN DISTRIBUTING/g, '', appBuildGradle);
yield regexFileAsync(/END UNCOMMENT WHEN DISTRIBUTING \*\//g, '', appBuildGradle);
yield regexFileAsync(`compile project(path: ':expoview')`, '', appBuildGradle);
// Don't need to compile expoview or ReactAndroid
// react-native link looks for a \n so we need that. See https://github.com/facebook/react-native/blob/master/local-cli/link/android/patches/makeSettingsPatch.js
yield fs.writeFile(path.join(shellPath, 'settings.gradle'), `include ':app'\n`);
yield regexFileAsync('TEMPLATE_INITIAL_URL', url, path.join(shellPath, 'app', 'src', 'main', 'java', 'host', 'exp', 'exponent', 'MainActivity.java'));
}
// Package
yield regexFileAsync(`applicationId 'host.exp.exponent'`, `applicationId '${javaPackage}'`, path.join(shellPath, 'app', 'build.gradle'));
yield regexFileAsync(`android:name="host.exp.exponent"`, `android:name="${javaPackage}"`, path.join(shellPath, 'app', 'src', 'main', 'AndroidManifest.xml'));
// Versions
let buildGradleFile = yield fs.readFileSync(path.join(shellPath, 'app', 'build.gradle'), 'utf8');
let androidVersion = buildGradleFile.match(/versionName '(\S+)'/)[1];
yield regexFileAsync('VERSION_NAME = null', `VERSION_NAME = "${androidVersion}"`, path.join(shellPath, 'app', 'src', 'main', 'java', 'host', 'exp', 'exponent', 'generated', 'AppConstants.java'));
yield deleteLinesInFileAsync(`BEGIN\ VERSIONS`, `END\ VERSIONS`, path.join(shellPath, 'app', 'build.gradle'));
yield regexFileAsync('// ADD VERSIONS HERE', `versionCode ${versionCode}
versionName '${version}'`, path.join(shellPath, 'app', 'build.gradle'));
// Remove Exponent build script
if (!isDetached) {
yield regexFileAsync(`preBuild.dependsOn generateDynamicMacros`, ``, path.join(shellPath, 'expoview', 'build.gradle'));
}
// change javaMaxHeapSize
yield regexFileAsync(`javaMaxHeapSize "8g"`, `javaMaxHeapSize "6g"`, path.join(shellPath, 'app', 'build.gradle'));
// Push notifications
yield regexFileAsync('"package_name": "host.exp.exponent"', `"package_name": "${javaPackage}"`, path.join(shellPath, 'app', 'google-services.json')); // TODO: actually use the correct file
// TODO: probably don't need this in both places
yield regexFileAsync(/host\.exp\.exponent\.permission\.C2D_MESSAGE/g, `${javaPackage}.permission.C2D_MESSAGE`, path.join(shellPath, 'app', 'src', 'main', 'AndroidManifest.xml'));
if (!isDetached) {
yield regexFileAsync(/host\.exp\.exponent\.permission\.C2D_MESSAGE/g, `${javaPackage}.permission.C2D_MESSAGE`, path.join(shellPath, 'expoview', 'src', 'main', 'AndroidManifest.xml'));
}
// Set INITIAL_URL, SHELL_APP_SCHEME and SHOW_LOADING_VIEW
yield regexFileAsync('INITIAL_URL = null', `INITIAL_URL = "${url}"`, path.join(shellPath, 'app', 'src', 'main', 'java', 'host', 'exp', 'exponent', 'generated', 'AppConstants.java'));
if (scheme) {
yield regexFileAsync('SHELL_APP_SCHEME = null', `SHELL_APP_SCHEME = "${scheme}"`, path.join(shellPath, 'app', 'src', 'main', 'java', 'host', 'exp', 'exponent', 'generated', 'AppConstants.java'));
}
if (shouldShowLoadingView(manifest)) {
yield regexFileAsync('SHOW_LOADING_VIEW_IN_SHELL_APP = false', 'SHOW_LOADING_VIEW_IN_SHELL_APP = true', path.join(shellPath, 'app', 'src', 'main', 'java', 'host', 'exp', 'exponent', 'generated', 'AppConstants.java'));
}
if (isDetached) {
yield regexFileAsync('IS_DETACHED = false', `IS_DETACHED = true`, path.join(shellPath, 'app', 'src', 'main', 'java', 'host', 'exp', 'exponent', 'generated', 'AppConstants.java'));
}
// App name
yield regexFileAsync('"app_name">Expo', `"app_name">${xmlWeirdAndroidEscape(name)}`, path.join(shellPath, 'app', 'src', 'main', 'res', 'values', 'strings.xml'));
// Splash Screen background color
yield regexFileAsync('"splashBackground">#FFFFFF', `"splashBackground">${splashBackgroundColor}`, path.join(shellPath, 'app', 'src', 'main', 'res', 'values', 'colors.xml'));
// show only background color if LoadingView will appear
if (shouldShowLoadingView(manifest)) {
yield regexFileAsync(/<item>.*<\/item>/, '', path.join(shellPath, 'app', 'src', 'main', 'res', 'drawable', 'splash_background.xml'));
}
// Remove exp:// scheme from LauncherActivity
yield deleteLinesInFileAsync(`START\ LAUNCHER\ INTENT\ FILTERS`, `END\ LAUNCHER\ INTENT\ FILTERS`, path.join(shellPath, 'app', 'src', 'main', 'AndroidManifest.xml'));
// Remove LAUNCHER category from HomeActivity
yield deleteLinesInFileAsync(`START\ HOME\ INTENT\ FILTERS`, `END\ HOME\ INTENT\ FILTERS`, path.join(shellPath, 'app', 'src', 'main', 'AndroidManifest.xml'));
if (isDetached) {
// Add LAUNCHER category to MainActivity
yield regexFileAsync('<!-- ADD DETACH INTENT FILTERS HERE -->', `<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>`, path.join(shellPath, 'app', 'src', 'main', 'AndroidManifest.xml'));
} else {
// Add LAUNCHER category to ShellAppActivity
yield regexFileAsync('<!-- ADD SHELL INTENT FILTERS HERE -->', `<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>`, path.join(shellPath, 'app', 'src', 'main', 'AndroidManifest.xml'));
}
// Add shell app scheme
if (scheme) {
yield regexFileAsync('<!-- ADD SHELL SCHEME HERE -->', `<intent-filter>
<data android:scheme="${scheme}"/>
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.DEFAULT"/>
<category android:name="android.intent.category.BROWSABLE"/>
</intent-filter>`, path.join(shellPath, 'app', 'src', 'main', 'AndroidManifest.xml'));
}
// Add permissions
if (manifest.android && manifest.android.permissions) {
const content = yield fs.readFileSync(path.join(shellPath, 'app', 'src', 'main', 'AndroidManifest.xml'), 'utf-8');
// Get the list of optional permissions form manifest
const permissions = content.replace(/(([\s\S]*<!-- BEGIN OPTIONAL PERMISSIONS -->)|(<!-- END OPTIONAL PERMISSIONS -->[\s\S]*))/g, '').match(/android:name=".+"/g).map(function (p) {
return p.replace(/(android:name=|")/g, '');
});
const whitelist = [];
manifest.android.permissions.forEach(function (s) {
if (s.includes('.')) {
whitelist.push(s);
} else {
permissions.forEach(function (identifier) {
if (identifier.split('.').pop() === s) {
whitelist.push(identifier);
}
});
}
});
// Permissions we need to remove from the generated manifest
const blacklist = ['android.permission.ACCESS_COARSE_LOCATION', 'android.permission.ACCESS_FINE_LOCATION', 'android.permission.CAMERA', 'android.permission.MANAGE_DOCUMENTS', 'android.permission.READ_CONTACTS', 'android.permission.READ_CALENDAR', 'android.permission.WRITE_CALENDAR', 'android.permission.READ_EXTERNAL_STORAGE', 'android.permission.READ_INTERNAL_STORAGE', 'android.permission.READ_PHONE_STATE', 'android.permission.RECORD_AUDIO', 'android.permission.USE_FINGERPRINT', 'android.permission.VIBRATE', 'android.permission.WRITE_EXTERNAL_STORAGE', 'com.anddoes.launcher.permission.UPDATE_COUNT', 'com.android.launcher.permission.INSTALL_SHORTCUT', 'com.google.android.gms.permission.ACTIVITY_RECOGNITION', 'com.google.android.providers.gsf.permission.READ_GSERVICES', 'com.htc.launcher.permission.READ_SETTINGS', 'com.htc.launcher.permission.UPDATE_SHORTCUT', 'com.majeur.launcher.permission.UPDATE_BADGE', 'com.sec.android.provider.badge.permission.READ', 'com.sec.android.provider.badge.permission.WRITE', 'com.sonyericsson.home.permission.BROADCAST_BADGE'].filter(function (p) {
return !whitelist.includes(p);
});
yield deleteLinesInFileAsync(`BEGIN\ OPTIONAL\ PERMISSIONS`, `END\ OPTIONAL\ PERMISSIONS`, path.join(shellPath, 'app', 'src', 'main', 'AndroidManifest.xml'));
yield regexFileAsync('<!-- ADD PERMISSIONS HERE -->', `
${whitelist.map(function (p) {
return `<uses-permission android:name="${p}" />`;
}).join('\n')}
${blacklist.map(function (p) {
return `<uses-permission android:name="${p}" tools:node="remove" />`;
}).join('\n')}
`, path.join(shellPath, 'app', 'src', 'main', 'AndroidManifest.xml'));
}
// OAuth redirect scheme
yield regexFileAsync('<data android:scheme="host.exp.exponent" android:path="oauthredirect"/>', `<data android:scheme="${javaPackage}" android:path="oauthredirect"/>`, path.join(shellPath, 'app', 'src', 'main', 'AndroidManifest.xml'));
// Embed manifest and bundle
if (isFullManifest) {
yield fs.writeFileSync(path.join(shellPath, 'app', 'src', 'main', 'assets', 'shell-app-manifest.json'), JSON.stringify(manifest));
yield saveUrlToPathAsync(bundleUrl, path.join(shellPath, 'app', 'src', 'main', 'assets', 'shell-app.bundle'));
yield regexFileAsync('// START EMBEDDED RESPONSES', `
// START EMBEDDED RESPONSES
embeddedResponses.add(new Constants.EmbeddedResponse("${fullManifestUrl}", "assets://shell-app-manifest.json", "application/json"));
embeddedResponses.add(new Constants.EmbeddedResponse("${bundleUrl}", "assets://shell-app.bundle", "application/javascript"));`, path.join(shellPath, 'app', 'src', 'main', 'java', 'host', 'exp', 'exponent', 'generated', 'AppConstants.java'));
}
yield regexFileAsync('RELEASE_CHANNEL = "default"', `RELEASE_CHANNEL = "${releaseChannel}"`, path.join(shellPath, 'app', 'src', 'main', 'java', 'host', 'exp', 'exponent', 'generated', 'AppConstants.java'));
// Icon
if (iconUrl) {
(yield globby(['**/ic_launcher.png'], {
cwd: path.join(shellPath, 'app', 'src', 'main', 'res'),
absolute: true
})).forEach(function (filePath) {
fs.removeSync(filePath);
});
yield copyIconsToResSubfolders(path.join(shellPath, 'app', 'src', 'main', 'res'), 'mipmap', 'ic_launcher.png', iconUrl, isDetached);
}
if (notificationIconUrl) {
(yield globby(['**/shell_notification_icon.png'], {
cwd: path.join(shellPath, 'app', 'src', 'main', 'res'),
absolute: true
})).forEach(function (filePath) {
fs.removeSync(filePath);
});
yield copyIconsToResSubfolders(path.join(shellPath, 'app', 'src', 'main', 'res'), 'drawable', 'shell_notification_icon.png', notificationIconUrl, isDetached);
}
// Splash Background
if (backgroundImages && backgroundImages.length > 0) {
// Delete the placeholder images
(yield globby(['**/shell_launch_background_image.png'], {
cwd: path.join(shellPath, 'app', 'src', 'main', 'res'),
absolute: true
})).forEach(function (filePath) {
fs.removeSync(filePath);
});
_.forEach(backgroundImages, (() => {
var _ref10 = _asyncToGenerator(function* (image) {
yield saveUrlToPathAsync(image.url, image.path);
});
return function (_x19) {
return _ref10.apply(this, arguments);
};
})());
}
if (manifest.bundledAssets) {
yield downloadAssetsAsync(manifest.bundledAssets, `${shellPath}/app/src/main/assets`);
}
let certificateHash = '';
let googleAndroidApiKey = '';
let privateConfig = context.data.privateConfig;
if (privateConfig) {
let branch = privateConfig.branch;
let fabric = privateConfig.fabric;
let googleMaps = privateConfig.googleMaps;
let googleSignIn = privateConfig.googleSignIn;
// Branch
if (branch) {
yield regexFileAsync('<!-- ADD BRANCH CONFIG HERE -->', `<meta-data
android:name="io.branch.sdk.BranchKey"
android:value="${branch.apiKey}"/>`, path.join(shellPath, 'app', 'src', 'main', 'AndroidManifest.xml'));
}
// Fabric
if (fabric) {
yield fs.remove(path.join(shellPath, 'app', 'fabric.properties'));
yield fs.writeFileSync(path.join(shellPath, 'app', 'fabric.properties'), `apiSecret=${fabric.buildSecret}\n`);
yield deleteLinesInFileAsync(`BEGIN\ FABRIC\ CONFIG`, `END\ FABRIC\ CONFIG`, path.join(shellPath, 'app', 'src', 'main', 'AndroidManifest.xml'));
yield regexFileAsync('<!-- ADD FABRIC CONFIG HERE -->', `<meta-data
android:name="io.fabric.ApiKey"
android:value="${fabric.apiKey}"/>`, path.join(shellPath, 'app', 'src', 'main', 'AndroidManifest.xml'));
}
// Google Maps
if (googleMaps) {
yield deleteLinesInFileAsync(`BEGIN\ GOOGLE\ MAPS\ CONFIG`, `END\ GOOGLE\ MAPS\ CONFIG`, path.join(shellPath, 'app', 'src', 'main', 'AndroidManifest.xml'));
yield regexFileAsync('<!-- ADD GOOGLE MAPS CONFIG HERE -->', `<meta-data
android:name="com.google.android.geo.API_KEY"
android:value="${googleMaps.apiKey}"/>`, path.join(shellPath, 'app', 'src', 'main', 'AndroidManifest.xml'));
}
// Google Login
if (googleSignIn) {
certificateHash = googleSignIn.certificateHash;
googleAndroidApiKey = googleSignIn.apiKey;
}
}
// Google sign in
yield regexFileAsync(/"current_key": "(.*?)"/, `"current_key": "${googleAndroidApiKey}"`, path.join(shellPath, 'app', 'google-services.json'));
yield regexFileAsync(/"certificate_hash": "(.*?)"/, `"certificate_hash": "${certificateHash}"`, path.join(shellPath, 'app', 'google-services.json'));
});
return function runShellAppModificationsAsync(_x18) {
return _ref9.apply(this, arguments);
};
})();
let buildShellAppAsync = (() => {
var _ref11 = _asyncToGenerator(function* (context) {
let shellPath = shellPathForContext(context);
if (context.build.android) {
let androidBuildConfiguration = context.build.android;
try {
yield fs.remove(`shell-unaligned.apk`);
yield fs.remove(`shell.apk`);
} catch (e) {}
const gradleArgs = [`assembleProdRelease`];
if (process.env.GRADLE_DAEMON_DISABLED) {
gradleArgs.unshift('--no-daemon');
}
yield spawnAsyncThrowError(`./gradlew`, gradleArgs, {
stdio: 'inherit',
cwd: shellPath
});
yield fs.copy(path.join(shellPath, 'app', 'build', 'outputs', 'apk', 'app-prod-release-unsigned.apk'), `shell-unaligned.apk`);
yield spawnAsync(`jarsigner`, ['-verbose', '-sigalg', 'SHA1withRSA', '-digestalg', 'SHA1', '-storepass', androidBuildConfiguration.keystorePassword, '-keypass', androidBuildConfiguration.keyPassword, '-keystore', androidBuildConfiguration.keystore, 'shell-unaligned.apk', androidBuildConfiguration.keyAlias]);
yield spawnAsync(`zipalign`, ['-v', '4', 'shell-unaligned.apk', 'shell.apk']);
try {
yield fs.remove('shell-unaligned.apk');
} catch (e) {}
yield spawnAsync(`jarsigner`, ['-verify', '-verbose', '-certs', '-keystore', androidBuildConfiguration.keystore, 'shell.apk']);
yield fs.copy('shell.apk', androidBuildConfiguration.outputFile || '/tmp/shell-signed.apk');
} else {
try {
yield fs.remove('shell-debug.apk');
} catch (e) {}
yield spawnAsyncThrowError(`./gradlew`, ['assembleDevRemoteKernelDebug'], {
stdio: 'inherit',
cwd: shellPath
});
yield fs.copy(path.join(shellPath, 'app', 'build', 'outputs', 'apk', 'app-devRemoteKernel-debug.apk'), `/tmp/shell-debug.apk`);
}
});
return function buildShellAppAsync(_x20) {
return _ref11.apply(this, arguments);
};
})();
let downloadAssetsAsync = (() => {
var _ref12 = _asyncToGenerator(function* (assets, dest) {
// Compat with exp 46.x.x, can remove when this version is phasing out.
if (typeof assets[0] === 'object') {
assets = assets.reduce(function (res, cur) {
return res.concat(cur.fileHashes.map(function (h) {
return 'asset_' + h + (cur.type ? '.' + cur.type : '');
}));
}, []);
}
yield fs.ensureDir(dest);
const batches = _.chunk(assets, 5);
for (const batch of batches) {
yield Promise.all(batch.map((() => {
var _ref13 = _asyncToGenerator(function* (asset) {
const extensionIndex = asset.lastIndexOf('.');
const prefixLength = 'asset_'.length;
const hash = extensionIndex >= 0 ? asset.substring(prefixLength, extensionIndex) : asset.substring(prefixLength);
yield saveUrlToPathAsync('https://d1wp6m56sqw74a.cloudfront.net/~assets/' + hash, path.join(dest, asset));
});
return function (_x23) {
return _ref13.apply(this, arguments);
};
})()));
}
});
return function downloadAssetsAsync(_x21, _x22) {
return _ref12.apply(this, arguments);
};
})();
var _ExponentTools;
function _load_ExponentTools() {
return _ExponentTools = _interopRequireWildcard(require('./ExponentTools'));
}
var _StandaloneBuildFlags;
function _load_StandaloneBuildFlags() {
return _StandaloneBuildFlags = _interopRequireDefault(require('./StandaloneBuildFlags'));
}
var _StandaloneContext;
function _load_StandaloneContext() {
return _StandaloneContext = _interopRequireDefault(require('./StandaloneContext'));
}
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
function _asyncToGenerator(fn) { return function () { var gen = fn.apply(this, arguments); return new Promise(function (resolve, reject) { function step(key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { return Promise.resolve(value).then(function (value) { step("next", value); }, function (err) { step("throw", err); }); } } return step("next"); }); }; }
const fs = require('fs-extra');
const path = require('path');
const JsonFile = require('@expo/json-file');
const replaceString = require('replace-string');
const _ = require('lodash');
const globby = require('globby');
const { getManifestAsync, saveUrlToPathAsync, spawnAsyncThrowError, spawnAsync } = _ExponentTools || _load_ExponentTools();
const imageKeys = ['ldpi', 'mdpi', 'hdpi', 'xhdpi', 'xxhdpi', 'xxxhdpi'];
// Do not call this from anything used by detach
function exponentDirectory() {
if (process.env.TURTLE_WORKING_DIR_PATH) {
return process.env.TURTLE_WORKING_DIR_PATH;
} else if (process.env.EXPO_UNIVERSE_DIR) {
return path.join(process.env.EXPO_UNIVERSE_DIR, 'exponent');
} else {
return null;
}
}
function xmlWeirdAndroidEscape(original) {
let noAmps = replaceString(original, '&', '&amp;');
let noLt = replaceString(noAmps, '<', '&lt;');
let noGt = replaceString(noLt, '>', '&gt;');
let noApos = replaceString(noGt, '"', '\\"');
return replaceString(noApos, "'", "\\'");
}
exports.updateAndroidShellAppAsync = (() => {
var _ref3 = _asyncToGenerator(function* (args) {
let {
url,
sdkVersion,
androidPackage,
privateConfigFile,
keystore,
alias,
keystorePassword,
keyPassword,
releaseChannel,
outputFile
} = args;
releaseChannel = releaseChannel ? releaseChannel : 'default';
let manifest = yield getManifestAsync(url, {
'Exponent-SDK-Version': sdkVersion,
'Exponent-Platform': 'android',
'Expo-Release-Channel': releaseChannel
});
let fullManifestUrl = `${url.replace('exp://', 'https://')}/index.exp`;
let bundleUrl = manifest.bundleUrl;
let shellPath = path.join(exponentDirectory(), 'android-shell-app');
yield fs.remove(path.join(shellPath, 'app', 'src', 'main', 'assets', 'shell-app-manifest.json'));
yield fs.writeFileSync(path.join(shellPath, 'app', 'src', 'main', 'assets', 'shell-app-manifest.json'), JSON.stringify(manifest));
yield fs.remove(path.join(shellPath, 'app', 'src', 'main', 'assets', 'shell-app.bundle'));
yield saveUrlToPathAsync(bundleUrl, path.join(shellPath, 'app', 'src', 'main', 'assets', 'shell-app.bundle'));
yield deleteLinesInFileAsync(`START\ EMBEDDED\ RESPONSES`, `END\ EMBEDDED\ RESPONSES`, path.join(shellPath, 'app', 'src', 'main', 'java', 'host', 'exp', 'exponent', 'generated', 'AppConstants.java'));
yield regexFileAsync('// ADD EMBEDDED RESPONSES HERE', `
// ADD EMBEDDED RESPONSES HERE
// START EMBEDDED RESPONSES
embeddedResponses.add(new Constants.EmbeddedResponse("${fullManifestUrl}", "assets://shell-app-manifest.json", "application/json"));
embeddedResponses.add(new Constants.EmbeddedResponse("${bundleUrl}", "assets://shell-app.bundle", "application/javascript"));
// END EMBEDDED RESPONSES`, path.join(shellPath, 'app', 'src', 'main', 'java', 'host', 'exp', 'exponent', 'generated', 'AppConstants.java'));
yield regexFileAsync('RELEASE_CHANNEL = "default"', `RELEASE_CHANNEL = "${releaseChannel}"`, path.join(shellPath, 'app', 'src', 'main', 'java', 'host', 'exp', 'exponent', 'generated', 'AppConstants.java'));
});
function updateAndroidShellAppAsync(_x7) {
return _ref3.apply(this, arguments);
}
return updateAndroidShellAppAsync;
})();
function backgroundImagesForApp(shellPath, manifest) {
// returns an array like:
// [
// {url: 'urlToDownload', path: 'pathToSaveTo'},
// {url: 'anotherURlToDownload', path: 'anotherPathToSaveTo'},
// ]
let basePath = path.join(shellPath, 'app', 'src', 'main', 'res');
if (_.get(manifest, 'android.splash')) {
var splash = _.get(manifest, 'android.splash');
return _.reduce(imageKeys, function (acc, imageKey) {
let url = _.get(splash, `${imageKey}Url`);
if (url) {
acc.push({
url,
path: path.join(basePath, `drawable-${imageKey}`, 'shell_launch_background_image.png')
});
}
return acc;
}, []);
}
if (_.get(manifest, 'splash.imageUrl')) {
let url = _.get(manifest, 'splash.imageUrl');
return [{
url,
path: path.join(basePath, 'drawable-xxxhdpi', 'shell_launch_background_image.png')
}];
}
return [];
}
function getSplashScreenBackgroundColor(manifest) {
let backgroundColor;
if (manifest.android && manifest.android.splash && manifest.android.splash.backgroundColor) {
backgroundColor = manifest.android.splash.backgroundColor;
} else if (manifest.splash && manifest.splash.backgroundColor) {
backgroundColor = manifest.splash.backgroundColor;
}
// Default to white
if (!backgroundColor) {
backgroundColor = '#FFFFFF';
}
return backgroundColor;
}
/*
if resizeMode is 'cover' we should show LoadingView:
using an ImageView, unlike having a BitmapDrawable
provides a fullscreen image without distortions
*/
function shouldShowLoadingView(manifest) {
return manifest.android && manifest.android.splash && manifest.android.splash.resizeMode && manifest.android.splash.resizeMode === 'cover' || manifest.splash && manifest.splash.resizeMode && manifest.splash.resizeMode === 'cover';
}
exports.createAndroidShellAppAsync = (() => {
var _ref6 = _asyncToGenerator(function* (args) {
let {
url,
sdkVersion,
releaseChannel,
privateConfigFile,
configuration,
keystore,
alias,
keystorePassword,
keyPassword,
outputFile
} = args;
let androidSrcPath = path.join(exponentDirectory(), 'android');
let shellPath = path.join(exponentDirectory(), 'android-shell-app');
yield fs.remove(shellPath);
yield fs.ensureDir(shellPath);
releaseChannel = releaseChannel ? releaseChannel : 'default';
let manifest = yield getManifestAsync(url, {
'Exponent-SDK-Version': sdkVersion,
'Exponent-Platform': 'android',
'Expo-Release-Channel': releaseChannel
});
configuration = configuration ? configuration : 'Release';
let privateConfig;
if (privateConfigFile) {
let privateConfigContents = yield fs.readFile(privateConfigFile, 'utf8');
privateConfig = JSON.parse(privateConfigContents);
}
let androidBuildConfiguration;
if (keystore && alias && keystorePassword && keyPassword) {
androidBuildConfiguration = {
keystore,
keystorePassword,
keyAlias: alias,
keyPassword,
outputFile
};
}
let buildFlags = (_StandaloneBuildFlags || _load_StandaloneBuildFlags()).default.createAndroid(configuration, androidBuildConfiguration);
let context = (_StandaloneContext || _load_StandaloneContext()).default.createServiceContext(androidSrcPath, null, manifest, privateConfig, buildFlags, url, releaseChannel);
yield copyInitialShellAppFilesAsync(androidSrcPath, shellPath);
yield runShellAppModificationsAsync(context);
if (!args.skipBuild) {
yield buildShellAppAsync(context);
}
});
function createAndroidShellAppAsync(_x11) {
return _ref6.apply(this, arguments);
}
return createAndroidShellAppAsync;
})();
function shellPathForContext(context) {
if (context.type === 'user') {
return path.join(context.data.projectPath, 'android');
} else {
return path.join(exponentDirectory(), 'android-shell-app');
}
}
//# sourceMappingURL=../__sourcemaps__/detach/AndroidShellApp.js.map