@@ -3,16 +3,13 @@ import { join } from 'path';
33import { rimraf } from 'rimraf' ;
44import { coerce , gte , lt } from 'semver' ;
55
6- import { getAndroidPlugins } from '../android/common' ;
76import c from '../colors' ;
87import { getCoreVersion , runTask , checkJDKMajorVersion } from '../common' ;
98import type { Config } from '../definitions' ;
109import { fatal } from '../errors' ;
1110import { getMajoriOSVersion } from '../ios/common' ;
1211import { logger , logPrompt , logSuccess } from '../log' ;
13- import { getPlugins } from '../plugin' ;
1412import { deleteFolderRecursive } from '../util/fs' ;
15- import { resolveNode } from '../util/node' ;
1613import { checkPackageManager } from '../util/spm' ;
1714import { runCommand } from '../util/subprocess' ;
1815import { extractTemplate } from '../util/template' ;
@@ -46,10 +43,10 @@ const plugins = [
4643 '@capacitor/text-zoom' ,
4744 '@capacitor/toast' ,
4845] ;
49- const coreVersion = '^7.0.0 ' ;
50- const pluginVersion = '^7.0.0 ' ;
51- const gradleVersion = '8.11.1 ' ;
52- const iOSVersion = '14 ' ;
46+ const coreVersion = 'next ' ;
47+ const pluginVersion = 'next ' ;
48+ const gradleVersion = '8.14.3 ' ;
49+ const iOSVersion = '15 ' ;
5350let installFailed = false ;
5451
5552export async function migrateCommand ( config : Config , noprompt : boolean , packagemanager : string ) : Promise < void > {
@@ -58,14 +55,14 @@ export async function migrateCommand(config: Config, noprompt: boolean, packagem
5855 }
5956
6057 const capMajor = await checkCapacitorMajorVersion ( config ) ;
61- if ( capMajor < 6 ) {
62- fatal ( 'Migrate can only be used on Capacitor 6 , please use the CLI in Capacitor 6 to upgrade to 6 first' ) ;
58+ if ( capMajor < 7 ) {
59+ fatal ( 'Migrate can only be used on Capacitor 7 , please use the CLI in Capacitor 7 to upgrade to 7 first' ) ;
6360 }
6461
6562 const jdkMajor = await checkJDKMajorVersion ( ) ;
6663
6764 if ( jdkMajor < 21 ) {
68- logger . warn ( 'Capacitor 7 requires JDK 21 or higher. Some steps may fail.' ) ;
65+ logger . warn ( 'Capacitor 8 requires JDK 21 or higher. Some steps may fail.' ) ;
6966 }
7067
7168 const variablesAndClasspaths :
@@ -86,13 +83,13 @@ export async function migrateCommand(config: Config, noprompt: boolean, packagem
8683 } ;
8784
8885 const monorepoWarning =
89- 'Please note this tool is not intended for use in a mono-repo environment, please check out the Ionic vscode extension for this functionality. ' ;
86+ 'Please note this tool is not intended for use in a mono-repo environment, you should migrate manually instead. Refer to https://capacitorjs.com/docs/next/updating/8-0 ' ;
9087
9188 logger . info ( monorepoWarning ) ;
9289
9390 const { migrateconfirm } = noprompt
9491 ? { migrateconfirm : 'y' }
95- : await logPrompt ( `Capacitor 7 sets a deployment target of iOS ${ iOSVersion } and Android 15 (SDK 35 ). \n` , {
92+ : await logPrompt ( `Capacitor 8 sets a deployment target of iOS ${ iOSVersion } and Android 16 (SDK 36 ). \n` , {
9693 type : 'text' ,
9794 name : 'migrateconfirm' ,
9895 message : `Are you sure you want to migrate? (Y/n)` ,
@@ -188,8 +185,8 @@ export async function migrateCommand(config: Config, noprompt: boolean, packagem
188185 }
189186
190187 if ( allDependencies [ '@capacitor/android' ] && existsSync ( config . android . platformDirAbs ) ) {
191- // AndroidManifest.xml add navigation "
192- await runTask ( `Migrating AndroidManifest.xml by adding navigation to Activity configChanges.` , ( ) => {
188+ // AndroidManifest.xml add "density "
189+ await runTask ( `Migrating AndroidManifest.xml by adding density to Activity configChanges.` , ( ) => {
193190 return updateAndroidManifest ( join ( config . android . srcMainDirAbs , 'AndroidManifest.xml' ) ) ;
194191 } ) ;
195192
@@ -222,10 +219,14 @@ export async function migrateCommand(config: Config, noprompt: boolean, packagem
222219 } else {
223220 logger . warn ( 'Skipped upgrading gradle wrapper files' ) ;
224221 }
225- await runTask ( `Migrating build.gradle file.` , ( ) => {
222+ await runTask ( `Migrating root build.gradle file.` , ( ) => {
226223 return updateBuildGradle ( join ( config . android . platformDirAbs , 'build.gradle' ) , variablesAndClasspaths ) ;
227224 } ) ;
228225
226+ await runTask ( `Migrating app build.gradle file.` , ( ) => {
227+ return updateAppBuildGradle ( join ( config . android . appDirAbs , 'build.gradle' ) ) ;
228+ } ) ;
229+
229230 // Variables gradle
230231 await runTask ( `Migrating variables.gradle file.` , ( ) => {
231232 return ( async ( ) : Promise < void > => {
@@ -274,18 +275,18 @@ export async function migrateCommand(config: Config, noprompt: boolean, packagem
274275 }
275276 }
276277 const pluginVariables : { [ key : string ] : string } = {
277- firebaseMessagingVersion : '24.1.0 ' ,
278+ firebaseMessagingVersion : '25.0.1 ' ,
278279 playServicesLocationVersion : '21.3.0' ,
279- androidxBrowserVersion : '1.8 .0' ,
280- androidxMaterialVersion : '1.12 .0' ,
281- androidxExifInterfaceVersion : '1.3.7 ' ,
282- androidxCoreKTXVersion : '1.12 .0' ,
283- googleMapsPlayServicesVersion : '18 .2.0' ,
284- googleMapsUtilsVersion : '3.8.2 ' ,
285- googleMapsKtxVersion : '5.0.0 ' ,
286- googleMapsUtilsKtxVersion : '5.0.0 ' ,
287- kotlinxCoroutinesVersion : '1.7.3 ' ,
288- coreSplashScreenVersion : '1.0.1 ' ,
280+ androidxBrowserVersion : '1.9 .0' ,
281+ androidxMaterialVersion : '1.13 .0' ,
282+ androidxExifInterfaceVersion : '1.4.1 ' ,
283+ androidxCoreKTXVersion : '1.17 .0' ,
284+ googleMapsPlayServicesVersion : '19 .2.0' ,
285+ googleMapsUtilsVersion : '3.19.1 ' ,
286+ googleMapsKtxVersion : '5.2.1 ' ,
287+ googleMapsUtilsKtxVersion : '5.2.1 ' ,
288+ kotlinxCoroutinesVersion : '1.10.2 ' ,
289+ coreSplashScreenVersion : '1.2.0 ' ,
289290 } ;
290291 for ( const variable of Object . keys ( pluginVariables ) ) {
291292 await updateFile ( config , variablesPath , `${ variable } = '` , `'` , pluginVariables [ variable ] , true ) ;
@@ -294,14 +295,6 @@ export async function migrateCommand(config: Config, noprompt: boolean, packagem
294295 } ) ;
295296
296297 rimraf . sync ( join ( config . android . appDirAbs , 'build' ) ) ;
297-
298- if ( ! installFailed ) {
299- await runTask ( 'Migrating package from Manifest to build.gradle in Capacitor plugins' , ( ) => {
300- return patchOldCapacitorPlugins ( config ) ;
301- } ) ;
302- } else {
303- logger . warn ( 'Skipped migrating package from Manifest to build.gradle in Capacitor plugins' ) ;
304- }
305298 }
306299
307300 // Write all breaking changes
@@ -373,11 +366,15 @@ async function installLatestLibs(dependencyManager: string, runInstall: boolean,
373366
374367async function writeBreakingChanges ( ) {
375368 const breaking = [
376- '@capacitor/app' ,
377- '@capacitor/device' ,
378- '@capacitor/haptics' ,
369+ '@capacitor/action-sheet' ,
370+ '@capacitor/barcode-scanner' ,
371+ '@capacitor/browser' ,
372+ '@capacitor/camera' ,
373+ '@capacitor/google-maps' ,
374+ '@capacitor/push-notifications' ,
375+ '@capacitor/screen-orientation' ,
379376 '@capacitor/splash-screen' ,
380- '@capacitor/statusbar ' ,
377+ '@capacitor/status-bar ' ,
381378 ] ;
382379 const broken = [ ] ;
383380 for ( const lib of breaking ) {
@@ -387,7 +384,7 @@ async function writeBreakingChanges() {
387384 }
388385 if ( broken . length > 0 ) {
389386 logger . info (
390- `IMPORTANT: Review https://capacitorjs.com/docs/next/updating/7 -0#plugins for breaking changes in these plugins that you use: ${ broken . join (
387+ `IMPORTANT: Review https://capacitorjs.com/docs/next/updating/8 -0#plugins for breaking changes in these plugins that you use: ${ broken . join (
391388 ', ' ,
392389 ) } .`,
393390 ) ;
@@ -464,59 +461,6 @@ async function updateGradleWrapperFiles(platformDir: string) {
464461 ) ;
465462}
466463
467- async function movePackageFromManifestToBuildGradle ( manifestFilename : string , buildGradleFilename : string ) {
468- const manifestText = readFile ( manifestFilename ) ;
469- const buildGradleText = readFile ( buildGradleFilename ) ;
470-
471- if ( ! manifestText ) {
472- logger . error ( `Could not read ${ manifestFilename } . Check its permissions and if it exists.` ) ;
473- return ;
474- }
475-
476- if ( ! buildGradleText ) {
477- logger . error ( `Could not read ${ buildGradleFilename } . Check its permissions and if it exists.` ) ;
478- return ;
479- }
480-
481- const namespaceExists = new RegExp ( / \s + n a m e s p a c e \s + / ) . test ( buildGradleText ) ;
482- if ( namespaceExists ) {
483- logger . error ( 'Found namespace in build.gradle already, skipping migration' ) ;
484- return ;
485- }
486-
487- let packageName : string ;
488- const manifestRegEx = new RegExp ( / p a c k a g e = " ( [ ^ " ] + ) " / ) ;
489- const manifestResults = manifestRegEx . exec ( manifestText ) ;
490-
491- if ( manifestResults === null ) {
492- logger . error ( `Unable to update Android Manifest. Package not found.` ) ;
493- return ;
494- } else {
495- packageName = manifestResults [ 1 ] ;
496- }
497-
498- let manifestReplaced = manifestText ;
499-
500- manifestReplaced = manifestReplaced . replace ( manifestRegEx , '' ) ;
501-
502- if ( manifestText == manifestReplaced ) {
503- logger . error ( `Unable to update Android Manifest: no changes were detected in Android Manifest file` ) ;
504- return ;
505- }
506-
507- let buildGradleReplaced = buildGradleText ;
508-
509- buildGradleReplaced = setAllStringIn ( buildGradleText , 'android {' , '\n' , `\n namespace "${ packageName } "` ) ;
510-
511- if ( buildGradleText == buildGradleReplaced ) {
512- logger . error ( `Unable to update buildGradleText: no changes were detected in Android Manifest file` ) ;
513- return ;
514- }
515-
516- writeFileSync ( manifestFilename , manifestReplaced , 'utf-8' ) ;
517- writeFileSync ( buildGradleFilename , buildGradleReplaced , 'utf-8' ) ;
518- }
519-
520464async function updateBuildGradle (
521465 filename : string ,
522466 variablesAndClasspaths : {
@@ -548,6 +492,24 @@ async function updateBuildGradle(
548492 writeFileSync ( filename , replaced , 'utf-8' ) ;
549493}
550494
495+ async function updateAppBuildGradle ( filename : string ) {
496+ const txt = readFile ( filename ) ;
497+ if ( ! txt ) {
498+ return ;
499+ }
500+ let replaced = txt ;
501+
502+ const gradlePproperties = [ 'compileSdk' , 'namespace' , 'ignoreAssetsPattern' ] ;
503+ for ( const prop of gradlePproperties ) {
504+ // Use updated Groovy DSL syntax with " = " assignment
505+ const regex = new RegExp ( `(^\\s*${ prop } )\\s+(?!=)(.+)$` , 'gm' ) ;
506+ replaced = replaced . replace ( regex , ( _match , key , value ) => {
507+ return `${ key } = ${ value . trim ( ) } ` ;
508+ } ) ;
509+ }
510+ writeFileSync ( filename , replaced , 'utf-8' ) ;
511+ }
512+
551513async function updateFile (
552514 config : Config ,
553515 filename : string ,
@@ -621,48 +583,23 @@ async function updateAndroidManifest(filename: string) {
621583 return ;
622584 }
623585
624- if ( txt . includes ( 'navigation ' ) ) {
586+ if ( txt . includes ( '|density' ) || txt . includes ( 'density| ') ) {
625587 return ; // Probably already updated
626588 }
627- const replaced = txt . replace (
628- 'android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|smallestScreenSize|screenLayout|uiMode"' ,
629- 'android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|smallestScreenSize|screenLayout|uiMode|navigation"' ,
630- ) ;
631-
632- writeFileSync ( filename , replaced , 'utf-8' ) ;
633- }
589+ // Since navigation was an optional change in Capacitor 7, attempting to add density and/or navigation
590+ const replaced = txt
591+ . replace (
592+ 'android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|smallestScreenSize|screenLayout|uiMode|navigation"' ,
593+ 'android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|smallestScreenSize|screenLayout|uiMode|navigation|density"' ,
594+ )
595+ . replace (
596+ 'android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|smallestScreenSize|screenLayout|uiMode"' ,
597+ 'android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|smallestScreenSize|screenLayout|uiMode|navigation|density"' ,
598+ ) ;
634599
635- export async function patchOldCapacitorPlugins ( config : Config ) : Promise < void [ ] > {
636- const allPlugins = await getPlugins ( config , 'android' ) ;
637- const androidPlugins = await getAndroidPlugins ( allPlugins ) ;
638- return await Promise . all (
639- androidPlugins . map ( async ( p ) => {
640- if ( p . manifest ?. android ?. src ) {
641- const buildGradlePath = resolveNode ( config . app . rootDir , p . id , p . manifest . android . src , 'build.gradle' ) ;
642- const manifestPath = resolveNode (
643- config . app . rootDir ,
644- p . id ,
645- p . manifest . android . src ,
646- 'src' ,
647- 'main' ,
648- 'AndroidManifest.xml' ,
649- ) ;
650- if ( buildGradlePath && manifestPath ) {
651- const gradleContent = readFile ( buildGradlePath ) ;
652- if ( ! gradleContent ?. includes ( 'namespace' ) ) {
653- if ( plugins . includes ( p . id ) ) {
654- logger . warn (
655- `You are using an outdated version of ${ p . id } , update the plugin to version ${ pluginVersion } ` ,
656- ) ;
657- } else {
658- logger . warn (
659- `${ p . id } @${ p . version } doesn't officially support Capacitor ${ coreVersion } yet, doing our best moving it's package to build.gradle so it builds` ,
660- ) ;
661- }
662- movePackageFromManifestToBuildGradle ( manifestPath , buildGradlePath ) ;
663- }
664- }
665- }
666- } ) ,
667- ) ;
600+ if ( ! replaced . includes ( '|density' ) ) {
601+ logger . error ( `Unable to add 'density' to 'android:configChanges' in ${ filename } . Try adding it manually` ) ;
602+ } else {
603+ writeFileSync ( filename , replaced , 'utf-8' ) ;
604+ }
668605}
0 commit comments