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