1"use strict"; 2 3Object.defineProperty(exports, "__esModule", { 4 value: true 5}); 6exports.getApplicationIdAsync = getApplicationIdAsync; 7exports.getPackage = getPackage; 8exports.renameJniOnDiskForType = renameJniOnDiskForType; 9exports.renamePackageOnDisk = renamePackageOnDisk; 10exports.renamePackageOnDiskForType = renamePackageOnDiskForType; 11exports.setPackageInBuildGradle = setPackageInBuildGradle; 12exports.withPackageRefactor = exports.withPackageGradle = void 0; 13function _debug() { 14 const data = _interopRequireDefault(require("debug")); 15 _debug = function () { 16 return data; 17 }; 18 return data; 19} 20function _fs() { 21 const data = _interopRequireDefault(require("fs")); 22 _fs = function () { 23 return data; 24 }; 25 return data; 26} 27function _glob() { 28 const data = require("glob"); 29 _glob = function () { 30 return data; 31 }; 32 return data; 33} 34function _path() { 35 const data = _interopRequireDefault(require("path")); 36 _path = function () { 37 return data; 38 }; 39 return data; 40} 41function _Paths() { 42 const data = require("./Paths"); 43 _Paths = function () { 44 return data; 45 }; 46 return data; 47} 48function _androidPlugins() { 49 const data = require("../plugins/android-plugins"); 50 _androidPlugins = function () { 51 return data; 52 }; 53 return data; 54} 55function _withDangerousMod() { 56 const data = require("../plugins/withDangerousMod"); 57 _withDangerousMod = function () { 58 return data; 59 }; 60 return data; 61} 62function _modules() { 63 const data = require("../utils/modules"); 64 _modules = function () { 65 return data; 66 }; 67 return data; 68} 69function _warnings() { 70 const data = require("../utils/warnings"); 71 _warnings = function () { 72 return data; 73 }; 74 return data; 75} 76function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 77const debug = (0, _debug().default)('expo:config-plugins:android:package'); 78const withPackageGradle = config => { 79 return (0, _androidPlugins().withAppBuildGradle)(config, config => { 80 if (config.modResults.language === 'groovy') { 81 config.modResults.contents = setPackageInBuildGradle(config, config.modResults.contents); 82 } else { 83 (0, _warnings().addWarningAndroid)('android.package', `Cannot automatically configure app build.gradle if it's not groovy`); 84 } 85 return config; 86 }); 87}; 88exports.withPackageGradle = withPackageGradle; 89const withPackageRefactor = config => { 90 return (0, _withDangerousMod().withDangerousMod)(config, ['android', async config => { 91 await renamePackageOnDisk(config, config.modRequest.projectRoot); 92 return config; 93 }]); 94}; 95exports.withPackageRefactor = withPackageRefactor; 96function getPackage(config) { 97 var _config$android$packa, _config$android; 98 return (_config$android$packa = (_config$android = config.android) === null || _config$android === void 0 ? void 0 : _config$android.package) !== null && _config$android$packa !== void 0 ? _config$android$packa : null; 99} 100function getPackageRoot(projectRoot, type) { 101 return _path().default.join(projectRoot, 'android', 'app', 'src', type, 'java'); 102} 103function getCurrentPackageName(projectRoot, packageRoot) { 104 const mainApplication = (0, _Paths().getProjectFilePath)(projectRoot, 'MainApplication'); 105 const packagePath = _path().default.dirname(mainApplication); 106 const packagePathParts = _path().default.relative(packageRoot, packagePath).split(_path().default.sep).filter(Boolean); 107 return packagePathParts.join('.'); 108} 109function getCurrentPackageForProjectFile(projectRoot, packageRoot, fileName, type) { 110 const filePath = (0, _glob().sync)(_path().default.join(projectRoot, `android/app/src/${type}/java/**/${fileName}.@(java|kt)`))[0]; 111 if (!filePath) { 112 return null; 113 } 114 const packagePath = _path().default.dirname(filePath); 115 const packagePathParts = _path().default.relative(packageRoot, packagePath).split(_path().default.sep).filter(Boolean); 116 return packagePathParts.join('.'); 117} 118function getCurrentPackageNameForType(projectRoot, type) { 119 const packageRoot = getPackageRoot(projectRoot, type); 120 if (type === 'main') { 121 return getCurrentPackageName(projectRoot, packageRoot); 122 } 123 // debug, etc.. 124 return getCurrentPackageForProjectFile(projectRoot, packageRoot, '*', type); 125} 126 127// NOTE(brentvatne): this assumes that our MainApplication.java file is in the root of the package 128// this makes sense for standard react-native projects but may not apply in customized projects, so if 129// we want this to be runnable in any app we need to handle other possibilities 130async function renamePackageOnDisk(config, projectRoot) { 131 const newPackageName = getPackage(config); 132 if (newPackageName === null) { 133 return; 134 } 135 for (const type of ['debug', 'main', 'release']) { 136 await renameJniOnDiskForType({ 137 projectRoot, 138 type, 139 packageName: newPackageName 140 }); 141 await renamePackageOnDiskForType({ 142 projectRoot, 143 type, 144 packageName: newPackageName 145 }); 146 } 147} 148async function renameJniOnDiskForType({ 149 projectRoot, 150 type, 151 packageName 152}) { 153 if (!packageName) { 154 return; 155 } 156 const currentPackageName = getCurrentPackageNameForType(projectRoot, type); 157 if (!currentPackageName || !packageName || currentPackageName === packageName) { 158 return; 159 } 160 const jniRoot = _path().default.join(projectRoot, 'android', 'app', 'src', type, 'jni'); 161 const filesToUpdate = [...(0, _glob().sync)('**/*', { 162 cwd: jniRoot, 163 absolute: true 164 })]; 165 // Replace all occurrences of the path in the project 166 filesToUpdate.forEach(filepath => { 167 try { 168 if (_fs().default.lstatSync(filepath).isFile() && ['.h', '.cpp'].includes(_path().default.extname(filepath))) { 169 let contents = _fs().default.readFileSync(filepath).toString(); 170 contents = contents.replace(new RegExp(transformJavaClassDescriptor(currentPackageName).replace(/\//g, '\\/'), 'g'), transformJavaClassDescriptor(packageName)); 171 _fs().default.writeFileSync(filepath, contents); 172 } 173 } catch { 174 debug(`Error updating "${filepath}" for type "${type}"`); 175 } 176 }); 177} 178async function renamePackageOnDiskForType({ 179 projectRoot, 180 type, 181 packageName 182}) { 183 if (!packageName) { 184 return; 185 } 186 const currentPackageName = getCurrentPackageNameForType(projectRoot, type); 187 debug(`Found package "${currentPackageName}" for type "${type}"`); 188 if (!currentPackageName || currentPackageName === packageName) { 189 return; 190 } 191 debug(`Refactor "${currentPackageName}" to "${packageName}" for type "${type}"`); 192 const packageRoot = getPackageRoot(projectRoot, type); 193 // Set up our paths 194 if (!(await (0, _modules().directoryExistsAsync)(packageRoot))) { 195 debug(`- skipping refactor of missing directory: ${packageRoot}`); 196 return; 197 } 198 const currentPackagePath = _path().default.join(packageRoot, ...currentPackageName.split('.')); 199 const newPackagePath = _path().default.join(packageRoot, ...packageName.split('.')); 200 201 // Create the new directory 202 _fs().default.mkdirSync(newPackagePath, { 203 recursive: true 204 }); 205 206 // Move everything from the old directory over 207 (0, _glob().sync)('**/*', { 208 cwd: currentPackagePath 209 }).forEach(relativePath => { 210 const filepath = _path().default.join(currentPackagePath, relativePath); 211 if (_fs().default.lstatSync(filepath).isFile()) { 212 moveFileSync(filepath, _path().default.join(newPackagePath, relativePath)); 213 } else { 214 _fs().default.mkdirSync(filepath, { 215 recursive: true 216 }); 217 } 218 }); 219 220 // Remove the old directory recursively from com/old/package to com/old and com, 221 // as long as the directories are empty 222 const oldPathParts = currentPackageName.split('.'); 223 while (oldPathParts.length) { 224 const pathToCheck = _path().default.join(packageRoot, ...oldPathParts); 225 try { 226 const files = _fs().default.readdirSync(pathToCheck); 227 if (files.length === 0) { 228 _fs().default.rmdirSync(pathToCheck); 229 } 230 } finally { 231 oldPathParts.pop(); 232 } 233 } 234 const filesToUpdate = [...(0, _glob().sync)('**/*', { 235 cwd: newPackagePath, 236 absolute: true 237 })]; 238 // Only update the BUCK file to match the main package name 239 if (type === 'main') { 240 // NOTE(EvanBacon): We dropped this file in SDK 48 but other templates may still use it. 241 filesToUpdate.push(_path().default.join(projectRoot, 'android', 'app', 'BUCK')); 242 } 243 // Replace all occurrences of the path in the project 244 filesToUpdate.forEach(filepath => { 245 try { 246 if (_fs().default.lstatSync(filepath).isFile()) { 247 let contents = _fs().default.readFileSync(filepath).toString(); 248 contents = contents.replace(new RegExp(currentPackageName, 'g'), packageName); 249 if (['.h', '.cpp'].includes(_path().default.extname(filepath))) { 250 contents = contents.replace(new RegExp(transformJavaClassDescriptor(currentPackageName).replace(/\//g, '\\'), 'g'), transformJavaClassDescriptor(packageName)); 251 } 252 _fs().default.writeFileSync(filepath, contents); 253 } 254 } catch { 255 debug(`Error updating "${filepath}" for type "${type}"`); 256 } 257 }); 258} 259function moveFileSync(src, dest) { 260 _fs().default.mkdirSync(_path().default.dirname(dest), { 261 recursive: true 262 }); 263 _fs().default.renameSync(src, dest); 264} 265function setPackageInBuildGradle(config, buildGradle) { 266 const packageName = getPackage(config); 267 if (packageName === null) { 268 return buildGradle; 269 } 270 const pattern = new RegExp(`(applicationId|namespace) ['"].*['"]`, 'g'); 271 return buildGradle.replace(pattern, `$1 '${packageName}'`); 272} 273async function getApplicationIdAsync(projectRoot) { 274 var _matchResult$; 275 const buildGradlePath = (0, _Paths().getAppBuildGradleFilePath)(projectRoot); 276 if (!_fs().default.existsSync(buildGradlePath)) { 277 return null; 278 } 279 const buildGradle = await _fs().default.promises.readFile(buildGradlePath, 'utf8'); 280 const matchResult = buildGradle.match(/applicationId ['"](.*)['"]/); 281 // TODO add fallback for legacy cases to read from AndroidManifest.xml 282 return (_matchResult$ = matchResult === null || matchResult === void 0 ? void 0 : matchResult[1]) !== null && _matchResult$ !== void 0 ? _matchResult$ : null; 283} 284 285/** 286 * Transform a java package name to java class descriptor, 287 * e.g. `com.helloworld` -> `Lcom/helloworld`. 288 */ 289function transformJavaClassDescriptor(packageName) { 290 return `L${packageName.replace(/\./g, '/')}`; 291} 292//# sourceMappingURL=Package.js.map