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 }); 6exports.modifyJavaMainActivity = void 0; 7const config_plugins_1 = require("@expo/config-plugins"); 8const fs_1 = __importDefault(require("fs")); 9const path_1 = __importDefault(require("path")); 10const semver_1 = __importDefault(require("semver")); 11const constants_1 = require("./constants"); 12const resolveExpoUpdatesVersion_1 = require("./resolveExpoUpdatesVersion"); 13const utils_1 = require("./utils"); 14const withDevLauncherAppDelegate_1 = require("./withDevLauncherAppDelegate"); 15const pkg = require('expo-dev-launcher/package.json'); 16const DEV_LAUNCHER_ANDROID_IMPORT = 'expo.modules.devlauncher.DevLauncherController'; 17const DEV_LAUNCHER_UPDATES_ANDROID_IMPORT = 'expo.modules.updates.UpdatesDevLauncherController'; 18const DEV_LAUNCHER_ON_NEW_INTENT = [ 19 '', 20 ' @Override', 21 ' public void onNewIntent(Intent intent) {', 22 ' super.onNewIntent(intent);', 23 ' }', 24 '', 25].join('\n'); 26const DEV_LAUNCHER_HANDLE_INTENT = [ 27 ' if (DevLauncherController.tryToHandleIntent(this, intent)) {', 28 ' return;', 29 ' }', 30].join('\n'); 31const DEV_LAUNCHER_WRAPPED_ACTIVITY_DELEGATE = (activityDelegateDeclaration) => `DevLauncherController.wrapReactActivityDelegate(this, () -> ${activityDelegateDeclaration})`; 32const DEV_LAUNCHER_ANDROID_INIT = 'DevLauncherController.initialize(this, getReactNativeHost());'; 33const DEV_LAUNCHER_UPDATES_ANDROID_INIT = `if (BuildConfig.DEBUG) { 34 DevLauncherController.getInstance().setUpdatesInterface(UpdatesDevLauncherController.initialize(this)); 35 }`; 36const DEV_LAUNCHER_UPDATES_DEVELOPER_SUPPORT = 'return DevLauncherController.getInstance().getUseDeveloperSupport();'; 37async function readFileAsync(path) { 38 return fs_1.default.promises.readFile(path, 'utf8'); 39} 40async function saveFileAsync(path, content) { 41 return fs_1.default.promises.writeFile(path, content, 'utf8'); 42} 43function findClosingBracketMatchIndex(str, pos) { 44 if (str[pos] !== '(') { 45 throw new Error("No '(' at index " + pos); 46 } 47 let depth = 1; 48 for (let i = pos + 1; i < str.length; i++) { 49 switch (str[i]) { 50 case '(': 51 depth++; 52 break; 53 case ')': 54 if (--depth === 0) { 55 return i; 56 } 57 break; 58 } 59 } 60 return -1; // No matching closing parenthesis 61} 62const replaceBetween = (origin, startIndex, endIndex, insertion) => `${origin.substring(0, startIndex)}${insertion}${origin.substring(endIndex)}`; 63function addJavaImports(javaSource, javaImports) { 64 const lines = javaSource.split('\n'); 65 const lineIndexWithPackageDeclaration = lines.findIndex((line) => line.match(/^package .*;$/)); 66 for (const javaImport of javaImports) { 67 if (!javaSource.includes(javaImport)) { 68 const importStatement = `import ${javaImport};`; 69 lines.splice(lineIndexWithPackageDeclaration + 1, 0, importStatement); 70 } 71 } 72 return lines.join('\n'); 73} 74async function editMainApplication(config, action) { 75 const mainApplicationPath = path_1.default.join(config.modRequest.platformProjectRoot, 'app', 'src', 'main', 'java', ...config.android.package.split('.'), 'MainApplication.java'); 76 try { 77 const mainApplication = action(await readFileAsync(mainApplicationPath)); 78 return await saveFileAsync(mainApplicationPath, mainApplication); 79 } 80 catch (e) { 81 config_plugins_1.WarningAggregator.addWarningAndroid('expo-dev-launcher', `Couldn't modify MainApplication.java - ${e}. 82See the expo-dev-client installation instructions to modify your MainApplication.java manually: ${constants_1.InstallationPage}`); 83 } 84} 85async function editPodfile(config, action) { 86 const podfilePath = path_1.default.join(config.modRequest.platformProjectRoot, 'Podfile'); 87 try { 88 const podfile = action(await readFileAsync(podfilePath)); 89 return await saveFileAsync(podfilePath, podfile); 90 } 91 catch (e) { 92 config_plugins_1.WarningAggregator.addWarningIOS('expo-dev-launcher', `Couldn't modify AppDelegate.m - ${e}. 93See the expo-dev-client installation instructions to modify your AppDelegate.m manually: ${constants_1.InstallationPage}`); 94 } 95} 96const withDevLauncherApplication = (config) => { 97 return (0, config_plugins_1.withDangerousMod)(config, [ 98 'android', 99 async (config) => { 100 await editMainApplication(config, (mainApplication) => { 101 mainApplication = addJavaImports(mainApplication, [DEV_LAUNCHER_ANDROID_IMPORT]); 102 mainApplication = (0, utils_1.addLines)(mainApplication, 'initializeFlipper\\(this', 0, [ 103 ` ${DEV_LAUNCHER_ANDROID_INIT}`, 104 ]); 105 let expoUpdatesVersion; 106 try { 107 expoUpdatesVersion = (0, resolveExpoUpdatesVersion_1.resolveExpoUpdatesVersion)(config.modRequest.projectRoot); 108 } 109 catch (e) { 110 config_plugins_1.WarningAggregator.addWarningAndroid('expo-dev-launcher', `Failed to check compatibility with expo-updates - ${e}`); 111 } 112 if (expoUpdatesVersion && semver_1.default.gt(expoUpdatesVersion, '0.6.0')) { 113 mainApplication = addJavaImports(mainApplication, [DEV_LAUNCHER_UPDATES_ANDROID_IMPORT]); 114 mainApplication = (0, utils_1.addLines)(mainApplication, 'initializeFlipper\\(this', 0, [ 115 ` ${DEV_LAUNCHER_UPDATES_ANDROID_INIT}`, 116 ]); 117 mainApplication = (0, utils_1.replaceLine)(mainApplication, 'return BuildConfig.DEBUG;', ` ${DEV_LAUNCHER_UPDATES_DEVELOPER_SUPPORT}`); 118 } 119 return mainApplication; 120 }); 121 return config; 122 }, 123 ]); 124}; 125function modifyJavaMainActivity(content) { 126 content = addJavaImports(content, [DEV_LAUNCHER_ANDROID_IMPORT, 'android.content.Intent']); 127 if (!content.includes('onNewIntent')) { 128 const lines = content.split('\n'); 129 const onCreateIndex = lines.findIndex((line) => line.includes('public class MainActivity')); 130 lines.splice(onCreateIndex + 1, 0, DEV_LAUNCHER_ON_NEW_INTENT); 131 content = lines.join('\n'); 132 } 133 if (!content.includes(DEV_LAUNCHER_HANDLE_INTENT)) { 134 content = (0, utils_1.addLines)(content, /super\.onNewIntent\(intent\)/, 0, [DEV_LAUNCHER_HANDLE_INTENT]); 135 } 136 if (!content.includes('DevLauncherController.wrapReactActivityDelegate')) { 137 const activityDelegateMatches = Array.from(content.matchAll(/new ReactActivityDelegate(Wrapper)/g)); 138 if (activityDelegateMatches.length !== 1) { 139 config_plugins_1.WarningAggregator.addWarningAndroid('expo-dev-launcher', `Failed to wrap 'ReactActivityDelegate' 140See the expo-dev-client installation instructions to modify your MainActivity.java manually: ${constants_1.InstallationPage}`); 141 return content; 142 } 143 const activityDelegateMatch = activityDelegateMatches[0]; 144 const matchIndex = activityDelegateMatch.index; 145 const openingBracketIndex = matchIndex + activityDelegateMatch[0].length; // next character after `new ReactActivityDelegateWrapper` 146 const closingBracketIndex = findClosingBracketMatchIndex(content, openingBracketIndex); 147 const reactActivityDelegateDeclaration = content.substring(matchIndex, closingBracketIndex + 1); 148 content = replaceBetween(content, matchIndex, closingBracketIndex + 1, DEV_LAUNCHER_WRAPPED_ACTIVITY_DELEGATE(reactActivityDelegateDeclaration)); 149 } 150 return content; 151} 152exports.modifyJavaMainActivity = modifyJavaMainActivity; 153const withDevLauncherActivity = (config) => { 154 return (0, config_plugins_1.withMainActivity)(config, (config) => { 155 if (config.modResults.language === 'java') { 156 config.modResults.contents = modifyJavaMainActivity(config.modResults.contents); 157 } 158 else { 159 config_plugins_1.WarningAggregator.addWarningAndroid('expo-dev-launcher', `Cannot automatically configure MainActivity if it's not java. 160See the expo-dev-client installation instructions to modify your MainActivity manually: ${constants_1.InstallationPage}`); 161 } 162 return config; 163 }); 164}; 165const withDevLauncherPodfile = (config) => { 166 return (0, config_plugins_1.withDangerousMod)(config, [ 167 'ios', 168 async (config) => { 169 await editPodfile(config, (podfile) => { 170 // replace all iOS versions below 12 171 podfile = podfile.replace(/platform :ios, '((\d\.0)|(1[0-1].0))'/, "platform :ios, '13.0'"); 172 // Match both variations of Ruby config: 173 // unknown: pod 'expo-dev-launcher', path: '../node_modules/expo-dev-launcher', :configurations => :debug 174 // Rubocop: pod 'expo-dev-launcher', path: '../node_modules/expo-dev-launcher', configurations: :debug 175 if (!podfile.match(/pod ['"]expo-dev-launcher['"],\s?path: ['"][^'"]*node_modules\/expo-dev-launcher['"],\s?:?configurations:?\s(?:=>\s)?:debug/)) { 176 const packagePath = path_1.default.dirname(require.resolve('expo-dev-launcher/package.json')); 177 const relativePath = path_1.default.relative(config.modRequest.platformProjectRoot, packagePath); 178 podfile = (0, utils_1.addLines)(podfile, 'use_react_native', 0, [ 179 ` pod 'expo-dev-launcher', path: '${relativePath}', :configurations => :debug`, 180 ]); 181 } 182 return podfile; 183 }); 184 return config; 185 }, 186 ]); 187}; 188const withDevLauncher = (config) => { 189 // projects using SDKs before 45 need the old regex-based integration 190 // TODO: remove these once we drop support for SDK 44 191 if (config.sdkVersion && semver_1.default.lt(config.sdkVersion, '45.0.0')) { 192 config = withDevLauncherActivity(config); 193 config = withDevLauncherApplication(config); 194 config = withDevLauncherPodfile(config); 195 config = (0, withDevLauncherAppDelegate_1.withDevLauncherAppDelegate)(config); 196 } 197 return config; 198}; 199exports.default = (0, config_plugins_1.createRunOncePlugin)(withDevLauncher, pkg.name, pkg.version); 200