android-wrapper/@capacitor/cli/dist/android/update.js

319 lines
16 KiB
JavaScript

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.handleCordovaPluginsGradle = exports.installGradlePlugins = exports.updateAndroid = void 0;
const tslib_1 = require("tslib");
const debug_1 = tslib_1.__importDefault(require("debug"));
const fs_extra_1 = require("fs-extra");
const path_1 = require("path");
const colors_1 = tslib_1.__importDefault(require("../colors"));
const common_1 = require("../common");
const cordova_1 = require("../cordova");
const errors_1 = require("../errors");
const plugin_1 = require("../plugin");
const copy_1 = require("../tasks/copy");
const migrate_1 = require("../tasks/migrate");
const fs_1 = require("../util/fs");
const node_1 = require("../util/node");
const template_1 = require("../util/template");
const common_2 = require("./common");
const platform = 'android';
const debug = (0, debug_1.default)('capacitor:android:update');
async function updateAndroid(config) {
var _a;
const plugins = await getPluginsTask(config);
const capacitorPlugins = plugins.filter((p) => (0, plugin_1.getPluginType)(p, platform) === 0 /* PluginType.Core */);
(0, plugin_1.printPlugins)(capacitorPlugins, 'android');
await writePluginsJson(config, capacitorPlugins);
await removePluginsNativeFiles(config);
const cordovaPlugins = plugins.filter((p) => (0, plugin_1.getPluginType)(p, platform) === 1 /* PluginType.Cordova */);
await (0, migrate_1.patchOldCapacitorPlugins)(config);
if (cordovaPlugins.length > 0) {
await copyPluginsNativeFiles(config, cordovaPlugins);
}
if (!(await (0, fs_extra_1.pathExists)(config.android.webDirAbs))) {
await (0, copy_1.copy)(config, platform);
}
await (0, cordova_1.handleCordovaPluginsJS)(cordovaPlugins, config, platform);
await (0, cordova_1.checkPluginDependencies)(plugins, platform, (_a = config.app.extConfig.cordova) === null || _a === void 0 ? void 0 : _a.failOnUninstalledPlugins);
await installGradlePlugins(config, capacitorPlugins, cordovaPlugins);
await handleCordovaPluginsGradle(config, cordovaPlugins);
await (0, cordova_1.writeCordovaAndroidManifest)(cordovaPlugins, config, platform);
const incompatibleCordovaPlugins = plugins.filter((p) => (0, plugin_1.getPluginType)(p, platform) === 2 /* PluginType.Incompatible */);
(0, plugin_1.printPlugins)(incompatibleCordovaPlugins, platform, 'incompatible');
await (0, common_1.checkPlatformVersions)(config, platform);
}
exports.updateAndroid = updateAndroid;
function getGradlePackageName(id) {
return id.replace('@', '').replace('/', '-');
}
async function writePluginsJson(config, plugins) {
const classes = await findAndroidPluginClasses(plugins);
const pluginsJsonPath = (0, path_1.resolve)(config.android.assetsDirAbs, 'capacitor.plugins.json');
await (0, fs_extra_1.writeJSON)(pluginsJsonPath, classes, { spaces: '\t' });
}
async function findAndroidPluginClasses(plugins) {
const entries = [];
for (const plugin of plugins) {
entries.push(...(await findAndroidPluginClassesInPlugin(plugin)));
}
return entries;
}
async function findAndroidPluginClassesInPlugin(plugin) {
if (!plugin.android || (0, plugin_1.getPluginType)(plugin, platform) !== 0 /* PluginType.Core */) {
return [];
}
const srcPath = (0, path_1.resolve)(plugin.rootPath, plugin.android.path, 'src/main');
const srcFiles = await (0, fs_1.readdirp)(srcPath, {
filter: (entry) => !entry.stats.isDirectory() && ['.java', '.kt'].includes((0, path_1.extname)(entry.path)),
});
const classRegex = /^@(?:CapacitorPlugin|NativePlugin)[\s\S]+?class ([\w]+)/gm;
const packageRegex = /^package ([\w.]+);?$/gm;
debug('Searching %O source files in %O by %O regex', srcFiles.length, srcPath, classRegex);
const entries = await Promise.all(srcFiles.map(async (srcFile) => {
const srcFileContents = await (0, fs_extra_1.readFile)(srcFile, { encoding: 'utf-8' });
classRegex.lastIndex = 0;
const classMatch = classRegex.exec(srcFileContents);
if (classMatch) {
const className = classMatch[1];
debug('Searching %O for package by %O regex', srcFile, packageRegex);
packageRegex.lastIndex = 0;
const packageMatch = packageRegex.exec(srcFileContents.substring(0, classMatch.index));
if (!packageMatch) {
(0, errors_1.fatal)(`Package could not be parsed from Android plugin.\n` + `Location: ${colors_1.default.strong(srcFile)}`);
}
const packageName = packageMatch[1];
const classpath = `${packageName}.${className}`;
debug('%O is a suitable plugin class', classpath);
return {
pkg: plugin.id,
classpath,
};
}
}));
return entries.filter((entry) => !!entry);
}
async function installGradlePlugins(config, capacitorPlugins, cordovaPlugins) {
const capacitorAndroidPackagePath = (0, node_1.resolveNode)(config.app.rootDir, '@capacitor/android', 'package.json');
if (!capacitorAndroidPackagePath) {
(0, errors_1.fatal)(`Unable to find ${colors_1.default.strong('node_modules/@capacitor/android')}.\n` +
`Are you sure ${colors_1.default.strong('@capacitor/android')} is installed?`);
}
const capacitorAndroidPath = (0, path_1.resolve)((0, path_1.dirname)(capacitorAndroidPackagePath), 'capacitor');
const settingsPath = config.android.platformDirAbs;
const dependencyPath = config.android.appDirAbs;
const relativeCapcitorAndroidPath = (0, fs_1.convertToUnixPath)((0, path_1.relative)(settingsPath, capacitorAndroidPath));
const settingsLines = `// DO NOT EDIT THIS FILE! IT IS GENERATED EACH TIME "capacitor update" IS RUN
include ':capacitor-android'
project(':capacitor-android').projectDir = new File('${relativeCapcitorAndroidPath}')
${capacitorPlugins
.map((p) => {
if (!p.android) {
return '';
}
const relativePluginPath = (0, fs_1.convertToUnixPath)((0, path_1.relative)(settingsPath, p.rootPath));
return `
include ':${getGradlePackageName(p.id)}'
project(':${getGradlePackageName(p.id)}').projectDir = new File('${relativePluginPath}/${p.android.path}')
`;
})
.join('')}`;
const applyArray = [];
const frameworksArray = [];
let prefsArray = [];
cordovaPlugins.map((p) => {
const relativePluginPath = (0, fs_1.convertToUnixPath)((0, path_1.relative)(dependencyPath, p.rootPath));
const frameworks = (0, plugin_1.getPlatformElement)(p, platform, 'framework');
frameworks.map((framework) => {
if (framework.$.custom &&
framework.$.custom === 'true' &&
framework.$.type &&
framework.$.type === 'gradleReference') {
applyArray.push(`apply from: "${relativePluginPath}/${framework.$.src}"`);
}
else if (!framework.$.type && !framework.$.custom) {
if (framework.$.src.startsWith('platform(')) {
frameworksArray.push(` implementation ${framework.$.src}`);
}
else {
frameworksArray.push(` implementation "${framework.$.src}"`);
}
}
});
prefsArray = prefsArray.concat((0, plugin_1.getAllElements)(p, platform, 'preference'));
});
let frameworkString = frameworksArray.join('\n');
frameworkString = await replaceFrameworkVariables(config, prefsArray, frameworkString);
const dependencyLines = `// DO NOT EDIT THIS FILE! IT IS GENERATED EACH TIME "capacitor update" IS RUN
android {
compileOptions {
sourceCompatibility JavaVersion.VERSION_21
targetCompatibility JavaVersion.VERSION_21
}
}
apply from: "../capacitor-cordova-android-plugins/cordova.variables.gradle"
dependencies {
${capacitorPlugins
.map((p) => {
return ` implementation project(':${getGradlePackageName(p.id)}')`;
})
.join('\n')}
${frameworkString}
}
${applyArray.join('\n')}
if (hasProperty('postBuildExtras')) {
postBuildExtras()
}
`;
await (0, fs_extra_1.writeFile)((0, path_1.join)(settingsPath, 'capacitor.settings.gradle'), settingsLines);
await (0, fs_extra_1.writeFile)((0, path_1.join)(dependencyPath, 'capacitor.build.gradle'), dependencyLines);
}
exports.installGradlePlugins = installGradlePlugins;
async function handleCordovaPluginsGradle(config, cordovaPlugins) {
var _a, _b, _c;
const pluginsGradlePath = (0, path_1.join)(config.android.cordovaPluginsDirAbs, 'build.gradle');
const kotlinNeeded = await kotlinNeededCheck(config, cordovaPlugins);
const kotlinVersionString = (_c = (_b = (_a = config.app.extConfig.cordova) === null || _a === void 0 ? void 0 : _a.preferences) === null || _b === void 0 ? void 0 : _b.GradlePluginKotlinVersion) !== null && _c !== void 0 ? _c : '1.9.25';
const frameworksArray = [];
let prefsArray = [];
const applyArray = [];
applyArray.push(`apply from: "cordova.variables.gradle"`);
cordovaPlugins.map((p) => {
const relativePluginPath = (0, fs_1.convertToUnixPath)((0, path_1.relative)(config.android.cordovaPluginsDirAbs, p.rootPath));
const frameworks = (0, plugin_1.getPlatformElement)(p, platform, 'framework');
frameworks.map((framework) => {
if (!framework.$.type && !framework.$.custom) {
frameworksArray.push(framework.$.src);
}
else if (framework.$.custom &&
framework.$.custom === 'true' &&
framework.$.type &&
framework.$.type === 'gradleReference') {
applyArray.push(`apply from: "${relativePluginPath}/${framework.$.src}"`);
}
});
prefsArray = prefsArray.concat((0, plugin_1.getAllElements)(p, platform, 'preference'));
});
let frameworkString = frameworksArray
.map((f) => {
if (f.startsWith('platform(')) {
return ` implementation ${f}`;
}
else {
return ` implementation "${f}"`;
}
})
.join('\n');
frameworkString = await replaceFrameworkVariables(config, prefsArray, frameworkString);
if (kotlinNeeded) {
frameworkString += `\n implementation "androidx.core:core-ktx:$androidxCoreKTXVersion"`;
frameworkString += `\n implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"`;
}
const applyString = applyArray.join('\n');
let buildGradle = await (0, fs_extra_1.readFile)(pluginsGradlePath, { encoding: 'utf-8' });
buildGradle = buildGradle.replace(/(SUB-PROJECT DEPENDENCIES START)[\s\S]*(\/\/ SUB-PROJECT DEPENDENCIES END)/, '$1\n' + frameworkString.concat('\n') + ' $2');
buildGradle = buildGradle.replace(/(PLUGIN GRADLE EXTENSIONS START)[\s\S]*(\/\/ PLUGIN GRADLE EXTENSIONS END)/, '$1\n' + applyString.concat('\n') + '$2');
if (kotlinNeeded) {
buildGradle = buildGradle.replace(/(buildscript\s{\n(\t|\s{4})repositories\s{\n((\t{2}|\s{8}).+\n)+(\t|\s{4})}\n(\t|\s{4})dependencies\s{\n(\t{2}|\s{8}).+)\n((\t|\s{4})}\n}\n)/, `$1\n classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"\n$8`);
buildGradle = buildGradle.replace(/(ext\s{)/, `$1\n androidxCoreKTXVersion = project.hasProperty('androidxCoreKTXVersion') ? rootProject.ext.androidxCoreKTXVersion : '1.8.0'`);
buildGradle = buildGradle.replace(/(buildscript\s{)/, `$1\n ext.kotlin_version = project.hasProperty('kotlin_version') ? rootProject.ext.kotlin_version : '${kotlinVersionString}'`);
buildGradle = buildGradle.replace(/(apply\splugin:\s'com\.android\.library')/, `$1\napply plugin: 'kotlin-android'`);
buildGradle = buildGradle.replace(/(compileOptions\s{\n((\t{2}|\s{8}).+\n)+(\t|\s{4})})\n(})/, `$1\n sourceSets {\n main.java.srcDirs += 'src/main/kotlin'\n }\n$5`);
}
await (0, fs_extra_1.writeFile)(pluginsGradlePath, buildGradle);
const cordovaVariables = `// DO NOT EDIT THIS FILE! IT IS GENERATED EACH TIME "capacitor update" IS RUN
ext {
cdvMinSdkVersion = project.hasProperty('minSdkVersion') ? rootProject.ext.minSdkVersion : ${config.android.minVersion}
// Plugin gradle extensions can append to this to have code run at the end.
cdvPluginPostBuildExtras = []
cordovaConfig = [:]
}`;
await (0, fs_extra_1.writeFile)((0, path_1.join)(config.android.cordovaPluginsDirAbs, 'cordova.variables.gradle'), cordovaVariables);
}
exports.handleCordovaPluginsGradle = handleCordovaPluginsGradle;
async function kotlinNeededCheck(config, cordovaPlugins) {
var _a, _b;
if (((_b = (_a = config.app.extConfig.cordova) === null || _a === void 0 ? void 0 : _a.preferences) === null || _b === void 0 ? void 0 : _b.GradlePluginKotlinEnabled) !== 'true') {
for (const plugin of cordovaPlugins) {
const androidPlatform = (0, plugin_1.getPluginPlatform)(plugin, platform);
const sourceFiles = androidPlatform['source-file'];
if (sourceFiles) {
for (const srcFile of sourceFiles) {
if (/^.*\.kt$/.test(srcFile['$'].src)) {
return true;
}
}
}
}
return false;
}
else {
return true;
}
}
async function copyPluginsNativeFiles(config, cordovaPlugins) {
const pluginsPath = (0, path_1.join)(config.android.cordovaPluginsDirAbs, 'src', 'main');
for (const p of cordovaPlugins) {
const androidPlatform = (0, plugin_1.getPluginPlatform)(p, platform);
if (androidPlatform) {
const sourceFiles = androidPlatform['source-file'];
if (sourceFiles) {
for (const sourceFile of sourceFiles) {
const fileName = sourceFile.$.src.split('/').pop();
let baseFolder = 'java/';
if (fileName.split('.').pop() === 'aidl') {
baseFolder = 'aidl/';
}
const target = sourceFile.$['target-dir'].replace('app/src/main/', '').replace('src/', baseFolder);
await (0, fs_extra_1.copy)((0, plugin_1.getFilePath)(config, p, sourceFile.$.src), (0, path_1.join)(pluginsPath, target, fileName));
}
}
const resourceFiles = androidPlatform['resource-file'];
if (resourceFiles) {
for (const resourceFile of resourceFiles) {
const target = resourceFile.$['target'];
if (resourceFile.$.src.split('.').pop() === 'aar') {
await (0, fs_extra_1.copy)((0, plugin_1.getFilePath)(config, p, resourceFile.$.src), (0, path_1.join)(pluginsPath, 'libs', target.split('/').pop()));
}
else if (target !== '.') {
await (0, fs_extra_1.copy)((0, plugin_1.getFilePath)(config, p, resourceFile.$.src), (0, path_1.join)(pluginsPath, target));
}
}
}
const libFiles = (0, plugin_1.getPlatformElement)(p, platform, 'lib-file');
for (const libFile of libFiles) {
await (0, fs_extra_1.copy)((0, plugin_1.getFilePath)(config, p, libFile.$.src), (0, path_1.join)(pluginsPath, 'libs', libFile.$.src.split('/').pop()));
}
}
}
}
async function removePluginsNativeFiles(config) {
await (0, fs_extra_1.remove)(config.android.cordovaPluginsDirAbs);
await (0, template_1.extractTemplate)(config.cli.assets.android.cordovaPluginsTemplateArchiveAbs, config.android.cordovaPluginsDirAbs);
}
async function getPluginsTask(config) {
return await (0, common_1.runTask)('Updating Android plugins', async () => {
const allPlugins = await (0, plugin_1.getPlugins)(config, 'android');
const androidPlugins = await (0, common_2.getAndroidPlugins)(allPlugins);
return androidPlugins;
});
}
async function getVariablesGradleFile(config) {
const variablesFile = (0, path_1.resolve)(config.android.platformDirAbs, 'variables.gradle');
let variablesGradle = '';
if (await (0, fs_extra_1.pathExists)(variablesFile)) {
variablesGradle = await (0, fs_extra_1.readFile)(variablesFile, { encoding: 'utf-8' });
}
return variablesGradle;
}
async function replaceFrameworkVariables(config, prefsArray, frameworkString) {
const variablesGradle = await getVariablesGradleFile(config);
prefsArray.map((preference) => {
if (!variablesGradle.includes(preference.$.name)) {
frameworkString = frameworkString.replace(new RegExp(('$' + preference.$.name).replace('$', '\\$&'), 'g'), preference.$.default);
}
});
return frameworkString;
}