1"use strict"; 2var __importDefault = (this && this.__importDefault) || function (mod) { 3 return (mod && mod.__esModule) ? mod : { "default": mod }; 4}; 5Object.defineProperty(exports, "__esModule", { value: true }); 6const config_plugins_1 = require("@expo/config-plugins"); 7const fs_1 = __importDefault(require("fs")); 8const path_1 = __importDefault(require("path")); 9const semver_1 = __importDefault(require("semver")); 10const resolveExpoUpdatesVersion_1 = require("./resolveExpoUpdatesVersion"); 11const withDevLauncherAppDelegate_1 = require("./withDevLauncherAppDelegate"); 12const pkg = require('expo-dev-launcher/package.json'); 13const DEV_LAUNCHER_ANDROID_IMPORT = 'expo.modules.devlauncher.DevLauncherController'; 14const DEV_LAUNCHER_UPDATES_ANDROID_IMPORT = 'expo.modules.updates.UpdatesDevLauncherController'; 15const DEV_LAUNCHER_ON_NEW_INTENT = ` 16 @Override 17 public void onNewIntent(Intent intent) { 18 if (DevLauncherController.tryToHandleIntent(this, intent)) { 19 return; 20 } 21 super.onNewIntent(intent); 22 } 23`; 24const DEV_LAUNCHER_WRAPPED_ACTIVITY_DELEGATE = `DevLauncherController.wrapReactActivityDelegate(this, () -> $1);`; 25const DEV_LAUNCHER_ANDROID_INIT = 'DevLauncherController.initialize(this, getReactNativeHost());'; 26const DEV_LAUNCHER_UPDATES_ANDROID_INIT = `if (BuildConfig.DEBUG) { 27 DevLauncherController.getInstance().setUpdatesInterface(UpdatesDevLauncherController.initialize(this)); 28 }`; 29const DEV_LAUNCHER_UPDATES_DEVELOPER_SUPPORT = 'return DevLauncherController.getInstance().getUseDeveloperSupport();'; 30const DEV_LAUNCHER_JS_REGISTER_ERROR_HANDLERS = `import 'expo-dev-client';`; 31async function readFileAsync(path) { 32 return fs_1.default.promises.readFile(path, 'utf8'); 33} 34async function saveFileAsync(path, content) { 35 return fs_1.default.promises.writeFile(path, content, 'utf8'); 36} 37function addLines(content, find, offset, toAdd) { 38 const lines = content.split('\n'); 39 let lineIndex = lines.findIndex(line => line.match(find)); 40 for (const newLine of toAdd) { 41 if (!content.includes(newLine)) { 42 lines.splice(lineIndex + offset, 0, newLine); 43 lineIndex++; 44 } 45 } 46 return lines.join('\n'); 47} 48function replaceLine(content, find, replace) { 49 const lines = content.split('\n'); 50 if (!content.includes(replace)) { 51 const lineIndex = lines.findIndex(line => line.match(find)); 52 lines.splice(lineIndex, 1, replace); 53 } 54 return lines.join('\n'); 55} 56function addJavaImports(javaSource, javaImports) { 57 const lines = javaSource.split('\n'); 58 const lineIndexWithPackageDeclaration = lines.findIndex(line => line.match(/^package .*;$/)); 59 for (const javaImport of javaImports) { 60 if (!javaSource.includes(javaImport)) { 61 const importStatement = `import ${javaImport};`; 62 lines.splice(lineIndexWithPackageDeclaration + 1, 0, importStatement); 63 } 64 } 65 return lines.join('\n'); 66} 67async function editMainApplication(config, action) { 68 const mainApplicationPath = path_1.default.join(config.modRequest.platformProjectRoot, 'app', 'src', 'main', 'java', ...config.android.package.split('.'), 'MainApplication.java'); 69 try { 70 const mainApplication = action(await readFileAsync(mainApplicationPath)); 71 return await saveFileAsync(mainApplicationPath, mainApplication); 72 } 73 catch (e) { 74 config_plugins_1.WarningAggregator.addWarningIOS('expo-dev-launcher', `Couldn't modify MainApplication.java - ${e}.`); 75 } 76} 77async function editPodfile(config, action) { 78 const podfilePath = path_1.default.join(config.modRequest.platformProjectRoot, 'Podfile'); 79 try { 80 const podfile = action(await readFileAsync(podfilePath)); 81 return await saveFileAsync(podfilePath, podfile); 82 } 83 catch (e) { 84 config_plugins_1.WarningAggregator.addWarningIOS('expo-dev-launcher', `Couldn't modify AppDelegate.m - ${e}.`); 85 } 86} 87async function editIndex(config, action) { 88 const indexPath = path_1.default.join(config.modRequest.projectRoot, 'index.js'); 89 try { 90 const index = action(await readFileAsync(indexPath)); 91 return await saveFileAsync(indexPath, index); 92 } 93 catch (e) { 94 config_plugins_1.WarningAggregator.addWarningIOS('expo-dev-launcher', `Couldn't modify index.js - ${e}.`); 95 } 96} 97const withDevLauncherApplication = config => { 98 return config_plugins_1.withDangerousMod(config, [ 99 'android', 100 async (config) => { 101 await editMainApplication(config, mainApplication => { 102 mainApplication = addJavaImports(mainApplication, [DEV_LAUNCHER_ANDROID_IMPORT]); 103 mainApplication = addLines(mainApplication, 'initializeFlipper\\(this', 0, [ 104 ` ${DEV_LAUNCHER_ANDROID_INIT}`, 105 ]); 106 let expoUpdatesVersion; 107 try { 108 expoUpdatesVersion = resolveExpoUpdatesVersion_1.resolveExpoUpdatesVersion(config.modRequest.projectRoot); 109 } 110 catch (e) { 111 config_plugins_1.WarningAggregator.addWarningAndroid('expo-dev-launcher', `Failed to check compatibility with expo-updates - ${e}`); 112 } 113 if (expoUpdatesVersion && semver_1.default.gt(expoUpdatesVersion, '0.6.0')) { 114 mainApplication = addJavaImports(mainApplication, [DEV_LAUNCHER_UPDATES_ANDROID_IMPORT]); 115 mainApplication = addLines(mainApplication, 'initializeFlipper\\(this', 0, [ 116 ` ${DEV_LAUNCHER_UPDATES_ANDROID_INIT}`, 117 ]); 118 mainApplication = replaceLine(mainApplication, 'return BuildConfig.DEBUG;', ` ${DEV_LAUNCHER_UPDATES_DEVELOPER_SUPPORT}`); 119 } 120 return mainApplication; 121 }); 122 return config; 123 }, 124 ]); 125}; 126const withDevLauncherActivity = config => { 127 return config_plugins_1.withMainActivity(config, config => { 128 if (config.modResults.language === 'java') { 129 let content = addJavaImports(config.modResults.contents, [ 130 DEV_LAUNCHER_ANDROID_IMPORT, 131 'android.content.Intent', 132 ]); 133 if (!content.includes(DEV_LAUNCHER_ON_NEW_INTENT)) { 134 const lines = content.split('\n'); 135 const onCreateIndex = lines.findIndex(line => line.includes('public class MainActivity')); 136 lines.splice(onCreateIndex + 1, 0, DEV_LAUNCHER_ON_NEW_INTENT); 137 content = lines.join('\n'); 138 } 139 if (!content.includes('DevLauncherController.wrapReactActivityDelegate')) { 140 content = content.replace(/(new ReactActivityDelegate(.*|\s)*});$/m, DEV_LAUNCHER_WRAPPED_ACTIVITY_DELEGATE); 141 } 142 config.modResults.contents = content; 143 } 144 else { 145 config_plugins_1.WarningAggregator.addWarningAndroid('expo-dev-launcher', `Cannot automatically configure MainActivity if it's not java`); 146 } 147 return config; 148 }); 149}; 150const withDevLauncherPodfile = config => { 151 return config_plugins_1.withDangerousMod(config, [ 152 'ios', 153 async (config) => { 154 await editPodfile(config, podfile => { 155 podfile = podfile.replace("platform :ios, '10.0'", "platform :ios, '11.0'"); 156 // Match both variations of Ruby config: 157 // unknown: pod 'expo-dev-launcher', path: '../node_modules/expo-dev-launcher', :configurations => :debug 158 // Rubocop: pod 'expo-dev-launcher', path: '../node_modules/expo-dev-launcher', configurations: :debug 159 if (!podfile.match(/pod ['"]expo-dev-launcher['"],\s?path: ['"][^'"]*node_modules\/expo-dev-launcher['"],\s?:?configurations:?\s(?:=>\s)?:debug/)) { 160 const packagePath = path_1.default.dirname(require.resolve('expo-dev-launcher/package.json')); 161 const relativePath = path_1.default.relative(config.modRequest.platformProjectRoot, packagePath); 162 podfile = addLines(podfile, 'use_react_native', 0, [ 163 ` pod 'expo-dev-launcher', path: '${relativePath}', :configurations => :debug`, 164 ]); 165 } 166 return podfile; 167 }); 168 return config; 169 }, 170 ]); 171}; 172const withErrorHandling = config => { 173 const injectErrorHandlers = async (config) => { 174 await editIndex(config, index => { 175 if (!index.includes(DEV_LAUNCHER_JS_REGISTER_ERROR_HANDLERS)) { 176 index = DEV_LAUNCHER_JS_REGISTER_ERROR_HANDLERS + '\n\n' + index; 177 } 178 return index; 179 }); 180 return config; 181 }; 182 // We need to run the same task twice to ensure it will work on both platforms, 183 // because if someone runs `expo run:ios`, it will trigger only dangerous mode for that specific platform. 184 // Note: after the first execution, the second one won't change anything. 185 config = config_plugins_1.withDangerousMod(config, ['android', injectErrorHandlers]); 186 config = config_plugins_1.withDangerousMod(config, ['ios', injectErrorHandlers]); 187 return config; 188}; 189const withDevLauncher = (config) => { 190 config = withDevLauncherActivity(config); 191 config = withDevLauncherApplication(config); 192 config = withDevLauncherPodfile(config); 193 config = withDevLauncherAppDelegate_1.withDevLauncherAppDelegate(config); 194 config = withErrorHandling(config); 195 return config; 196}; 197exports.default = config_plugins_1.createRunOncePlugin(withDevLauncher, pkg.name, pkg.version); 198