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