@capacitor/plugin-migration-v5-to-v6
Version:
Utility to help migrate Capacitor 5 plugins to Capacitor 6
259 lines (258 loc) • 11.8 kB
JavaScript
;
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' });
}