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