From 764bd897d86520136e578e1fd50e20cf919557f7 Mon Sep 17 00:00:00 2001 From: jcesarmobile Date: Wed, 2 Sep 2026 17:02:30 +0200 Subject: [PATCH 1/2] fix: remove AGP 9 property shims and jcenter() --- src/index.ts | 116 ++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 97 insertions(+), 19 deletions(-) diff --git a/src/index.ts b/src/index.ts index 12fa32d..ff9d53b 100644 --- a/src/index.ts +++ b/src/index.ts @@ -57,6 +57,23 @@ const variables = { kotlinxCoroutinesVersion: '1.11.0', }; +// AGP 9 changed the defaults of these properties and Android Studio's AGP Upgrade Assistant +// writes them into gradle.properties as compatibility shims. Capacitor apps need none of them, +// most are deprecated and will be removed in AGP 10, and some (android.builtInKotlin, +// android.sdk.defaultTargetSdkToCompileSdkIfUnset) break a Capacitor 9 build. +const agpMigrationAssistantProperties = [ + 'android.builtInKotlin', + 'android.defaults.buildfeatures.resvalues', + 'android.dependency.useConstraints', + 'android.enableAppCompileTimeRClass', + 'android.newDsl', + 'android.r8.optimizedResourceShrinking', + 'android.r8.strictFullModeForKeepRules', + 'android.sdk.defaultTargetSdkToCompileSdkIfUnset', + 'android.uniquePackageNames', + 'android.usesSdkInManifest.disallowed', +]; + process.on('unhandledRejection', (error) => { process.stderr.write(`ERR: ${error}\n`); process.exit(1); @@ -183,6 +200,15 @@ export const run = async (): Promise => { logger.info('Updating Android files'); logger.info('Updating gradle files'); + const buildGradle = join(androidDir, 'build.gradle'); + + let gradleText = readFileSync(buildGradle, 'utf-8'); + gradleText = gradleText.replace(/\s*jcenter\(\)/g, ''); + writeFileSync(buildGradle, gradleText, { encoding: 'utf-8' }); + + // gradle.properties + await updateGradleProperties(join(androidDir, 'gradle.properties')); + await runCommand( './gradlew', ['wrapper', '--distribution-type', 'all', '--gradle-version', gradleVersion, '--warning-mode', 'all'], @@ -206,7 +232,7 @@ export const run = async (): Promise => { 'com.android.tools.build:gradle': AGPVersion, 'com.google.gms:google-services': gmsVersion, }; - await updateBuildGradle(join(androidDir, 'build.gradle'), variablesAndClasspaths); + await updateBuildGradle(buildGradle, variablesAndClasspaths); } } @@ -230,7 +256,10 @@ export const run = async (): Promise => { ` from: "${coreVersion}"`, ); let packageSwiftText = readFileSync(packageSwift, 'utf-8'); - packageSwiftText = packageSwiftText.replace(/^[ \t]*\.product\(name:\s*"Cordova",\s*package:\s*"capacitor-swift-pm"\),?\n?/m, ''); + packageSwiftText = packageSwiftText.replace( + /^[ \t]*\.product\(name:\s*"Cordova",\s*package:\s*"capacitor-swift-pm"\),?\n?/m, + '', + ); writeFileSync(packageSwift, packageSwiftText, { encoding: 'utf-8' }); await updatePodspec(dir, pluginJSON); } @@ -241,10 +270,38 @@ export const run = async (): Promise => { if (prettierUpdatedFromV2) { logger.info(''); logger.info('⚠️ Note: Prettier has been updated from v2 to v3.'); - logger.info('We recommend running your formatting and linting scripts to ensure your codebase is formatted correctly.'); + logger.info( + 'We recommend running your formatting and linting scripts to ensure your codebase is formatted correctly.', + ); } }; +async function updateGradleProperties(filename: string): Promise { + const txt = readFile(filename); + if (!txt) { + return; + } + + const replaced = removeAGPMigrationProperties(txt); + if (replaced !== txt) { + writeFileSync(filename, replaced, 'utf-8'); + } +} + +function removeAGPMigrationProperties(txt: string): string { + return txt + .split('\n') + .filter((line) => { + const property = line.split('=')[0].trim(); + if (!agpMigrationAssistantProperties.includes(property)) { + return true; + } + logger.info(`Removed ${property} from gradle.properties.`); + return false; + }) + .join('\n'); +} + function updatePodspec(dir: string, pluginJSON: any) { const podspecFile = pluginJSON.files.find((file: string) => file.includes('.podspec')); let txt = readFile(join(dir, podspecFile)); @@ -252,7 +309,7 @@ function updatePodspec(dir: string, pluginJSON: any) { return false; } txt = txt.replace('s.ios.deployment_target =', 's.ios.deployment_target ='); - const prevIOS = Number(iOSVersion)-1; + const prevIOS = Number(iOSVersion) - 1; txt = txt.replace(`s.ios.deployment_target = '${prevIOS}.0'`, `s.ios.deployment_target = '${iOSVersion}.0'`); writeFileSync(podspecFile, txt, { encoding: 'utf-8' }); } @@ -318,28 +375,49 @@ async function updateBuildGradle( gradleFile = updateDeprecatedPropertySyntax(gradleFile); gradleFile = updateKotlinOptions(gradleFile); - gradleFile = gradleFile.replace(/^\s*ext\.kotlin_version = project\.hasProperty\("kotlin_version"\) \? rootProject\.ext\.kotlin_version : '\d+\.\d+\.\d+'\n?/m, ''); - gradleFile = gradleFile.replace(/^\s*ext \{\n\s*kotlin_version = project\.hasProperty\("kotlin_version"\) \? rootProject\.ext\.kotlin_version : '[\d.]+'\n\s*\}\n?/gm, ''); - gradleFile = gradleFile.replace(/^\s*classpath "org\.jetbrains\.kotlin:kotlin-gradle-plugin:\$kotlin_version"\n?/m, ''); - gradleFile = gradleFile.replace(`apply plugin: 'kotlin-android'\n`,''); + gradleFile = gradleFile.replace( + /^\s*ext\.kotlin_version = project\.hasProperty\("kotlin_version"\) \? rootProject\.ext\.kotlin_version : '\d+\.\d+\.\d+'\n?/m, + '', + ); + gradleFile = gradleFile.replace( + /^\s*ext \{\n\s*kotlin_version = project\.hasProperty\("kotlin_version"\) \? rootProject\.ext\.kotlin_version : '[\d.]+'\n\s*\}\n?/gm, + '', + ); + gradleFile = gradleFile.replace( + /^\s*classpath "org\.jetbrains\.kotlin:kotlin-gradle-plugin:\$kotlin_version"\n?/m, + '', + ); + if (!gradleFile.includes(`project.extensions.findByName('kotlin')`)) { + gradleFile = gradleFile.replace(`apply plugin: 'kotlin-android'\n`, ''); + } else { + gradleFile = gradleFile.replace( + /\s*if\s*\(\s*project\.extensions\.findByName\('kotlin'\)\s*==\s*null\s*\)\s*\{\s*apply\s+plugin:\s*'kotlin-android'\s*\}*/gm, + '', + ); + } + gradleFile = gradleFile.replace(`apply plugin: 'org.jetbrains.kotlin.android'\n`, ''); - gradleFile = gradleFile.replace(/^\s*implementation "org\.jetbrains\.kotlin:kotlin-stdlib:\$kotlin_version"\n?/gm, '') - gradleFile = gradleFile.replace(/^\s*targetSdkVersion project\.hasProperty\('targetSdkVersion'\) \? rootProject\.ext\.targetSdkVersion : \d+\n?/m, ''); - gradleFile = gradleFile.replace(`implementation "androidx.core:core-ktx:$androidxCoreVersion"`, `implementation "androidx.core:core:$androidxCoreVersion"`) + gradleFile = gradleFile.replace( + /^\s*implementation "org\.jetbrains\.kotlin:kotlin-stdlib:\$kotlin_version"\n?/gm, + '', + ); + gradleFile = gradleFile.replace( + /^\s*targetSdkVersion project\.hasProperty\('targetSdkVersion'\) \? rootProject\.ext\.targetSdkVersion : \d+\n?/m, + '', + ); + gradleFile = gradleFile.replace( + `implementation "androidx.core:core-ktx:$androidxCoreVersion"`, + `implementation "androidx.core:core:$androidxCoreVersion"`, + ); if (gradleFile.includes(`androidx.core:core-ktx:1`)) { - gradleFile = setAllStringIn(gradleFile, `androidx.core:core`, `'`, `:${variables.androidxCoreVersion}`) + gradleFile = setAllStringIn(gradleFile, `androidx.core:core`, `'`, `:${variables.androidxCoreVersion}`); } writeFileSync(filename, gradleFile, 'utf-8'); } function updateDeprecatedPropertySyntax(gradleFile: string): string { - const propertiesToUpdate = [ - 'namespace', - 'compileSdk', - 'url', - 'abortOnError', - ]; + const propertiesToUpdate = ['namespace', 'compileSdk', 'url', 'abortOnError']; let result = gradleFile; @@ -376,7 +454,7 @@ function updateKotlinOptions(gradleFile: string): string { } } - result = result.replace(/\n\s*kotlinOptions\s*\{[\s\S]*?\}\s*\n/g, '\n'); + result = result.replace(/\n\s*kotlinOptions\s*\{[\s\S]*?\}\s*\n/g, '\n'); const kotlinBlockRegex = /\nkotlin\s*\{([^}]*(?:\{[^}]*\}[^}]*)*)\}/; const kotlinBlockMatch = kotlinBlockRegex.exec(result); From 46e18c15ac1609b26b2105253e110a12b1d49c1c Mon Sep 17 00:00:00 2001 From: jcesarmobile Date: Wed, 2 Sep 2026 18:31:16 +0200 Subject: [PATCH 2/2] proguard --- src/index.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/index.ts b/src/index.ts index ff9d53b..dec9af6 100644 --- a/src/index.ts +++ b/src/index.ts @@ -204,6 +204,7 @@ export const run = async (): Promise => { let gradleText = readFileSync(buildGradle, 'utf-8'); gradleText = gradleText.replace(/\s*jcenter\(\)/g, ''); + gradleText = gradleText.replace(`proguard-android.txt`, `proguard-android-optimize.txt`); writeFileSync(buildGradle, gradleText, { encoding: 'utf-8' }); // gradle.properties