UNPKG

@capacitor/plugin-migration-v5-to-v6

Version:

Utility to help migrate Capacitor 5 plugins to Capacitor 6

259 lines (258 loc) 11.8 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.run = void 0; const utils_fs_1 = require("@ionic/utils-fs"); const path_1 = require("path"); const rimraf_1 = require("rimraf"); const log_1 = require("./log"); const subprocess_1 = require("./subprocess"); const coreVersion = '^6.0.0'; const gradleVersion = '8.2.1'; const AGPVersion = '8.2.1'; const gmsVersion = '4.4.0'; const kotlinVersion = '1.9.10'; const eslintVersion = '^8.57.0'; const ionicEslintVersion = '^0.4.0'; const variables = { minSdkVersion: 22, compileSdkVersion: 34, targetSdkVersion: 34, androidxActivityVersion: '1.8.0', androidxAppCompatVersion: '1.6.1', androidxCoordinatorLayoutVersion: '1.2.0', androidxCoreVersion: '1.12.0', androidxFragmentVersion: '1.6.2', firebaseMessagingVersion: '23.3.1', playServicesLocationVersion: '21.1.0', androidxBrowserVersion: '1.7.0', androidxMaterialVersion: '1.10.0', androidxExifInterfaceVersion: '1.3.6', androidxCoreKTXVersion: '1.12.0', googleMapsPlayServicesVersion: '18.2.0', googleMapsUtilsVersion: '3.8.2', googleMapsKtxVersion: '5.0.0', googleMapsUtilsKtxVersion: '5.0.0', kotlinxCoroutinesVersion: '1.7.3', coreSplashScreenVersion: '1.0.1', androidxWebkitVersion: '1.9.0', junitVersion: '4.13.2', androidxJunitVersion: '1.1.5', androidxEspressoCoreVersion: '3.5.1', }; process.on('unhandledRejection', (error) => { process.stderr.write(`ERR: ${error}\n`); process.exit(1); }); const run = async () => { const dir = process.cwd(); const opts = { cwd: dir, stdio: 'inherit' }; const packageJson = (0, path_1.join)(dir, 'package.json'); const pluginJSON = await (0, utils_fs_1.readJSON)(packageJson); for (const dep of ['@capacitor/ios', '@capacitor/android', '@capacitor/core', '@capacitor/cli']) { if (pluginJSON.devDependencies?.[dep]) { pluginJSON.devDependencies[dep] = coreVersion; } if (pluginJSON.dependencies?.[dep]) { pluginJSON.dependencies[dep] = coreVersion; } if (pluginJSON.peerDependencies?.[dep]) { pluginJSON.peerDependencies[dep] = coreVersion; } } if (pluginJSON.devDependencies?.['@ionic/eslint-config']) { pluginJSON.devDependencies['@ionic/eslint-config'] = ionicEslintVersion; if (pluginJSON.devDependencies?.['eslint']) { pluginJSON.devDependencies['eslint'] = eslintVersion; } } if (pluginJSON.version.startsWith('5.')) { pluginJSON.version = '6.0.0'; } await (0, utils_fs_1.writeJSON)(packageJson, pluginJSON, { spaces: 2 }); rimraf_1.rimraf.sync((0, path_1.join)(dir, 'node_modules/@capacitor')); rimraf_1.rimraf.sync((0, path_1.join)(dir, 'package-lock.json')); try { await (0, subprocess_1.runCommand)('npm', ['install'], { ...opts, cwd: dir, }); } catch (e) { log_1.logger.warn('npm install failed, please, install the dependencies using your package manager of choice'); } if (pluginJSON.capacitor?.android?.src) { const androidDir = (0, path_1.resolve)(dir, pluginJSON.capacitor.android.src); if (await (0, utils_fs_1.pathExists)(androidDir)) { log_1.logger.info('Updating Android files'); updateGradleProperties((0, path_1.join)(androidDir, 'gradle.properties')); const variablesAndClasspaths = { variables: variables, 'com.android.tools.build:gradle': AGPVersion, 'com.google.gms:google-services': gmsVersion, }; await updateBuildGradle((0, path_1.join)(androidDir, 'build.gradle'), variablesAndClasspaths); await movePackageFromManifestToBuildGradle((0, path_1.join)(androidDir, 'src', 'main', 'AndroidManifest.xml'), (0, path_1.join)(androidDir, 'build.gradle')); updateGradleWrapper((0, path_1.join)(androidDir, 'gradle', 'wrapper', 'gradle-wrapper.properties')); log_1.logger.info('Updating gradle files'); await (0, subprocess_1.runCommand)('./gradlew', ['wrapper', '--distribution-type', 'all', '--gradle-version', gradleVersion, '--warning-mode', 'all'], { ...opts, cwd: androidDir, }); } } log_1.logger.info('Plugin migrated to Capacitor 6!'); }; exports.run = run; async function updateBuildGradle(filename, variablesAndClasspaths) { let gradleFile = readFile(filename); if (!gradleFile) { return; } gradleFile = gradleFile.replaceAll(' = ', ' = '); log_1.logger.info('Updating build.gradle'); gradleFile = setAllStringIn(gradleFile, `sourceCompatibility JavaVersion.`, `\n`, `VERSION_17`); gradleFile = setAllStringIn(gradleFile, `targetCompatibility JavaVersion.`, `\n`, `VERSION_17`); const neededDeps = { 'com.android.tools.build:gradle': variablesAndClasspaths['com.android.tools.build:gradle'], 'com.google.gms:google-services': variablesAndClasspaths['com.google.gms:google-services'], }; for (const dep of Object.keys(neededDeps)) { if (gradleFile.includes(`classpath '${dep}`)) { const semver = await Promise.resolve().then(() => __importStar(require('semver'))); const firstIndex = gradleFile.indexOf(dep) + dep.length + 1; const existingVersion = '' + gradleFile.substring(firstIndex, gradleFile.indexOf("'", firstIndex)); if (semver.gte(neededDeps[dep], existingVersion)) { gradleFile = setAllStringIn(gradleFile, `classpath '${dep}:`, `'`, neededDeps[dep]); log_1.logger.info(`Set ${dep} = ${neededDeps[dep]}.`); } } } for (const [dep, depValue] of Object.entries(variablesAndClasspaths.variables)) { let depString = `${dep} = project.hasProperty('${dep}') ? rootProject.ext.${dep} : '`; let depValueString = depValue; let endString = `'`; if (typeof depValue === 'number') { depString = `${dep} project.hasProperty('${dep}') ? rootProject.ext.${dep} : `; depValueString = depValue.toString(); endString = '\n'; } if (gradleFile.includes(depString) && typeof depValueString === 'string') { const semver = await Promise.resolve().then(() => __importStar(require('semver'))); const firstIndex = gradleFile.indexOf(depString) + depString.length; const existingVersion = '' + gradleFile.substring(firstIndex, gradleFile.indexOf(endString, firstIndex)); if ((semver.valid(depValueString) && semver.gte(depValueString, existingVersion)) || (!semver.valid(depValueString) && depValue > Number(existingVersion))) { gradleFile = setAllStringIn(gradleFile, depString, endString, depValueString); log_1.logger.info(`Set ${dep} = ${depValueString}.`); } } } gradleFile = setAllStringIn(gradleFile, `ext.kotlin_version = `, `\n`, `project.hasProperty("kotlin_version") ? rootProject.ext.kotlin_version : '${kotlinVersion}'`); gradleFile = setAllStringIn(gradleFile, `implementation "org.jetbrains.kotlin:kotlin-stdlib`, `"`, `:$kotlin_version`); const compileSdk = `compileSdkVersion project.hasProperty`; if (gradleFile.includes(compileSdk)) { log_1.logger.info('Replacing deprecated compileSdkVersion from build.gradle'); gradleFile = gradleFile.replace(compileSdk, `compileSdk project.hasProperty`); } (0, utils_fs_1.writeFileSync)(filename, gradleFile, 'utf-8'); } async function updateGradleWrapper(filename) { const txt = readFile(filename); if (!txt) { return; } log_1.logger.info('Updating gradle wrapper file'); const replaced = setAllStringIn(txt, 'distributionUrl=', '\n', // eslint-disable-next-line no-useless-escape `https\\://services.gradle.org/distributions/gradle-${gradleVersion}-all.zip`); (0, utils_fs_1.writeFileSync)(filename, replaced, 'utf-8'); } function readFile(filename) { try { if (!(0, utils_fs_1.existsSync)(filename)) { log_1.logger.error(`Unable to find ${filename}. Try updating it manually`); return; } return (0, utils_fs_1.readFileSync)(filename, 'utf-8'); } catch (err) { log_1.logger.error(`Unable to read ${filename}. Verify it is not already open. ${err}`); } } function setAllStringIn(data, start, end, replacement) { let position = 0; let result = data; let replaced = true; while (replaced) { const foundIdx = result.indexOf(start, position); if (foundIdx == -1) { replaced = false; } else { const idx = foundIdx + start.length; position = idx + replacement.length; result = result.substring(0, idx) + replacement + result.substring(result.indexOf(end, idx)); } } return result; } async function movePackageFromManifestToBuildGradle(manifestFilename, buildGradleFilename) { const manifestText = readFile(manifestFilename); const buildGradleText = readFile(buildGradleFilename); if (!manifestText) { log_1.logger.error(`Could not read ${manifestFilename}. Check its permissions and if it exists.`); return; } if (!buildGradleText) { log_1.logger.error(`Could not read ${buildGradleFilename}. Check its permissions and if it exists.`); return; } const namespaceExists = new RegExp(/\s+namespace\s+/).test(buildGradleText); if (namespaceExists) { return; } let packageName; const manifestRegEx = new RegExp(/package="([^"]+)"/); const manifestResults = manifestRegEx.exec(manifestText); if (manifestResults === null) { log_1.logger.error(`Unable to update Android Manifest. Package not found.`); return; } else { packageName = manifestResults[1]; } let manifestReplaced = manifestText; manifestReplaced = manifestReplaced.replace(manifestRegEx, ''); manifestReplaced = manifestReplaced.replace(` \n`, '\n'); if (manifestText == manifestReplaced) { log_1.logger.error(`Unable to update Android Manifest: no changes were detected in Android Manifest file`); return; } let buildGradleReplaced = buildGradleText; buildGradleReplaced = setAllStringIn(buildGradleText, 'android {', '\n', `\n namespace "${packageName}"`); if (buildGradleText == buildGradleReplaced) { log_1.logger.error(`Unable to update buildGradleText: no changes were detected in Android Manifest file`); return; } log_1.logger.info('Moving package from AndroidManifest.xml to build.gradle'); (0, utils_fs_1.writeFileSync)(manifestFilename, manifestReplaced, 'utf-8'); (0, utils_fs_1.writeFileSync)(buildGradleFilename, buildGradleReplaced, 'utf-8'); } async function updateGradleProperties(filename) { const txt = readFile(filename); if (!txt?.includes('android.enableJetifier=true')) { return; } log_1.logger.info('Remove android.enableJetifier=true from gradle.properties'); const lines = txt.split('\n'); let linesToKeep = ''; for (const line of lines) { // check for enableJetifier const jetifierMatch = line.match(/android\.enableJetifier\s*=\s*true/) || []; const commentMatch = line.match(/# Automatically convert third-party libraries to use AndroidX/) || []; if (jetifierMatch.length == 0 && commentMatch.length == 0) { linesToKeep += line + '\n'; } } (0, utils_fs_1.writeFileSync)(filename, linesToKeep, { encoding: 'utf-8' }); }