diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index 7b3c3d1bec..d2dff062a0 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -30,8 +30,7 @@ jobs:
fi
setup:
runs-on: ubuntu-latest
- # Keep this job capped at 10 minutes; never raise it unless explicitly asked.
- timeout-minutes: 10
+ timeout-minutes: 30
steps:
- name: Get Latest
uses: actions/setup-node@v6
@@ -45,8 +44,7 @@ jobs:
key: ${{ runner.OS }}-dependencies-cache-${{ hashFiles('**/package.json') }}
lint:
runs-on: macos-15
- # Keep this job capped at 10 minutes; never raise it unless explicitly asked.
- timeout-minutes: 10
+ timeout-minutes: 30
steps:
- uses: actions/setup-node@v6
with:
@@ -62,8 +60,7 @@ jobs:
- run: npm run lint
test-cli:
runs-on: macos-15
- # Keep this job capped at 10 minutes; never raise it unless explicitly asked.
- timeout-minutes: 10
+ timeout-minutes: 30
needs:
- setup
- lint
@@ -84,8 +81,7 @@ jobs:
working-directory: ./cli
test-core:
runs-on: ubuntu-latest
- # Keep this job capped at 10 minutes; never raise it unless explicitly asked.
- timeout-minutes: 10
+ timeout-minutes: 30
needs:
- setup
- lint
@@ -106,8 +102,7 @@ jobs:
working-directory: ./core
test-ios:
runs-on: macos-15
- # Keep this job capped at 10 minutes; never raise it unless explicitly asked.
- timeout-minutes: 10
+ timeout-minutes: 30
needs:
- setup
- lint
@@ -131,12 +126,11 @@ jobs:
- run: npm install
- run: npm run verify
working-directory: ./ios
- - name: Validate native podspec
- run: sh ./scripts/native-podspec.sh lint
+# - name: Validate native podspec
+# run: sh ./scripts/native-podspec.sh lint
test-android:
runs-on: ubuntu-latest
- # Keep this job capped at 10 minutes; never raise it unless explicitly asked.
- timeout-minutes: 10
+ timeout-minutes: 30
needs:
- setup
- lint
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 71f3de9e69..83d8f8fb16 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -3,8 +3,112 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
-## [8.3.4](https://github.com/Cap-go/capacitor-plus/compare/8.3.3...8.3.4) (2026-05-07)
+# [9.0.0-alpha.5](https://github.com/ionic-team/capacitor/compare/8.4.1...9.0.0-alpha.5) (2026-06-23)
+### Bug Fixes
+
+- add missing logic from merge ([#8515](https://github.com/ionic-team/capacitor/issues/8515)) ([356cafa](https://github.com/ionic-team/capacitor/commit/356cafa7a06dd4a2b6d535f421ddc62132b34343))
+- **android:** restore verify script ([#8513](https://github.com/ionic-team/capacitor/issues/8513)) ([0585c18](https://github.com/ionic-team/capacitor/commit/0585c180843064d4f704f38710bd0db5050b70b1))
+- **cli:** Add missing imports ([#8512](https://github.com/ionic-team/capacitor/issues/8512)) ([904b22e](https://github.com/ionic-team/capacitor/commit/904b22e69f4f750ed0b2e006157baaa0c7fc2a7f))
+
+# [9.0.0-alpha.4](https://github.com/ionic-team/capacitor/compare/9.0.0-alpha.3...9.0.0-alpha.4) (2026-06-19)
+
+### Bug Fixes
+
+- **ios:** eliminate double comma in SPM generation ([#8505](https://github.com/ionic-team/capacitor/issues/8505)) ([1a5543f](https://github.com/ionic-team/capacitor/commit/1a5543fbfcf4ba911270002d573275342f680bde))
+
+# [9.0.0-alpha.3](https://github.com/ionic-team/capacitor/compare/8.4.0...9.0.0-alpha.3) (2026-06-02)
+
+# [9.0.0-alpha.2](https://github.com/ionic-team/capacitor/compare/8.3.4...9.0.0-alpha.2) (2026-05-12)
+
+# [9.0.0-alpha.1](https://github.com/ionic-team/capacitor/compare/8.3.3...9.0.0-alpha.1) (2026-05-08)
+
+# [9.0.0-alpha.0](https://github.com/ionic-team/capacitor/compare/8.3.2...9.0.0-alpha.0) (2026-05-07)
+
+### Bug Fixes
+
+- **android:** conditionally add Cordova ([#8453](https://github.com/ionic-team/capacitor/issues/8453)) ([e136b3f](https://github.com/ionic-team/capacitor/commit/e136b3f0cdd1437cac5234576301ed388edf85e7))
+- **android:** Handle activity result without plugin handle ([#8436](https://github.com/ionic-team/capacitor/issues/8436)) ([65ad1fd](https://github.com/ionic-team/capacitor/commit/65ad1fd55b9793a3e078e4a837a00e2f28c75c17))
+- **cli:** conditionally add capacitor-cordova-android-plugins module ([#8449](https://github.com/ionic-team/capacitor/issues/8449)) ([9e85905](https://github.com/ionic-team/capacitor/commit/9e85905bf36c1e2300994e231cf10e829f2074ed))
+- **http:** handle URL objects on fetch ([#8386](https://github.com/ionic-team/capacitor/issues/8386)) ([0aac1f0](https://github.com/ionic-team/capacitor/commit/0aac1f0aee8083dc5013f0d8e3c180eb02f21141))
+- **ios:** make getArray accesible on Objective-C plugins ([#8392](https://github.com/ionic-team/capacitor/issues/8392)) ([ef57c77](https://github.com/ionic-team/capacitor/commit/ef57c773e70af6b94685a2dc0f808db3ed4cda6e))
+- **SystemBars:** use native safe area insets on Android ([#8384](https://github.com/ionic-team/capacitor/issues/8384)) ([d55f4f8](https://github.com/ionic-team/capacitor/commit/d55f4f859bd88fa5617699e874c48c451bcb5e5f))
+
+# [9.0.0-alpha.4](https://github.com/ionic-team/capacitor/compare/9.0.0-alpha.3...9.0.0-alpha.4) (2026-06-19)
+
+## [8.4.1](https://github.com/ionic-team/capacitor/compare/8.4.0...8.4.1) (2026-06-19)
+
+### Bug Fixes
+
+- **cli:** make SPM dependency patch work on prereleases ([#8508](https://github.com/ionic-team/capacitor/issues/8508)) ([6048e90](https://github.com/ionic-team/capacitor/commit/6048e90171afa0229a3c25b52a23c377c6bb804c))
+- **cli:** patch Capacitor SPM dependency version in plugins ([#8492](https://github.com/ionic-team/capacitor/issues/8492)) ([28bb2c6](https://github.com/ionic-team/capacitor/commit/28bb2c687069dfdd6aa7abc866004a1c6388d103))
+- **ios:** eliminate double comma in SPM generation ([#8505](https://github.com/ionic-team/capacitor/issues/8505)) ([1a5543f](https://github.com/ionic-team/capacitor/commit/1a5543fbfcf4ba911270002d573275342f680bde))
+
+# [8.4.0](https://github.com/ionic-team/capacitor/compare/9.0.0-alpha.2...8.4.0) (2026-06-02)
+
+# [9.0.0-alpha.3](https://github.com/ionic-team/capacitor/compare/9.0.0-alpha.2...9.0.0-alpha.3) (2026-06-02)
+
+**Note:** Version bump only for package capacitor
+
+# [9.0.0-alpha.2](https://github.com/ionic-team/capacitor/compare/9.0.0-alpha.1...9.0.0-alpha.2) (2026-05-12)
+
+**Note:** Version bump only for package capacitor
+
+# [9.0.0-alpha.1](https://github.com/ionic-team/capacitor/compare/9.0.0-alpha.0...9.0.0-alpha.1) (2026-05-08)
+
+**Note:** Version bump only for package capacitor
+
+# [9.0.0-alpha.0](https://github.com/ionic-team/capacitor/compare/8.3.2...9.0.0-alpha.0) (2026-05-07)
+
+### Bug Fixes
+
+- **android:** conditionally add Cordova ([#8453](https://github.com/ionic-team/capacitor/issues/8453)) ([e136b3f](https://github.com/ionic-team/capacitor/commit/e136b3f0cdd1437cac5234576301ed388edf85e7))
+- **android:** Handle activity result without plugin handle ([#8436](https://github.com/ionic-team/capacitor/issues/8436)) ([65ad1fd](https://github.com/ionic-team/capacitor/commit/65ad1fd55b9793a3e078e4a837a00e2f28c75c17))
+- **cli:** conditionally add capacitor-cordova-android-plugins module ([#8449](https://github.com/ionic-team/capacitor/issues/8449)) ([9e85905](https://github.com/ionic-team/capacitor/commit/9e85905bf36c1e2300994e231cf10e829f2074ed))
+- **http:** handle URL objects on fetch ([#8386](https://github.com/ionic-team/capacitor/issues/8386)) ([0aac1f0](https://github.com/ionic-team/capacitor/commit/0aac1f0aee8083dc5013f0d8e3c180eb02f21141))
+- **ios:** make getArray accesible on Objective-C plugins ([#8392](https://github.com/ionic-team/capacitor/issues/8392)) ([ef57c77](https://github.com/ionic-team/capacitor/commit/ef57c773e70af6b94685a2dc0f808db3ed4cda6e))
+- **SystemBars:** use native safe area insets on Android ([#8384](https://github.com/ionic-team/capacitor/issues/8384)) ([d55f4f8](https://github.com/ionic-team/capacitor/commit/d55f4f859bd88fa5617699e874c48c451bcb5e5f))
+
+# [8.4.0](https://github.com/ionic-team/capacitor/compare/8.3.4...8.4.0) (2026-06-02)
+
+## Bug Fixes
+
+- **android:** show only the requested system bar ([#8480](https://github.com/ionic-team/capacitor/issues/8480)) ([4c6c321](https://github.com/ionic-team/capacitor/commit/4c6c3219afb5223211e857457e46283c37eb9424))
+- **cli:** revert live reload config on failure ([#8485](https://github.com/ionic-team/capacitor/issues/8485)) ([1d031a4](https://github.com/ionic-team/capacitor/commit/1d031a4abec2c793079ba8897ad2e40c4cc6c7f9))
+- **SystemBars:** make `safe-area-inset-x` available on API <= 34 ([#8424](https://github.com/ionic-team/capacitor/issues/8424)) ([e456de0](https://github.com/ionic-team/capacitor/commit/e456de083e19644f484bec5a5359cb67960ac8bc))
+- **SystemBars:** respect `insetsHandling` disable ([#8481](https://github.com/ionic-team/capacitor/issues/8481)) ([d4ad7ff](https://github.com/ionic-team/capacitor/commit/d4ad7ffe39daf66e0cfc63af9028d5c05543bde7))
+
+### Features
+
+- add method getDouble to plugin config ([#7638](https://github.com/ionic-team/capacitor/issues/7638)) ([93c72de](https://github.com/ionic-team/capacitor/commit/93c72de40a2ec4c78b33659250cb08340083088e))
+- **cli:** add experimental packageOptions ([#8471](https://github.com/ionic-team/capacitor/issues/8471)) ([258867b](https://github.com/ionic-team/capacitor/commit/258867b7bf37b1837b99b02ec9638e5a6df08d97))
+- **cli:** capture ios_package_manager in telemetry ([#8482](https://github.com/ionic-team/capacitor/issues/8482)) ([b4b297a](https://github.com/ionic-team/capacitor/commit/b4b297a52f8732659662d5e5aaeff81c0f7d9835))
+
+## [8.3.4](https://github.com/ionic-team/capacitor/compare/8.3.3...8.3.4) (2026-05-12)
+
+**Note:** Version bump only for package capacitor
+
+## [8.3.3](https://github.com/ionic-team/capacitor/compare/8.3.2...8.3.3) (2026-05-08)
+
+### Bug Fixes
+
+- **cli:** copy plugin files in CocoaPods projects ([#8467](https://github.com/ionic-team/capacitor/issues/8467)) ([b2d7719](https://github.com/ionic-team/capacitor/commit/b2d771926a180e60deea31992d7d4abcd5ca3bc7))
+
+## [8.3.2](https://github.com/ionic-team/capacitor/compare/8.3.1...8.3.2) (2026-05-07)
+
+### Bug Fixes
+
+- **cli:** add cSettings support for compiler flags in generated Package.swift ([#8448](https://github.com/ionic-team/capacitor/issues/8448)) ([0bd0676](https://github.com/ionic-team/capacitor/commit/0bd0676315c5fd77e50312dd7b5bf4990dcbd7d0))
+- **cli:** add system framework and weak framework support in SPM Package.swift ([#8447](https://github.com/ionic-team/capacitor/issues/8447)) ([3232f0f](https://github.com/ionic-team/capacitor/commit/3232f0fe1d9811b0b5c500e3dc05cb8a250177f8))
+- **cli:** correct Capacitor plugin SPM compat check ([#8440](https://github.com/ionic-team/capacitor/issues/8440)) ([e5ccc45](https://github.com/ionic-team/capacitor/commit/e5ccc451dda27d56bca824ed644bd20fe4d988cb))
+- **cli:** generate binaryTarget entries for custom xcframeworks in Package.swift ([#8445](https://github.com/ionic-team/capacitor/issues/8445)) ([1f7e33f](https://github.com/ionic-team/capacitor/commit/1f7e33fca43d183332ec19d22b0d75ef81d8cc6d))
+- **cli:** generate resource entries in Package.swift ([#8455](https://github.com/ionic-team/capacitor/issues/8455)) ([790bd27](https://github.com/ionic-team/capacitor/commit/790bd27123497111984227010c3162cec94a108e))
+- **cli:** handle Cordova plugins without iOS source files ([#8443](https://github.com/ionic-team/capacitor/issues/8443)) ([0da130e](https://github.com/ionic-team/capacitor/commit/0da130eb7a861bee4e2c35bc0aac53ba9c983fc3))
+- **cli:** link plugin dependencies in Package.swift ([#8457](https://github.com/ionic-team/capacitor/issues/8457)) ([b3c769e](https://github.com/ionic-team/capacitor/commit/b3c769e856c826b1174518877cf86ac7ce73bf09))
+- **ios:** support Cordova plugins with Package.swift ([#8438](https://github.com/ionic-team/capacitor/issues/8438)) ([139943b](https://github.com/ionic-team/capacitor/commit/139943b0c05fddb2d1ce2d6f468800fddf17b4cf))
+- **SystemBars:** avoid extra view padding on API <= 34 ([#8439](https://github.com/ionic-team/capacitor/issues/8439)) ([5b135a7](https://github.com/ionic-team/capacitor/commit/5b135a70217be560e7176c8d5b514cc92ed3e4e4))
+
+## [8.3.1](https://github.com/ionic-team/capacitor/compare/8.3.0...8.3.1) (2026-04-16)
### Bug Fixes
diff --git a/android-template/app/build.gradle b/android-template/app/build.gradle
index 363eb2f77d..5ac536dc7a 100644
--- a/android-template/app/build.gradle
+++ b/android-template/app/build.gradle
@@ -6,7 +6,6 @@ android {
defaultConfig {
applicationId "com.getcapacitor.app"
minSdkVersion rootProject.ext.minSdkVersion
- targetSdkVersion rootProject.ext.targetSdkVersion
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
@@ -24,12 +23,6 @@ android {
}
}
-repositories {
- flatDir{
- dirs '../capacitor-cordova-android-plugins/src/main/libs', 'libs'
- }
-}
-
dependencies {
implementation fileTree(include: ['*.jar'], dir: 'libs')
implementation "androidx.appcompat:appcompat:$androidxAppCompatVersion"
@@ -39,7 +32,6 @@ dependencies {
testImplementation "junit:junit:$junitVersion"
androidTestImplementation "androidx.test.ext:junit:$androidxJunitVersion"
androidTestImplementation "androidx.test.espresso:espresso-core:$androidxEspressoCoreVersion"
- implementation project(':capacitor-cordova-android-plugins')
}
apply from: 'capacitor.build.gradle'
diff --git a/android-template/build.gradle b/android-template/build.gradle
index f8f0e43b6d..d72a753c67 100644
--- a/android-template/build.gradle
+++ b/android-template/build.gradle
@@ -7,8 +7,8 @@ buildscript {
mavenCentral()
}
dependencies {
- classpath 'com.android.tools.build:gradle:8.13.0'
- classpath 'com.google.gms:google-services:4.4.4'
+ classpath 'com.android.tools.build:gradle:9.2.1'
+ classpath 'com.google.gms:google-services:4.5.0'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
diff --git a/android-template/gradle/wrapper/gradle-wrapper.jar b/android-template/gradle/wrapper/gradle-wrapper.jar
index 1b33c55baa..b1b8ef56b4 100644
Binary files a/android-template/gradle/wrapper/gradle-wrapper.jar and b/android-template/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/android-template/gradle/wrapper/gradle-wrapper.properties b/android-template/gradle/wrapper/gradle-wrapper.properties
index 7705927e94..e74c8700b2 100644
--- a/android-template/gradle/wrapper/gradle-wrapper.properties
+++ b/android-template/gradle/wrapper/gradle-wrapper.properties
@@ -1,7 +1,9 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.3-all.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-9.5.1-all.zip
networkTimeout=10000
+retries=0
+retryBackOffMs=500
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
diff --git a/android-template/gradlew b/android-template/gradlew
index 23d15a9367..b9bb139f79 100755
--- a/android-template/gradlew
+++ b/android-template/gradlew
@@ -1,7 +1,7 @@
#!/bin/sh
#
-# Copyright © 2015-2021 the original authors.
+# Copyright © 2015 the original authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -57,7 +57,7 @@
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
-# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
+# https://github.com/gradle/gradle/blob/3d91ce3b8caaf77ad09f381f43615b715b53f72c/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
@@ -114,7 +114,6 @@ case "$( uname )" in #(
NONSTOP* ) nonstop=true ;;
esac
-CLASSPATH="\\\"\\\""
# Determine the Java command to use to start the JVM.
@@ -172,7 +171,6 @@ fi
# For Cygwin or MSYS, switch paths to Windows format before running java
if "$cygwin" || "$msys" ; then
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
- CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
JAVACMD=$( cygpath --unix "$JAVACMD" )
@@ -212,7 +210,6 @@ DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
- -classpath "$CLASSPATH" \
-jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \
"$@"
diff --git a/android-template/gradlew.bat b/android-template/gradlew.bat
index 5eed7ee845..aa5f10b069 100644
--- a/android-template/gradlew.bat
+++ b/android-template/gradlew.bat
@@ -23,8 +23,8 @@
@rem
@rem ##########################################################################
-@rem Set local scope for the variables with windows NT shell
-if "%OS%"=="Windows_NT" setlocal
+@rem Set local scope for the variables, and ensure extensions are enabled
+setlocal EnableExtensions
set DIRNAME=%~dp0
if "%DIRNAME%"=="" set DIRNAME=.
@@ -51,7 +51,7 @@ echo. 1>&2
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
echo location of your Java installation. 1>&2
-goto fail
+"%COMSPEC%" /c exit 1
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
@@ -65,30 +65,18 @@ echo. 1>&2
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
echo location of your Java installation. 1>&2
-goto fail
+"%COMSPEC%" /c exit 1
:execute
@rem Setup the command line
-set CLASSPATH=
@rem Execute Gradle
-"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %*
+@rem endlocal doesn't take effect until after the line is parsed and variables are expanded
+@rem which allows us to clear the local environment before executing the java command
+endlocal & "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* & call :exitWithErrorLevel
-:end
-@rem End local scope for the variables with windows NT shell
-if %ERRORLEVEL% equ 0 goto mainEnd
-
-:fail
-rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
-rem the _cmd.exe /c_ return code!
-set EXIT_CODE=%ERRORLEVEL%
-if %EXIT_CODE% equ 0 set EXIT_CODE=1
-if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
-exit /b %EXIT_CODE%
-
-:mainEnd
-if "%OS%"=="Windows_NT" endlocal
-
-:omega
+:exitWithErrorLevel
+@rem Use "%COMSPEC%" /c exit to allow operators to work properly in scripts
+"%COMSPEC%" /c exit %ERRORLEVEL%
diff --git a/android-template/settings.gradle b/android-template/settings.gradle
index 3b4431d772..fb68af1dfb 100644
--- a/android-template/settings.gradle
+++ b/android-template/settings.gradle
@@ -1,5 +1,3 @@
include ':app'
-include ':capacitor-cordova-android-plugins'
-project(':capacitor-cordova-android-plugins').projectDir = new File('./capacitor-cordova-android-plugins/')
apply from: 'capacitor.settings.gradle'
\ No newline at end of file
diff --git a/android-template/variables.gradle b/android-template/variables.gradle
index ee4ba41c46..4f68607cae 100644
--- a/android-template/variables.gradle
+++ b/android-template/variables.gradle
@@ -1,16 +1,16 @@
ext {
- minSdkVersion = 24
- compileSdkVersion = 36
- targetSdkVersion = 36
- androidxActivityVersion = '1.11.0'
+ minSdkVersion = 26
+ compileSdkVersion = 37
+ targetSdkVersion = 37
+ androidxActivityVersion = '1.13.0'
androidxAppCompatVersion = '1.7.1'
androidxCoordinatorLayoutVersion = '1.3.0'
- androidxCoreVersion = '1.17.0'
+ androidxCoreVersion = '1.19.0'
androidxFragmentVersion = '1.8.9'
coreSplashScreenVersion = '1.2.0'
- androidxWebkitVersion = '1.14.0'
+ androidxWebkitVersion = '1.16.0'
junitVersion = '4.13.2'
androidxJunitVersion = '1.3.0'
androidxEspressoCoreVersion = '3.7.0'
- cordovaAndroidVersion = '14.0.1'
+ cordovaAndroidVersion = '15.0.0'
}
\ No newline at end of file
diff --git a/android/CHANGELOG.md b/android/CHANGELOG.md
index 4e2d978738..345687b6e0 100644
--- a/android/CHANGELOG.md
+++ b/android/CHANGELOG.md
@@ -3,261 +3,85 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
-## [8.3.4](https://github.com/Cap-go/capacitor-plus/compare/8.3.3...8.3.4) (2026-05-07)
-
-**Note:** Version bump only for package @capacitor-plus/android
-
-
-
-
-
-## [8.3.3](https://github.com/Cap-go/capacitor-plus/compare/8.3.2...8.3.3) (2026-05-06)
-
-**Note:** Version bump only for package @capacitor-plus/android
-
-
-
-
-
-## [8.3.2](https://github.com/Cap-go/capacitor-plus/compare/8.0.8...8.3.2) (2026-05-05)
-
+# [9.0.0-alpha.5](https://github.com/ionic-team/capacitor/compare/8.4.1...9.0.0-alpha.5) (2026-06-23)
### Bug Fixes
-* address follow-up review comments ([8bee786](https://github.com/Cap-go/capacitor-plus/commit/8bee786e2c68ca6c351e88f104b518291c1f81e3))
-* **android:** Add missing null checks in BridgeActivity ([#8185](https://github.com/Cap-go/capacitor-plus/issues/8185)) ([bd29b99](https://github.com/Cap-go/capacitor-plus/commit/bd29b9913a9279de26fc21c6cb0b93b8f5e5433a))
-* **android:** AGP 9.0 no longer supports `proguard-android.txt` ([#8315](https://github.com/Cap-go/capacitor-plus/issues/8315)) ([dcc76c3](https://github.com/Cap-go/capacitor-plus/commit/dcc76c37508a9b71fb36d95707748c2dd115cf52))
-* **android:** Concurrent Range Requests for assets ([#8357](https://github.com/Cap-go/capacitor-plus/issues/8357)) ([5e82c89](https://github.com/Cap-go/capacitor-plus/commit/5e82c89f1bff6d0e9ccea2554007aacb920d4c58))
-* **android:** correctly parsing `server.url` when they include paths ([#8391](https://github.com/Cap-go/capacitor-plus/issues/8391)) ([a9f2181](https://github.com/Cap-go/capacitor-plus/commit/a9f218179b60555d86b44bf2b33354da3e64e98c))
-* **android:** handle lowercase range header ([#8368](https://github.com/Cap-go/capacitor-plus/issues/8368)) ([ae0e2dd](https://github.com/Cap-go/capacitor-plus/commit/ae0e2ddccb2904ee4b3d47d4be1f7556ac7000a1))
-* **android:** handle null versionName in isNewBinary() ([#8397](https://github.com/Cap-go/capacitor-plus/issues/8397)) ([aa1a660](https://github.com/Cap-go/capacitor-plus/commit/aa1a660f364f9b5f5a1e350e279c8864b04dd13b))
-* **android:** invalid http range seeking ([#8369](https://github.com/Cap-go/capacitor-plus/issues/8369)) ([3109d22](https://github.com/Cap-go/capacitor-plus/commit/3109d22547253ed44293777c60652f14cf83e416))
-* boundary value extraction for form-data requests ([#7518](https://github.com/Cap-go/capacitor-plus/issues/7518)) ([64ab854](https://github.com/Cap-go/capacitor-plus/commit/64ab854c12330804c24275d88d3a9f7c8e52a73d))
-* **http:** handle URL objects on fetch ([#8386](https://github.com/Cap-go/capacitor-plus/issues/8386)) ([003099a](https://github.com/Cap-go/capacitor-plus/commit/003099aef246adfd76d890074d46b1484951824b))
-* resolve upstream sync conflicts ([75cbb30](https://github.com/Cap-go/capacitor-plus/commit/75cbb3097a7068bcb37313cbe6301628079101ca))
-* **system-bars:** use separate current styles ([#8409](https://github.com/Cap-go/capacitor-plus/issues/8409)) ([3d1f8d1](https://github.com/Cap-go/capacitor-plus/commit/3d1f8d1b61480187375f5cd4de7ba999db007542))
-* **SystemBars:** avoid extra view padding on API <= 34 ([#8439](https://github.com/Cap-go/capacitor-plus/issues/8439)) ([5b135a7](https://github.com/Cap-go/capacitor-plus/commit/5b135a70217be560e7176c8d5b514cc92ed3e4e4))
-* **SystemBars:** get correct style on handleOnConfigurationChanged ([#8295](https://github.com/Cap-go/capacitor-plus/issues/8295)) ([2a66b44](https://github.com/Cap-go/capacitor-plus/commit/2a66b44915895f971e4a26a8612798aa2f95ea11))
-* **SystemBars:** Set window background color according to theme ([#8306](https://github.com/Cap-go/capacitor-plus/issues/8306)) ([6037e38](https://github.com/Cap-go/capacitor-plus/commit/6037e3836ec24c9ddf26e74e5fbec20ab506adfd))
-* **SystemBars:** Skipping margin manipulation when on a fixed WebView ([#8309](https://github.com/Cap-go/capacitor-plus/issues/8309)) ([53c33b6](https://github.com/Cap-go/capacitor-plus/commit/53c33b614218bf635322fbdf9a38038a7964e3d4))
-* **SystemBars:** use native safe area insets on Android ([#8384](https://github.com/Cap-go/capacitor-plus/issues/8384)) ([4e99598](https://github.com/Cap-go/capacitor-plus/commit/4e99598a2a57ee97e82be1aaa09492744622fa60))
-
-
-### Reverts
-
-* revert version bump from [#8319](https://github.com/Cap-go/capacitor-plus/issues/8319) and [#8320](https://github.com/Cap-go/capacitor-plus/issues/8320) ([a48ebb6](https://github.com/Cap-go/capacitor-plus/commit/a48ebb622ea4ebe92927bf1756a4d8ac6012884b))
+- **android:** restore verify script ([#8513](https://github.com/ionic-team/capacitor/issues/8513)) ([0585c18](https://github.com/ionic-team/capacitor/commit/0585c180843064d4f704f38710bd0db5050b70b1))
+# [9.0.0-alpha.4](https://github.com/ionic-team/capacitor/compare/9.0.0-alpha.3...9.0.0-alpha.4) (2026-06-19)
+# [9.0.0-alpha.3](https://github.com/ionic-team/capacitor/compare/8.4.0...9.0.0-alpha.3) (2026-06-02)
+# [9.0.0-alpha.2](https://github.com/ionic-team/capacitor/compare/8.3.4...9.0.0-alpha.2) (2026-05-12)
+# [9.0.0-alpha.1](https://github.com/ionic-team/capacitor/compare/8.3.3...9.0.0-alpha.1) (2026-05-08)
-## [8.0.8](https://github.com/Cap-go/capacitor-plus/compare/8.0.7...8.0.8) (2026-04-08)
-
+# [9.0.0-alpha.0](https://github.com/ionic-team/capacitor/compare/8.3.2...9.0.0-alpha.0) (2026-05-07)
### Bug Fixes
-* **android:** use proguard-android-optimize for AGP 9 compatibility ([52ceef3](https://github.com/Cap-go/capacitor-plus/commit/52ceef3769544c6cb0cbc83963dcc4552983578b))
-
-
-
-
+- **android:** conditionally add Cordova ([#8453](https://github.com/ionic-team/capacitor/issues/8453)) ([e136b3f](https://github.com/ionic-team/capacitor/commit/e136b3f0cdd1437cac5234576301ed388edf85e7))
+- **android:** Handle activity result without plugin handle ([#8436](https://github.com/ionic-team/capacitor/issues/8436)) ([65ad1fd](https://github.com/ionic-team/capacitor/commit/65ad1fd55b9793a3e078e4a837a00e2f28c75c17))
+- **http:** handle URL objects on fetch ([#8386](https://github.com/ionic-team/capacitor/issues/8386)) ([0aac1f0](https://github.com/ionic-team/capacitor/commit/0aac1f0aee8083dc5013f0d8e3c180eb02f21141))
+- **SystemBars:** use native safe area insets on Android ([#8384](https://github.com/ionic-team/capacitor/issues/8384)) ([d55f4f8](https://github.com/ionic-team/capacitor/commit/d55f4f859bd88fa5617699e874c48c451bcb5e5f))
-## [8.0.7](https://github.com/Cap-go/capacitor-plus/compare/8.0.6...8.0.7) (2026-01-12)
+# [9.0.0-alpha.4](https://github.com/ionic-team/capacitor/compare/9.0.0-alpha.3...9.0.0-alpha.4) (2026-06-19)
-**Note:** Version bump only for package @capacitor-plus/android
+## [8.4.1](https://github.com/ionic-team/capacitor/compare/8.4.0...8.4.1) (2026-06-19)
+# [8.4.0](https://github.com/ionic-team/capacitor/compare/9.0.0-alpha.2...8.4.0) (2026-06-02)
+**Note:** Version bump only for package @capacitor/android
+# [9.0.0-alpha.3](https://github.com/ionic-team/capacitor/compare/9.0.0-alpha.2...9.0.0-alpha.3) (2026-06-02)
+# [8.4.0](https://github.com/ionic-team/capacitor/compare/8.3.4...8.4.0) (2026-06-02)
-## [8.0.6](https://github.com/Cap-go/capacitor-plus/compare/8.0.5...8.0.6) (2026-01-09)
-
-**Note:** Version bump only for package @capacitor-plus/android
-
-
-
-
-
-## [8.0.5](https://github.com/Cap-go/capacitor-plus/compare/8.0.4...8.0.5) (2026-01-08)
-
-**Note:** Version bump only for package @capacitor-plus/android
-
-
+### Bug Fixes
+- **android:** show only the requested system bar ([#8480](https://github.com/ionic-team/capacitor/issues/8480)) ([4c6c321](https://github.com/ionic-team/capacitor/commit/4c6c3219afb5223211e857457e46283c37eb9424))
+- **SystemBars:** make `safe-area-inset-x` available on API <= 34 ([#8424](https://github.com/ionic-team/capacitor/issues/8424)) ([e456de0](https://github.com/ionic-team/capacitor/commit/e456de083e19644f484bec5a5359cb67960ac8bc))
+- **SystemBars:** respect `insetsHandling` disable ([#8481](https://github.com/ionic-team/capacitor/issues/8481)) ([d4ad7ff](https://github.com/ionic-team/capacitor/commit/d4ad7ffe39daf66e0cfc63af9028d5c05543bde7))
+### Features
-## [8.0.4](https://github.com/Cap-go/capacitor-plus/compare/8.0.3...8.0.4) (2025-12-16)
+- add method getDouble to plugin config ([#7638](https://github.com/ionic-team/capacitor/issues/7638)) ([93c72de](https://github.com/ionic-team/capacitor/commit/93c72de40a2ec4c78b33659250cb08340083088e))
-**Note:** Version bump only for package @capacitor-plus/android
+## [8.3.4](https://github.com/ionic-team/capacitor/compare/9.0.0-alpha.1...8.3.4) (2026-05-12)
+## [8.3.3](https://github.com/ionic-team/capacitor/compare/9.0.0-alpha.0...8.3.3) (2026-05-08)
+# [9.0.0-alpha.2](https://github.com/ionic-team/capacitor/compare/9.0.0-alpha.1...9.0.0-alpha.2) (2026-05-12)
+**Note:** Version bump only for package @capacitor/android
+# [9.0.0-alpha.1](https://github.com/ionic-team/capacitor/compare/9.0.0-alpha.0...9.0.0-alpha.1) (2026-05-08)
-## [8.0.3](https://github.com/Cap-go/capacitor-plus/compare/8.0.2...8.0.3) (2025-12-16)
+**Note:** Version bump only for package @capacitor/android
+# [9.0.0-alpha.0](https://github.com/ionic-team/capacitor/compare/8.3.2...9.0.0-alpha.0) (2026-05-07)
### Bug Fixes
-* update homepage URL in package.json files for all platforms ([61ccdc4](https://github.com/Cap-go/capacitor-plus/commit/61ccdc4128a1ce2a7178eb0a195b188876ec0a9d))
-
-
-
+- **android:** conditionally add Cordova ([#8453](https://github.com/ionic-team/capacitor/issues/8453)) ([e136b3f](https://github.com/ionic-team/capacitor/commit/e136b3f0cdd1437cac5234576301ed388edf85e7))
+- **android:** Handle activity result without plugin handle ([#8436](https://github.com/ionic-team/capacitor/issues/8436)) ([65ad1fd](https://github.com/ionic-team/capacitor/commit/65ad1fd55b9793a3e078e4a837a00e2f28c75c17))
+- **http:** handle URL objects on fetch ([#8386](https://github.com/ionic-team/capacitor/issues/8386)) ([0aac1f0](https://github.com/ionic-team/capacitor/commit/0aac1f0aee8083dc5013f0d8e3c180eb02f21141))
+- **SystemBars:** use native safe area insets on Android ([#8384](https://github.com/ionic-team/capacitor/issues/8384)) ([d55f4f8](https://github.com/ionic-team/capacitor/commit/d55f4f859bd88fa5617699e874c48c451bcb5e5f))
+## [8.3.4](https://github.com/ionic-team/capacitor/compare/8.3.3...8.3.4) (2026-05-12)
-## [8.0.2](https://github.com/Cap-go/capacitor-plus/compare/8.0.1...8.0.2) (2025-12-16)
+**Note:** Version bump only for package @capacitor/android
+## [8.3.3](https://github.com/ionic-team/capacitor/compare/8.3.2...8.3.3) (2026-05-08)
-### Features
+**Note:** Version bump only for package @capacitor/android
-* add new workflows for testing and version bumping; update README files for all packages ([a01c2a8](https://github.com/Cap-go/capacitor-plus/commit/a01c2a842c363c2aa58e5681210fa62fac8e5de5))
-
-
-
-
-
-## [8.0.1](https://github.com/Cap-go/capacitor-plus/compare/3.3.4...8.0.1) (2025-12-16)
-
-### Bug Fixes
-
-- 204 http response ([#6266](https://github.com/Cap-go/capacitor-plus/issues/6266)) ([771f6ce](https://github.com/Cap-go/capacitor-plus/commit/771f6ce1f35159848db218a42dc4f56b5106f750))
-- add http method to prototype.open ([#6740](https://github.com/Cap-go/capacitor-plus/issues/6740)) ([1fd2d87](https://github.com/Cap-go/capacitor-plus/commit/1fd2d8762ff2341a8fe20eec9e774c6a29576e88))
-- allow single parameter on setRequestBody ([#6728](https://github.com/Cap-go/capacitor-plus/issues/6728)) ([5343bdb](https://github.com/Cap-go/capacitor-plus/commit/5343bdb60d26849cd8f9c8ff28ba7d9ddbd05b26))
-- **android:** add EdgeToEdge compatibility ([#7871](https://github.com/Cap-go/capacitor-plus/issues/7871)) ([64a8bc4](https://github.com/Cap-go/capacitor-plus/commit/64a8bc40de2522c75a94a40cba6c8ccd82481cb8))
-- **android:** added ServerPath object and building options for setting initial load from portals ([#6008](https://github.com/Cap-go/capacitor-plus/issues/6008)) ([205b6e6](https://github.com/Cap-go/capacitor-plus/commit/205b6e61806158244846608b1e6c0c7b26ee4ab7))
-- **android:** allow single input file selection from samsumg gallery ([#6778](https://github.com/Cap-go/capacitor-plus/issues/6778)) ([3d57ecd](https://github.com/Cap-go/capacitor-plus/commit/3d57ecdf7631d1581047bd5d9f86ea657ecad845))
-- **android:** Allow WebView to load blob urls ([#7551](https://github.com/Cap-go/capacitor-plus/issues/7551)) ([0dca917](https://github.com/Cap-go/capacitor-plus/commit/0dca917da54b01c6cf4fcd063f8191a8457d7c93))
-- **android:** Allow WebView to load data urls ([#6418](https://github.com/Cap-go/capacitor-plus/issues/6418)) ([daf2ec6](https://github.com/Cap-go/capacitor-plus/commit/daf2ec64df0c567c6a42560488e5d2515eff8a33))
-- **android:** avoid crash if server url ends in / ([#7426](https://github.com/Cap-go/capacitor-plus/issues/7426)) ([f8264cc](https://github.com/Cap-go/capacitor-plus/commit/f8264ccae1f2fec553521bc62d767c4909ea6d79))
-- **android:** avoid R8 optimizations remove plugin classes ([#6783](https://github.com/Cap-go/capacitor-plus/issues/6783)) ([cc85df5](https://github.com/Cap-go/capacitor-plus/commit/cc85df5f3a6999883623054573bafc30665e41e7))
-- **android:** better cleaning of allowedOrigin url ([#7607](https://github.com/Cap-go/capacitor-plus/issues/7607)) ([d123260](https://github.com/Cap-go/capacitor-plus/commit/d123260c70f26b0e786515ced9c95447f9ee81a0))
-- **android:** consider display cutout area for insets ([#8042](https://github.com/Cap-go/capacitor-plus/issues/8042)) ([b478211](https://github.com/Cap-go/capacitor-plus/commit/b4782116856c35e3fb567393f10a36ce4632b44c))
-- **android:** don't proxy requests if no jsInjector ([#7199](https://github.com/Cap-go/capacitor-plus/issues/7199)) ([7dc5585](https://github.com/Cap-go/capacitor-plus/commit/7dc5585996c17eedd154b5d9118eb880fef616fe))
-- **android:** Don't run Cordova plugins on ui thread ([#6108](https://github.com/Cap-go/capacitor-plus/issues/6108)) ([592ee86](https://github.com/Cap-go/capacitor-plus/commit/592ee862a58f5cb0737620a0246fe8ae295d27cf))
-- **android:** get application/x-www-form-urlencoded as string ([#6165](https://github.com/Cap-go/capacitor-plus/issues/6165)) ([0735e89](https://github.com/Cap-go/capacitor-plus/commit/0735e89d48e77a1ddca97a48e3851f4a0a3ea2c1))
-- **android:** handle deprecation warnings ([#7190](https://github.com/Cap-go/capacitor-plus/issues/7190)) ([06636d7](https://github.com/Cap-go/capacitor-plus/commit/06636d73a1b12c8f932642ee7caf91432690fea5))
-- **android:** handle empty permission list ([#6375](https://github.com/Cap-go/capacitor-plus/issues/6375)) ([b11a9df](https://github.com/Cap-go/capacitor-plus/commit/b11a9df070f18a25364a9109e295556fc75ea7f9))
-- **android:** handle http errors on the proxy ([#7280](https://github.com/Cap-go/capacitor-plus/issues/7280)) ([cca3c80](https://github.com/Cap-go/capacitor-plus/commit/cca3c80298b768a5eaf1da4d95f659e303ed7042))
-- **android:** handle null http headers and params ([#6370](https://github.com/Cap-go/capacitor-plus/issues/6370)) ([e486672](https://github.com/Cap-go/capacitor-plus/commit/e486672731818d5c64c50956562aa4766f169d41))
-- **android:** handle webview version for developer builds ([#6907](https://github.com/Cap-go/capacitor-plus/issues/6907)) ([88498e6](https://github.com/Cap-go/capacitor-plus/commit/88498e6228492a9ae917d3a7b37c242881f9fe52))
-- **android:** incorrect http url params encoding ([#6586](https://github.com/Cap-go/capacitor-plus/issues/6586)) ([e9ddb0c](https://github.com/Cap-go/capacitor-plus/commit/e9ddb0cfdb1ed320b650e1d01a04d37e644f6dd3))
-- **android:** javascript injection not working on urls with query ([#7545](https://github.com/Cap-go/capacitor-plus/issues/7545)) ([57ce5c6](https://github.com/Cap-go/capacitor-plus/commit/57ce5c65560c34d106e8b88cffe26ad22947bba6))
-- **android:** launching intents without host ([#6489](https://github.com/Cap-go/capacitor-plus/issues/6489)) ([95f7474](https://github.com/Cap-go/capacitor-plus/commit/95f747401ac5a666de4338a18666060e9c1ff39e))
-- **android:** let WebView handle errors ([#7286](https://github.com/Cap-go/capacitor-plus/issues/7286)) ([286b694](https://github.com/Cap-go/capacitor-plus/commit/286b69460f1227a75a9865f91fb51c455fd4370e))
-- **android:** make JSInjector replace first
only ([#6895](https://github.com/Cap-go/capacitor-plus/issues/6895)) ([93c8a8d](https://github.com/Cap-go/capacitor-plus/commit/93c8a8ddbc547a6a9501e02a73719268228ebdca))
-- **android:** make local urls use unpatched fetch ([#6953](https://github.com/Cap-go/capacitor-plus/issues/6953)) ([e50e56c](https://github.com/Cap-go/capacitor-plus/commit/e50e56c5231f230497d1bd420e02e2e065c38f86))
-- **android:** make removeAllListeners return a promise ([#5527](https://github.com/Cap-go/capacitor-plus/issues/5527)) ([6f4d858](https://github.com/Cap-go/capacitor-plus/commit/6f4d858ea879d97109c0c7da2d664d04806adc2a))
-- **android:** Move bridge localUrl initialization to initWebView ([#6685](https://github.com/Cap-go/capacitor-plus/issues/6685)) ([7f5f0ca](https://github.com/Cap-go/capacitor-plus/commit/7f5f0ca4220d40d6a19c778c18f9534ef3b65899))
-- **android:** move initialFocus on webview into config ([#5579](https://github.com/Cap-go/capacitor-plus/issues/5579)) ([8b4e861](https://github.com/Cap-go/capacitor-plus/commit/8b4e861514b0fbe08e9296f49c280234f54742e1))
-- **android:** open external links in browser ([#5913](https://github.com/Cap-go/capacitor-plus/issues/5913)) ([7553ede](https://github.com/Cap-go/capacitor-plus/commit/7553ede93170971e21ab3dec1798443d084ead2a))
-- **android:** prevent app from loading if server.url is invalid ([d4a0dea](https://github.com/Cap-go/capacitor-plus/commit/d4a0deaa37eda4476f0be030e266c2c1260fc6e8))
-- **android:** prevent crash on script injection if the script is too long ([#7308](https://github.com/Cap-go/capacitor-plus/issues/7308)) ([c9895e8](https://github.com/Cap-go/capacitor-plus/commit/c9895e89aeb69613906fc8a2270f7bf3f4913fda))
-- **android:** prevent input file crash if accept has . ([#5363](https://github.com/Cap-go/capacitor-plus/issues/5363)) ([bdacb30](https://github.com/Cap-go/capacitor-plus/commit/bdacb300bb6391dc4b84bb2bab075df993a15cba))
-- **android:** proper app url check for launching intents ([#6450](https://github.com/Cap-go/capacitor-plus/issues/6450)) ([302ba35](https://github.com/Cap-go/capacitor-plus/commit/302ba353acbd6d67e96e2b28870bc9c5bb4e9af0))
-- **android:** Publish proguard-rules.pro on npm ([#5761](https://github.com/Cap-go/capacitor-plus/issues/5761)) ([df77103](https://github.com/Cap-go/capacitor-plus/commit/df77103ca411fa452239099769289eeeea2404d2))
-- **android:** Remove calculated bottom inset if keyboard is visible ([#8280](https://github.com/Cap-go/capacitor-plus/issues/8280)) ([196b642](https://github.com/Cap-go/capacitor-plus/commit/196b642236d293a5012e3c307fcd942766e56cce))
-- **android:** remove kotlin-bom dependency ([#8237](https://github.com/Cap-go/capacitor-plus/issues/8237)) ([a894749](https://github.com/Cap-go/capacitor-plus/commit/a89474920569d404e3b19e22e782e656d5b59bdd))
-- **android:** Remove path from allowedOriginRules ([#7293](https://github.com/Cap-go/capacitor-plus/issues/7293)) ([9eb565c](https://github.com/Cap-go/capacitor-plus/commit/9eb565cddd30888125d1503d1c0a5aa5aa5e48cb))
-- **android:** remove stored references to bridge that holds it in memory ([#6448](https://github.com/Cap-go/capacitor-plus/issues/6448)) ([4737d2b](https://github.com/Cap-go/capacitor-plus/commit/4737d2b46b480c7c0246ac6414494cbbdac7811b))
-- **android:** rename bridge layout to avoid collision ([#7919](https://github.com/Cap-go/capacitor-plus/issues/7919)) ([a629f16](https://github.com/Cap-go/capacitor-plus/commit/a629f167b345cda1c44f37131235d14353eff504))
-- **android:** replace deprecated Gradle property name syntax ([b68ac9e](https://github.com/Cap-go/capacitor-plus/commit/b68ac9e2dfc3ed292b7879bd7aeaab3d05ac84d5))
-- **android:** revert cookie manager initialization to plugin load ([53a2d47](https://github.com/Cap-go/capacitor-plus/commit/53a2d4792e026a89723a672a01fc34990add71f0))
-- **android:** sanitize portable file name ([#7894](https://github.com/Cap-go/capacitor-plus/issues/7894)) ([5f09297](https://github.com/Cap-go/capacitor-plus/commit/5f092970e33da1ec896efc4e2a5ae3fb77fca658))
-- **android:** send FormData on older devices ([#7519](https://github.com/Cap-go/capacitor-plus/issues/7519)) ([de8b50d](https://github.com/Cap-go/capacitor-plus/commit/de8b50dc1d87510c5f19d04f30b6be12b51d8482))
-- **android:** set all cookies on proxied requests ([#5781](https://github.com/Cap-go/capacitor-plus/issues/5781)) ([5ef6a38](https://github.com/Cap-go/capacitor-plus/commit/5ef6a3889121dd39a9159ff80250df18854bc557))
-- **android:** set WebViewClient on the WebView ([#5919](https://github.com/Cap-go/capacitor-plus/issues/5919)) ([020ed8e](https://github.com/Cap-go/capacitor-plus/commit/020ed8eaeb7864399d4b93f54ab7601c607d8e0d))
-- **android:** Silence deprecation warning on handlePermissionResult ([#6092](https://github.com/Cap-go/capacitor-plus/issues/6092)) ([888b13e](https://github.com/Cap-go/capacitor-plus/commit/888b13e89c48dab949b38135a3ec443ac4fd852e))
-- **android:** solve and/or silence lint errors ([#6358](https://github.com/Cap-go/capacitor-plus/issues/6358)) ([c627415](https://github.com/Cap-go/capacitor-plus/commit/c627415743bec92dcb65ab8b8840003d8c0a5286))
-- **android:** unify kotlin dependency version ([#6501](https://github.com/Cap-go/capacitor-plus/issues/6501)) ([0a40477](https://github.com/Cap-go/capacitor-plus/commit/0a4047768cbde9bc17d92955e64ab11d2e3b3335))
-- **android:** Use Logger class instead of Log in CapacitorCookieManager ([#6923](https://github.com/Cap-go/capacitor-plus/issues/6923)) ([8aaa356](https://github.com/Cap-go/capacitor-plus/commit/8aaa356ab1f14b56df821e8ac0bb7e43bfa094fa))
-- **android:** UTF-8 encode form data value ([#7525](https://github.com/Cap-go/capacitor-plus/issues/7525)) ([a73ed31](https://github.com/Cap-go/capacitor-plus/commit/a73ed318cdb819863425f6b1b7ec23ea53454931))
-- **cookies:** check isEnabled before setting cookieHandler ([bb04f24](https://github.com/Cap-go/capacitor-plus/commit/bb04f24f0b4a99e46ed5ca047d3d3df81804d516))
-- **cookies:** hide httpOnly cookies from client ([0cc927e](https://github.com/Cap-go/capacitor-plus/commit/0cc927ef5f0f7076a6d486d666d78483f1d71c54))
-- **cookies:** init cookie manager after server url is set ([0ee772f](https://github.com/Cap-go/capacitor-plus/commit/0ee772ff6456ad0948a0dd025dfcf2658a5563a0))
-- **cookies:** make document.cookie setter synchronous ([2272abf](https://github.com/Cap-go/capacitor-plus/commit/2272abf3d3d9dc82d9ca0d03b17e2b78f11f61fc))
-- **cookies:** remove session cookies when initializing the cookie manager ([037863b](https://github.com/Cap-go/capacitor-plus/commit/037863bea6f3a00978125dc2f8ecba1e896c0740))
-- **cookies:** sanitize url before retrieving/setting cookies ([ca40634](https://github.com/Cap-go/capacitor-plus/commit/ca4063471f215d3f7525e51592d9c72138a52855))
-- **cookies:** Use Set-Cookie headers to persist cookies ([57f8b39](https://github.com/Cap-go/capacitor-plus/commit/57f8b39d7f4c5ee0e5e5cb316913e9450a81d22b))
-- **core:** Exception object was not set on Cap ([#5917](https://github.com/Cap-go/capacitor-plus/issues/5917)) ([9ca27a4](https://github.com/Cap-go/capacitor-plus/commit/9ca27a4f8441b368f8bf9d97dda57b1a55ac0e4e))
-- **core:** make 'content-type' header count for XMLHttpRequest patch ([#7161](https://github.com/Cap-go/capacitor-plus/issues/7161)) ([26d7f68](https://github.com/Cap-go/capacitor-plus/commit/26d7f688284914c6ef795564ba424119efc32a1c))
-- handle fetch headers that are Headers objects ([#6320](https://github.com/Cap-go/capacitor-plus/issues/6320)) ([cb00e49](https://github.com/Cap-go/capacitor-plus/commit/cb00e4952acca8e877555f30b2190f6685d25934))
-- http content headers not sent when using axios ([#8039](https://github.com/Cap-go/capacitor-plus/issues/8039)) ([67cac40](https://github.com/Cap-go/capacitor-plus/commit/67cac40660b3e8cc78d1d228b7c6915450948ef1))
-- **http:** add support for Request objects in fetch ([24b3cc1](https://github.com/Cap-go/capacitor-plus/commit/24b3cc113e3d8aae5d85dbf2d25bec0c35136477))
-- **http:** Add URLSearchParams support ([#7374](https://github.com/Cap-go/capacitor-plus/issues/7374)) ([9367ecc](https://github.com/Cap-go/capacitor-plus/commit/9367ecc56a0c78249dccdf95dca5006422144289))
-- **http:** better handling of active requests and shutting down gracefully ([5d294c9](https://github.com/Cap-go/capacitor-plus/commit/5d294c9b84f09bab649a7112c86959a41a9a4f5e))
-- **http:** boundary not added for Request objects ([#7897](https://github.com/Cap-go/capacitor-plus/issues/7897)) ([bdaa6f3](https://github.com/Cap-go/capacitor-plus/commit/bdaa6f3c38c33f3a021ac61f2de89101a5b66cff))
-- **http:** change proxy url generation ([#7354](https://github.com/Cap-go/capacitor-plus/issues/7354)) ([318c316](https://github.com/Cap-go/capacitor-plus/commit/318c316847c5b059fb88b46d4acd31e1ced477e5))
-- **http:** disconnect active connections if call or bridge is destroyed ([a1ed6cc](https://github.com/Cap-go/capacitor-plus/commit/a1ed6cc6f07465d683b95e3796d944f863a7b857))
-- **http:** don't override readyState for non POST requests ([#7488](https://github.com/Cap-go/capacitor-plus/issues/7488)) ([30c13a8](https://github.com/Cap-go/capacitor-plus/commit/30c13a865e7710e6dc5f0ee014e951d52d030795))
-- **http:** don't throw errors when content-type is null on response ([#6627](https://github.com/Cap-go/capacitor-plus/issues/6627)) ([538821f](https://github.com/Cap-go/capacitor-plus/commit/538821f267aa3b79548fed6aaea8880ff949ffdd))
-- **http:** fire events in correct order when using xhr ([5ed3617](https://github.com/Cap-go/capacitor-plus/commit/5ed361787596bb5949f6ae5e366495f296352bf3))
-- **http:** fix exception thrown on 204 responses ([1f6e8be](https://github.com/Cap-go/capacitor-plus/commit/1f6e8be9d8813c4397e2c54ac4c06beb55f97b5f))
-- **http:** fix local http requests on native platforms ([c4e040a](https://github.com/Cap-go/capacitor-plus/commit/c4e040a6f8c6b54bac6ae320e5f0f008604fe50f))
-- **http:** handle proxy urls with port ([#7273](https://github.com/Cap-go/capacitor-plus/issues/7273)) ([514409a](https://github.com/Cap-go/capacitor-plus/commit/514409aeb93ad65be105bbe2da8d2cd86ff159b0))
-- **http:** handle UInt8Array on body ([#7546](https://github.com/Cap-go/capacitor-plus/issues/7546)) ([cfb9ce1](https://github.com/Cap-go/capacitor-plus/commit/cfb9ce175615f69fe86b61af6d51ec2044d147cd))
-- **http:** inherit object properties on window.XMLHttpRequest ([91c11d0](https://github.com/Cap-go/capacitor-plus/commit/91c11d06f773c45a10f6f2d52f672ae6f189b162))
-- **http:** keep original URL properties on proxy ([#7329](https://github.com/Cap-go/capacitor-plus/issues/7329)) ([cbb6407](https://github.com/Cap-go/capacitor-plus/commit/cbb6407225b42a0d9db4f335a9766f119501021d))
-- **http:** Make proxy work with Request objects ([#7348](https://github.com/Cap-go/capacitor-plus/issues/7348)) ([7e68725](https://github.com/Cap-go/capacitor-plus/commit/7e6872573df03ab5cdc10a1a27db3e9fe81a141d))
-- **http:** parse readablestream data on fetch request objects ([#6919](https://github.com/Cap-go/capacitor-plus/issues/6919)) ([80ec3b7](https://github.com/Cap-go/capacitor-plus/commit/80ec3b73db18b7b6841bf90ed50a67389946ab87))
-- **http:** pass original url as query param on the proxy url ([#7527](https://github.com/Cap-go/capacitor-plus/issues/7527)) ([1da06e6](https://github.com/Cap-go/capacitor-plus/commit/1da06e66cb9cfbf5a5cc48ba6c23cdbe18bc8fc0))
-- **http:** prevent POST request from being proxied ([#7395](https://github.com/Cap-go/capacitor-plus/issues/7395)) ([7b8c352](https://github.com/Cap-go/capacitor-plus/commit/7b8c3523decd5610dcf09e926640bf35b382d61d))
-- **http:** Properly URL-encode key and values during `x-www-form-urlencoded` POSTs ([#8037](https://github.com/Cap-go/capacitor-plus/issues/8037)) ([87b4641](https://github.com/Cap-go/capacitor-plus/commit/87b4641d1fa32b78e6fc2e87ee7b2c49b625b213))
-- **http:** properly write form-urlencoded data on android request body ([#7001](https://github.com/Cap-go/capacitor-plus/issues/7001)) ([a986ee5](https://github.com/Cap-go/capacitor-plus/commit/a986ee541f54a1d3ac637b514fe547b224b36903))
-- **http:** return numbers and booleans as-is when application/json is the content type ([03dd3f9](https://github.com/Cap-go/capacitor-plus/commit/03dd3f96c7ee75b6fff2b7c40d0c9a58fb04fce5))
-- **http:** return valid response for relative url xhr requests ([bde6569](https://github.com/Cap-go/capacitor-plus/commit/bde65696218f97a8328041f137457f46e5eb766a))
-- **http:** route get requests through custom handler ([#6818](https://github.com/Cap-go/capacitor-plus/issues/6818)) ([b853d06](https://github.com/Cap-go/capacitor-plus/commit/b853d065055b5a819949551be58b62d40b52e37c))
-- **http:** set port for proxy url ([#7341](https://github.com/Cap-go/capacitor-plus/issues/7341)) ([a3059dc](https://github.com/Cap-go/capacitor-plus/commit/a3059dca4a7746d9fb7102a7d41f4da80e2f48b4))
-- **ios/android:** better http error handling ([#6208](https://github.com/Cap-go/capacitor-plus/issues/6208)) ([7d4d70a](https://github.com/Cap-go/capacitor-plus/commit/7d4d70a0500b7996c710c0762907f44bdf27c92b))
-- **ios/android:** copy url from nativeResponse to response ([#6482](https://github.com/Cap-go/capacitor-plus/issues/6482)) ([828fb71](https://github.com/Cap-go/capacitor-plus/commit/828fb71ebb52c0655d5879ad0edaac7368ab2b96))
-- **ios:** Correctly Attach Headers to Request ([#6303](https://github.com/Cap-go/capacitor-plus/issues/6303)) ([a3f875c](https://github.com/Cap-go/capacitor-plus/commit/a3f875cf42e111fde07d6e87643264b19ed77573))
-- **ios:** crash when http headers contain numbers ([#6251](https://github.com/Cap-go/capacitor-plus/issues/6251)) ([028c556](https://github.com/Cap-go/capacitor-plus/commit/028c556a50b41ee99fe8f4f1aa2f42d3fd57f92d))
-- make Plugin.resolve act consistently ([#8225](https://github.com/Cap-go/capacitor-plus/issues/8225)) ([06aeb9e](https://github.com/Cap-go/capacitor-plus/commit/06aeb9e85d162d6be9d96820edcb2008cd74da84))
-- remove accept-charset ([#6386](https://github.com/Cap-go/capacitor-plus/issues/6386)) ([bbf6f7e](https://github.com/Cap-go/capacitor-plus/commit/bbf6f7e1af0c49c0bc917942b6715c613be3f557))
-- Remove all plugin listeners in bridge reset ([#7962](https://github.com/Cap-go/capacitor-plus/issues/7962)) ([06aeea9](https://github.com/Cap-go/capacitor-plus/commit/06aeea973aa56ac2fb791f893ebd899253ee65f9))
-- secure cookies often are not set by the cookie plugin ([#7261](https://github.com/Cap-go/capacitor-plus/issues/7261)) ([cda1886](https://github.com/Cap-go/capacitor-plus/commit/cda18861aea3ced7835f959cba612cea98761c58))
-- vue 3 log warning causes error on iOS ([#6993](https://github.com/Cap-go/capacitor-plus/issues/6993)) ([87271e2](https://github.com/Cap-go/capacitor-plus/commit/87271e2671013ad35d13b22f2e96d4fe8f4eeaf0))
+## [8.3.2](https://github.com/ionic-team/capacitor/compare/8.3.1...8.3.2) (2026-05-07)
-### Features
+### Bug Fixes
-- Add function to inject external JS into WebView before document load ([#7864](https://github.com/Cap-go/capacitor-plus/issues/7864)) ([ec0954c](https://github.com/Cap-go/capacitor-plus/commit/ec0954c197543e913939f3ab9c4bcb172bfa3530))
-- Add global initialFocus configuration ([#7775](https://github.com/Cap-go/capacitor-plus/issues/7775)) ([61d0165](https://github.com/Cap-go/capacitor-plus/commit/61d01653685d8e3594d2d8a6bd870fa9643ba95c))
-- Add option for custom error page ([#5723](https://github.com/Cap-go/capacitor-plus/issues/5723)) ([e8bdef3](https://github.com/Cap-go/capacitor-plus/commit/e8bdef3b4634e4ad45fa8fc34c7c0ab8dfa383f3))
-- **android:** don't allow server.androidScheme to be set to schemes handled by WebView ([01285ba](https://github.com/Cap-go/capacitor-plus/commit/01285ba253d602b08a41240ad2ccf370730d51a3))
-- **android/cli:** Allow to use the old addJavascriptInterface bridge ([#6043](https://github.com/Cap-go/capacitor-plus/issues/6043)) ([a6e7c54](https://github.com/Cap-go/capacitor-plus/commit/a6e7c5422687b703492a5fcc49369eacc376143d))
-- **android:** add ability to create config from a custom file path ([#6264](https://github.com/Cap-go/capacitor-plus/issues/6264)) ([42b4f0f](https://github.com/Cap-go/capacitor-plus/commit/42b4f0f416c8038ae368860007910bb09c8ec84e))
-- **android:** add adjustMarginsForEdgeToEdge configuration option ([#7885](https://github.com/Cap-go/capacitor-plus/issues/7885)) ([1ea86d1](https://github.com/Cap-go/capacitor-plus/commit/1ea86d166afd315e72847c5e734a8c175fb90e04))
-- **android:** Add android.minWebviewVersion configuration option ([#5768](https://github.com/Cap-go/capacitor-plus/issues/5768)) ([ad83827](https://github.com/Cap-go/capacitor-plus/commit/ad838279e9cd190ce6f1a020a0ac9e3916786324))
-- **android:** add check for excluded domains before ssl request ([7906d36](https://github.com/Cap-go/capacitor-plus/commit/7906d3616e8bfb2e2c1c81ee123424c06fc4e5ab))
-- **android:** Add getLong helper on PluginCall ([#5235](https://github.com/Cap-go/capacitor-plus/issues/5235)) ([26261fb](https://github.com/Cap-go/capacitor-plus/commit/26261fb49211330c4db72c259359565da7d7bc4b))
-- **android:** Add Optional Data Param for Error Object ([#5719](https://github.com/Cap-go/capacitor-plus/issues/5719)) ([174172b](https://github.com/Cap-go/capacitor-plus/commit/174172b6c64dc9117c48ed0e20c25e0b6c2fb625))
-- **android:** Add overridable routing for WebViewLocalServer ([#5553](https://github.com/Cap-go/capacitor-plus/issues/5553)) ([3bb288e](https://github.com/Cap-go/capacitor-plus/commit/3bb288e848c5c0e49c1e58c0782e0b1ffd7b1f31))
-- **android:** Add SSL Pinning logic ([#6314](https://github.com/Cap-go/capacitor-plus/issues/6314)) ([07f113e](https://github.com/Cap-go/capacitor-plus/commit/07f113e6933e15c45d772f69f7128cbb3706f7b9))
-- **android:** allow developers to provide logic for onRenderProcessGone in WebViewListener ([#6966](https://github.com/Cap-go/capacitor-plus/issues/6966)) ([79e17bb](https://github.com/Cap-go/capacitor-plus/commit/79e17bb5e6ccd813bddc626703152d3983f6d93b))
-- **android:** Bump default minSdkVersion to 24 ([#8083](https://github.com/Cap-go/capacitor-plus/issues/8083)) ([c022ddf](https://github.com/Cap-go/capacitor-plus/commit/c022ddf21452379bb183ff7c846f73bd07a15dbf))
-- **android:** enable loading of assets outside of the content web asset directory ([#6301](https://github.com/Cap-go/capacitor-plus/issues/6301)) ([364497d](https://github.com/Cap-go/capacitor-plus/commit/364497d4aca93fc716a0673ef9103479aed791ec))
-- **android:** Fix for [#6258](https://github.com/Cap-go/capacitor-plus/issues/6258), Add support for modern Huawei devices ([#6402](https://github.com/Cap-go/capacitor-plus/issues/6402)) ([17f2f4a](https://github.com/Cap-go/capacitor-plus/commit/17f2f4ac744a038c1dae3cbd74a670d5ede92ef3))
-- **android:** Improving SystemBars inset handling ([#8268](https://github.com/Cap-go/capacitor-plus/issues/8268)) ([81ae30a](https://github.com/Cap-go/capacitor-plus/commit/81ae30a503797e417dd125b06262dabc4696c88a))
-- **android:** Load alternative layout when no WebView ([#7141](https://github.com/Cap-go/capacitor-plus/issues/7141)) ([87c399a](https://github.com/Cap-go/capacitor-plus/commit/87c399ab6b41f217b4d8a58bfb916a5d78641fd0))
-- **android:** Plugin Instance Support ([#6073](https://github.com/Cap-go/capacitor-plus/issues/6073)) ([3d5b7c2](https://github.com/Cap-go/capacitor-plus/commit/3d5b7c2d372cf764c625f46d1e8761e05b8959da))
-- **android:** Removing enableJetifier ([#6333](https://github.com/Cap-go/capacitor-plus/issues/6333)) ([fc0b403](https://github.com/Cap-go/capacitor-plus/commit/fc0b403265f63eab35cdb2f262fb1e047db4b6bd))
-- **android:** set default targetSDK to 31 ([#5442](https://github.com/Cap-go/capacitor-plus/issues/5442)) ([4442459](https://github.com/Cap-go/capacitor-plus/commit/4442459b24cdbac25cb1e4de11583d22c21452b3))
-- **android:** set default targetSDK to 32 ([#5611](https://github.com/Cap-go/capacitor-plus/issues/5611)) ([416b966](https://github.com/Cap-go/capacitor-plus/commit/416b9662fbf6233d23216c0c0441862603c3a723))
-- **android:** update gradle to 8.0.2 and gradle plugin to 8.0.0 ([#6497](https://github.com/Cap-go/capacitor-plus/issues/6497)) ([01b5b39](https://github.com/Cap-go/capacitor-plus/commit/01b5b399324ae5d0896989478a6910fb946542d7))
-- **android:** update support for Portals for Capacitor to include Live Updates ([#5660](https://github.com/Cap-go/capacitor-plus/issues/5660)) ([62f0a5e](https://github.com/Cap-go/capacitor-plus/commit/62f0a5eaa40776aad79dbf8f8c0900037d3cc97e))
-- **android:** Upgrade gradle to 7.4 ([#5445](https://github.com/Cap-go/capacitor-plus/issues/5445)) ([28eaf18](https://github.com/Cap-go/capacitor-plus/commit/28eaf1851fa7a912917dbb40c68fb4dd583d08ad))
-- **android:** Use addWebMessageListener where available ([#5427](https://github.com/Cap-go/capacitor-plus/issues/5427)) ([c2dfe80](https://github.com/Cap-go/capacitor-plus/commit/c2dfe808446717412b35e82713d123b7a052f264))
-- **android:** Use java 11 ([#5552](https://github.com/Cap-go/capacitor-plus/issues/5552)) ([e47959f](https://github.com/Cap-go/capacitor-plus/commit/e47959fcbd6a89b97b1275a5814fdb4e7ce30672))
-- Capacitor Cookies & Capacitor Http core plugins ([d4047cf](https://github.com/Cap-go/capacitor-plus/commit/d4047cfa947676777f400389a8d65defae140b45))
-- **cookies:** add get cookies plugin method ([ba1e770](https://github.com/Cap-go/capacitor-plus/commit/ba1e7702a3338714aee24388c0afea39706c9341))
-- expose `appStartPath` on cap config server configuration ([#8019](https://github.com/Cap-go/capacitor-plus/issues/8019)) ([a274fef](https://github.com/Cap-go/capacitor-plus/commit/a274fef069176a8e528a22f4734d1e29a539709c))
-- **http:** Apply overrideUserAgent to requests ([#7906](https://github.com/Cap-go/capacitor-plus/issues/7906)) ([52482c9](https://github.com/Cap-go/capacitor-plus/commit/52482c9d3c575b737054b41f9d1730c70cc5f471))
-- **http:** support for FormData requests ([#6708](https://github.com/Cap-go/capacitor-plus/issues/6708)) ([849c564](https://github.com/Cap-go/capacitor-plus/commit/849c56458205bea3b078b1ee19807d7fd84c47b1))
-- Implement automated upstream sync and review process for Capacitor+ ([54a5dfb](https://github.com/Cap-go/capacitor-plus/commit/54a5dfbd1f81ca4144e13b3051bf592d3aaf1f4a))
-- **iOS, Android:** add AppUUID Lib for plugins ([#5690](https://github.com/Cap-go/capacitor-plus/issues/5690)) ([05e76cf](https://github.com/Cap-go/capacitor-plus/commit/05e76cf526a44e07fa75f9482fa2223a13918638))
-- retain multiple calls per event until consumed ([#6419](https://github.com/Cap-go/capacitor-plus/issues/6419)) ([5aba2cb](https://github.com/Cap-go/capacitor-plus/commit/5aba2cbe29bdbab2a7af861c65d8323acf9c54a6))
-- support for Amazon Fire WebView ([#6603](https://github.com/Cap-go/capacitor-plus/issues/6603)) ([3cb4eb8](https://github.com/Cap-go/capacitor-plus/commit/3cb4eb89632bce8dc872418fdb130bfd4de40b68))
-- System Bars Plugin ([#8180](https://github.com/Cap-go/capacitor-plus/issues/8180)) ([a32216a](https://github.com/Cap-go/capacitor-plus/commit/a32216ac0607172a3a9c7ae5cdbfc598769294a6))
-- **webview:** add setServerAssetPath method ([881235b](https://github.com/Cap-go/capacitor-plus/commit/881235b14de23ef988746bfb89a5a0fc3c8d8466))
+- **SystemBars:** avoid extra view padding on API <= 34 ([#8439](https://github.com/ionic-team/capacitor/issues/8439)) ([5b135a7](https://github.com/ionic-team/capacitor/commit/5b135a70217be560e7176c8d5b514cc92ed3e4e4))
## [8.3.1](https://github.com/ionic-team/capacitor/compare/8.3.0...8.3.1) (2026-04-16)
diff --git a/android/capacitor-cordova/build.gradle b/android/capacitor-cordova/build.gradle
new file mode 100644
index 0000000000..4ce5f5eaaa
--- /dev/null
+++ b/android/capacitor-cordova/build.gradle
@@ -0,0 +1,44 @@
+ext {
+ androidxAppCompatVersion = project.hasProperty('androidxAppCompatVersion') ? rootProject.ext.androidxAppCompatVersion : '1.7.1'
+ cordovaAndroidVersion = project.hasProperty('cordovaAndroidVersion') ? rootProject.ext.cordovaAndroidVersion : '14.0.1'
+}
+
+buildscript {
+ repositories {
+ google()
+ mavenCentral()
+ }
+ dependencies {
+ classpath 'com.android.tools.build:gradle:9.2.1'
+ }
+}
+
+apply plugin: 'com.android.library'
+
+android {
+ namespace = "com.getcapacitor.cordova"
+ compileSdk = project.hasProperty('compileSdkVersion') ? rootProject.ext.compileSdkVersion : 37
+ defaultConfig {
+ minSdkVersion project.hasProperty('minSdkVersion') ? rootProject.ext.minSdkVersion : 26
+ versionCode 1
+ versionName "1.0"
+ consumerProguardFiles 'proguard-rules.pro'
+ }
+ compileOptions {
+ sourceCompatibility JavaVersion.VERSION_21
+ targetCompatibility JavaVersion.VERSION_21
+ }
+ publishing {
+ singleVariant("release")
+ }
+}
+
+repositories {
+ google()
+ mavenCentral()
+}
+
+dependencies {
+ implementation project(':capacitor-android')
+ implementation "org.apache.cordova:framework:$cordovaAndroidVersion"
+}
diff --git a/android/capacitor-cordova/proguard-rules.pro b/android/capacitor-cordova/proguard-rules.pro
new file mode 100644
index 0000000000..9a21635529
--- /dev/null
+++ b/android/capacitor-cordova/proguard-rules.pro
@@ -0,0 +1,4 @@
+-keep public class * extends org.apache.cordova.* {
+ public ;
+ public ;
+}
diff --git a/android/capacitor-cordova/src/main/AndroidManifest.xml b/android/capacitor-cordova/src/main/AndroidManifest.xml
new file mode 100644
index 0000000000..9a40236b94
--- /dev/null
+++ b/android/capacitor-cordova/src/main/AndroidManifest.xml
@@ -0,0 +1,3 @@
+
+
+
diff --git a/android/capacitor/src/main/java/com/getcapacitor/cordova/CapacitorCordovaCookieManager.java b/android/capacitor-cordova/src/main/java/com/getcapacitor/cordova/CapacitorCordovaCookieManager.java
similarity index 100%
rename from android/capacitor/src/main/java/com/getcapacitor/cordova/CapacitorCordovaCookieManager.java
rename to android/capacitor-cordova/src/main/java/com/getcapacitor/cordova/CapacitorCordovaCookieManager.java
diff --git a/android/capacitor-cordova/src/main/java/com/getcapacitor/cordova/CordovaPlugin.java b/android/capacitor-cordova/src/main/java/com/getcapacitor/cordova/CordovaPlugin.java
new file mode 100644
index 0000000000..5fe4e74b5b
--- /dev/null
+++ b/android/capacitor-cordova/src/main/java/com/getcapacitor/cordova/CordovaPlugin.java
@@ -0,0 +1,147 @@
+package com.getcapacitor.cordova;
+
+import android.content.Intent;
+import android.os.Bundle;
+import android.webkit.WebView;
+import com.getcapacitor.Logger;
+import com.getcapacitor.Plugin;
+import com.getcapacitor.annotation.CapacitorPlugin;
+import java.util.List;
+import org.apache.cordova.ConfigXmlParser;
+import org.apache.cordova.CordovaInterface;
+import org.apache.cordova.CordovaPreferences;
+import org.apache.cordova.CordovaWebView;
+import org.apache.cordova.PluginEntry;
+import org.apache.cordova.PluginManager;
+import org.json.JSONException;
+
+@CapacitorPlugin(name = "__CordovaPlugin")
+public class CordovaPlugin extends Plugin {
+
+ private MockCordovaInterfaceImpl cordovaInterface;
+ private CordovaWebView webView;
+ private CordovaPreferences preferences;
+
+ private boolean pluginHadActivityResult = false;
+ private boolean pluginHadPermissionResult = false;
+
+ @Override
+ public void load() {
+ ConfigXmlParser parser = new ConfigXmlParser();
+ parser.parse(getActivity().getApplicationContext());
+ preferences = parser.getPreferences();
+ preferences.setPreferencesBundle(getActivity().getIntent().getExtras());
+ List pluginEntries = parser.getPluginEntries();
+
+ cordovaInterface = new MockCordovaInterfaceImpl(getActivity());
+
+ MockCordovaWebViewImpl mockWebView = new MockCordovaWebViewImpl(getActivity().getApplicationContext());
+ mockWebView.init(cordovaInterface, pluginEntries, preferences, bridge.getWebView());
+ webView = mockWebView;
+ PluginManager pluginManager = mockWebView.getPluginManager();
+ cordovaInterface.onCordovaInit(pluginManager);
+
+ bridge.registerInterceptor("cordova", (postData) -> {
+ String callbackId = postData.getString("callbackId");
+
+ String service = postData.getString("service");
+ String action = postData.getString("action");
+ String actionArgs = postData.getString("actionArgs");
+
+ Logger.verbose(
+ Logger.tags("Plugin"),
+ "To native (Cordova plugin): callbackId: " +
+ callbackId +
+ ", service: " +
+ service +
+ ", action: " +
+ action +
+ ", actionArgs: " +
+ actionArgs
+ );
+
+ bridge.execute(() -> {
+ pluginManager.exec(service, action, callbackId, actionArgs);
+ });
+ });
+ }
+
+ @Override
+ protected void restoreState(Bundle state) {
+ if (state != null) {
+ cordovaInterface.restoreInstanceState(state);
+ }
+ }
+
+ @Override
+ protected void handleRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
+ try {
+ pluginHadPermissionResult = cordovaInterface.handlePermissionResult(requestCode, permissions, grantResults);
+ } catch (JSONException e) {
+ Logger.debug("Error on Cordova plugin permissions request " + e.getMessage());
+ }
+ }
+
+ @Override
+ public boolean hasPermission(String permission) {
+ if (permission.equals("DisableDeploy")) {
+ return preferences.getBoolean(permission, false);
+ }
+
+ if (permission.equals("KeepRunning")) {
+ return preferences.getBoolean(permission, true);
+ }
+
+ return false;
+ }
+
+ @Override
+ public boolean hasDefinedRequiredPermissions() {
+ boolean currentPermissionResult = pluginHadPermissionResult;
+ pluginHadPermissionResult = false;
+ return currentPermissionResult;
+ }
+
+ @Override
+ protected void handleOnActivityResult(int requestCode, int resultCode, Intent data) {
+ pluginHadActivityResult = cordovaInterface.onActivityResult(requestCode, resultCode, data);
+ }
+
+ @Override
+ public boolean hasRequiredPermissions() {
+ boolean currentActivityResult = pluginHadActivityResult;
+ pluginHadActivityResult = false;
+ return currentActivityResult;
+ }
+
+ @Override
+ protected void handleOnNewIntent(Intent intent) {
+ webView.onNewIntent(intent);
+ }
+
+ @Override
+ protected void handleOnStart() {
+ webView.handleStart();
+ }
+
+ @Override
+ protected void handleOnResume() {
+ webView.handleResume(bridge.shouldKeepRunning());
+ }
+
+ @Override
+ protected void handleOnPause() {
+ boolean keepRunning = bridge.shouldKeepRunning() || cordovaInterface.getActivityResultCallback() != null;
+ webView.handlePause(keepRunning);
+ }
+
+ @Override
+ protected void handleOnStop() {
+ webView.handleStop();
+ }
+
+ @Override
+ protected void handleOnDestroy() {
+ webView.handleDestroy();
+ }
+}
diff --git a/android/capacitor/src/main/java/com/getcapacitor/cordova/MockCordovaInterfaceImpl.java b/android/capacitor-cordova/src/main/java/com/getcapacitor/cordova/MockCordovaInterfaceImpl.java
similarity index 95%
rename from android/capacitor/src/main/java/com/getcapacitor/cordova/MockCordovaInterfaceImpl.java
rename to android/capacitor-cordova/src/main/java/com/getcapacitor/cordova/MockCordovaInterfaceImpl.java
index 7e8358da5e..11116bf131 100644
--- a/android/capacitor/src/main/java/com/getcapacitor/cordova/MockCordovaInterfaceImpl.java
+++ b/android/capacitor-cordova/src/main/java/com/getcapacitor/cordova/MockCordovaInterfaceImpl.java
@@ -7,7 +7,7 @@
import org.apache.cordova.CordovaPlugin;
import org.json.JSONException;
-public class MockCordovaInterfaceImpl extends CordovaInterfaceImpl {
+class MockCordovaInterfaceImpl extends CordovaInterfaceImpl {
public MockCordovaInterfaceImpl(AppCompatActivity activity) {
super(activity, Executors.newCachedThreadPool());
diff --git a/android/capacitor/src/main/java/com/getcapacitor/cordova/MockCordovaWebViewImpl.java b/android/capacitor-cordova/src/main/java/com/getcapacitor/cordova/MockCordovaWebViewImpl.java
similarity index 94%
rename from android/capacitor/src/main/java/com/getcapacitor/cordova/MockCordovaWebViewImpl.java
rename to android/capacitor-cordova/src/main/java/com/getcapacitor/cordova/MockCordovaWebViewImpl.java
index 1115429d7b..7d6694866e 100644
--- a/android/capacitor/src/main/java/com/getcapacitor/cordova/MockCordovaWebViewImpl.java
+++ b/android/capacitor-cordova/src/main/java/com/getcapacitor/cordova/MockCordovaWebViewImpl.java
@@ -20,7 +20,7 @@
import org.apache.cordova.PluginManager;
import org.apache.cordova.PluginResult;
-public class MockCordovaWebViewImpl implements CordovaWebView {
+class MockCordovaWebViewImpl implements CordovaWebView {
private Context context;
private PluginManager pluginManager;
@@ -32,7 +32,7 @@ public class MockCordovaWebViewImpl implements CordovaWebView {
private WebView webView;
private boolean hasPausedEver;
- public MockCordovaWebViewImpl(Context context) {
+ MockCordovaWebViewImpl(Context context) {
this.context = context;
}
@@ -70,14 +70,12 @@ public CapacitorEvalBridgeMode(WebView webView, CordovaInterface cordova) {
@Override
public void onNativeToJsMessageAvailable(final NativeToJsMessageQueue queue) {
- cordova
- .getActivity()
- .runOnUiThread(() -> {
- String js = queue.popAndEncodeAsJs();
- if (js != null) {
- webView.evaluateJavascript(js, null);
- }
- });
+ cordova.getActivity().runOnUiThread(() -> {
+ String js = queue.popAndEncodeAsJs();
+ if (js != null) {
+ webView.evaluateJavascript(js, null);
+ }
+ });
}
}
diff --git a/android/capacitor/build.gradle b/android/capacitor/build.gradle
index 6ece3eda05..ad5e9e5c3f 100644
--- a/android/capacitor/build.gradle
+++ b/android/capacitor/build.gradle
@@ -8,7 +8,6 @@ ext {
junitVersion = project.hasProperty('junitVersion') ? rootProject.ext.junitVersion : '4.13.2'
androidxJunitVersion = project.hasProperty('androidxJunitVersion') ? rootProject.ext.androidxJunitVersion : '1.3.0'
androidxEspressoCoreVersion = project.hasProperty('androidxEspressoCoreVersion') ? rootProject.ext.androidxEspressoCoreVersion : '3.7.0'
- cordovaAndroidVersion = project.hasProperty('cordovaAndroidVersion') ? rootProject.ext.cordovaAndroidVersion : '14.0.1'
}
@@ -21,7 +20,7 @@ buildscript {
}
}
dependencies {
- classpath 'com.android.tools.build:gradle:8.13.0'
+ classpath 'com.android.tools.build:gradle:9.2.1'
if (System.getenv("CAP_PUBLISH") == "true") {
classpath 'io.github.gradle-nexus:publish-plugin:1.3.0'
@@ -41,10 +40,9 @@ if (System.getenv("CAP_PUBLISH") == "true") {
android {
namespace = "com.getcapacitor.android"
- compileSdk = project.hasProperty('compileSdkVersion') ? rootProject.ext.compileSdkVersion : 36
+ compileSdk = project.hasProperty('compileSdkVersion') ? rootProject.ext.compileSdkVersion : 37
defaultConfig {
- minSdkVersion project.hasProperty('minSdkVersion') ? rootProject.ext.minSdkVersion : 24
- targetSdkVersion project.hasProperty('targetSdkVersion') ? rootProject.ext.targetSdkVersion : 36
+ minSdkVersion project.hasProperty('minSdkVersion') ? rootProject.ext.minSdkVersion : 26
versionCode 1
versionName "1.0"
consumerProguardFiles 'proguard-rules.pro'
@@ -87,8 +85,7 @@ dependencies {
testImplementation "junit:junit:$junitVersion"
androidTestImplementation "androidx.test.ext:junit:$androidxJunitVersion"
androidTestImplementation "androidx.test.espresso:espresso-core:$androidxEspressoCoreVersion"
- implementation "org.apache.cordova:framework:$cordovaAndroidVersion"
- testImplementation 'org.json:json:20250517'
+testImplementation 'org.json:json:20250517'
testImplementation 'org.mockito:mockito-core:5.20.0'
}
diff --git a/android/capacitor/proguard-rules.pro b/android/capacitor/proguard-rules.pro
index 96db065b39..d34e7df58e 100644
--- a/android/capacitor/proguard-rules.pro
+++ b/android/capacitor/proguard-rules.pro
@@ -20,9 +20,3 @@
-keep @com.getcapacitor.NativePlugin public class * {
@com.getcapacitor.PluginMethod public ;
}
-
-# Rules for Cordova plugins
--keep public class * extends org.apache.cordova.* {
- public ;
- public ;
-}
\ No newline at end of file
diff --git a/android/capacitor/src/main/java/com/getcapacitor/Bridge.java b/android/capacitor/src/main/java/com/getcapacitor/Bridge.java
index d4995fbbc9..00dd89d60e 100644
--- a/android/capacitor/src/main/java/com/getcapacitor/Bridge.java
+++ b/android/capacitor/src/main/java/com/getcapacitor/Bridge.java
@@ -11,7 +11,6 @@
import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.net.Uri;
-import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
@@ -35,8 +34,6 @@
import com.getcapacitor.android.R;
import com.getcapacitor.annotation.CapacitorPlugin;
import com.getcapacitor.annotation.Permission;
-import com.getcapacitor.cordova.MockCordovaInterfaceImpl;
-import com.getcapacitor.cordova.MockCordovaWebViewImpl;
import com.getcapacitor.util.HostMask;
import com.getcapacitor.util.InternalUtils;
import com.getcapacitor.util.PermissionHelper;
@@ -55,11 +52,6 @@
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
-import org.apache.cordova.ConfigXmlParser;
-import org.apache.cordova.CordovaPreferences;
-import org.apache.cordova.CordovaWebView;
-import org.apache.cordova.PluginEntry;
-import org.apache.cordova.PluginManager;
import org.json.JSONException;
/**
@@ -125,9 +117,6 @@ public class Bridge {
private Boolean canInjectJS = true;
// A reference to the main WebView for the app
private final WebView webView;
- public final MockCordovaInterfaceImpl cordovaInterface;
- private CordovaWebView cordovaWebView;
- private CordovaPreferences preferences;
private BridgeWebViewClient webViewClient;
private App app;
@@ -147,6 +136,8 @@ public class Bridge {
// A map of Plugin Id's to PluginHandle's
private Map plugins = new HashMap<>();
+ private Map interceptors = new HashMap<>();
+
// Stored plugin calls that we're keeping around to call again someday
private Map savedCalls = new HashMap<>();
@@ -169,26 +160,6 @@ public class Bridge {
// A pre-determined path to load the bridge
private ServerPath serverPath;
- /**
- * Create the Bridge with a reference to the main {@link Activity} for the
- * app, and a reference to the {@link WebView} our app will use.
- * @param context
- * @param webView
- * @deprecated Use {@link Bridge.Builder} to create Bridge instances
- */
- @Deprecated
- public Bridge(
- AppCompatActivity context,
- WebView webView,
- List> initialPlugins,
- MockCordovaInterfaceImpl cordovaInterface,
- PluginManager pluginManager,
- CordovaPreferences preferences,
- CapConfig config
- ) {
- this(context, null, null, webView, initialPlugins, new ArrayList<>(), cordovaInterface, pluginManager, preferences, config);
- }
-
private Bridge(
AppCompatActivity context,
ServerPath serverPath,
@@ -196,9 +167,6 @@ private Bridge(
WebView webView,
List> initialPlugins,
List pluginInstances,
- MockCordovaInterfaceImpl cordovaInterface,
- PluginManager pluginManager,
- CordovaPreferences preferences,
CapConfig config
) {
this.app = new App();
@@ -209,8 +177,6 @@ private Bridge(
this.webViewClient = new BridgeWebViewClient(this);
this.initialPlugins = initialPlugins;
this.pluginInstances = pluginInstances;
- this.cordovaInterface = cordovaInterface;
- this.preferences = preferences;
// Start our plugin execution threads and handlers
handlerThread.start();
@@ -218,11 +184,10 @@ private Bridge(
this.config = config != null ? config : CapConfig.loadDefault(getActivity());
Logger.init(this.config);
-
// Initialize web view and message handler for it
this.initWebView();
this.setAllowedOriginRules();
- this.msgHandler = new MessageHandler(this, webView, pluginManager);
+ this.msgHandler = new MessageHandler(this, webView);
// Grab any intent info that our app was launched with
Intent intent = context.getIntent();
@@ -327,63 +292,19 @@ public WebResourceResponse shouldInterceptRequest(WebResourceRequest request) {
@SuppressLint("WebViewApiAvailability")
public boolean isMinimumWebViewInstalled() {
- PackageManager pm = getContext().getPackageManager();
-
- // Check getCurrentWebViewPackage() directly if above Android 8
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
- PackageInfo info = WebView.getCurrentWebViewPackage();
- Pattern pattern = Pattern.compile("(\\d+)");
- Matcher matcher = pattern.matcher(info.versionName);
- if (matcher.find()) {
- String majorVersionStr = matcher.group(0);
- int majorVersion = Integer.parseInt(majorVersionStr);
- if (info.packageName.equals("com.huawei.webview")) {
- return majorVersion >= config.getMinHuaweiWebViewVersion();
- }
- return majorVersion >= config.getMinWebViewVersion();
- } else {
- return false;
- }
- }
-
- // Otherwise manually check WebView versions
- try {
- PackageInfo info = InternalUtils.getPackageInfo(pm, "com.android.chrome");
- String majorVersionStr = info.versionName.split("\\.")[0];
- int majorVersion = Integer.parseInt(majorVersionStr);
- return majorVersion >= config.getMinWebViewVersion();
- } catch (Exception ex) {
- Logger.warn("Unable to get package info for 'com.google.android.webview'" + ex.toString());
- }
-
- try {
- PackageInfo info = InternalUtils.getPackageInfo(pm, "com.android.webview");
- String majorVersionStr = info.versionName.split("\\.")[0];
+ PackageInfo info = WebView.getCurrentWebViewPackage();
+ Pattern pattern = Pattern.compile("(\\d+)");
+ Matcher matcher = pattern.matcher(info.versionName);
+ if (matcher.find()) {
+ String majorVersionStr = matcher.group(0);
int majorVersion = Integer.parseInt(majorVersionStr);
+ if (info.packageName.equals("com.huawei.webview")) {
+ return majorVersion >= config.getMinHuaweiWebViewVersion();
+ }
return majorVersion >= config.getMinWebViewVersion();
- } catch (Exception ex) {
- Logger.warn("Unable to get package info for 'com.android.webview'" + ex.toString());
- }
-
- final int amazonFireMajorWebViewVersion = extractWebViewMajorVersion(pm, "com.amazon.webview.chromium");
- if (amazonFireMajorWebViewVersion >= config.getMinWebViewVersion()) {
- return true;
- }
-
- // Could not detect any webview, return false
- return false;
- }
-
- private int extractWebViewMajorVersion(final PackageManager pm, final String webViewPackageName) {
- try {
- final PackageInfo info = InternalUtils.getPackageInfo(pm, webViewPackageName);
- final String majorVersionStr = info.versionName.split("\\.")[0];
- final int majorVersion = Integer.parseInt(majorVersionStr);
- return majorVersion;
- } catch (Exception ex) {
- Logger.warn(String.format("Unable to get package info for '%s' with err '%s'", webViewPackageName, ex));
+ } else {
+ return false;
}
- return 0;
}
public boolean launchIntent(Uri url) {
@@ -450,12 +371,30 @@ private boolean isNewBinary() {
return false;
}
+ private Plugin cordova() {
+ PluginHandle handle = getPlugin("__CordovaPlugin");
+ if (handle != null) {
+ return handle.getInstance();
+ }
+ return null;
+ }
+
public boolean isDeployDisabled() {
- return preferences.getBoolean("DisableDeploy", false);
+ Plugin cordova = this.cordova();
+ if (cordova != null) {
+ return cordova.hasPermission("DisableDeploy");
+ } else {
+ return false;
+ }
}
public boolean shouldKeepRunning() {
- return preferences.getBoolean("KeepRunning", true);
+ Plugin cordova = this.cordova();
+ if (cordova != null) {
+ return cordova.hasPermission("KeepRunning");
+ } else {
+ return false;
+ }
}
public void handleAppUrlLoadError(Exception ex) {
@@ -474,10 +413,6 @@ public boolean isDevMode() {
return (getActivity().getApplicationInfo().flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0;
}
- protected void setCordovaWebView(CordovaWebView cordovaWebView) {
- this.cordovaWebView = cordovaWebView;
- }
-
/**
* Get the Context for the App
* @return
@@ -567,6 +502,14 @@ public CapConfig getConfig() {
return this.config;
}
+ public MessageHandler.Interceptor getCallInterceptor(String type) {
+ return this.interceptors.get(type);
+ }
+
+ public void registerInterceptor(String type, MessageHandler.Interceptor interceptor) {
+ this.interceptors.put(type, interceptor);
+ }
+
public void reset() {
savedCalls = new HashMap<>();
for (PluginHandle handle : this.plugins.values()) {
@@ -1132,11 +1075,14 @@ boolean onRequestPermissionsResult(int requestCode, String[] permissions, int[]
if (plugin == null) {
boolean permissionHandled = false;
Logger.debug("Unable to find a Capacitor plugin to handle permission requestCode, trying Cordova plugins " + requestCode);
- try {
- permissionHandled = cordovaInterface.handlePermissionResult(requestCode, permissions, grantResults);
- } catch (JSONException e) {
- Logger.debug("Error on Cordova plugin permissions request " + e.getMessage());
+ PluginHandle cordovaHandle = getPlugin("__CordovaPlugin");
+
+ if (cordovaHandle != null) {
+ Plugin cordovaPlugin = cordovaHandle.getInstance();
+ cordovaPlugin.handleRequestPermissionsResult(requestCode, permissions, grantResults);
+ permissionHandled = cordovaPlugin.hasDefinedRequiredPermissions();
}
+
return permissionHandled;
}
@@ -1271,7 +1217,14 @@ boolean onActivityResult(int requestCode, int resultCode, Intent data) {
if (plugin == null || plugin.getInstance() == null) {
Logger.debug("Unable to find a Capacitor plugin to handle requestCode, trying Cordova plugins " + requestCode);
- return cordovaInterface.onActivityResult(requestCode, resultCode, data);
+ PluginHandle cordovaHandle = getPlugin("__CordovaPlugin");
+ if (cordovaHandle != null) {
+ Plugin cordovaPlugin = cordovaHandle.getInstance();
+ cordovaPlugin.handleOnActivityResult(requestCode, resultCode, data);
+ // This is a bit hacky but required to return the boolean out of the cordova interface
+ return cordovaPlugin.hasRequiredPermissions();
+ }
+ return false;
}
// deprecated, to be removed
@@ -1301,10 +1254,6 @@ public void onNewIntent(Intent intent) {
for (PluginHandle plugin : plugins.values()) {
plugin.getInstance().handleOnNewIntent(intent);
}
-
- if (cordovaWebView != null) {
- cordovaWebView.onNewIntent(intent);
- }
}
/**
@@ -1333,10 +1282,6 @@ public void onStart() {
for (PluginHandle plugin : plugins.values()) {
plugin.getInstance().handleOnStart();
}
-
- if (cordovaWebView != null) {
- cordovaWebView.handleStart();
- }
}
/**
@@ -1346,10 +1291,6 @@ public void onResume() {
for (PluginHandle plugin : plugins.values()) {
plugin.getInstance().handleOnResume();
}
-
- if (cordovaWebView != null) {
- cordovaWebView.handleResume(this.shouldKeepRunning());
- }
}
/**
@@ -1359,11 +1300,6 @@ public void onPause() {
for (PluginHandle plugin : plugins.values()) {
plugin.getInstance().handleOnPause();
}
-
- if (cordovaWebView != null) {
- boolean keepRunning = this.shouldKeepRunning() || cordovaInterface.getActivityResultCallback() != null;
- cordovaWebView.handlePause(keepRunning);
- }
}
/**
@@ -1373,10 +1309,6 @@ public void onStop() {
for (PluginHandle plugin : plugins.values()) {
plugin.getInstance().handleOnStop();
}
-
- if (cordovaWebView != null) {
- cordovaWebView.handleStop();
- }
}
/**
@@ -1388,10 +1320,6 @@ public void onDestroy() {
}
handlerThread.quitSafely();
-
- if (cordovaWebView != null) {
- cordovaWebView.handleDestroy();
- }
}
/**
@@ -1578,49 +1506,54 @@ public Builder setServerPath(ServerPath serverPath) {
public Bridge create() {
// Cordova initialization
- ConfigXmlParser parser = new ConfigXmlParser();
- parser.parse(activity.getApplicationContext());
- CordovaPreferences preferences = parser.getPreferences();
- preferences.setPreferencesBundle(activity.getIntent().getExtras());
- List pluginEntries = parser.getPluginEntries();
-
- MockCordovaInterfaceImpl cordovaInterface = new MockCordovaInterfaceImpl(activity);
- if (instanceState != null) {
- cordovaInterface.restoreInstanceState(instanceState);
- }
-
WebView webView = this.fragment != null ? fragment.getView().findViewById(R.id.webview) : activity.findViewById(R.id.webview);
- MockCordovaWebViewImpl mockWebView = new MockCordovaWebViewImpl(activity.getApplicationContext());
- mockWebView.init(cordovaInterface, pluginEntries, preferences, webView);
- PluginManager pluginManager = mockWebView.getPluginManager();
- cordovaInterface.onCordovaInit(pluginManager);
// Bridge initialization
- Bridge bridge = new Bridge(
- activity,
- serverPath,
- fragment,
- webView,
- plugins,
- pluginInstances,
- cordovaInterface,
- pluginManager,
- preferences,
- config
- );
+ Bridge bridge = new Bridge(activity, serverPath, fragment, webView, plugins, pluginInstances, config);
if (webView instanceof CapacitorWebView capacitorWebView) {
capacitorWebView.setBridge(bridge);
}
- bridge.setCordovaWebView(mockWebView);
bridge.setWebViewListeners(webViewListeners);
bridge.setRouteProcessor(routeProcessor);
if (instanceState != null) {
+ PluginHandle maybeCordova = bridge.getPlugin("__CordovaPlugin");
+ if (maybeCordova != null) {
+ maybeCordova.getInstance().restoreState(instanceState);
+ }
bridge.restoreInstanceState(instanceState);
}
+ bridge.registerInterceptor("message", (postData) -> {
+ try {
+ String callbackId = postData.getString("callbackId");
+ String pluginId = postData.getString("pluginId");
+ String methodName = postData.getString("methodName");
+ JSObject methodData = postData.getJSObject("options", new JSObject());
+
+ Logger.verbose(
+ Logger.tags("Plugin"),
+ "To native (Capacitor plugin): callbackId: " +
+ callbackId +
+ ", pluginId: " +
+ pluginId +
+ ", methodName: " +
+ methodName
+ );
+
+ PluginCall call = new PluginCall(bridge.msgHandler, pluginId, callbackId, methodName, methodData);
+ bridge.callPluginMethod(pluginId, methodName, call);
+ } catch (JSONException e) {
+ Logger.error(e.getMessage());
+ }
+ });
+
+ bridge.registerInterceptor("js.error", (postData) -> {
+ Logger.error("JavaScript Error: " + postData.toString());
+ });
+
return bridge;
}
}
diff --git a/android/capacitor/src/main/java/com/getcapacitor/BridgeWebChromeClient.java b/android/capacitor/src/main/java/com/getcapacitor/BridgeWebChromeClient.java
index 6ca1c8a838..ec7867369e 100644
--- a/android/capacitor/src/main/java/com/getcapacitor/BridgeWebChromeClient.java
+++ b/android/capacitor/src/main/java/com/getcapacitor/BridgeWebChromeClient.java
@@ -282,7 +282,7 @@ public boolean onShowFileChooser(
boolean captureEnabled = fileChooserParams.isCaptureEnabled();
boolean capturePhoto = captureEnabled && acceptTypes.contains("image/*");
final boolean captureVideo = captureEnabled && acceptTypes.contains("video/*");
- if ((capturePhoto || captureVideo)) {
+ if (capturePhoto || captureVideo) {
if (isMediaCaptureSupported()) {
showMediaCaptureOrFilePicker(filePathCallback, fileChooserParams, captureVideo);
} else {
@@ -447,7 +447,7 @@ public boolean onConsoleMessage(ConsoleMessage consoleMessage) {
}
public boolean isValidMsg(String msg) {
- return !(msg.contains("%cresult %c") || (msg.contains("%cnative %c")) || msg.equalsIgnoreCase("console.groupEnd"));
+ return !(msg.contains("%cresult %c") || msg.contains("%cnative %c") || msg.equalsIgnoreCase("console.groupEnd"));
}
private Uri createImageFileUri() throws IOException {
diff --git a/android/capacitor/src/main/java/com/getcapacitor/FileUtils.java b/android/capacitor/src/main/java/com/getcapacitor/FileUtils.java
index ce09e7c2f0..cec171946c 100644
--- a/android/capacitor/src/main/java/com/getcapacitor/FileUtils.java
+++ b/android/capacitor/src/main/java/com/getcapacitor/FileUtils.java
@@ -218,7 +218,7 @@ private static String getCopyFilePath(Uri uri, Context context) {
Cursor cursor = context.getContentResolver().query(uri, null, null, null, null);
int nameIndex = cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME);
cursor.moveToFirst();
- String name = (cursor.getString(nameIndex));
+ String name = cursor.getString(nameIndex);
String fileName = sanitizeFilename(name);
File file = new File(context.getFilesDir(), fileName);
try {
diff --git a/android/capacitor/src/main/java/com/getcapacitor/MessageHandler.java b/android/capacitor/src/main/java/com/getcapacitor/MessageHandler.java
index dc91c9b01e..4de485b6fe 100644
--- a/android/capacitor/src/main/java/com/getcapacitor/MessageHandler.java
+++ b/android/capacitor/src/main/java/com/getcapacitor/MessageHandler.java
@@ -5,7 +5,7 @@
import androidx.webkit.JavaScriptReplyProxy;
import androidx.webkit.WebViewCompat;
import androidx.webkit.WebViewFeature;
-import org.apache.cordova.PluginManager;
+import java.util.function.Function;
/**
* MessageHandler handles messages from the WebView, dispatching them
@@ -13,15 +13,18 @@
*/
public class MessageHandler {
+ @FunctionalInterface
+ public interface Interceptor {
+ void intercept(JSObject object);
+ }
+
private Bridge bridge;
private WebView webView;
- private PluginManager cordovaPluginManager;
private JavaScriptReplyProxy javaScriptReplyProxy;
- public MessageHandler(Bridge bridge, WebView webView, PluginManager cordovaPluginManager) {
+ public MessageHandler(Bridge bridge, WebView webView) {
this.bridge = bridge;
this.webView = webView;
- this.cordovaPluginManager = cordovaPluginManager;
if (WebViewFeature.isFeatureSupported(WebViewFeature.WEB_MESSAGE_LISTENER) && !bridge.getConfig().isUsingLegacyBridge()) {
WebViewCompat.WebMessageListener capListener = (view, message, sourceOrigin, isMainFrame, replyProxy) -> {
@@ -42,6 +45,11 @@ public MessageHandler(Bridge bridge, WebView webView, PluginManager cordovaPlugi
}
}
+ @Deprecated
+ public MessageHandler(Bridge bridge, WebView webView, Object cordovaPluginManager) {
+ this(bridge, webView);
+ }
+
/**
* The main message handler that will be called from JavaScript
* to send a message to the native bridge.
@@ -55,43 +63,11 @@ public void postMessage(String jsonStr) {
String type = postData.getString("type");
- boolean typeIsNotNull = type != null;
- boolean isCordovaPlugin = typeIsNotNull && type.equals("cordova");
- boolean isJavaScriptError = typeIsNotNull && type.equals("js.error");
-
- String callbackId = postData.getString("callbackId");
-
- if (isCordovaPlugin) {
- String service = postData.getString("service");
- String action = postData.getString("action");
- String actionArgs = postData.getString("actionArgs");
-
- Logger.verbose(
- Logger.tags("Plugin"),
- "To native (Cordova plugin): callbackId: " +
- callbackId +
- ", service: " +
- service +
- ", action: " +
- action +
- ", actionArgs: " +
- actionArgs
- );
-
- this.callCordovaPluginMethod(callbackId, service, action, actionArgs);
- } else if (isJavaScriptError) {
- Logger.error("JavaScript Error: " + jsonStr);
- } else {
- String pluginId = postData.getString("pluginId");
- String methodName = postData.getString("methodName");
- JSObject methodData = postData.getJSObject("options", new JSObject());
-
- Logger.verbose(
- Logger.tags("Plugin"),
- "To native (Capacitor plugin): callbackId: " + callbackId + ", pluginId: " + pluginId + ", methodName: " + methodName
- );
+ if (type == null) type = "message";
- this.callPluginMethod(callbackId, pluginId, methodName, methodData);
+ Interceptor interceptor = bridge.getCallInterceptor(type);
+ if (interceptor != null) {
+ interceptor.intercept(postData);
}
} catch (Exception ex) {
Logger.error("Post message error:", ex);
@@ -148,10 +124,4 @@ private void callPluginMethod(String callbackId, String pluginId, String methodN
PluginCall call = new PluginCall(this, pluginId, callbackId, methodName, methodData);
bridge.callPluginMethod(pluginId, methodName, call);
}
-
- private void callCordovaPluginMethod(String callbackId, String service, String action, String actionArgs) {
- bridge.execute(() -> {
- cordovaPluginManager.exec(service, action, callbackId, actionArgs);
- });
- }
}
diff --git a/android/capacitor/src/main/java/com/getcapacitor/PluginConfig.java b/android/capacitor/src/main/java/com/getcapacitor/PluginConfig.java
index 0f00fc530f..1d21ae90e1 100644
--- a/android/capacitor/src/main/java/com/getcapacitor/PluginConfig.java
+++ b/android/capacitor/src/main/java/com/getcapacitor/PluginConfig.java
@@ -65,6 +65,17 @@ public int getInt(String configKey, int defaultValue) {
return JSONUtils.getInt(config, configKey, defaultValue);
}
+ /**
+ * Get a double value for a plugin in the Capacitor config.
+ *
+ * @param configKey The key of the value to retrieve
+ * @param defaultValue A default value to return if the key does not exist in the config
+ * @return The value from the config, if key exists. Default value returned if not
+ */
+ public double getDouble(String configKey, double defaultValue) {
+ return JSONUtils.getDouble(config, configKey, defaultValue);
+ }
+
/**
* Get a string array value for a plugin in the Capacitor config.
*
diff --git a/android/capacitor/src/main/java/com/getcapacitor/WebViewLocalServer.java b/android/capacitor/src/main/java/com/getcapacitor/WebViewLocalServer.java
index a39483de91..0a2708facb 100755
--- a/android/capacitor/src/main/java/com/getcapacitor/WebViewLocalServer.java
+++ b/android/capacitor/src/main/java/com/getcapacitor/WebViewLocalServer.java
@@ -128,19 +128,6 @@ public String getReasonPhrase() {
return reasonPhrase;
}
- /**
- * @deprecated This method may return incorrect headers in concurrent range requests.
- *
- * Use {@link #buildDefaultResponseHeaders()} instead, which returns a copy of the map.
- *
- * This method will be removed in a future major version of Capacitor.
- *
- */
- @Deprecated(forRemoval = true) // adjust version as appropriate
- public Map getResponseHeaders() {
- return responseHeaders;
- }
-
public Map buildDefaultResponseHeaders() {
return new HashMap<>(responseHeaders);
}
@@ -221,7 +208,7 @@ private boolean isErrorUrl(Uri uri) {
}
private boolean isMainUrl(Uri loadingUrl) {
- return (bridge.getServerUrl() == null && loadingUrl.getHost().equalsIgnoreCase(bridge.getHost()));
+ return bridge.getServerUrl() == null && loadingUrl.getHost().equalsIgnoreCase(bridge.getHost());
}
private boolean isAllowedUrl(Uri loadingUrl) {
@@ -722,31 +709,31 @@ private InputStream getInputStream() {
@Override
public int available() throws IOException {
InputStream is = getInputStream();
- return (is != null) ? is.available() : -1;
+ return is != null ? is.available() : -1;
}
@Override
public int read() throws IOException {
InputStream is = getInputStream();
- return (is != null) ? is.read() : -1;
+ return is != null ? is.read() : -1;
}
@Override
public int read(byte[] b) throws IOException {
InputStream is = getInputStream();
- return (is != null) ? is.read(b) : -1;
+ return is != null ? is.read(b) : -1;
}
@Override
public int read(byte[] b, int off, int len) throws IOException {
InputStream is = getInputStream();
- return (is != null) ? is.read(b, off, len) : -1;
+ return is != null ? is.read(b, off, len) : -1;
}
@Override
public long skip(long n) throws IOException {
InputStream is = getInputStream();
- return (is != null) ? is.skip(n) : 0;
+ return is != null ? is.skip(n) : 0;
}
}
diff --git a/android/capacitor/src/main/java/com/getcapacitor/plugin/CapacitorCookieManager.java b/android/capacitor/src/main/java/com/getcapacitor/plugin/CapacitorCookieManager.java
index cf4ab63266..472323bbc4 100644
--- a/android/capacitor/src/main/java/com/getcapacitor/plugin/CapacitorCookieManager.java
+++ b/android/capacitor/src/main/java/com/getcapacitor/plugin/CapacitorCookieManager.java
@@ -192,12 +192,12 @@ public void flush() {
@Override
public void put(URI uri, Map> responseHeaders) {
// make sure our args are valid
- if ((uri == null) || (responseHeaders == null)) return;
+ if (uri == null || responseHeaders == null) return;
// go over the headers
for (String headerKey : responseHeaders.keySet()) {
// ignore headers which aren't cookie related
- if ((headerKey == null) || !(headerKey.equalsIgnoreCase("Set-Cookie2") || headerKey.equalsIgnoreCase("Set-Cookie"))) continue;
+ if (headerKey == null || !(headerKey.equalsIgnoreCase("Set-Cookie2") || headerKey.equalsIgnoreCase("Set-Cookie"))) continue;
// process each of the headers
for (String headerValue : Objects.requireNonNull(responseHeaders.get(headerKey))) {
@@ -215,7 +215,7 @@ public void put(URI uri, Map> responseHeaders) {
@Override
public Map> get(URI uri, Map> requestHeaders) {
// make sure our args are valid
- if ((uri == null) || (requestHeaders == null)) throw new IllegalArgumentException("Argument is null");
+ if (uri == null || requestHeaders == null) throw new IllegalArgumentException("Argument is null");
// save our url once
String url = uri.toString();
diff --git a/android/capacitor/src/main/java/com/getcapacitor/plugin/SystemBars.java b/android/capacitor/src/main/java/com/getcapacitor/plugin/SystemBars.java
index b335b4b1cf..fd71370945 100644
--- a/android/capacitor/src/main/java/com/getcapacitor/plugin/SystemBars.java
+++ b/android/capacitor/src/main/java/com/getcapacitor/plugin/SystemBars.java
@@ -16,6 +16,7 @@
import androidx.core.view.WindowInsetsCompat;
import androidx.core.view.WindowInsetsControllerCompat;
import androidx.webkit.WebViewCompat;
+import com.getcapacitor.Logger;
import com.getcapacitor.Plugin;
import com.getcapacitor.PluginCall;
import com.getcapacitor.PluginMethod;
@@ -32,6 +33,7 @@ public class SystemBars extends Plugin {
static final String BAR_STATUS_BAR = "StatusBar";
static final String BAR_GESTURE_BAR = "NavigationBar";
+ // TODO: In Cap 9, add an additional option "full"
static final String INSETS_HANDLING_CSS = "css";
static final String INSETS_HANDLING_DISABLE = "disable";
@@ -53,7 +55,7 @@ function capacitorSystemBarsCheckMetaViewport() {
capacitorSystemBarsCheckMetaViewport();
""";
- private boolean insetHandlingEnabled = true;
+ private String insetsHandling = INSETS_HANDLING_CSS;
private boolean hasViewportCover = false;
private String currentStatusBarStyle = STYLE_DEFAULT;
@@ -94,9 +96,15 @@ private void initSystemBars() {
String style = getConfig().getString("style", STYLE_DEFAULT).toUpperCase(Locale.US);
boolean hidden = getConfig().getBoolean("hidden", false);
- String insetsHandling = getConfig().getString("insetsHandling", "css");
- if (insetsHandling.equals(INSETS_HANDLING_DISABLE)) {
- insetHandlingEnabled = false;
+ String configuredInsetsHandling = getConfig().getString("insetsHandling", INSETS_HANDLING_CSS);
+ if (INSETS_HANDLING_CSS.equals(configuredInsetsHandling) || INSETS_HANDLING_DISABLE.equals(configuredInsetsHandling)) {
+ insetsHandling = configuredInsetsHandling;
+ } else {
+ Logger.warn(
+ "SystemBars",
+ "Unknown insetsHandling value '" + configuredInsetsHandling + "'. Falling back to '" + INSETS_HANDLING_CSS + "'."
+ );
+ insetsHandling = INSETS_HANDLING_CSS;
}
initWindowInsetsListener();
@@ -146,13 +154,15 @@ public void setAnimation(final PluginCall call) {
@JavascriptInterface
public void onDOMReady() {
- getActivity().runOnUiThread(() -> {
- this.bridge.getWebView().evaluateJavascript(viewportMetaJSFunction, (res) -> {
- hasViewportCover = res.equals("true");
+ if (INSETS_HANDLING_CSS.equals(insetsHandling)) {
+ getActivity().runOnUiThread(() -> {
+ this.bridge.getWebView().evaluateJavascript(viewportMetaJSFunction, (res) -> {
+ hasViewportCover = res.equals("true");
- getBridge().getWebView().requestApplyInsets();
+ getBridge().getWebView().requestApplyInsets();
+ });
});
- });
+ }
}
private Insets calcSafeAreaInsets(WindowInsetsCompat insets) {
@@ -164,9 +174,16 @@ private Insets calcSafeAreaInsets(WindowInsetsCompat insets) {
}
private void initSafeAreaCSSVariables() {
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.VANILLA_ICE_CREAM && insetHandlingEnabled) {
- View v = (View) this.getBridge().getWebView().getParent();
- WindowInsetsCompat insets = ViewCompat.getRootWindowInsets(v);
+ if (INSETS_HANDLING_CSS.equals(insetsHandling)) {
+ WindowInsetsCompat insets;
+
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.VANILLA_ICE_CREAM) {
+ View v = (View) this.getBridge().getWebView().getParent();
+ insets = ViewCompat.getRootWindowInsets(v);
+ } else {
+ insets = WindowInsetsCompat.CONSUMED;
+ }
+
if (insets != null) {
Insets safeAreaInsets = calcSafeAreaInsets(insets);
injectSafeAreaCSS(safeAreaInsets.top, safeAreaInsets.right, safeAreaInsets.bottom, safeAreaInsets.left);
@@ -175,6 +192,10 @@ private void initSafeAreaCSSVariables() {
}
private void initWindowInsetsListener() {
+ if (INSETS_HANDLING_DISABLE.equals(insetsHandling)) {
+ return;
+ }
+
ViewCompat.setOnApplyWindowInsetsListener((View) getBridge().getWebView().getParent(), (v, insets) -> {
boolean shouldPassthroughInsets = getWebViewMajorVersion() >= WEBVIEW_VERSION_WITH_SAFE_AREA_FIX && hasViewportCover;
@@ -186,10 +207,8 @@ private void initWindowInsetsListener() {
// We need to correct for a possible shown IME
v.setPadding(0, 0, 0, keyboardVisible ? imeInsets.bottom : 0);
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.VANILLA_ICE_CREAM && hasViewportCover && insetHandlingEnabled) {
- Insets safeAreaInsets = calcSafeAreaInsets(insets);
- injectSafeAreaCSS(safeAreaInsets.top, safeAreaInsets.right, safeAreaInsets.bottom, safeAreaInsets.left);
- }
+ Insets safeAreaInsets = calcSafeAreaInsets(insets);
+ injectSafeAreaCSS(safeAreaInsets.top, safeAreaInsets.right, safeAreaInsets.bottom, safeAreaInsets.left);
return new WindowInsetsCompat.Builder(insets)
.setInsets(
@@ -221,10 +240,8 @@ private void initWindowInsetsListener() {
.setInsets(WindowInsetsCompat.Type.systemBars() | WindowInsetsCompat.Type.displayCutout(), Insets.of(0, 0, 0, 0))
.build();
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.VANILLA_ICE_CREAM && hasViewportCover && insetHandlingEnabled) {
- Insets safeAreaInsets = calcSafeAreaInsets(newInsets);
- injectSafeAreaCSS(safeAreaInsets.top, safeAreaInsets.right, safeAreaInsets.bottom, safeAreaInsets.left);
- }
+ Insets safeAreaInsets = calcSafeAreaInsets(newInsets);
+ injectSafeAreaCSS(safeAreaInsets.top, safeAreaInsets.right, safeAreaInsets.bottom, safeAreaInsets.left);
return newInsets;
});
@@ -287,19 +304,21 @@ private void setHidden(boolean hide, String bar) {
WindowInsetsControllerCompat windowInsetsControllerCompat = WindowCompat.getInsetsController(window, window.getDecorView());
if (hide) {
- if (bar.isEmpty() || bar.equals(BAR_STATUS_BAR)) {
+ if (bar.isEmpty()) {
+ windowInsetsControllerCompat.hide(WindowInsetsCompat.Type.systemBars());
+ } else if (bar.equals(BAR_STATUS_BAR)) {
windowInsetsControllerCompat.hide(WindowInsetsCompat.Type.statusBars());
- }
- if (bar.isEmpty() || bar.equals(BAR_GESTURE_BAR)) {
+ } else if (bar.equals(BAR_GESTURE_BAR)) {
windowInsetsControllerCompat.hide(WindowInsetsCompat.Type.navigationBars());
}
return;
}
- if (bar.isEmpty() || bar.equals(BAR_STATUS_BAR)) {
+ if (bar.isEmpty()) {
windowInsetsControllerCompat.show(WindowInsetsCompat.Type.systemBars());
- }
- if (bar.isEmpty() || bar.equals(BAR_GESTURE_BAR)) {
+ } else if (bar.equals(BAR_STATUS_BAR)) {
+ windowInsetsControllerCompat.show(WindowInsetsCompat.Type.statusBars());
+ } else if (bar.equals(BAR_GESTURE_BAR)) {
windowInsetsControllerCompat.show(WindowInsetsCompat.Type.navigationBars());
}
}
diff --git a/android/capacitor/src/main/java/com/getcapacitor/plugin/util/CapacitorHttpUrlConnection.java b/android/capacitor/src/main/java/com/getcapacitor/plugin/util/CapacitorHttpUrlConnection.java
index 6180d64200..7cb0f34690 100644
--- a/android/capacitor/src/main/java/com/getcapacitor/plugin/util/CapacitorHttpUrlConnection.java
+++ b/android/capacitor/src/main/java/com/getcapacitor/plugin/util/CapacitorHttpUrlConnection.java
@@ -1,6 +1,5 @@
package com.getcapacitor.plugin.util;
-import android.os.Build;
import android.os.LocaleList;
import android.text.TextUtils;
import com.getcapacitor.Bridge;
@@ -211,9 +210,7 @@ public void setRequestBody(PluginCall call, JSValue body, String bodyType) throw
this.writeRequestBody(dataString != null ? dataString : "");
} else if (bodyType != null && bodyType.equals("file")) {
try (DataOutputStream os = new DataOutputStream(connection.getOutputStream())) {
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
- os.write(Base64.getDecoder().decode(body.toString()));
- }
+ os.write(Base64.getDecoder().decode(body.toString()));
os.flush();
}
} else if (contentType.contains("application/x-www-form-urlencoded")) {
@@ -295,13 +292,7 @@ private void writeFormDataRequestBody(String boundary, JSArray entries) throws I
os.writeBytes("Content-Type: " + fileContentType + lineEnd);
os.writeBytes("Content-Transfer-Encoding: binary" + lineEnd);
os.writeBytes(lineEnd);
-
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
- os.write(Base64.getDecoder().decode(value));
- } else {
- os.write(android.util.Base64.decode(value, android.util.Base64.DEFAULT));
- }
-
+ os.write(Base64.getDecoder().decode(value));
os.writeBytes(lineEnd);
}
}
diff --git a/android/capacitor/src/main/java/com/getcapacitor/plugin/util/HttpRequestHandler.java b/android/capacitor/src/main/java/com/getcapacitor/plugin/util/HttpRequestHandler.java
index b47d57cf10..69278bc63b 100644
--- a/android/capacitor/src/main/java/com/getcapacitor/plugin/util/HttpRequestHandler.java
+++ b/android/capacitor/src/main/java/com/getcapacitor/plugin/util/HttpRequestHandler.java
@@ -168,8 +168,8 @@ public HttpURLConnectionBuilder setUrlParams(JSObject params, boolean shouldEnco
"://" +
uri.getAuthority() +
uri.getPath() +
- ((!urlQuery.equals("")) ? "?" + urlQuery : "") +
- ((uri.getFragment() != null) ? uri.getFragment() : "");
+ (!urlQuery.equals("") ? "?" + urlQuery : "") +
+ (uri.getFragment() != null ? uri.getFragment() : "");
this.url = new URL(unEncodedUrlString);
return this;
diff --git a/android/capacitor/src/main/java/com/getcapacitor/util/JSONUtils.java b/android/capacitor/src/main/java/com/getcapacitor/util/JSONUtils.java
index 1d2fc20785..f24e5aa0b4 100644
--- a/android/capacitor/src/main/java/com/getcapacitor/util/JSONUtils.java
+++ b/android/capacitor/src/main/java/com/getcapacitor/util/JSONUtils.java
@@ -75,6 +75,26 @@ public static int getInt(JSONObject jsonObject, String key, int defaultValue) {
return defaultValue;
}
+ /**
+ * Get a double value from the given JSON object.
+ *
+ * @param jsonObject A JSON object to search
+ * @param key A key to fetch from the JSON object
+ * @param defaultValue A default value to return if the key cannot be found
+ * @return The value at the given key in the JSON object, or the default value
+ */
+ public static double getDouble(JSONObject jsonObject, String key, double defaultValue) {
+ String k = getDeepestKey(key);
+ try {
+ JSONObject o = getDeepestObject(jsonObject, key);
+ return o.getDouble(k);
+ } catch (JSONException ignore) {
+ // value was not found
+ }
+
+ return defaultValue;
+ }
+
/**
* Get a JSON object value from the given JSON object.
*
diff --git a/android/capacitor/src/test/java/com/getcapacitor/plugin/SystemBarsTest.java b/android/capacitor/src/test/java/com/getcapacitor/plugin/SystemBarsTest.java
new file mode 100644
index 0000000000..f72373a88e
--- /dev/null
+++ b/android/capacitor/src/test/java/com/getcapacitor/plugin/SystemBarsTest.java
@@ -0,0 +1,73 @@
+package com.getcapacitor.plugin;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.mockStatic;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.view.View;
+import android.view.Window;
+import androidx.appcompat.app.AppCompatActivity;
+import androidx.core.view.WindowCompat;
+import androidx.core.view.WindowInsetsCompat;
+import androidx.core.view.WindowInsetsControllerCompat;
+import com.getcapacitor.Bridge;
+import java.lang.reflect.Method;
+import org.junit.Test;
+import org.mockito.MockedStatic;
+
+public class SystemBarsTest {
+
+ @Test
+ public void showWithEmptyBarShowsSystemBars() throws Exception {
+ WindowInsetsControllerCompat controller = invokeSetHidden("");
+
+ verify(controller).show(WindowInsetsCompat.Type.systemBars());
+ verify(controller, never()).show(WindowInsetsCompat.Type.statusBars());
+ verify(controller, never()).show(WindowInsetsCompat.Type.navigationBars());
+ }
+
+ @Test
+ public void showWithStatusBarShowsOnlyStatusBars() throws Exception {
+ WindowInsetsControllerCompat controller = invokeSetHidden("StatusBar");
+
+ verify(controller).show(WindowInsetsCompat.Type.statusBars());
+ verify(controller, never()).show(WindowInsetsCompat.Type.systemBars());
+ verify(controller, never()).show(WindowInsetsCompat.Type.navigationBars());
+ }
+
+ @Test
+ public void showWithNavigationBarShowsOnlyNavigationBars() throws Exception {
+ WindowInsetsControllerCompat controller = invokeSetHidden("NavigationBar");
+
+ verify(controller).show(WindowInsetsCompat.Type.navigationBars());
+ verify(controller, never()).show(WindowInsetsCompat.Type.systemBars());
+ verify(controller, never()).show(WindowInsetsCompat.Type.statusBars());
+ }
+
+ private WindowInsetsControllerCompat invokeSetHidden(String bar) throws Exception {
+ SystemBars plugin = new SystemBars();
+ Bridge bridge = mock(Bridge.class);
+ AppCompatActivity activity = mock(AppCompatActivity.class);
+ Window window = mock(Window.class);
+ View decorView = mock(View.class);
+ WindowInsetsControllerCompat controller = mock(WindowInsetsControllerCompat.class);
+
+ when(bridge.getActivity()).thenReturn(activity);
+ when(activity.getWindow()).thenReturn(window);
+ when(window.getDecorView()).thenReturn(decorView);
+
+ plugin.setBridge(bridge);
+
+ try (MockedStatic windowCompat = mockStatic(WindowCompat.class)) {
+ windowCompat.when(() -> WindowCompat.getInsetsController(window, decorView)).thenReturn(controller);
+
+ Method setHidden = SystemBars.class.getDeclaredMethod("setHidden", boolean.class, String.class);
+ setHidden.setAccessible(true);
+ setHidden.invoke(plugin, false, bar);
+ }
+
+ return controller;
+ }
+}
diff --git a/android/gradle/wrapper/gradle-wrapper.jar b/android/gradle/wrapper/gradle-wrapper.jar
index 1b33c55baa..b1b8ef56b4 100644
Binary files a/android/gradle/wrapper/gradle-wrapper.jar and b/android/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/android/gradle/wrapper/gradle-wrapper.properties b/android/gradle/wrapper/gradle-wrapper.properties
index 7705927e94..e74c8700b2 100644
--- a/android/gradle/wrapper/gradle-wrapper.properties
+++ b/android/gradle/wrapper/gradle-wrapper.properties
@@ -1,7 +1,9 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.3-all.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-9.5.1-all.zip
networkTimeout=10000
+retries=0
+retryBackOffMs=500
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
diff --git a/android/gradlew b/android/gradlew
index 23d15a9367..b9bb139f79 100755
--- a/android/gradlew
+++ b/android/gradlew
@@ -1,7 +1,7 @@
#!/bin/sh
#
-# Copyright © 2015-2021 the original authors.
+# Copyright © 2015 the original authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -57,7 +57,7 @@
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
-# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
+# https://github.com/gradle/gradle/blob/3d91ce3b8caaf77ad09f381f43615b715b53f72c/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
@@ -114,7 +114,6 @@ case "$( uname )" in #(
NONSTOP* ) nonstop=true ;;
esac
-CLASSPATH="\\\"\\\""
# Determine the Java command to use to start the JVM.
@@ -172,7 +171,6 @@ fi
# For Cygwin or MSYS, switch paths to Windows format before running java
if "$cygwin" || "$msys" ; then
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
- CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
JAVACMD=$( cygpath --unix "$JAVACMD" )
@@ -212,7 +210,6 @@ DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
- -classpath "$CLASSPATH" \
-jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \
"$@"
diff --git a/android/gradlew.bat b/android/gradlew.bat
index 5eed7ee845..aa5f10b069 100644
--- a/android/gradlew.bat
+++ b/android/gradlew.bat
@@ -23,8 +23,8 @@
@rem
@rem ##########################################################################
-@rem Set local scope for the variables with windows NT shell
-if "%OS%"=="Windows_NT" setlocal
+@rem Set local scope for the variables, and ensure extensions are enabled
+setlocal EnableExtensions
set DIRNAME=%~dp0
if "%DIRNAME%"=="" set DIRNAME=.
@@ -51,7 +51,7 @@ echo. 1>&2
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
echo location of your Java installation. 1>&2
-goto fail
+"%COMSPEC%" /c exit 1
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
@@ -65,30 +65,18 @@ echo. 1>&2
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
echo location of your Java installation. 1>&2
-goto fail
+"%COMSPEC%" /c exit 1
:execute
@rem Setup the command line
-set CLASSPATH=
@rem Execute Gradle
-"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %*
+@rem endlocal doesn't take effect until after the line is parsed and variables are expanded
+@rem which allows us to clear the local environment before executing the java command
+endlocal & "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* & call :exitWithErrorLevel
-:end
-@rem End local scope for the variables with windows NT shell
-if %ERRORLEVEL% equ 0 goto mainEnd
-
-:fail
-rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
-rem the _cmd.exe /c_ return code!
-set EXIT_CODE=%ERRORLEVEL%
-if %EXIT_CODE% equ 0 set EXIT_CODE=1
-if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
-exit /b %EXIT_CODE%
-
-:mainEnd
-if "%OS%"=="Windows_NT" endlocal
-
-:omega
+:exitWithErrorLevel
+@rem Use "%COMSPEC%" /c exit to allow operators to work properly in scripts
+"%COMSPEC%" /c exit %ERRORLEVEL%
diff --git a/android/package.json b/android/package.json
index 5e85ca240e..27b380e948 100644
--- a/android/package.json
+++ b/android/package.json
@@ -1,9 +1,9 @@
{
- "name": "@capacitor-plus/android",
- "version": "8.3.4",
- "description": "Capacitor+: Enhanced Capacitor with automated upstream sync - Cross-platform apps with JavaScript and the web",
- "homepage": "https://capgo.app/docs/plugins/capacitor-plus/",
- "author": "Capgo Team (https://capgo.app)",
+ "name": "@capacitor/android",
+ "version": "9.0.0-alpha.5",
+ "description": "Capacitor: Cross-platform apps with JavaScript and the web",
+ "homepage": "https://capacitorjs.com",
+ "author": "Ionic Team (https://ionic.io)",
"license": "MIT",
"repository": {
"type": "git",
@@ -17,14 +17,16 @@
"capacitor/lint-baseline.xml",
"capacitor/lint.xml",
"capacitor/proguard-rules.pro",
- "capacitor/src/main/"
+ "capacitor/src/main/",
+ "capacitor-cordova/build.gradle",
+ "capacitor-cordova/proguard-rules.pro",
+ "capacitor-cordova/src/main/"
],
"scripts": {
- "verify": "./gradlew clean lint build test -b capacitor/build.gradle"
+ "verify": "./gradlew :capacitor-android:clean :capacitor-android:lint :capacitor-android:build :capacitor-android:test"
},
"peerDependencies": {
- "@capacitor-plus/core": "^8.3.0",
- "@capacitor/core": "^8.3.0"
+ "@capacitor/core": "^9.0.0-alpha.5"
},
"publishConfig": {
"access": "public"
diff --git a/android/settings.gradle b/android/settings.gradle
index e69de29bb2..85956d0c11 100644
--- a/android/settings.gradle
+++ b/android/settings.gradle
@@ -0,0 +1,5 @@
+include ':capacitor-android'
+project(':capacitor-android').projectDir = new File('capacitor')
+
+include ':capacitor-cordova-android'
+project(':capacitor-cordova-android').projectDir = new File('capacitor-cordova')
diff --git a/capacitor-cordova-android-plugins/build.gradle b/capacitor-cordova-android-plugins/build.gradle
index 5edcbfd2c2..8048084302 100644
--- a/capacitor-cordova-android-plugins/build.gradle
+++ b/capacitor-cordova-android-plugins/build.gradle
@@ -9,7 +9,7 @@ buildscript {
mavenCentral()
}
dependencies {
- classpath 'com.android.tools.build:gradle:8.13.0'
+ classpath 'com.android.tools.build:gradle:9.2.1'
}
}
@@ -17,10 +17,9 @@ apply plugin: 'com.android.library'
android {
namespace = "capacitor.cordova.android.plugins"
- compileSdk = project.hasProperty('compileSdkVersion') ? rootProject.ext.compileSdkVersion : 36
+ compileSdk = project.hasProperty('compileSdkVersion') ? rootProject.ext.compileSdkVersion : 37
defaultConfig {
- minSdkVersion project.hasProperty('minSdkVersion') ? rootProject.ext.minSdkVersion : 24
- targetSdkVersion project.hasProperty('targetSdkVersion') ? rootProject.ext.targetSdkVersion : 36
+ minSdkVersion project.hasProperty('minSdkVersion') ? rootProject.ext.minSdkVersion : 26
versionCode 1
versionName "1.0"
}
diff --git a/cli/CHANGELOG.md b/cli/CHANGELOG.md
index 8cb2f68072..28a28d4519 100644
--- a/cli/CHANGELOG.md
+++ b/cli/CHANGELOG.md
@@ -3,292 +3,104 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
-## [8.3.4](https://github.com/Cap-go/capacitor-plus/compare/8.3.3...8.3.4) (2026-05-07)
-
+# [9.0.0-alpha.5](https://github.com/ionic-team/capacitor/compare/8.4.1...9.0.0-alpha.5) (2026-06-23)
### Bug Fixes
-* **cli:** link plugin dependencies in Package.swift ([#8457](https://github.com/Cap-go/capacitor-plus/issues/8457)) ([b3c769e](https://github.com/Cap-go/capacitor-plus/commit/b3c769e856c826b1174518877cf86ac7ce73bf09))
-
-
-
-
-
-## [8.3.3](https://github.com/Cap-go/capacitor-plus/compare/8.3.2...8.3.3) (2026-05-06)
+- add missing logic from merge ([#8515](https://github.com/ionic-team/capacitor/issues/8515)) ([356cafa](https://github.com/ionic-team/capacitor/commit/356cafa7a06dd4a2b6d535f421ddc62132b34343))
+- **cli:** Add missing imports ([#8512](https://github.com/ionic-team/capacitor/issues/8512)) ([904b22e](https://github.com/ionic-team/capacitor/commit/904b22e69f4f750ed0b2e006157baaa0c7fc2a7f))
+# [9.0.0-alpha.4](https://github.com/ionic-team/capacitor/compare/9.0.0-alpha.3...9.0.0-alpha.4) (2026-06-19)
### Bug Fixes
-* **cli:** generate resource entries in Package.swift ([#8455](https://github.com/Cap-go/capacitor-plus/issues/8455)) ([790bd27](https://github.com/Cap-go/capacitor-plus/commit/790bd27123497111984227010c3162cec94a108e))
-
+- **ios:** eliminate double comma in SPM generation ([#8505](https://github.com/ionic-team/capacitor/issues/8505)) ([1a5543f](https://github.com/ionic-team/capacitor/commit/1a5543fbfcf4ba911270002d573275342f680bde))
+# [9.0.0-alpha.3](https://github.com/ionic-team/capacitor/compare/8.4.0...9.0.0-alpha.3) (2026-06-02)
+# [9.0.0-alpha.2](https://github.com/ionic-team/capacitor/compare/8.3.4...9.0.0-alpha.2) (2026-05-12)
+# [9.0.0-alpha.1](https://github.com/ionic-team/capacitor/compare/8.3.3...9.0.0-alpha.1) (2026-05-08)
-## [8.3.2](https://github.com/Cap-go/capacitor-plus/compare/8.0.8...8.3.2) (2026-05-05)
-
+# [9.0.0-alpha.0](https://github.com/ionic-team/capacitor/compare/8.3.2...9.0.0-alpha.0) (2026-05-07)
### Bug Fixes
-* address follow-up review comments ([8bee786](https://github.com/Cap-go/capacitor-plus/commit/8bee786e2c68ca6c351e88f104b518291c1f81e3))
-* **cli:** add cSettings support for compiler flags in generated Package.swift ([#8448](https://github.com/Cap-go/capacitor-plus/issues/8448)) ([0bd0676](https://github.com/Cap-go/capacitor-plus/commit/0bd0676315c5fd77e50312dd7b5bf4990dcbd7d0))
-* **cli:** add system framework and weak framework support in SPM Package.swift ([#8447](https://github.com/Cap-go/capacitor-plus/issues/8447)) ([3232f0f](https://github.com/Cap-go/capacitor-plus/commit/3232f0fe1d9811b0b5c500e3dc05cb8a250177f8))
-* **cli:** Allow to run update on non macOS ([#8344](https://github.com/Cap-go/capacitor-plus/issues/8344)) ([a441280](https://github.com/Cap-go/capacitor-plus/commit/a441280d7c6b310ca516d6fb2736c09525987774))
-* **cli:** check CAPACITOR_COCOAPODS_PATH in determinePackageManager ([#8407](https://github.com/Cap-go/capacitor-plus/issues/8407)) ([acb64ab](https://github.com/Cap-go/capacitor-plus/commit/acb64ab92a37ff53701cde453558e272e2e11eb6))
-* **cli:** correct Capacitor plugin SPM compat check ([#8440](https://github.com/Cap-go/capacitor-plus/issues/8440)) ([e5ccc45](https://github.com/Cap-go/capacitor-plus/commit/e5ccc451dda27d56bca824ed644bd20fe4d988cb))
-* **cli:** Don't overwrite config.server section with `--live-reload` ([#7528](https://github.com/Cap-go/capacitor-plus/issues/7528)) ([782b9d9](https://github.com/Cap-go/capacitor-plus/commit/782b9d9c26dcf1282b918996becb0224c0baca1d))
-* **cli:** generate binaryTarget entries for custom xcframeworks in Package.swift ([#8445](https://github.com/Cap-go/capacitor-plus/issues/8445)) ([1f7e33f](https://github.com/Cap-go/capacitor-plus/commit/1f7e33fca43d183332ec19d22b0d75ef81d8cc6d))
-* **cli:** handle Cordova plugins without iOS source files ([#8443](https://github.com/Cap-go/capacitor-plus/issues/8443)) ([0da130e](https://github.com/Cap-go/capacitor-plus/commit/0da130eb7a861bee4e2c35bc0aac53ba9c983fc3))
-* **cli:** inline CSS sourcemaps in addition to JS sourcemaps ([#8377](https://github.com/Cap-go/capacitor-plus/issues/8377)) ([69476ab](https://github.com/Cap-go/capacitor-plus/commit/69476ab9c0b47911a14d2482cab53a877a5ae784))
-* **cli:** Update tar package ([#8311](https://github.com/Cap-go/capacitor-plus/issues/8311)) ([0969c5c](https://github.com/Cap-go/capacitor-plus/commit/0969c5cd0b16cf23d2489a85a3b8fa1bee2ebf3b))
-* **ios:** support Cordova plugins with Package.swift ([#8438](https://github.com/Cap-go/capacitor-plus/issues/8438)) ([139943b](https://github.com/Cap-go/capacitor-plus/commit/139943b0c05fddb2d1ce2d6f468800fddf17b4cf))
-* resolve upstream sync conflicts ([75cbb30](https://github.com/Cap-go/capacitor-plus/commit/75cbb3097a7068bcb37313cbe6301628079101ca))
-* **SystemBars:** use native safe area insets on Android ([#8384](https://github.com/Cap-go/capacitor-plus/issues/8384)) ([4e99598](https://github.com/Cap-go/capacitor-plus/commit/4e99598a2a57ee97e82be1aaa09492744622fa60))
-
-
-### Features
-
-* **cli:** Add --https option for --live-reload ([#8194](https://github.com/Cap-go/capacitor-plus/issues/8194)) ([5db81e6](https://github.com/Cap-go/capacitor-plus/commit/5db81e68c67652e9d2b29d7ad30629b423d2ad30))
-* **cli:** Add packageManager to iOS config ([#8321](https://github.com/Cap-go/capacitor-plus/issues/8321)) ([a125498](https://github.com/Cap-go/capacitor-plus/commit/a1254983bbb9dcb273d93f3c5f639b792e516406))
-* **cli:** Experimental config for swift-tools-version in SPM apps ([#8372](https://github.com/Cap-go/capacitor-plus/issues/8372)) ([d2ee84f](https://github.com/Cap-go/capacitor-plus/commit/d2ee84f8186909b142b418c02fc19f79d3c6a6ed))
-* **cli:** support SPM package traits in generated Package.swift ([#8351](https://github.com/Cap-go/capacitor-plus/issues/8351)) ([27e6aa8](https://github.com/Cap-go/capacitor-plus/commit/27e6aa89cf22e0b1a6d46710faed9aa8899600b0))
-
-
-### Reverts
-
-* revert version bump from [#8319](https://github.com/Cap-go/capacitor-plus/issues/8319) and [#8320](https://github.com/Cap-go/capacitor-plus/issues/8320) ([a48ebb6](https://github.com/Cap-go/capacitor-plus/commit/a48ebb622ea4ebe92927bf1756a4d8ac6012884b))
-
-
-
-
-
-## [8.0.8](https://github.com/Cap-go/capacitor-plus/compare/8.0.7...8.0.8) (2026-04-08)
-
-**Note:** Version bump only for package @capacitor-plus/cli
-
-
-
+- **android:** conditionally add Cordova ([#8453](https://github.com/ionic-team/capacitor/issues/8453)) ([e136b3f](https://github.com/ionic-team/capacitor/commit/e136b3f0cdd1437cac5234576301ed388edf85e7))
+- **cli:** conditionally add capacitor-cordova-android-plugins module ([#8449](https://github.com/ionic-team/capacitor/issues/8449)) ([9e85905](https://github.com/ionic-team/capacitor/commit/9e85905bf36c1e2300994e231cf10e829f2074ed))
+- **SystemBars:** use native safe area insets on Android ([#8384](https://github.com/ionic-team/capacitor/issues/8384)) ([d55f4f8](https://github.com/ionic-team/capacitor/commit/d55f4f859bd88fa5617699e874c48c451bcb5e5f))
+# [9.0.0-alpha.4](https://github.com/ionic-team/capacitor/compare/9.0.0-alpha.3...9.0.0-alpha.4) (2026-06-19)
-## [8.0.7](https://github.com/Cap-go/capacitor-plus/compare/8.0.6...8.0.7) (2026-01-12)
-
-**Note:** Version bump only for package @capacitor-plus/cli
-
-
-
-
-
-## [8.0.6](https://github.com/Cap-go/capacitor-plus/compare/8.0.5...8.0.6) (2026-01-09)
-
+## [8.4.1](https://github.com/ionic-team/capacitor/compare/8.4.0...8.4.1) (2026-06-19)
### Bug Fixes
-* **cli:** Support wireless iOS devices in `cap run` ([#8301](https://github.com/Cap-go/capacitor-plus/issues/8301)) ([dcb368c](https://github.com/Cap-go/capacitor-plus/commit/dcb368c33555487f1b6f46a6d8e30736bdd78955))
+- **cli:** make SPM dependency patch work on prereleases ([#8508](https://github.com/ionic-team/capacitor/issues/8508)) ([6048e90](https://github.com/ionic-team/capacitor/commit/6048e90171afa0229a3c25b52a23c377c6bb804c))
+- **cli:** patch Capacitor SPM dependency version in plugins ([#8492](https://github.com/ionic-team/capacitor/issues/8492)) ([28bb2c6](https://github.com/ionic-team/capacitor/commit/28bb2c687069dfdd6aa7abc866004a1c6388d103))
+- **ios:** eliminate double comma in SPM generation ([#8505](https://github.com/ionic-team/capacitor/issues/8505)) ([1a5543f](https://github.com/ionic-team/capacitor/commit/1a5543fbfcf4ba911270002d573275342f680bde))
+# [8.4.0](https://github.com/ionic-team/capacitor/compare/9.0.0-alpha.2...8.4.0) (2026-06-02)
+# [9.0.0-alpha.3](https://github.com/ionic-team/capacitor/compare/9.0.0-alpha.2...9.0.0-alpha.3) (2026-06-02)
-
-
-## [8.0.5](https://github.com/Cap-go/capacitor-plus/compare/8.0.4...8.0.5) (2026-01-08)
-
+# [8.4.0](https://github.com/ionic-team/capacitor/compare/8.3.4...8.4.0) (2026-06-02)
### Bug Fixes
-* **cli:** use latest native-run ([#8296](https://github.com/Cap-go/capacitor-plus/issues/8296)) ([121d830](https://github.com/Cap-go/capacitor-plus/commit/121d83013f39e25009121533a2c3ad86e428d6b2))
-
-
-
+- **cli:** revert live reload config on failure ([#8485](https://github.com/ionic-team/capacitor/issues/8485)) ([1d031a4](https://github.com/ionic-team/capacitor/commit/1d031a4abec2c793079ba8897ad2e40c4cc6c7f9))
+### Features
-## [8.0.4](https://github.com/Cap-go/capacitor-plus/compare/8.0.3...8.0.4) (2025-12-16)
+- **cli:** add experimental packageOptions ([#8471](https://github.com/ionic-team/capacitor/issues/8471)) ([258867b](https://github.com/ionic-team/capacitor/commit/258867b7bf37b1837b99b02ec9638e5a6df08d97))
+- **cli:** capture ios_package_manager in telemetry ([#8482](https://github.com/ionic-team/capacitor/issues/8482)) ([b4b297a](https://github.com/ionic-team/capacitor/commit/b4b297a52f8732659662d5e5aaeff81c0f7d9835))
+## [8.3.4](https://github.com/ionic-team/capacitor/compare/9.0.0-alpha.1...8.3.4) (2026-05-12)
-### Features
+## [8.3.3](https://github.com/ionic-team/capacitor/compare/9.0.0-alpha.0...8.3.3) (2026-05-08)
-* enhance package resolution by adding fallbacks for Capacitor packages ([7a03a14](https://github.com/Cap-go/capacitor-plus/commit/7a03a14fdf223088594b45f5ddeca29306eab3c6))
+### Bug Fixes
+- **cli:** copy plugin files in CocoaPods projects ([#8467](https://github.com/ionic-team/capacitor/issues/8467)) ([b2d7719](https://github.com/ionic-team/capacitor/commit/b2d771926a180e60deea31992d7d4abcd5ca3bc7))
+# [9.0.0-alpha.2](https://github.com/ionic-team/capacitor/compare/9.0.0-alpha.1...9.0.0-alpha.2) (2026-05-12)
+**Note:** Version bump only for package @capacitor/cli
+# [9.0.0-alpha.1](https://github.com/ionic-team/capacitor/compare/9.0.0-alpha.0...9.0.0-alpha.1) (2026-05-08)
-## [8.0.3](https://github.com/Cap-go/capacitor-plus/compare/8.0.2...8.0.3) (2025-12-16)
+**Note:** Version bump only for package @capacitor/cli
+# [9.0.0-alpha.0](https://github.com/ionic-team/capacitor/compare/8.3.2...9.0.0-alpha.0) (2026-05-07)
### Bug Fixes
-* update homepage URL in package.json files for all platforms ([61ccdc4](https://github.com/Cap-go/capacitor-plus/commit/61ccdc4128a1ce2a7178eb0a195b188876ec0a9d))
-
-
+- **android:** conditionally add Cordova ([#8453](https://github.com/ionic-team/capacitor/issues/8453)) ([e136b3f](https://github.com/ionic-team/capacitor/commit/e136b3f0cdd1437cac5234576301ed388edf85e7))
+- **cli:** conditionally add capacitor-cordova-android-plugins module ([#8449](https://github.com/ionic-team/capacitor/issues/8449)) ([9e85905](https://github.com/ionic-team/capacitor/commit/9e85905bf36c1e2300994e231cf10e829f2074ed))
+- **SystemBars:** use native safe area insets on Android ([#8384](https://github.com/ionic-team/capacitor/issues/8384)) ([d55f4f8](https://github.com/ionic-team/capacitor/commit/d55f4f859bd88fa5617699e874c48c451bcb5e5f))
+## [8.3.4](https://github.com/ionic-team/capacitor/compare/8.3.3...8.3.4) (2026-05-12)
+**Note:** Version bump only for package @capacitor/cli
-## [8.0.2](https://github.com/Cap-go/capacitor-plus/compare/8.0.1...8.0.2) (2025-12-16)
+## [8.3.3](https://github.com/ionic-team/capacitor/compare/8.3.2...8.3.3) (2026-05-08)
+### Bug Fixes
-### Features
+- **cli:** copy plugin files in CocoaPods projects ([#8467](https://github.com/ionic-team/capacitor/issues/8467)) ([b2d7719](https://github.com/ionic-team/capacitor/commit/b2d771926a180e60deea31992d7d4abcd5ca3bc7))
-* add new workflows for testing and version bumping; update README files for all packages ([a01c2a8](https://github.com/Cap-go/capacitor-plus/commit/a01c2a842c363c2aa58e5681210fa62fac8e5de5))
-
-
-
-
-
-## [8.0.1](https://github.com/Cap-go/capacitor-plus/compare/3.3.4...8.0.1) (2025-12-16)
-
-### Bug Fixes
-
-- add error code checking to `runPlatformHook` ([#7994](https://github.com/Cap-go/capacitor-plus/issues/7994)) ([8717680](https://github.com/Cap-go/capacitor-plus/commit/871768049187afe9f5d358d3fe08b6f18f70533e))
-- allow double quotes in Gemfile ([#6903](https://github.com/Cap-go/capacitor-plus/issues/6903)) ([3abdbed](https://github.com/Cap-go/capacitor-plus/commit/3abdbed38844d5d59d244f6f0dfc2647f29ce446))
-- **android:** add command not changing namespace ([#8224](https://github.com/Cap-go/capacitor-plus/issues/8224)) ([60cf666](https://github.com/Cap-go/capacitor-plus/commit/60cf66675159fb09cd41c94ce657202d01e05c74))
-- **android:** compatibility with cordova kotlin plugins ([#5438](https://github.com/Cap-go/capacitor-plus/issues/5438)) ([55bf004](https://github.com/Cap-go/capacitor-plus/commit/55bf004897b3feb280ab6b6575d2a2c1a0a183e2))
-- **android:** move initialFocus on webview into config ([#5579](https://github.com/Cap-go/capacitor-plus/issues/5579)) ([8b4e861](https://github.com/Cap-go/capacitor-plus/commit/8b4e861514b0fbe08e9296f49c280234f54742e1))
-- check for android and JDK ([#6554](https://github.com/Cap-go/capacitor-plus/issues/6554)) ([ddcc818](https://github.com/Cap-go/capacitor-plus/commit/ddcc818e828b290459d3ddffe9102fc312139823))
-- **cli/cordova:** Exclude private framework Headers ([#6229](https://github.com/Cap-go/capacitor-plus/issues/6229)) ([6c2726d](https://github.com/Cap-go/capacitor-plus/commit/6c2726dc0817c9e57c8b7909e4a69a9b376c425d))
-- **cli/ios:** Read handleApplicationNotifications configuration option ([#6030](https://github.com/Cap-go/capacitor-plus/issues/6030)) ([99ccf18](https://github.com/Cap-go/capacitor-plus/commit/99ccf181f6ee8a00ed97bdbf9076e2b2ea27cd57))
-- **cli:** add vite config to framework detection ([#6039](https://github.com/Cap-go/capacitor-plus/issues/6039)) ([3796d42](https://github.com/Cap-go/capacitor-plus/commit/3796d42665f3150f99c761aa561a9e34d03cae28))
-- **cli:** adjust SPM parameters for build and run commands ([#7342](https://github.com/Cap-go/capacitor-plus/issues/7342)) ([02f8983](https://github.com/Cap-go/capacitor-plus/commit/02f8983300c102125db6b41b0bb174fe41e1785b))
-- **cli:** also generate packageClassList on copy ([#7358](https://github.com/Cap-go/capacitor-plus/issues/7358)) ([865cceb](https://github.com/Cap-go/capacitor-plus/commit/865cceb1bf7e1b973e8f83f3c77040add71b403c))
-- **cli:** Also update preferences plugin if present ([#5831](https://github.com/Cap-go/capacitor-plus/issues/5831)) ([b9d5954](https://github.com/Cap-go/capacitor-plus/commit/b9d5954ca0b333f2caa20179b96b049379860ea5))
-- **cli:** Android apk name multi flavor dimensions parsing ([#7598](https://github.com/Cap-go/capacitor-plus/issues/7598)) ([2dc20ee](https://github.com/Cap-go/capacitor-plus/commit/2dc20ee894c2f5761431caa8269e9f418fc222b6))
-- **cli:** apkName for multi-dimensional flavors ([#6704](https://github.com/Cap-go/capacitor-plus/issues/6704)) ([d7b23f2](https://github.com/Cap-go/capacitor-plus/commit/d7b23f21c554c94029b24d6e0c9ad4635f055759))
-- **cli:** Attempt to verify non-cjs modules exist if cjs resolution fails ([#7310](https://github.com/Cap-go/capacitor-plus/issues/7310)) ([663e7b3](https://github.com/Cap-go/capacitor-plus/commit/663e7b383be0ceee1d23b929ceb6374d00faf011))
-- **cli:** Avoid duplicate entries in packageClassList ([#7470](https://github.com/Cap-go/capacitor-plus/issues/7470)) ([cca0b80](https://github.com/Cap-go/capacitor-plus/commit/cca0b805291bd002c515be0a1c15de84ee23c5d3))
-- **cli:** Avoid infinite loop in namespace migration ([#6551](https://github.com/Cap-go/capacitor-plus/issues/6551)) ([d3aacde](https://github.com/Cap-go/capacitor-plus/commit/d3aacdeb0c86d3941464954e7d1f582e405be489))
-- **cli:** avoid srcFiles is not iterable on kotlinNeededCheck ([#5481](https://github.com/Cap-go/capacitor-plus/issues/5481)) ([3c2b579](https://github.com/Cap-go/capacitor-plus/commit/3c2b579c6edb1fc69d85689b268eb92067b7821b))
-- **cli:** Better error on gradlew permission problems ([#5405](https://github.com/Cap-go/capacitor-plus/issues/5405)) ([9420f08](https://github.com/Cap-go/capacitor-plus/commit/9420f08dedad78cfaa5500cccf8bdbf1a9140684))
-- **cli:** calculate padding of super.onCreate(savedInstanceState); line ([#6016](https://github.com/Cap-go/capacitor-plus/issues/6016)) ([5729ac1](https://github.com/Cap-go/capacitor-plus/commit/5729ac19e7880713ec52bac431a2756da5aa3109))
-- **cli:** Change Capacitor plugin files check ([#7375](https://github.com/Cap-go/capacitor-plus/issues/7375)) ([fbfb778](https://github.com/Cap-go/capacitor-plus/commit/fbfb77825fdd3343e85868ea28b8e14a482dcf4a))
-- **cli:** change SPM incompatible plugin message ([#8129](https://github.com/Cap-go/capacitor-plus/issues/8129)) ([28c2a96](https://github.com/Cap-go/capacitor-plus/commit/28c2a96d898b07a05ae763f798e8903601cc3f67))
-- **cli:** config file android release type not overridden ([#6205](https://github.com/Cap-go/capacitor-plus/issues/6205)) ([1441c55](https://github.com/Cap-go/capacitor-plus/commit/1441c551737ce42dd2b82fc1a9da1e8311e27f1a))
-- **cli:** correct build path for non flavor builds ([#7281](https://github.com/Cap-go/capacitor-plus/issues/7281)) ([0f9651d](https://github.com/Cap-go/capacitor-plus/commit/0f9651d99cdd9cb463e494ed016838cd6d4a34c4))
-- **cli:** correct migration of package from AndroidManifest.xml to build.gradle ([#6607](https://github.com/Cap-go/capacitor-plus/issues/6607)) ([1c26a3e](https://github.com/Cap-go/capacitor-plus/commit/1c26a3e57f356a0972bd43854ca86770a49f2d63))
-- **cli:** correct rimraf import ([#7811](https://github.com/Cap-go/capacitor-plus/issues/7811)) ([0891624](https://github.com/Cap-go/capacitor-plus/commit/0891624c46b78a0fd39f617f834d5cdd1f54f5e6))
-- **cli:** Correct Splash theme update ([#5805](https://github.com/Cap-go/capacitor-plus/issues/5805)) ([25b82a8](https://github.com/Cap-go/capacitor-plus/commit/25b82a84425bf09b2be45b213788b0e13982b9b3))
-- **cli:** correctly build and sign Android apps using Flavors ([#7082](https://github.com/Cap-go/capacitor-plus/issues/7082)) ([7d3a99d](https://github.com/Cap-go/capacitor-plus/commit/7d3a99d15ba024b4bde9e698e57937002da38bd4))
-- **cli:** Don't add google-services plugin if missing ([#5825](https://github.com/Cap-go/capacitor-plus/issues/5825)) ([48ff9e6](https://github.com/Cap-go/capacitor-plus/commit/48ff9e6461e8037a5c6da87c90efc6bc872d7f08))
-- **cli:** Don't downgrade deployment target on migrate ([#7953](https://github.com/Cap-go/capacitor-plus/issues/7953)) ([46e8792](https://github.com/Cap-go/capacitor-plus/commit/46e87925b675933b413737854b1376eb1c71a23e))
-- **cli:** Don't downgrade gradle version on migrate ([#7385](https://github.com/Cap-go/capacitor-plus/issues/7385)) ([c79211e](https://github.com/Cap-go/capacitor-plus/commit/c79211ec9dde81a57aca5cee8ab09cdef0c9ad86))
-- **cli:** Don't exclude Cordova plugins from SPM management ([#8140](https://github.com/Cap-go/capacitor-plus/issues/8140)) ([69bbd3d](https://github.com/Cap-go/capacitor-plus/commit/69bbd3dc59cd6f56252c06f23b351952af8661be))
-- **cli:** Don't migrate Podfile on SPM projects ([#7939](https://github.com/Cap-go/capacitor-plus/issues/7939)) ([ab4e700](https://github.com/Cap-go/capacitor-plus/commit/ab4e700035289f445668dfd2f86278ffc71ab269))
-- **cli:** don't run bundle if not installed ([#7896](https://github.com/Cap-go/capacitor-plus/issues/7896)) ([ee55f6c](https://github.com/Cap-go/capacitor-plus/commit/ee55f6c54639c1a61fa4f9eed1f366ba2d968b86))
-- **cli:** Don't succeed migration if npm install failed ([#6595](https://github.com/Cap-go/capacitor-plus/issues/6595)) ([6843d96](https://github.com/Cap-go/capacitor-plus/commit/6843d9642fad9a322579cbe5f01563929a83dbf5))
-- **cli:** enable cleartext for live reload ([#7563](https://github.com/Cap-go/capacitor-plus/issues/7563)) ([e06648f](https://github.com/Cap-go/capacitor-plus/commit/e06648f4566c0b80ab420f977e02f1b4cd73fc1f))
-- **cli:** ensures the execution order of CLI hooks ([#7947](https://github.com/Cap-go/capacitor-plus/issues/7947)) ([c3ea809](https://github.com/Cap-go/capacitor-plus/commit/c3ea8094cdd385ac02a5aae89f8b44b6c53d493a))
-- **cli:** Find the Info.plist when using scheme ([#5914](https://github.com/Cap-go/capacitor-plus/issues/5914)) ([f7029ac](https://github.com/Cap-go/capacitor-plus/commit/f7029acb885ec60f85a434b6f71e4f2a633c7651))
-- **cli:** fix cap run command for yarn pnp mode ([#7754](https://github.com/Cap-go/capacitor-plus/issues/7754)) ([79ace5c](https://github.com/Cap-go/capacitor-plus/commit/79ace5c7054d86d5b33ce325751ff738c63d4b0c))
-- **cli:** Fix cordova plugin config checker over checking 5.x ([#6444](https://github.com/Cap-go/capacitor-plus/issues/6444)) ([9d21a0e](https://github.com/Cap-go/capacitor-plus/commit/9d21a0e363141fa0792c12d977b13692be67cf6d))
-- **cli:** flavor flag not using correct apk ([#6151](https://github.com/Cap-go/capacitor-plus/issues/6151)) ([f4e7f19](https://github.com/Cap-go/capacitor-plus/commit/f4e7f19f186e334404b2cd0decc3205e57bf4469))
-- **cli:** force latest native-run version for iOS 17 support ([#6926](https://github.com/Cap-go/capacitor-plus/issues/6926)) ([7e7c8b9](https://github.com/Cap-go/capacitor-plus/commit/7e7c8b9113f541d530c5883dea1f52b2957c0859))
-- **cli:** handle unrecognized java --version ([#6577](https://github.com/Cap-go/capacitor-plus/issues/6577)) ([56b0037](https://github.com/Cap-go/capacitor-plus/commit/56b0037a70d64019563b6e55e53de423f471fe2f))
-- **cli:** install minor Capacitor 5 version ([#6562](https://github.com/Cap-go/capacitor-plus/issues/6562)) ([f4af0a2](https://github.com/Cap-go/capacitor-plus/commit/f4af0a298fb5a5f8257f175327058341a230ae4f))
-- **cli:** make Cordova plugins use same default kotlin version as Capacitor ([#7752](https://github.com/Cap-go/capacitor-plus/issues/7752)) ([a4aeb55](https://github.com/Cap-go/capacitor-plus/commit/a4aeb55720ecc83b3870bf32bf9825d6aee4644f))
-- **cli:** make migrate not error if there are no dependencies ([#6707](https://github.com/Cap-go/capacitor-plus/issues/6707)) ([25ca83a](https://github.com/Cap-go/capacitor-plus/commit/25ca83a8a76fe0eaf73c0db24fd950b33fd16063))
-- **cli:** make migrate update to 8.0.0 ([#8250](https://github.com/Cap-go/capacitor-plus/issues/8250)) ([ee8ba7b](https://github.com/Cap-go/capacitor-plus/commit/ee8ba7bbeeeef6db0461f7a59c91095fd7cbd78b))
-- **cli:** make migrator also update plugin variables ([#5871](https://github.com/Cap-go/capacitor-plus/issues/5871)) ([478d48c](https://github.com/Cap-go/capacitor-plus/commit/478d48c3e322cffc6f0ff7ce590b635de4b41279))
-- **cli:** Make migrator update gradle wrapper files ([#5910](https://github.com/Cap-go/capacitor-plus/issues/5910)) ([b8b9b1f](https://github.com/Cap-go/capacitor-plus/commit/b8b9b1f96249908435017eea6c427221f1971836))
-- **cli:** Make update from windows use proper paths on Podfile ([#5906](https://github.com/Cap-go/capacitor-plus/issues/5906)) ([c41d28f](https://github.com/Cap-go/capacitor-plus/commit/c41d28f8cc829c6bf69d776280c9f1fdba9f866f))
-- **cli:** Migrate more plugin variables ([#6552](https://github.com/Cap-go/capacitor-plus/issues/6552)) ([b7da5b9](https://github.com/Cap-go/capacitor-plus/commit/b7da5b988ce7da5ea3991eaec46b9e52ff3635f1))
-- **cli:** Migrate variables to newer dependency versions ([#7235](https://github.com/Cap-go/capacitor-plus/issues/7235)) ([aaf01ab](https://github.com/Cap-go/capacitor-plus/commit/aaf01ab938e02220d7e6b5cd9329baa3edd02b68))
-- **cli:** Migrator put registerPlugin before super.onCreate ([#5828](https://github.com/Cap-go/capacitor-plus/issues/5828)) ([8cd3373](https://github.com/Cap-go/capacitor-plus/commit/8cd3373133903f97a836fd6ac6b7ce4e1ba9317e))
-- **cli:** Move package to build.gradle in Capacitor plugins ([#6569](https://github.com/Cap-go/capacitor-plus/issues/6569)) ([8cb26cd](https://github.com/Cap-go/capacitor-plus/commit/8cb26cd97a4f9cf59abb6b3828a07555a6af0b15))
-- **cli:** Pin @ionic/utils-subprocess version ([#7057](https://github.com/Cap-go/capacitor-plus/issues/7057)) ([0ac019a](https://github.com/Cap-go/capacitor-plus/commit/0ac019a36070b4cb9917a82e406453169c7d5559))
-- **cli:** point build to proper workspace name ([#6371](https://github.com/Cap-go/capacitor-plus/issues/6371)) ([78b7a59](https://github.com/Cap-go/capacitor-plus/commit/78b7a591429b5fc1dc7bf87e06e9a1afd3599408))
-- **cli:** prefer studio executable over studio.sh on linux if available ([#8110](https://github.com/Cap-go/capacitor-plus/issues/8110)) ([62bd16f](https://github.com/Cap-go/capacitor-plus/commit/62bd16f675cb492b52c0b73483fddfd63c608189))
-- **cli:** prevent error on manifest element without children ([#6278](https://github.com/Cap-go/capacitor-plus/issues/6278)) ([a7e374f](https://github.com/Cap-go/capacitor-plus/commit/a7e374fc4d834ded437edb4c8a0be98b6691be4c))
-- **cli:** prevent error on migrate when devDependencies is missing ([#5863](https://github.com/Cap-go/capacitor-plus/issues/5863)) ([474ad1f](https://github.com/Cap-go/capacitor-plus/commit/474ad1f4d4a9ea0636a457836c938dac9f6534e8))
-- **cli:** proper plugin module patch in monorepos ([#6589](https://github.com/Cap-go/capacitor-plus/issues/6589)) ([d49e632](https://github.com/Cap-go/capacitor-plus/commit/d49e6324ab5e0bea58ff6ca32feb7ea39d33a772))
-- **cli:** Remove buildOptions from platform capacitor.config.json ([#6292](https://github.com/Cap-go/capacitor-plus/issues/6292)) ([acddcd9](https://github.com/Cap-go/capacitor-plus/commit/acddcd95b40a7d4cc6c7682d2d1019f96dacf68d))
-- **cli:** remove certificate file extension check on copy ([#7240](https://github.com/Cap-go/capacitor-plus/issues/7240)) ([93a0044](https://github.com/Cap-go/capacitor-plus/commit/93a004473d7c4008bf02e8077460dfbdc3042312))
-- **cli:** remove double space in cap 2 variables file ([#5826](https://github.com/Cap-go/capacitor-plus/issues/5826)) ([7184097](https://github.com/Cap-go/capacitor-plus/commit/7184097da88ed34f3e754119f967d262aa5e2add))
-- **cli:** remove package related checks on doctor command ([#6773](https://github.com/Cap-go/capacitor-plus/issues/6773)) ([4499b6b](https://github.com/Cap-go/capacitor-plus/commit/4499b6bb6c52e9bc7fdfdb35ee2519881996eedf))
-- **cli:** Removing extra dash in android apk name flavor parsing ([#7382](https://github.com/Cap-go/capacitor-plus/issues/7382)) ([3c411fd](https://github.com/Cap-go/capacitor-plus/commit/3c411fd0a400b18c2d032e3b8be3fc4b5449bcbd))
-- **cli:** replace app-store deprecated method on build ([#7637](https://github.com/Cap-go/capacitor-plus/issues/7637)) ([942b108](https://github.com/Cap-go/capacitor-plus/commit/942b108c1d506539c0c53276ed4ec35eed36634e))
-- **cli:** Revert some splash migration errors ([#5806](https://github.com/Cap-go/capacitor-plus/issues/5806)) ([471feed](https://github.com/Cap-go/capacitor-plus/commit/471feedc07bef357ac798fcba664bd373e9f8ebf))
-- **cli:** Run sync before updating gradle ([#7497](https://github.com/Cap-go/capacitor-plus/issues/7497)) ([f27786e](https://github.com/Cap-go/capacitor-plus/commit/f27786ea1367bc0ec53697eeb6d654a7e12a1507))
-- **cli:** show error if npm install on migration failed ([#5904](https://github.com/Cap-go/capacitor-plus/issues/5904)) ([aa60a75](https://github.com/Cap-go/capacitor-plus/commit/aa60a75d9c2c784e127a4d89e4079b412fbe7262))
-- **cli:** signing type option issue ([#6716](https://github.com/Cap-go/capacitor-plus/issues/6716)) ([ee0f745](https://github.com/Cap-go/capacitor-plus/commit/ee0f7457e458ca4bb4eb74f67552ac2ace76016b))
-- **cli:** Specify keystore alias and alias password build options for apksigner ([#7073](https://github.com/Cap-go/capacitor-plus/issues/7073)) ([6612c49](https://github.com/Cap-go/capacitor-plus/commit/6612c49f5fde5ef2fee555206018391fc00e2be0))
-- **cli:** Support of BoM dependencies on cordova plugins ([#5827](https://github.com/Cap-go/capacitor-plus/issues/5827)) ([ea2d95b](https://github.com/Cap-go/capacitor-plus/commit/ea2d95ba43467cd2d4c4637aacab6bf655d9c596))
-- **cli:** support variables in config warn checks ([#6136](https://github.com/Cap-go/capacitor-plus/issues/6136)) ([b460add](https://github.com/Cap-go/capacitor-plus/commit/b460add5e22139f234ca8fae98f174bb7c447292))
-- **cli:** type only import in config ([#6765](https://github.com/Cap-go/capacitor-plus/issues/6765)) ([2b493ae](https://github.com/Cap-go/capacitor-plus/commit/2b493ae77b9ee6e5fbcb2fafb27bc04693d7e02b))
-- **cli:** unexpected error on target device list ([#8015](https://github.com/Cap-go/capacitor-plus/issues/8015)) ([f827c48](https://github.com/Cap-go/capacitor-plus/commit/f827c48f08b13a265e8671291c24f3506e14a094))
-- **cli:** Update gradle versions only if they are older ([#6015](https://github.com/Cap-go/capacitor-plus/issues/6015)) ([ae94101](https://github.com/Cap-go/capacitor-plus/commit/ae941017fff3bcfa75e0788535f356a56ce6fa05))
-- **cli:** update link to telemetry information ([e922e2b](https://github.com/Cap-go/capacitor-plus/commit/e922e2b718f5c6f2e4062cdccdeb92da3321e67d))
-- **cli:** Update migration link ([#6560](https://github.com/Cap-go/capacitor-plus/issues/6560)) ([e03062e](https://github.com/Cap-go/capacitor-plus/commit/e03062e6025fea0edfabbff2081b3f91017aece4))
-- **cli:** Update plugins with breaking changes ([#7148](https://github.com/Cap-go/capacitor-plus/issues/7148)) ([b8c2a92](https://github.com/Cap-go/capacitor-plus/commit/b8c2a92390f21fe653563d7bad73a3f2b5628acb))
-- **cli:** use correct pass signature for apksigner signing ([#7365](https://github.com/Cap-go/capacitor-plus/issues/7365)) ([e4f8610](https://github.com/Cap-go/capacitor-plus/commit/e4f86103c2806df4ca2729600361e6338c30f083))
-- **cli:** use helper in Podfile with correct path ([#6878](https://github.com/Cap-go/capacitor-plus/issues/6878)) ([8e95be9](https://github.com/Cap-go/capacitor-plus/commit/8e95be9f91169e258ab5cdd8fd673106392b8429))
-- **cli:** Use latest native-run ([#7023](https://github.com/Cap-go/capacitor-plus/issues/7023)) ([4125160](https://github.com/Cap-go/capacitor-plus/commit/412516069e15fbdbc17ad130c2f3a67891b6bc45))
-- **cli:** use proper build params ([#8016](https://github.com/Cap-go/capacitor-plus/issues/8016)) ([12ce2a4](https://github.com/Cap-go/capacitor-plus/commit/12ce2a486542011c8d6f4cd89a67464f3f27e28d))
-- **cli:** useLegacyBridge should be optional ([#6095](https://github.com/Cap-go/capacitor-plus/issues/6095)) ([20f68fe](https://github.com/Cap-go/capacitor-plus/commit/20f68feab2cb88cf8a79a987533839aa49255607))
-- **cli:** warns about config that is present ([#6060](https://github.com/Cap-go/capacitor-plus/issues/6060)) ([7ac43e7](https://github.com/Cap-go/capacitor-plus/commit/7ac43e722139a61129cfecf98da373659b1aeac8))
-- fallback to plain `pod` if `Gemfile` does not contain CocoaPods ([#6581](https://github.com/Cap-go/capacitor-plus/issues/6581)) ([3a41b4c](https://github.com/Cap-go/capacitor-plus/commit/3a41b4c1b70af7a45201fb11b04dc5558893aa7e))
-- generate correct SPM platforms iOS version ([ddde15c](https://github.com/Cap-go/capacitor-plus/commit/ddde15cd1387496389b2085f008dbe0223a9ae96))
-- improve readability of getMajorMinoriOSVersion function ([937ab97](https://github.com/Cap-go/capacitor-plus/commit/937ab977e4f5b24463ac7fc57d94c97b47eea94b))
-- inject cordova files if a cordova plugin is present ([#7363](https://github.com/Cap-go/capacitor-plus/issues/7363)) ([ce9d505](https://github.com/Cap-go/capacitor-plus/commit/ce9d50585b1cab183245197878bf625cf0289275))
-- iOS enum ([e78f602](https://github.com/Cap-go/capacitor-plus/commit/e78f602389ae23a2e68b205bfc216ef0eb7402a5))
-- **ios:** Make Bridge webView first responder ([#7753](https://github.com/Cap-go/capacitor-plus/issues/7753)) ([77e4668](https://github.com/Cap-go/capacitor-plus/commit/77e4668fa8dbb24b4561387e101547f74e37538e))
-- **ios:** Match CapApp-SPM iOS version with project version ([#7556](https://github.com/Cap-go/capacitor-plus/issues/7556)) ([df4dc9a](https://github.com/Cap-go/capacitor-plus/commit/df4dc9a17f1b999a68093091d201ba15d234c5f8))
-- make migrate use 7.0.0 ([#7837](https://github.com/Cap-go/capacitor-plus/issues/7837)) ([5dc309e](https://github.com/Cap-go/capacitor-plus/commit/5dc309ea8dd7905e9e6236744f29162df80b5ed8))
-- **migrate:** update install command suggestion to 'yarn add' ([d3c8f54](https://github.com/Cap-go/capacitor-plus/commit/d3c8f54e10236503ee59f17488d056af3392341d))
-- **spm:** add product lines to Package.swift ([#7278](https://github.com/Cap-go/capacitor-plus/issues/7278)) ([e45d60d](https://github.com/Cap-go/capacitor-plus/commit/e45d60d15445fa55320eb6274de67d4b4191f30a))
-- stop crashing from `objc_getClassList` ([#7187](https://github.com/Cap-go/capacitor-plus/issues/7187)) ([e148db7](https://github.com/Cap-go/capacitor-plus/commit/e148db7758e4186ad45fd74185a10fb757ff9b29))
-- support dependencies with ".swift" at the end of name ([#7583](https://github.com/Cap-go/capacitor-plus/issues/7583)) ([ceee68a](https://github.com/Cap-go/capacitor-plus/commit/ceee68a2db363e9d9a638aa4ed8569fd82d1013a))
-- Update migrate to Capacitor 6 ([#6872](https://github.com/Cap-go/capacitor-plus/issues/6872)) ([98eec8f](https://github.com/Cap-go/capacitor-plus/commit/98eec8fe9fd332d6669965fa5a21412233b3e06e))
-- update package references to use [@capacitor-plus](https://github.com/capacitor-plus) namespace ([6dd88e6](https://github.com/Cap-go/capacitor-plus/commit/6dd88e6c3101b3ab051dfc216a397bc1d1aca0f0))
-- use Capacitor 7 for SPM dependency ([#7835](https://github.com/Cap-go/capacitor-plus/issues/7835)) ([640c3cb](https://github.com/Cap-go/capacitor-plus/commit/640c3cb22a62e4b8fb13cd36031d39307622c60a))
+## [8.3.2](https://github.com/ionic-team/capacitor/compare/8.3.1...8.3.2) (2026-05-07)
-### Features
+### Bug Fixes
-- Add global initialFocus configuration ([#7775](https://github.com/Cap-go/capacitor-plus/issues/7775)) ([61d0165](https://github.com/Cap-go/capacitor-plus/commit/61d01653685d8e3594d2d8a6bd870fa9643ba95c))
-- add livereload to run command ([#6831](https://github.com/Cap-go/capacitor-plus/issues/6831)) ([4099969](https://github.com/Cap-go/capacitor-plus/commit/4099969f70e9b995182bacecc16e160d89bbc746))
-- Add option for custom error page ([#5723](https://github.com/Cap-go/capacitor-plus/issues/5723)) ([e8bdef3](https://github.com/Cap-go/capacitor-plus/commit/e8bdef3b4634e4ad45fa8fc34c7c0ab8dfa383f3))
-- **android/cli:** Allow to use the old addJavascriptInterface bridge ([#6043](https://github.com/Cap-go/capacitor-plus/issues/6043)) ([a6e7c54](https://github.com/Cap-go/capacitor-plus/commit/a6e7c5422687b703492a5fcc49369eacc376143d))
-- **android:** add adjustMarginsForEdgeToEdge configuration option ([#7885](https://github.com/Cap-go/capacitor-plus/issues/7885)) ([1ea86d1](https://github.com/Cap-go/capacitor-plus/commit/1ea86d166afd315e72847c5e734a8c175fb90e04))
-- **android:** Add android.minWebviewVersion configuration option ([#5768](https://github.com/Cap-go/capacitor-plus/issues/5768)) ([ad83827](https://github.com/Cap-go/capacitor-plus/commit/ad838279e9cd190ce6f1a020a0ac9e3916786324))
-- **android:** Fix for [#6258](https://github.com/Cap-go/capacitor-plus/issues/6258), Add support for modern Huawei devices ([#6402](https://github.com/Cap-go/capacitor-plus/issues/6402)) ([17f2f4a](https://github.com/Cap-go/capacitor-plus/commit/17f2f4ac744a038c1dae3cbd74a670d5ede92ef3))
-- **android:** Improving SystemBars inset handling ([#8268](https://github.com/Cap-go/capacitor-plus/issues/8268)) ([81ae30a](https://github.com/Cap-go/capacitor-plus/commit/81ae30a503797e417dd125b06262dabc4696c88a))
-- **android:** update support for Portals for Capacitor to include Live Updates ([#5660](https://github.com/Cap-go/capacitor-plus/issues/5660)) ([62f0a5e](https://github.com/Cap-go/capacitor-plus/commit/62f0a5eaa40776aad79dbf8f8c0900037d3cc97e))
-- **android:** Use java 11 ([#5552](https://github.com/Cap-go/capacitor-plus/issues/5552)) ([e47959f](https://github.com/Cap-go/capacitor-plus/commit/e47959fcbd6a89b97b1275a5814fdb4e7ce30672))
-- better support monorepos ([#6811](https://github.com/Cap-go/capacitor-plus/issues/6811)) ([ae35e29](https://github.com/Cap-go/capacitor-plus/commit/ae35e29fb8c886dea867683a23a558d2d344073b))
-- Capacitor Cookies & Capacitor Http core plugins ([d4047cf](https://github.com/Cap-go/capacitor-plus/commit/d4047cfa947676777f400389a8d65defae140b45))
-- **cli:** Add --forwardPorts option to Capacitor CLI ([#5645](https://github.com/Cap-go/capacitor-plus/issues/5645)) ([2f04d29](https://github.com/Cap-go/capacitor-plus/commit/2f04d29a17eb46f9bd140b93e821e11380699367))
-- **cli:** add apksigner as a build option ([#6442](https://github.com/Cap-go/capacitor-plus/issues/6442)) ([9818a76](https://github.com/Cap-go/capacitor-plus/commit/9818a76ab4ea6660b444354f239344d37c77d3b3))
-- **cli:** add build command for android ([#5891](https://github.com/Cap-go/capacitor-plus/issues/5891)) ([6d4e620](https://github.com/Cap-go/capacitor-plus/commit/6d4e620308b6dd97376e3af7de1dd1a530083f1c))
-- **cli:** add build command for ios ([#5925](https://github.com/Cap-go/capacitor-plus/issues/5925)) ([8e8414f](https://github.com/Cap-go/capacitor-plus/commit/8e8414fa6f4ccb245576cc113eb969937613bbf7))
-- **cli:** add inline option to copy command ([#5901](https://github.com/Cap-go/capacitor-plus/issues/5901)) ([17fbabb](https://github.com/Cap-go/capacitor-plus/commit/17fbabb2a77d1b356d24048efc5883bd4d049104))
-- **cli:** add migrator for cap3 to cap4 ([#5762](https://github.com/Cap-go/capacitor-plus/issues/5762)) ([7cb660a](https://github.com/Cap-go/capacitor-plus/commit/7cb660a34d9a87274761d4492d0d77c9ef44ace8))
-- **cli:** Add missing Cap 4 to Cap 5 migration tasks ([#6453](https://github.com/Cap-go/capacitor-plus/issues/6453)) ([7dff363](https://github.com/Cap-go/capacitor-plus/commit/7dff36376d6efa6ea8793b81550979ee9254991b))
-- **cli:** add more configurations to build command ([#7769](https://github.com/Cap-go/capacitor-plus/issues/7769)) ([90f95d1](https://github.com/Cap-go/capacitor-plus/commit/90f95d1a829f3d87cb46af827b5bfaac319a9694))
-- **cli:** add npm update step to migrate ([#6462](https://github.com/Cap-go/capacitor-plus/issues/6462)) ([65520c3](https://github.com/Cap-go/capacitor-plus/commit/65520c36cdb4ac6f8811eb72624c447f2a0d884a))
-- **cli:** add scheme and flavor options to run command ([#5873](https://github.com/Cap-go/capacitor-plus/issues/5873)) ([e4c143d](https://github.com/Cap-go/capacitor-plus/commit/e4c143d4da653533570215964808c2f32f5469d3))
-- **cli:** add spm-migration-assistant command ([#7963](https://github.com/Cap-go/capacitor-plus/issues/7963)) ([ef42722](https://github.com/Cap-go/capacitor-plus/commit/ef427225f63056b1731b3cd8941aea2311d3bc4d))
-- **cli:** add ssl pinning copy logic ([#6312](https://github.com/Cap-go/capacitor-plus/issues/6312)) ([cce66c1](https://github.com/Cap-go/capacitor-plus/commit/cce66c1d59370ba35db879f4d7a3620d22175ab0))
-- **cli:** Add support for Android build `--flavor` ([#6437](https://github.com/Cap-go/capacitor-plus/issues/6437)) ([e91a8e7](https://github.com/Cap-go/capacitor-plus/commit/e91a8e795604042684ec9e20b620eee36e0dfda2))
-- **cli:** allow async in capacitor config file ([#4299](https://github.com/Cap-go/capacitor-plus/issues/4299)) ([5cecc3e](https://github.com/Cap-go/capacitor-plus/commit/5cecc3ee22868f9397792ec80a4b753a07b68f30))
-- **cli:** android manifest to build.gradle migration ([#6533](https://github.com/Cap-go/capacitor-plus/issues/6533)) ([245b6ab](https://github.com/Cap-go/capacitor-plus/commit/245b6ab85b0f481f08c21e25f2b2a7eb6da9996c))
-- **cli:** copy signature when using secure live updates ([#5896](https://github.com/Cap-go/capacitor-plus/issues/5896)) ([0f17177](https://github.com/Cap-go/capacitor-plus/commit/0f17177b1c64c0f69f86e990e4e150b820da497b))
-- **cli:** fail cap update on uninstalled cordova dependencies ([#8032](https://github.com/Cap-go/capacitor-plus/issues/8032)) ([b393de8](https://github.com/Cap-go/capacitor-plus/commit/b393de8bc9e68aff2cb70428a7c86c98367feade))
-- **cli:** Initial Cordova plugin SPM support ([#7999](https://github.com/Cap-go/capacitor-plus/issues/7999)) ([c030354](https://github.com/Cap-go/capacitor-plus/commit/c03035426343ddc4e303ca3420e476bb7f1e2201))
-- **cli:** Migrate update to gradle 8 ([#6530](https://github.com/Cap-go/capacitor-plus/issues/6530)) ([da3ac0e](https://github.com/Cap-go/capacitor-plus/commit/da3ac0e72c0559223e9b91f31830810d39638734))
-- **cli:** non interactive migrate ([#6461](https://github.com/Cap-go/capacitor-plus/issues/6461)) ([53dfeaf](https://github.com/Cap-go/capacitor-plus/commit/53dfeaf77ace5b165260b68351eae8e5bf72ea0a))
-- **cli:** Option to inline JS source maps during sync ([#5843](https://github.com/Cap-go/capacitor-plus/issues/5843)) ([7ce6dd4](https://github.com/Cap-go/capacitor-plus/commit/7ce6dd4b6fb5cdc395add6f656fbedc785178ae3))
-- **cli:** run plugin hooks ([#7499](https://github.com/Cap-go/capacitor-plus/issues/7499)) ([3b847ea](https://github.com/Cap-go/capacitor-plus/commit/3b847eac42673c812a4538c319b81c8f8afc9955))
-- **cli:** Select a cap run target by target name ([#8199](https://github.com/Cap-go/capacitor-plus/issues/8199)) ([b30c472](https://github.com/Cap-go/capacitor-plus/commit/b30c472490117a5dbb14a9556ef1b6ca6e39b45b))
-- **cli:** Support bun when running cap migrate ([#7386](https://github.com/Cap-go/capacitor-plus/issues/7386)) ([3f96ff9](https://github.com/Cap-go/capacitor-plus/commit/3f96ff911588c517dc2d924f55ef28a25c30bd33))
-- **cli:** support capacitor portals plugin changes needed ([#5558](https://github.com/Cap-go/capacitor-plus/issues/5558)) ([6810a19](https://github.com/Cap-go/capacitor-plus/commit/6810a19ae2bbda1f4b2afad61d37ca822ca157f5))
-- **cli:** supports secure live updates in Portals for Capacitor config ([#5955](https://github.com/Cap-go/capacitor-plus/issues/5955)) ([a309b45](https://github.com/Cap-go/capacitor-plus/commit/a309b455fdd190613353bdf0eb04469cf4aa6ccd))
-- **cli:** update init to set androidScheme to https ([#6342](https://github.com/Cap-go/capacitor-plus/issues/6342)) ([158b27e](https://github.com/Cap-go/capacitor-plus/commit/158b27e53fd803c87de32e8da9f0c5117f81a3a5))
-- **cli:** update migrate command for cap4 -> cap5 ([#6447](https://github.com/Cap-go/capacitor-plus/issues/6447)) ([b1f0a37](https://github.com/Cap-go/capacitor-plus/commit/b1f0a3744d3158dab083ea31ea3e747b937729d2))
-- expose `appStartPath` on cap config server configuration ([#8019](https://github.com/Cap-go/capacitor-plus/issues/8019)) ([a274fef](https://github.com/Cap-go/capacitor-plus/commit/a274fef069176a8e528a22f4734d1e29a539709c))
-- Implement automated upstream sync and review process for Capacitor+ ([54a5dfb](https://github.com/Cap-go/capacitor-plus/commit/54a5dfbd1f81ca4144e13b3051bf592d3aaf1f4a))
-- **ios:** Add Bundler support ([#5205](https://github.com/Cap-go/capacitor-plus/issues/5205)) ([f21c6d0](https://github.com/Cap-go/capacitor-plus/commit/f21c6d01fc30e46c151afc93da9727dbf6c9ddcf))
-- **ios:** Add preferredContentMode configuration option ([#5583](https://github.com/Cap-go/capacitor-plus/issues/5583)) ([5b6dfa3](https://github.com/Cap-go/capacitor-plus/commit/5b6dfa3fe29c85632546b299f03cc04a77cf7475))
-- **ios:** add webContentsDebuggingEnabled configuration ([#6495](https://github.com/Cap-go/capacitor-plus/issues/6495)) ([c691e4a](https://github.com/Cap-go/capacitor-plus/commit/c691e4aecbfb7a45ce0465d1fe9020ab715815d3))
-- **iOS:** Allow plugins to hook into handling WebView URL authentication challenges ([#8216](https://github.com/Cap-go/capacitor-plus/issues/8216)) ([e8507cf](https://github.com/Cap-go/capacitor-plus/commit/e8507cfe4d93337ddee8ab6597aab5209ebb4858))
-- modify package.swift on update and sync ([#7042](https://github.com/Cap-go/capacitor-plus/issues/7042)) ([24573fb](https://github.com/Cap-go/capacitor-plus/commit/24573fb864c43551e2ce42721b45ff901155627d))
-- System Bars Plugin ([#8180](https://github.com/Cap-go/capacitor-plus/issues/8180)) ([a32216a](https://github.com/Cap-go/capacitor-plus/commit/a32216ac0607172a3a9c7ae5cdbfc598769294a6))
-- Upgrade to Typescript 5.x ([#6433](https://github.com/Cap-go/capacitor-plus/issues/6433)) ([88d0ded](https://github.com/Cap-go/capacitor-plus/commit/88d0ded9e7356531ffc4563b9b81a0f3f069484b))
+- **cli:** add cSettings support for compiler flags in generated Package.swift ([#8448](https://github.com/ionic-team/capacitor/issues/8448)) ([0bd0676](https://github.com/ionic-team/capacitor/commit/0bd0676315c5fd77e50312dd7b5bf4990dcbd7d0))
+- **cli:** add system framework and weak framework support in SPM Package.swift ([#8447](https://github.com/ionic-team/capacitor/issues/8447)) ([3232f0f](https://github.com/ionic-team/capacitor/commit/3232f0fe1d9811b0b5c500e3dc05cb8a250177f8))
+- **cli:** correct Capacitor plugin SPM compat check ([#8440](https://github.com/ionic-team/capacitor/issues/8440)) ([e5ccc45](https://github.com/ionic-team/capacitor/commit/e5ccc451dda27d56bca824ed644bd20fe4d988cb))
+- **cli:** generate binaryTarget entries for custom xcframeworks in Package.swift ([#8445](https://github.com/ionic-team/capacitor/issues/8445)) ([1f7e33f](https://github.com/ionic-team/capacitor/commit/1f7e33fca43d183332ec19d22b0d75ef81d8cc6d))
+- **cli:** generate resource entries in Package.swift ([#8455](https://github.com/ionic-team/capacitor/issues/8455)) ([790bd27](https://github.com/ionic-team/capacitor/commit/790bd27123497111984227010c3162cec94a108e))
+- **cli:** handle Cordova plugins without iOS source files ([#8443](https://github.com/ionic-team/capacitor/issues/8443)) ([0da130e](https://github.com/ionic-team/capacitor/commit/0da130eb7a861bee4e2c35bc0aac53ba9c983fc3))
+- **cli:** link plugin dependencies in Package.swift ([#8457](https://github.com/ionic-team/capacitor/issues/8457)) ([b3c769e](https://github.com/ionic-team/capacitor/commit/b3c769e856c826b1174518877cf86ac7ce73bf09))
+- **ios:** support Cordova plugins with Package.swift ([#8438](https://github.com/ionic-team/capacitor/issues/8438)) ([139943b](https://github.com/ionic-team/capacitor/commit/139943b0c05fddb2d1ce2d6f468800fddf17b4cf))
## [8.3.1](https://github.com/ionic-team/capacitor/compare/8.3.0...8.3.1) (2026-04-16)
diff --git a/cli/package.json b/cli/package.json
index f7bf432521..ae3b65bee2 100644
--- a/cli/package.json
+++ b/cli/package.json
@@ -1,9 +1,9 @@
{
- "name": "@capacitor-plus/cli",
- "version": "8.3.4",
- "description": "Capacitor+: Enhanced Capacitor with automated upstream sync - Cross-platform apps with JavaScript and the web",
- "homepage": "https://capgo.app/docs/plugins/capacitor-plus/",
- "author": "Capgo Team (https://capgo.app)",
+ "name": "@capacitor/cli",
+ "version": "9.0.0-alpha.5",
+ "description": "Capacitor: Cross-platform apps with JavaScript and the web",
+ "homepage": "https://capacitorjs.com",
+ "author": "Ionic Team (https://ionic.io)",
"license": "MIT",
"repository": {
"type": "git",
diff --git a/cli/src/android/update.ts b/cli/src/android/update.ts
index c8e4b71a00..d05b68b92b 100644
--- a/cli/src/android/update.ts
+++ b/cli/src/android/update.ts
@@ -7,6 +7,7 @@ import { checkPlatformVersions, runTask } from '../common';
import { checkPluginDependencies, handleCordovaPluginsJS, writeCordovaAndroidManifest } from '../cordova';
import type { Config } from '../definitions';
import { fatal } from '../errors';
+import { logger } from '../log';
import {
PluginType,
getAllElements,
@@ -35,10 +36,13 @@ export async function updateAndroid(config: Config): Promise {
printPlugins(capacitorPlugins, 'android');
- await writePluginsJson(config, capacitorPlugins);
- await removePluginsNativeFiles(config);
const cordovaPlugins = plugins.filter((p) => getPluginType(p, platform) === PluginType.Cordova);
- if (cordovaPlugins.length > 0) {
+ const enableCordova = cordovaPlugins.length > 0;
+
+ await writePluginsJson(config, capacitorPlugins, enableCordova);
+ await removePluginsNativeFiles(config);
+ if (enableCordova) {
+ logger.info('Found Cordova Plugins: Including Android Cordova Support');
await copyPluginsNativeFiles(config, cordovaPlugins);
}
if (!(await pathExists(config.android.webDirAbs))) {
@@ -47,8 +51,10 @@ export async function updateAndroid(config: Config): Promise {
await handleCordovaPluginsJS(cordovaPlugins, config, platform);
await checkPluginDependencies(plugins, platform, config.app.extConfig.cordova?.failOnUninstalledPlugins);
await installGradlePlugins(config, capacitorPlugins, cordovaPlugins);
- await handleCordovaPluginsGradle(config, cordovaPlugins);
- await writeCordovaAndroidManifest(cordovaPlugins, config, platform);
+ if (enableCordova) {
+ await handleCordovaPluginsGradle(config, cordovaPlugins);
+ await writeCordovaAndroidManifest(cordovaPlugins, config, platform);
+ }
const incompatibleCordovaPlugins = plugins.filter((p) => getPluginType(p, platform) === PluginType.Incompatible);
printPlugins(incompatibleCordovaPlugins, platform, 'incompatible');
@@ -64,8 +70,16 @@ interface PluginsJsonEntry {
classpath: string;
}
-async function writePluginsJson(config: Config, plugins: Plugin[]): Promise {
+async function writePluginsJson(config: Config, plugins: Plugin[], includeCordova: boolean): Promise {
const classes = await findAndroidPluginClasses(plugins);
+
+ if (includeCordova) {
+ classes.push({
+ pkg: '@capacitor/android',
+ classpath: 'com.getcapacitor.cordova.CordovaPlugin',
+ });
+ }
+
const pluginsJsonPath = resolve(config.android.assetsDirAbs, 'capacitor.plugins.json');
await writeJSON(pluginsJsonPath, classes, { spaces: '\t' });
@@ -149,14 +163,27 @@ export async function installGradlePlugins(
);
}
+ const enableCordova = cordovaPlugins.length > 0;
+
const capacitorAndroidPath = resolve(dirname(capacitorAndroidPackagePath), 'capacitor');
+ const capacitorCordovaAndroidPath = resolve(dirname(capacitorAndroidPackagePath), 'capacitor-cordova');
const settingsPath = config.android.platformDirAbs;
const dependencyPath = config.android.appDirAbs;
const relativeCapcitorAndroidPath = convertToUnixPath(relative(settingsPath, capacitorAndroidPath));
+ const relativeCapacitorCordovaAndroidPath = convertToUnixPath(relative(settingsPath, capacitorCordovaAndroidPath));
+ const cdvIncludeText = enableCordova
+ ? `
+include ':capacitor-cordova-android'
+project(':capacitor-cordova-android').projectDir = new File('${relativeCapacitorCordovaAndroidPath}')
+
+include ':capacitor-cordova-android-plugins'
+project(':capacitor-cordova-android-plugins').projectDir = new File('./capacitor-cordova-android-plugins/')`
+ : '';
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}')
+${cdvIncludeText}
${capacitorPlugins
.map((p) => {
if (!p.android) {
@@ -196,6 +223,20 @@ project(':${getGradlePackageName(p.id)}').projectDir = new File('${relativePlugi
});
prefsArray = prefsArray.concat(getAllElements(p, platform, 'preference'));
});
+ const cdvRepoApplyText = enableCordova
+ ? `
+repositories {
+ flatDir{
+ dirs '../capacitor-cordova-android-plugins/src/main/libs', 'libs'
+ }
+}
+
+apply from: "../capacitor-cordova-android-plugins/cordova.variables.gradle"
+`
+ : '';
+ const cdvDependencyText = enableCordova
+ ? ` implementation project(':capacitor-cordova-android')\n implementation project(':capacitor-cordova-android-plugins')\n`
+ : '';
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
@@ -206,14 +247,13 @@ android {
targetCompatibility JavaVersion.VERSION_21
}
}
-
-apply from: "../capacitor-cordova-android-plugins/cordova.variables.gradle"
+${cdvRepoApplyText}
dependencies {
-${capacitorPlugins
- .map((p) => {
- return ` implementation project(':${getGradlePackageName(p.id)}')`;
- })
- .join('\n')}
+${cdvDependencyText}${capacitorPlugins
+ .map((p) => {
+ return ` implementation project(':${getGradlePackageName(p.id)}')`;
+ })
+ .join('\n')}
${frameworkString}
}
${applyArray.join('\n')}
@@ -229,8 +269,6 @@ if (hasProperty('postBuildExtras')) {
export async function handleCordovaPluginsGradle(config: Config, cordovaPlugins: Plugin[]): Promise {
const pluginsGradlePath = join(config.android.cordovaPluginsDirAbs, 'build.gradle');
- const kotlinNeeded = await kotlinNeededCheck(config, cordovaPlugins);
- const kotlinVersionString = config.app.extConfig.cordova?.preferences?.GradlePluginKotlinVersion ?? '2.2.20';
const frameworksArray: any[] = [];
let prefsArray: any[] = [];
const applyArray: any[] = [];
@@ -262,10 +300,6 @@ export async function handleCordovaPluginsGradle(config: Config, cordovaPlugins:
})
.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 readFile(pluginsGradlePath, { encoding: 'utf-8' });
buildGradle = buildGradle.replace(
@@ -276,28 +310,6 @@ export async function handleCordovaPluginsGradle(config: Config, cordovaPlugins:
/(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 writeFile(pluginsGradlePath, buildGradle);
const cordovaVariables = `// DO NOT EDIT THIS FILE! IT IS GENERATED EACH TIME "capacitor update" IS RUN
ext {
@@ -309,25 +321,6 @@ ext {
await writeFile(join(config.android.cordovaPluginsDirAbs, 'cordova.variables.gradle'), cordovaVariables);
}
-async function kotlinNeededCheck(config: Config, cordovaPlugins: Plugin[]) {
- if (config.app.extConfig.cordova?.preferences?.GradlePluginKotlinEnabled !== 'true') {
- for (const plugin of cordovaPlugins) {
- const androidPlatform = 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: Config, cordovaPlugins: Plugin[]) {
const pluginsPath = join(config.android.cordovaPluginsDirAbs, 'src', 'main');
for (const p of cordovaPlugins) {
diff --git a/cli/src/config.ts b/cli/src/config.ts
index dcdd61038f..280cad60ba 100644
--- a/cli/src/config.ts
+++ b/cli/src/config.ts
@@ -236,7 +236,7 @@ async function loadAndroidConfig(
return {
name,
- minVersion: '24',
+ minVersion: '26',
studioPath,
platformDir,
platformDirAbs,
@@ -286,7 +286,7 @@ async function loadIOSConfig(rootDir: string, extConfig: ExternalConfig): Promis
};
return {
name,
- minVersion: '15.0',
+ minVersion: '16.0',
platformDir,
platformDirAbs,
scheme,
diff --git a/cli/src/declarations.ts b/cli/src/declarations.ts
index 6c8645406d..1103b65850 100644
--- a/cli/src/declarations.ts
+++ b/cli/src/declarations.ts
@@ -559,6 +559,13 @@ export interface CapacitorConfig {
* @since 8.3.0
*/
packageTraits?: { [pluginId: string]: string[] };
+ /**
+ * Define options to apply to the package.
+ * The key is the plugin ID (e.g. `@capacitor-community/device`)
+ *
+ * @since 8.4.0
+ */
+ packageOptions?: { [pluginId: string]: PackageOptions };
};
};
};
@@ -597,7 +604,7 @@ export interface CapacitorConfig {
* Configure the local scheme on Android.
*
* Custom schemes on Android are unable to change the URL path as of Webview 117. Changing this value from anything other than `http` or `https` can result in your
- * application unable to resolve routing. If you must change this for some reason, consider using a hash-based url strategy, but there are no guarentees that this
+ * application unable to resolve routing. If you must change this for some reason, consider using a hash-based url strategy, but there are no guarantees that this
* will continue to work long term as allowing non-standard schemes to modify query parameters and url fragments is only allowed for compatibility reasons.
* https://ionic.io/blog/capacitor-android-customscheme-issue-with-chrome-117
*
@@ -799,3 +806,16 @@ export interface PluginsConfig {
animation?: 'FADE' | 'NONE';
};
}
+
+export interface PackageOptions {
+ /**
+ * Create a symlink to the plugin folder instead of pointing to the plugin path.
+ * Useful when plugin names conflict.
+ */
+ symlink?: boolean;
+ /**
+ * Useful to avoid target name conflicts in dependencies
+ * [see](https://docs.swift.org/swiftpm/documentation/packagemanagerdocs/modulealiasing/)
+ */
+ moduleAliases?: { [target: string]: string };
+}
diff --git a/cli/src/index.ts b/cli/src/index.ts
index fb70e1039b..185df15bac 100644
--- a/cli/src/index.ts
+++ b/cli/src/index.ts
@@ -249,11 +249,8 @@ export function runProgram(config: Config): void {
)
.option('--no-sync', `do not run ${c.input('sync')}`)
.option('--forwardPorts ', 'Automatically run "adb reverse" for better live-reloading support')
- .option('-l, --live-reload', 'Set live-reload URL via CLI (uses defaults, overrides server.url config)')
- .option('--host ', 'Configure host for live-reload URL (used with --live-reload)')
- .option('--port ', 'Configure port for live-reload URL (used with --live-reload)')
+ .option('--url ', 'Load an external URL in the Web View, useful for live-reload (overrides server.url config)')
.option('--configuration ', 'Configuration name of the iOS Scheme')
- .option('--https', 'Use https:// instead of http:// for live-reload URL (used with --live-reload)')
.action(
wrapAction(
telemetryAction(
@@ -270,11 +267,8 @@ export function runProgram(config: Config): void {
targetNameSdkVersion,
sync,
forwardPorts,
- liveReload,
- host,
- port,
+ url,
configuration,
- https,
},
) => {
const { runCommand } = await import('./tasks/run');
@@ -288,11 +282,8 @@ export function runProgram(config: Config): void {
targetNameSdkVersion,
sync,
forwardPorts,
- liveReload,
- host,
- port,
+ url,
configuration,
- https,
});
},
),
diff --git a/cli/src/ios/update.ts b/cli/src/ios/update.ts
index b79e253778..b2ffa4d0bb 100644
--- a/cli/src/ios/update.ts
+++ b/cli/src/ios/update.ts
@@ -1,34 +1,31 @@
-import { copy, remove, pathExists, readFile, realpath, writeFile } from 'fs-extra';
+import { pathExists, readFile, realpath, writeFile } from 'fs-extra';
import { basename, dirname, join, relative } from 'path';
+import { major, prerelease } from 'semver';
import c from '../colors';
import { checkPlatformVersions, getCapacitorPackageVersion, runTask } from '../common';
-import { checkPluginDependencies, handleCordovaPluginsJS, logCordovaManualSteps, needsStaticPod } from '../cordova';
+import { checkPluginDependencies, handleCordovaPluginsJS, logCordovaManualSteps } from '../cordova';
import type { Config } from '../definitions';
import { fatal } from '../errors';
import { logger } from '../log';
import type { Plugin } from '../plugin';
-import {
- PluginType,
- getAllElements,
- getFilePath,
- getPlatformElement,
- getPluginPlatform,
- getPluginType,
- getPlugins,
- printPlugins,
- resolvePlugin,
-} from '../plugin';
+import { PluginType, getPluginType, getPlugins, printPlugins } from '../plugin';
import { copy as copyTask } from '../tasks/copy';
import { setAllStringIn } from '../tasks/migrate';
+import {
+ generateCordovaPodspecs,
+ generateCordovaPackageFiles,
+ copyPluginsNativeFiles,
+ removePluginsNativeFiles,
+ cordovaPodfileLines,
+} from '../util/cordova-ios';
import { convertToUnixPath } from '../util/fs';
import { generateIOSPackageJSON } from '../util/iosplugin';
import { resolveNode } from '../util/node';
import { generatePackageFile, checkPluginsForPackageSwift } from '../util/spm';
import { runCommand, isInstalled } from '../util/subprocess';
-import { extractTemplate } from '../util/template';
-import { getIOSPlugins, getMajoriOSVersion } from './common';
+import { getIOSPlugins } from './common';
const platform = 'ios';
@@ -46,260 +43,90 @@ export async function updateIOS(config: Config, deployment: boolean): Promise getPluginType(p, platform) === PluginType.Cordova);
- if (cordovaPlugins.length > 0) {
+ const enableCordova = cordovaPlugins.length > 0;
+
+ if (enableCordova) {
+ logger.info('Found Cordova Plugins: Including iOS Cordova Support');
await copyPluginsNativeFiles(config, cordovaPlugins);
}
+
if (!(await pathExists(await config.ios.webDirAbs))) {
await copyTask(config, platform);
}
+
await handleCordovaPluginsJS(cordovaPlugins, config, platform);
await checkPluginDependencies(plugins, platform, config.app.extConfig.cordova?.failOnUninstalledPlugins);
if ((await config.ios.packageManager) === 'SPM') {
- await generateCordovaPackageFiles(cordovaPlugins, config);
+ if (enableCordova) {
+ await generateCordovaPackageFiles(cordovaPlugins, config);
+ }
const validSPMPackages = await checkPluginsForPackageSwift(config, plugins);
+ await Promise.all(
+ validSPMPackages.map(async (plugin) => {
+ const iosPlatformVersion = await getCapacitorPackageVersion(config, config.ios.name);
+ const packageSwiftPath = join(plugin.rootPath, 'Package.swift');
+ let content = await readFile(packageSwiftPath, { encoding: 'utf-8' });
+ const regex = new RegExp(
+ 'url:\\s*"https://github.com/ionic-team/capacitor-swift-pm\\.git",\\s*from:\\s*"([^"]+)"',
+ );
+ const version = content.match(regex)?.[1];
+ const majorCapVersion = major(iosPlatformVersion);
+ if (version && major(version) != majorCapVersion) {
+ const preCapVersion = prerelease(iosPlatformVersion);
+ const forceVersion = preCapVersion ? iosPlatformVersion : `${majorCapVersion}.0.0`;
+ content = setAllStringIn(
+ content,
+ `url: "https://github.com/ionic-team/capacitor-swift-pm.git",`,
+ `)`,
+ ` from: "${forceVersion}"`,
+ );
+ await writeFile(packageSwiftPath, content);
+ logger.warn(`${plugin.id} is built for Capacitor ${major(version)}, it might cause issues`);
+ }
+ }),
+ );
await generatePackageFile(config, validSPMPackages.concat(cordovaPlugins));
} else {
- await generateCordovaPodspecs(cordovaPlugins, config);
- await installCocoaPodsPlugins(config, plugins, deployment);
- }
- await logCordovaManualSteps(cordovaPlugins, config, platform);
-
- const incompatibleCordovaPlugins = plugins.filter((p) => getPluginType(p, platform) === PluginType.Incompatible);
- printPlugins(incompatibleCordovaPlugins, platform, 'incompatible');
-}
-
-async function generateCordovaPackageFiles(cordovaPlugins: Plugin[], config: Config) {
- cordovaPlugins.map((plugin: any) => {
- generateCordovaPackageFile(plugin, config);
- });
-}
-
-async function generateCordovaPackageFile(p: Plugin, config: Config) {
- const iosPlatformVersion = await getCapacitorPackageVersion(config, config.ios.name);
-
- const platformTag = getPluginPlatform(p, platform);
- if (platformTag.$?.package) {
- const packageSwiftPath = join(p.rootPath, 'Package.swift');
- let content = await readFile(packageSwiftPath, { encoding: 'utf-8' });
- content = content.replace(`apache`, `ionic-team`).replaceAll(`cordova-ios`, `capacitor-swift-pm`);
- content = setAllStringIn(
- content,
- `url: "https://github.com/ionic-team/capacitor-swift-pm.git",`,
- `)`,
- ` from: "${iosPlatformVersion}"`,
- );
- await writeFile(packageSwiftPath, content);
- } else {
- await writeGeneratedPackageSwift(p, config, iosPlatformVersion);
- }
-}
-
-function buildBinaryTargetEntries(p: Plugin, frameworks: any[]): { binaryTargetsText: string; binaryDepsText: string } {
- const customXcframeworks = frameworks.filter((f: any) => f.$.custom === 'true' && f.$.src.endsWith('.xcframework'));
- const customFrameworks = frameworks.filter((f: any) => f.$.custom === 'true' && f.$.src.endsWith('.framework'));
-
- if (customFrameworks.length > 0) {
- customFrameworks.forEach((f: any) => {
- logger.warn(
- `${p.id}: custom .framework files are not supported as binaryTarget in SPM (${f.$.src}). Convert to .xcframework for SPM compatibility.`,
- );
- });
- }
-
- const binaryTargetsText = customXcframeworks
- .map((f: any) => {
- const name = f.$.src.split('/').pop().replace('.xcframework', '');
- return `,
- .binaryTarget(
- name: "${name}",
- path: "${f.$.src}"
- )`;
- })
- .join('');
-
- const binaryDepsText = customXcframeworks
- .map((f: any) => {
- const name = f.$.src.split('/').pop().replace('.xcframework', '');
- return `,\n .target(name: "${name}")`;
- })
- .join('');
-
- return { binaryTargetsText, binaryDepsText };
-}
-
-function buildResourcesText(resources: any[]) {
- const resourceEntry = [];
- for (const resource of resources) {
- resourceEntry.push(`.copy("resources/${resource.$.src.split('/').pop()}")`);
- }
- return resources.length > 0
- ? `,
- resources: [
- ${resourceEntry.join(',\n ')}
- ]`
- : '';
-}
-
-async function buildDependencyTexts(p: Plugin, config: Config) {
- let allDependencies: string[] = getPlatformElement(p, platform, 'dependency');
- if (p.xml['dependency']) {
- allDependencies = allDependencies.concat(p.xml['dependency']);
- }
- let packageText = '';
- let productText = '';
- await Promise.all(
- allDependencies.map(async (dep: any) => {
- let plugin = dep.$.id;
- if (plugin.includes('@') && plugin.indexOf('@') !== 0) {
- [plugin] = plugin.split('@');
- }
- const depPlugin = await resolvePlugin(config, plugin);
- if (depPlugin) {
- const headerFiles = getPlatformElement(depPlugin, platform, 'header-file');
- const resources = getPlatformElement(depPlugin, platform, 'resource-file');
- const sourceFiles = getPlatformElement(depPlugin, platform, 'source-file');
- if (sourceFiles.length === 0 && headerFiles.length === 0 && resources.length === 0) {
- return;
- }
- packageText += `,\n .package(name: "${depPlugin.name}", path: "../${depPlugin.name}")`;
- productText += `,\n .product(name: "${depPlugin.name}", package: "${depPlugin.name}")`;
- }
- }),
- );
- return { packageText, productText };
-}
-
-function buildCSettingsText(p: Plugin, sourceFiles: any[]): string {
- const pluginId = p.id;
- const allFlags = new Set();
- for (const sourceFile of sourceFiles) {
- const flags = sourceFile.$?.['compiler-flags'];
- if (flags) {
- flags
- .split(/\s+/)
- .map((f: string) => f.trim())
- .filter((f: string) => f.length > 0)
- .forEach((f: string) => allFlags.add(f));
- }
- }
-
- if (allFlags.size === 0) {
- return '';
+ await installCocoaPodsPlugins(config, plugins, deployment, enableCordova);
}
- const entries: string[] = [];
- const unsupportedFlags: string[] = [];
-
- for (const flag of allFlags) {
- if (flag.startsWith('-D')) {
- const definition = flag.slice(2);
- const eqIndex = definition.indexOf('=');
- if (eqIndex !== -1) {
- const name = definition.slice(0, eqIndex);
- const value = definition.slice(eqIndex + 1);
- entries.push(` .define("${name}", to: "${value}")`);
- } else {
- entries.push(` .define("${definition}")`);
- }
- } else {
- unsupportedFlags.push(flag);
- }
+ if (enableCordova) {
+ await logCordovaManualSteps(cordovaPlugins, config, platform);
+ const incompatibleCordovaPlugins = plugins.filter((p) => getPluginType(p, platform) === PluginType.Incompatible);
+ printPlugins(incompatibleCordovaPlugins, platform, 'incompatible');
}
-
- if (unsupportedFlags.length > 0) {
- logger.warn(
- `${pluginId}: the following compiler flags are not supported in SPM and were ignored: ${unsupportedFlags.join(', ')}. ` +
- `This might cause the plugin to fail to compile.`,
- );
- }
-
- if (entries.length === 0) {
- return '';
- }
-
- return `,
- cSettings: [
-${entries.join(',\n')}
- ]`;
}
-async function writeGeneratedPackageSwift(p: Plugin, config: Config, iosPlatformVersion: string) {
- const iosVersion = getMajoriOSVersion(config);
- const headerFiles = getPlatformElement(p, platform, 'header-file');
- const headersText =
- headerFiles.length > 0
- ? `,
- publicHeadersPath: "."`
- : '';
- const resources = getPlatformElement(p, platform, 'resource-file');
- const sourceFiles = getPlatformElement(p, platform, 'source-file');
- if (sourceFiles.length === 0 && headerFiles.length === 0 && resources.length === 0) {
- return;
+export async function installCocoaPodsPlugins(
+ config: Config,
+ plugins: Plugin[],
+ deployment: boolean,
+ enableCordova: boolean,
+): Promise {
+ if (enableCordova) {
+ const cordovaPlugins = plugins.filter((p) => getPluginType(p, platform) === PluginType.Cordova);
+ await generateCordovaPodspecs(cordovaPlugins, config);
}
- const frameworks = getPlatformElement(p, platform, 'framework');
- const { binaryTargetsText, binaryDepsText } = buildBinaryTargetEntries(p, frameworks);
- const cSettingsText = buildCSettingsText(p, sourceFiles);
- const systemFrameworks = frameworks.filter((f: any) => !f.$.custom && f.$.src.endsWith('.framework'));
- const hasWeakFrameworks = systemFrameworks.some((f: any) => f.$.weak === 'true');
- const requiredSystemFrameworks = systemFrameworks.filter((f: any) => f.$.weak !== 'true');
- const resourcesText = buildResourcesText(resources);
-
- const libraryTypeText = hasWeakFrameworks ? `\n type: .dynamic,` : '';
- const linkerSettingsText =
- requiredSystemFrameworks.length > 0
- ? `,
- linkerSettings: [
-${requiredSystemFrameworks.map((f: any) => ` .linkedFramework("${f.$.src.replace('.framework', '')}")`).join(',\n')}
- ]`
- : '';
- const { packageText, productText } = await buildDependencyTexts(p, config);
-
- const content = `// swift-tools-version: 5.9
-
-import PackageDescription
-
-let package = Package(
- name: "${p.name}",
- platforms: [.iOS(.v${iosVersion})],
- products: [
- .library(
- name: "${p.name}",${libraryTypeText}
- targets: ["${p.name}"]
- )
- ],
- dependencies: [
- .package(url: "https://github.com/ionic-team/capacitor-swift-pm.git", from: "${iosPlatformVersion}")${packageText}
- ],
- targets: [
- .target(
- name: "${p.name}",
- dependencies: [
- .product(name: "Cordova", package: "capacitor-swift-pm")${binaryDepsText}${productText}
- ],
- path: "."${resourcesText}${headersText}${cSettingsText}${linkerSettingsText}
- )${binaryTargetsText}
- ]
-)`;
-
- await writeFile(join(config.ios.cordovaPluginsDirAbs, 'sources', p.name, 'Package.swift'), content);
-}
-
-export async function installCocoaPodsPlugins(config: Config, plugins: Plugin[], deployment: boolean): Promise {
await runTask(`Updating iOS native dependencies with ${c.input(`${await config.ios.podPath} install`)}`, () => {
- return updatePodfile(config, plugins, deployment);
+ return updatePodfile(config, plugins, deployment, enableCordova);
});
}
-async function updatePodfile(config: Config, plugins: Plugin[], deployment: boolean): Promise {
- const dependenciesContent = await generatePodFile(config, plugins);
+async function updatePodfile(
+ config: Config,
+ plugins: Plugin[],
+ deployment: boolean,
+ enableCordova: boolean,
+): Promise {
+ const dependenciesContent = await generatePodFile(config, plugins, enableCordova);
const relativeCapacitoriOSPath = await getRelativeCapacitoriOSPath(config);
const podfilePath = join(config.ios.nativeProjectDirAbs, 'Podfile');
let podfileContent = await readFile(podfilePath, { encoding: 'utf-8' });
podfileContent = podfileContent.replace(/(def capacitor_pods)[\s\S]+?(\nend)/, `$1${dependenciesContent}$2`);
podfileContent = podfileContent.replace(
- /(require_relative)[\s\S]+?(@capacitor\/ios\/scripts\/pods_helpers')/,
+ /(require_relative)[\s\S]+?(ios\/scripts\/pods_helpers')/,
`require_relative '${relativeCapacitoriOSPath}/scripts/pods_helpers'`,
);
await writeFile(podfilePath, podfileContent, { encoding: 'utf-8' });
@@ -346,10 +173,12 @@ async function getRelativeCapacitoriOSPath(config: Config) {
return convertToUnixPath(relative(config.ios.nativeProjectDirAbs, await realpath(dirname(capacitoriOSPath))));
}
-async function generatePodFile(config: Config, plugins: Plugin[]): Promise {
+async function generatePodFile(config: Config, plugins: Plugin[], enableCordova: boolean): Promise {
const relativeCapacitoriOSPath = await getRelativeCapacitoriOSPath(config);
const capacitorPlugins = plugins.filter((p) => getPluginType(p, platform) === PluginType.Core);
+ const cordovaPodlines = cordovaPodfileLines(config, plugins);
+
const pods = await Promise.all(
capacitorPlugins.map(async (p) => {
if (!p.ios) {
@@ -361,308 +190,17 @@ async function generatePodFile(config: Config, plugins: Plugin[]): Promise getPluginType(p, platform) === PluginType.Cordova);
- cordovaPlugins.map(async (p) => {
- const podspecs = getPlatformElement(p, platform, 'podspec');
- podspecs.map((podspec: any) => {
- podspec.pods.map((pPods: any) => {
- pPods.pod.map((pod: any) => {
- if (pod.$.git) {
- let gitRef = '';
- if (pod.$.tag) {
- gitRef = `, :tag => '${pod.$.tag}'`;
- } else if (pod.$.branch) {
- gitRef = `, :branch => '${pod.$.branch}'`;
- } else if (pod.$.commit) {
- gitRef = `, :commit => '${pod.$.commit}'`;
- }
- pods.push(` pod '${pod.$.name}', :git => '${pod.$.git}'${gitRef}\n`);
- }
- });
- });
- });
- });
- const staticPlugins = cordovaPlugins.filter((p) => needsStaticPod(p));
- const noStaticPlugins = cordovaPlugins.filter((el) => !staticPlugins.includes(el));
- if (noStaticPlugins.length > 0) {
- pods.push(` pod 'CordovaPlugins', :path => '../capacitor-cordova-ios-plugins'\n`);
- }
- if (staticPlugins.length > 0) {
- pods.push(` pod 'CordovaPluginsStatic', :path => '../capacitor-cordova-ios-plugins'\n`);
- }
- const resourcesPlugins = cordovaPlugins.filter(filterResources);
- if (resourcesPlugins.length > 0) {
- pods.push(` pod 'CordovaPluginsResources', :path => '../capacitor-cordova-ios-plugins'\n`);
- }
- return `
- pod 'Capacitor', :path => '${relativeCapacitoriOSPath}'
- pod 'CapacitorCordova', :path => '${relativeCapacitoriOSPath}'
-${pods.join('').trimRight()}`;
-}
-
-function getFrameworkName(framework: any) {
- if (isFramework(framework)) {
- if (framework.$.custom && framework.$.custom === 'true') {
- return framework.$.src;
- }
- return framework.$.src.substr(0, framework.$.src.indexOf('.'));
- }
- return framework.$.src.substr(0, framework.$.src.indexOf('.')).replace('lib', '');
-}
-
-function isFramework(framework: any) {
- return framework.$.src.split('.').pop().includes('framework');
-}
-
-async function generateCordovaPodspecs(cordovaPlugins: Plugin[], config: Config) {
- const staticPlugins = cordovaPlugins.filter((p) => needsStaticPod(p));
- const noStaticPlugins = cordovaPlugins.filter((el) => !staticPlugins.includes(el));
- generateCordovaPodspec(noStaticPlugins, config, false);
- generateCordovaPodspec(staticPlugins, config, true);
-}
-
-async function generateCordovaPodspec(cordovaPlugins: Plugin[], config: Config, isStatic: boolean) {
- const weakFrameworks: string[] = [];
- const linkedFrameworks: string[] = [];
- const customFrameworks: string[] = [];
- const systemLibraries: string[] = [];
- const sourceFrameworks: string[] = [];
- const frameworkDeps: string[] = [];
- const compilerFlags: string[] = [];
- let prefsArray: any[] = [];
- let name = 'CordovaPlugins';
- let sourcesFolderName = 'sources';
- if (isStatic) {
- name += 'Static';
- frameworkDeps.push('s.static_framework = true');
- sourcesFolderName += 'static';
- }
- cordovaPlugins.map((plugin: any) => {
- const frameworks = getPlatformElement(plugin, platform, 'framework');
- frameworks.map((framework: any) => {
- if (!framework.$.type) {
- const name = getFrameworkName(framework);
- if (isFramework(framework)) {
- if (framework.$.weak && framework.$.weak === 'true') {
- if (!weakFrameworks.includes(name)) {
- weakFrameworks.push(name);
- }
- } else if (framework.$.custom && framework.$.custom === 'true') {
- const frameworktPath = join(sourcesFolderName, plugin.name, name);
- if (!customFrameworks.includes(frameworktPath)) {
- customFrameworks.push(frameworktPath);
- }
- } else {
- if (!linkedFrameworks.includes(name)) {
- linkedFrameworks.push(name);
- }
- }
- } else {
- if (!systemLibraries.includes(name)) {
- systemLibraries.push(name);
- }
- }
- } else if (framework.$.type && framework.$.type === 'podspec') {
- let depString = `s.dependency '${framework.$.src}'`;
- if (framework.$.spec && framework.$.spec !== '') {
- depString += `, '${framework.$.spec}'`;
- }
- if (!frameworkDeps.includes(depString)) {
- frameworkDeps.push(depString);
- }
- }
- });
- prefsArray = prefsArray.concat(getAllElements(plugin, platform, 'preference'));
- const podspecs = getPlatformElement(plugin, platform, 'podspec');
- podspecs.map((podspec: any) => {
- podspec.pods.map((pods: any) => {
- pods.pod.map((pod: any) => {
- let depString = `s.dependency '${pod.$.name}'`;
- if (pod.$.spec && pod.$.spec !== '') {
- depString += `, '${pod.$.spec}'`;
- }
- if (!frameworkDeps.includes(depString)) {
- frameworkDeps.push(depString);
- }
- });
- });
- });
- const sourceFiles = getPlatformElement(plugin, platform, 'source-file');
- sourceFiles.map((sourceFile: any) => {
- if (sourceFile.$.framework && sourceFile.$.framework === 'true') {
- let fileName = sourceFile.$.src.split('/').pop();
- if (!fileName.startsWith('lib')) {
- fileName = 'lib' + fileName;
- }
- const frameworktPath = join(sourcesFolderName, plugin.name, fileName);
- if (!sourceFrameworks.includes(frameworktPath)) {
- sourceFrameworks.push(frameworktPath);
- }
- } else if (sourceFile.$['compiler-flags']) {
- const cFlag = sourceFile.$['compiler-flags'];
- if (!compilerFlags.includes(cFlag)) {
- compilerFlags.push(cFlag);
- }
- }
- });
- });
- const onlySystemLibraries = systemLibraries.filter((library) => removeNoSystem(library, sourceFrameworks));
- if (weakFrameworks.length > 0) {
- frameworkDeps.push(`s.weak_frameworks = '${weakFrameworks.join(`', '`)}'`);
- }
- if (linkedFrameworks.length > 0) {
- frameworkDeps.push(`s.frameworks = '${linkedFrameworks.join(`', '`)}'`);
- }
- if (onlySystemLibraries.length > 0) {
- frameworkDeps.push(`s.libraries = '${onlySystemLibraries.join(`', '`)}'`);
- }
- if (customFrameworks.length > 0) {
- frameworkDeps.push(`s.vendored_frameworks = '${customFrameworks.join(`', '`)}'`);
- frameworkDeps.push(
- `s.exclude_files = 'sources/**/*.framework/Headers/*.h', 'sources/**/*.framework/PrivateHeaders/*.h'`,
- );
- }
- if (sourceFrameworks.length > 0) {
- frameworkDeps.push(`s.vendored_libraries = '${sourceFrameworks.join(`', '`)}'`);
- }
- if (compilerFlags.length > 0) {
- frameworkDeps.push(`s.compiler_flags = '${compilerFlags.join(' ')}'`);
- }
- const arcPlugins = cordovaPlugins.filter(filterARCFiles);
- if (arcPlugins.length > 0) {
- frameworkDeps.push(`s.subspec 'noarc' do |sna|
- sna.requires_arc = false
- sna.source_files = 'noarc/**/*.{swift,h,m,c,cc,mm,cpp}'
- end`);
- }
- let frameworksString = frameworkDeps.join('\n ');
- frameworksString = await replaceFrameworkVariables(config, prefsArray, frameworksString);
- const content = `
- Pod::Spec.new do |s|
- s.name = '${name}'
- s.version = '${config.cli.package.version}'
- s.summary = 'Autogenerated spec'
- s.license = 'Unknown'
- s.homepage = 'https://example.com'
- s.authors = { 'Capacitor Generator' => 'hi@example.com' }
- s.source = { :git => 'https://github.com/ionic-team/does-not-exist.git', :tag => '${config.cli.package.version}' }
- s.source_files = '${sourcesFolderName}/**/*.{swift,h,m,c,cc,mm,cpp}'
- s.ios.deployment_target = '${config.ios.minVersion}'
- s.xcconfig = {'GCC_PREPROCESSOR_DEFINITIONS' => '$(inherited) COCOAPODS=1 WK_WEB_VIEW_ONLY=1' }
- s.dependency 'CapacitorCordova'${getLinkerFlags(config)}
- s.swift_version = '5.1'
- ${frameworksString}
- end`;
- await writeFile(join(config.ios.cordovaPluginsDirAbs, `${name}.podspec`), content);
-}
-function getLinkerFlags(config: Config) {
- if (config.app.extConfig.ios?.cordovaLinkerFlags) {
- return `\n s.pod_target_xcconfig = { 'OTHER_LDFLAGS' => '${config.app.extConfig.ios.cordovaLinkerFlags.join(
- ' ',
- )}' }`;
- }
- return '';
-}
+ let podfileString = '\n';
+ podfileString += ` pod 'Capacitor', :path => '${relativeCapacitoriOSPath}'\n`;
-async function copyPluginsNativeFiles(config: Config, cordovaPlugins: Plugin[]) {
- const isSPM = (await config.ios.packageManager) === 'SPM';
- for (const p of cordovaPlugins) {
- const platformTag = getPluginPlatform(p, platform);
- if (platformTag.$?.package) {
- continue;
- }
- const sourceFiles = getPlatformElement(p, platform, 'source-file');
- const headerFiles = getPlatformElement(p, platform, 'header-file');
- const codeFiles = sourceFiles.concat(headerFiles);
- const frameworks = getPlatformElement(p, platform, 'framework');
- let sourcesFolderName = 'sources';
- if (!isSPM && needsStaticPod(p)) {
- sourcesFolderName += 'static';
- }
- const sourcesFolder = join(config.ios.cordovaPluginsDirAbs, sourcesFolderName, p.name);
- for (const codeFile of codeFiles) {
- let fileName = codeFile.$.src.split('/').pop();
- const fileExt = codeFile.$.src.split('.').pop();
- if (fileExt === 'a' && !fileName.startsWith('lib')) {
- fileName = 'lib' + fileName;
- }
- let destFolder = sourcesFolderName;
- if (!isSPM && codeFile.$['compiler-flags'] && codeFile.$['compiler-flags'] === '-fno-objc-arc') {
- destFolder = 'noarc';
- }
- const filePath = getFilePath(config, p, codeFile.$.src);
- const fileDest = join(config.ios.cordovaPluginsDirAbs, destFolder, p.name, fileName);
- await copy(filePath, fileDest);
- if (!codeFile.$.framework) {
- let fileContent = await readFile(fileDest, { encoding: 'utf-8' });
- if (fileExt === 'swift') {
- fileContent = 'import Cordova\n' + fileContent;
- await writeFile(fileDest, fileContent, { encoding: 'utf-8' });
- } else {
- if (fileContent.includes('@import Firebase;')) {
- fileContent = fileContent.replace('@import Firebase;', '#import ');
- await writeFile(fileDest, fileContent, { encoding: 'utf-8' });
- }
- if (
- fileContent.includes('[NSBundle bundleForClass:[self class]]') ||
- fileContent.includes('[NSBundle bundleForClass:[CDVCapture class]]')
- ) {
- const bundleName = isSPM ? 'SWIFTPM_MODULE_BUNDLE' : '[NSBundle mainBundle]';
- fileContent = fileContent.replace('[NSBundle bundleForClass:[self class]]', bundleName);
- fileContent = fileContent.replace('[NSBundle bundleForClass:[CDVCapture class]]', bundleName);
- await writeFile(fileDest, fileContent, { encoding: 'utf-8' });
- }
- if (isSPM && fileContent.includes('[NSBundle mainBundle] URLForResource')) {
- fileContent = fileContent.replace(
- '[NSBundle mainBundle] URLForResource',
- 'SWIFTPM_MODULE_BUNDLE URLForResource',
- );
- await writeFile(fileDest, fileContent, { encoding: 'utf-8' });
- }
- if (fileContent.includes('[self.webView superview]') || fileContent.includes('self.webView.superview')) {
- fileContent = fileContent.replace(/\[self.webView superview\]/g, 'self.viewController.view');
- fileContent = fileContent.replace(/self.webView.superview/g, 'self.viewController.view');
- await writeFile(fileDest, fileContent, { encoding: 'utf-8' });
- }
- }
- }
- }
- const resourceFiles = getPlatformElement(p, platform, 'resource-file');
- for (const resourceFile of resourceFiles) {
- const fileName = resourceFile.$.src.split('/').pop();
- const rootResFolder = isSPM ? sourcesFolder : config.ios.cordovaPluginsDirAbs;
- await copy(getFilePath(config, p, resourceFile.$.src), join(rootResFolder, 'resources', fileName));
- }
- for (const framework of frameworks) {
- if (framework.$.custom && framework.$.custom === 'true') {
- await copy(getFilePath(config, p, framework.$.src), join(sourcesFolder, framework.$.src));
- }
- }
+ if (enableCordova) {
+ podfileString += ` pod 'CapacitorCordova', :path => '${relativeCapacitoriOSPath}'\n`;
+ podfileString += cordovaPodlines.join('').trimEnd() + '\n';
}
-}
-async function removePluginsNativeFiles(config: Config) {
- await remove(config.ios.cordovaPluginsDirAbs);
- await extractTemplate(config.cli.assets.ios.cordovaPluginsTemplateArchiveAbs, config.ios.cordovaPluginsDirAbs);
-}
-
-function filterResources(plugin: Plugin) {
- const resources = getPlatformElement(plugin, platform, 'resource-file');
- return resources.length > 0;
-}
-
-function filterARCFiles(plugin: Plugin) {
- const sources = getPlatformElement(plugin, platform, 'source-file');
- const sourcesARC = sources.filter(
- (sourceFile: any) => sourceFile.$['compiler-flags'] && sourceFile.$['compiler-flags'] === '-fno-objc-arc',
- );
- return sourcesARC.length > 0;
-}
-
-function removeNoSystem(library: string, sourceFrameworks: string[]) {
- const libraries = sourceFrameworks.filter((framework) => framework.includes(library));
- return libraries.length === 0;
+ podfileString += pods.join('').trimEnd();
+ return podfileString;
}
async function getPluginsTask(config: Config) {
@@ -672,13 +210,3 @@ async function getPluginsTask(config: Config) {
return iosPlugins;
});
}
-
-async function replaceFrameworkVariables(config: Config, prefsArray: any[], frameworkString: string) {
- prefsArray.map((preference: any) => {
- frameworkString = frameworkString.replace(
- new RegExp(('$' + preference.$.name).replace('$', '\\$&'), 'g'),
- preference.$.default,
- );
- });
- return frameworkString;
-}
diff --git a/cli/src/ipc.ts b/cli/src/ipc.ts
index 41894e53a7..37c38110bb 100644
--- a/cli/src/ipc.ts
+++ b/cli/src/ipc.ts
@@ -49,9 +49,9 @@ export async function receive(msg: IPCMessage): Promise {
// This request is only made if telemetry is on.
const req = request(
{
- hostname: 'api.ionicjs.com',
+ hostname: 'metrics-capacitor.outsystems.com',
port: 443,
- path: '/events/metrics',
+ path: '/metrics',
method: 'POST',
headers: {
'Content-Type': 'application/json',
@@ -60,7 +60,7 @@ export async function receive(msg: IPCMessage): Promise {
(response) => {
debug('Sent %O metric to events service (status: %O)', data.name, response.statusCode);
- if (response.statusCode !== 204) {
+ if (response.statusCode !== 202) {
response.on('data', (chunk) => {
debug('Bad response from events service. Request body: %O', chunk.toString());
});
diff --git a/cli/src/tasks/migrate.ts b/cli/src/tasks/migrate.ts
index 2f60074448..4e538e1f6c 100644
--- a/cli/src/tasks/migrate.ts
+++ b/cli/src/tasks/migrate.ts
@@ -1,6 +1,6 @@
import { writeFileSync, readFileSync, existsSync } from 'fs-extra';
import { join } from 'path';
-import { rimraf } from 'rimraf';
+import rimraf from 'rimraf';
import { coerce, gte, lt } from 'semver';
import c from '../colors';
@@ -79,9 +79,9 @@ const plugins = [
];
const coreVersion = '^8.0.0';
const pluginVersion = '^8.0.0';
-const gradleVersion = '8.14.3';
-const iOSVersion = '15';
-const kotlinVersion = '2.2.20';
+const gradleVersion = '9.5.1';
+const iOSVersion = '16';
+const kotlinVersion = '2.4.0';
let installFailed = false;
export async function migrateCommand(config: Config, noprompt: boolean, packagemanager: string): Promise {
@@ -124,7 +124,7 @@ export async function migrateCommand(config: Config, noprompt: boolean, packagem
const { migrateconfirm } = noprompt
? { migrateconfirm: 'y' }
- : await logPrompt(`Capacitor 8 sets a deployment target of iOS ${iOSVersion} and Android 16 (SDK 36). \n`, {
+ : await logPrompt(`Capacitor 8 sets a deployment target of iOS ${iOSVersion} and Android 17 (SDK 37). \n`, {
type: 'text',
name: 'migrateconfirm',
message: `Are you sure you want to migrate? (Y/n)`,
diff --git a/cli/src/tasks/run.ts b/cli/src/tasks/run.ts
index 2efeccf0a1..124422e6e9 100644
--- a/cli/src/tasks/run.ts
+++ b/cli/src/tasks/run.ts
@@ -30,11 +30,8 @@ export interface RunCommandOptions {
targetNameSdkVersion?: string;
sync?: boolean;
forwardPorts?: string;
- liveReload?: boolean;
- host?: string;
- port?: string;
+ url?: string;
configuration?: string;
- https?: boolean;
}
export async function runCommand(
@@ -42,9 +39,16 @@ export async function runCommand(
selectedPlatformName: string,
options: RunCommandOptions,
): Promise {
- options.host = options.host ?? CapLiveReloadHelper.getIpAddress() ?? 'localhost';
- if (!options.port) {
- options.port = '3000';
+ if (options.url) {
+ let parsed: URL;
+ try {
+ parsed = new URL(options.url);
+ } catch {
+ fatal(`Invalid --url: "${options.url}" is not a valid URL`);
+ }
+ if (parsed.protocol !== 'http:' && parsed.protocol !== 'https:') {
+ fatal(`Invalid --url: must use http:// or https:// (got "${parsed.protocol}//")`);
+ }
}
if (selectedPlatformName && !(await isValidPlatform(selectedPlatformName))) {
const platformDir = resolvePlatform(config, selectedPlatformName);
@@ -94,14 +98,14 @@ export async function runCommand(
await sync(config, platformName, false, true);
}
const cordovaPlugins = await getCordovaPlugins(config, platformName);
- if (options.liveReload) {
+ if (options.url) {
await CapLiveReloadHelper.editCapConfigForLiveReload(config, platformName, options);
if (platformName === config.android.name) {
await await writeCordovaAndroidManifest(cordovaPlugins, config, platformName, true);
}
}
await run(config, platformName, options);
- if (options.liveReload) {
+ if (options.url) {
new Promise((resolve) => process.on('SIGINT', resolve))
.then(async () => {
await CapLiveReloadHelper.revertCapConfigForLiveReload();
@@ -110,12 +114,13 @@ export async function runCommand(
}
})
.then(() => process.exit());
- logger.info(
- `App running with live reload listing for: ${options.https ? 'https' : 'http'}://${options.host}${options.port ? `:${options.port}` : ''}. Press Ctrl+C to quit.`,
- );
+ logger.info(`App running with live reload listening for: ${options.url}. Press Ctrl+C to quit.`);
await sleepForever();
}
} catch (e: any) {
+ if (options.url) {
+ await CapLiveReloadHelper.revertCapConfigForLiveReload();
+ }
if (!isFatal(e)) {
fatal(e.stack ?? e);
}
diff --git a/cli/src/telemetry.ts b/cli/src/telemetry.ts
index ef5e0be5aa..9e87ac38c9 100644
--- a/cli/src/telemetry.ts
+++ b/cli/src/telemetry.ts
@@ -1,8 +1,9 @@
import { Command } from 'commander';
import Debug from 'debug';
+import { pathExists } from 'fs-extra';
import c from './colors';
-import type { Config } from './definitions';
+import type { Config, PackageManager } from './definitions';
import { send } from './ipc';
import { output } from './log';
import { readConfig, writeConfig } from './sysconfig';
@@ -26,6 +27,7 @@ export interface CommandMetricData {
error: string | null;
node_version: string;
os: string;
+ ios_package_manager: PackageManager | 'unknown';
}
export interface Metric {
@@ -80,9 +82,12 @@ export function telemetryAction(config: Config, action: CommanderAction): Comman
error: error ? (error.message ? error.message : String(error)) : null,
node_version: process.version,
os: config.cli.os,
+ ios_package_manager: await getIOSPackageManager(config),
...Object.fromEntries(versions),
};
+ debug('metric payload: %O', data);
+
if (isInteractive()) {
let sysconfig = await readConfig();
@@ -126,6 +131,24 @@ export async function sendMetric(
}
}
+/**
+ * Resolve the iOS dependency manager for telemetry. Returns 'unknown' for
+ * non-iOS projects or when detection throws, so callers never have to handle
+ * errors from this signal.
+ */
+export async function getIOSPackageManager(config: Config): Promise {
+ try {
+ if (!(await pathExists(config.ios.platformDirAbs))) {
+ return 'unknown';
+ }
+
+ return await config.ios.packageManager;
+ } catch (e) {
+ debug('Could not resolve iOS package manager for telemetry: %O', e);
+ return 'unknown';
+ }
+}
+
/**
* Get a unique anonymous identifier for this app.
*/
diff --git a/cli/src/util/cordova-ios.ts b/cli/src/util/cordova-ios.ts
new file mode 100644
index 0000000000..371bd96d33
--- /dev/null
+++ b/cli/src/util/cordova-ios.ts
@@ -0,0 +1,398 @@
+import { copy, readFile, writeFile, remove } from 'fs-extra';
+import { join } from 'path';
+
+import { getCapacitorPackageVersion } from '../common';
+import { needsStaticPod } from '../cordova';
+import type { Config } from '../definitions';
+import { getMajoriOSVersion } from '../ios/common';
+import {
+ PluginType,
+ getAllElements,
+ getFilePath,
+ getPlatformElement,
+ getPluginPlatform,
+ getPluginType,
+} from '../plugin';
+import type { Plugin } from '../plugin';
+import { setAllStringIn } from '../tasks/migrate';
+import { extractTemplate } from '../util/template';
+
+const platform = 'ios';
+
+export async function generateCordovaPodspecs(cordovaPlugins: Plugin[], config: Config): Promise {
+ const staticPlugins = cordovaPlugins.filter((p) => needsStaticPod(p));
+ const noStaticPlugins = cordovaPlugins.filter((el) => !staticPlugins.includes(el));
+ generateCordovaPodspec(noStaticPlugins, config, false);
+ generateCordovaPodspec(staticPlugins, config, true);
+}
+
+async function generateCordovaPodspec(cordovaPlugins: Plugin[], config: Config, isStatic: boolean) {
+ const weakFrameworks: string[] = [];
+ const linkedFrameworks: string[] = [];
+ const customFrameworks: string[] = [];
+ const systemLibraries: string[] = [];
+ const sourceFrameworks: string[] = [];
+ const frameworkDeps: string[] = [];
+ const compilerFlags: string[] = [];
+ let prefsArray: any[] = [];
+ let name = 'CordovaPlugins';
+ let sourcesFolderName = 'sources';
+ if (isStatic) {
+ name += 'Static';
+ frameworkDeps.push('s.static_framework = true');
+ sourcesFolderName += 'static';
+ }
+ cordovaPlugins.map((plugin: any) => {
+ const frameworks = getPlatformElement(plugin, platform, 'framework');
+ frameworks.map((framework: any) => {
+ if (!framework.$.type) {
+ const name = getFrameworkName(framework);
+ if (isFramework(framework)) {
+ if (framework.$.weak && framework.$.weak === 'true') {
+ if (!weakFrameworks.includes(name)) {
+ weakFrameworks.push(name);
+ }
+ } else if (framework.$.custom && framework.$.custom === 'true') {
+ const frameworktPath = join(sourcesFolderName, plugin.name, name);
+ if (!customFrameworks.includes(frameworktPath)) {
+ customFrameworks.push(frameworktPath);
+ }
+ } else {
+ if (!linkedFrameworks.includes(name)) {
+ linkedFrameworks.push(name);
+ }
+ }
+ } else {
+ if (!systemLibraries.includes(name)) {
+ systemLibraries.push(name);
+ }
+ }
+ } else if (framework.$.type && framework.$.type === 'podspec') {
+ let depString = `s.dependency '${framework.$.src}'`;
+ if (framework.$.spec && framework.$.spec !== '') {
+ depString += `, '${framework.$.spec}'`;
+ }
+ if (!frameworkDeps.includes(depString)) {
+ frameworkDeps.push(depString);
+ }
+ }
+ });
+ prefsArray = prefsArray.concat(getAllElements(plugin, platform, 'preference'));
+ const podspecs = getPlatformElement(plugin, platform, 'podspec');
+ podspecs.map((podspec: any) => {
+ podspec.pods.map((pods: any) => {
+ pods.pod.map((pod: any) => {
+ let depString = `s.dependency '${pod.$.name}'`;
+ if (pod.$.spec && pod.$.spec !== '') {
+ depString += `, '${pod.$.spec}'`;
+ }
+ if (!frameworkDeps.includes(depString)) {
+ frameworkDeps.push(depString);
+ }
+ });
+ });
+ });
+ const sourceFiles = getPlatformElement(plugin, platform, 'source-file');
+ sourceFiles.map((sourceFile: any) => {
+ if (sourceFile.$.framework && sourceFile.$.framework === 'true') {
+ let fileName = sourceFile.$.src.split('/').pop();
+ if (!fileName.startsWith('lib')) {
+ fileName = 'lib' + fileName;
+ }
+ const frameworktPath = join(sourcesFolderName, plugin.name, fileName);
+ if (!sourceFrameworks.includes(frameworktPath)) {
+ sourceFrameworks.push(frameworktPath);
+ }
+ } else if (sourceFile.$['compiler-flags']) {
+ const cFlag = sourceFile.$['compiler-flags'];
+ if (!compilerFlags.includes(cFlag)) {
+ compilerFlags.push(cFlag);
+ }
+ }
+ });
+ });
+ const onlySystemLibraries = systemLibraries.filter((library) => removeNoSystem(library, sourceFrameworks));
+ if (weakFrameworks.length > 0) {
+ frameworkDeps.push(`s.weak_frameworks = '${weakFrameworks.join(`', '`)}'`);
+ }
+ if (linkedFrameworks.length > 0) {
+ frameworkDeps.push(`s.frameworks = '${linkedFrameworks.join(`', '`)}'`);
+ }
+ if (onlySystemLibraries.length > 0) {
+ frameworkDeps.push(`s.libraries = '${onlySystemLibraries.join(`', '`)}'`);
+ }
+ if (customFrameworks.length > 0) {
+ frameworkDeps.push(`s.vendored_frameworks = '${customFrameworks.join(`', '`)}'`);
+ frameworkDeps.push(
+ `s.exclude_files = 'sources/**/*.framework/Headers/*.h', 'sources/**/*.framework/PrivateHeaders/*.h'`,
+ );
+ }
+ if (sourceFrameworks.length > 0) {
+ frameworkDeps.push(`s.vendored_libraries = '${sourceFrameworks.join(`', '`)}'`);
+ }
+ if (compilerFlags.length > 0) {
+ frameworkDeps.push(`s.compiler_flags = '${compilerFlags.join(' ')}'`);
+ }
+ const arcPlugins = cordovaPlugins.filter(filterARCFiles);
+ if (arcPlugins.length > 0) {
+ frameworkDeps.push(`s.subspec 'noarc' do |sna|
+ sna.requires_arc = false
+ sna.source_files = 'noarc/**/*.{swift,h,m,c,cc,mm,cpp}'
+ end`);
+ }
+ let frameworksString = frameworkDeps.join('\n ');
+ frameworksString = await replaceFrameworkVariables(config, prefsArray, frameworksString);
+ const content = `
+ Pod::Spec.new do |s|
+ s.name = '${name}'
+ s.version = '${config.cli.package.version}'
+ s.summary = 'Autogenerated spec'
+ s.license = 'Unknown'
+ s.homepage = 'https://example.com'
+ s.authors = { 'Capacitor Generator' => 'hi@example.com' }
+ s.source = { :git => 'https://github.com/ionic-team/does-not-exist.git', :tag => '${config.cli.package.version}' }
+ s.source_files = '${sourcesFolderName}/**/*.{swift,h,m,c,cc,mm,cpp}'
+ s.ios.deployment_target = '${config.ios.minVersion}'
+ s.xcconfig = {'GCC_PREPROCESSOR_DEFINITIONS' => '$(inherited) COCOAPODS=1 WK_WEB_VIEW_ONLY=1' }
+ s.dependency 'CapacitorCordova'${getLinkerFlags(config)}
+ s.swift_version = '5.1'
+ ${frameworksString}
+ end`;
+ await writeFile(join(config.ios.cordovaPluginsDirAbs, `${name}.podspec`), content);
+}
+
+function getLinkerFlags(config: Config) {
+ if (config.app.extConfig.ios?.cordovaLinkerFlags) {
+ return `\n s.pod_target_xcconfig = { 'OTHER_LDFLAGS' => '${config.app.extConfig.ios.cordovaLinkerFlags.join(
+ ' ',
+ )}' }`;
+ }
+ return '';
+}
+
+export async function copyPluginsNativeFiles(config: Config, cordovaPlugins: Plugin[]): Promise {
+ const isSPM = (await config.ios.packageManager) === 'SPM';
+ for (const p of cordovaPlugins) {
+ const platformTag = getPluginPlatform(p, platform);
+ if (isSPM && platformTag.$?.package) {
+ continue;
+ }
+ const sourceFiles = getPlatformElement(p, platform, 'source-file');
+ const headerFiles = getPlatformElement(p, platform, 'header-file');
+ const codeFiles = sourceFiles.concat(headerFiles);
+ const frameworks = getPlatformElement(p, platform, 'framework');
+ let sourcesFolderName = 'sources';
+ if (!isSPM && needsStaticPod(p)) {
+ sourcesFolderName += 'static';
+ }
+ const sourcesFolder = join(config.ios.cordovaPluginsDirAbs, sourcesFolderName, p.name);
+ for (const codeFile of codeFiles) {
+ let fileName = codeFile.$.src.split('/').pop();
+ const fileExt = codeFile.$.src.split('.').pop();
+ if (fileExt === 'a' && !fileName.startsWith('lib')) {
+ fileName = 'lib' + fileName;
+ }
+ let destFolder = sourcesFolderName;
+ if (!isSPM && codeFile.$['compiler-flags'] && codeFile.$['compiler-flags'] === '-fno-objc-arc') {
+ destFolder = 'noarc';
+ }
+ const filePath = getFilePath(config, p, codeFile.$.src);
+ const fileDest = join(config.ios.cordovaPluginsDirAbs, destFolder, p.name, fileName);
+ await copy(filePath, fileDest);
+ if (!codeFile.$.framework) {
+ let fileContent = await readFile(fileDest, { encoding: 'utf-8' });
+ if (fileExt === 'swift') {
+ fileContent = 'import Cordova\n' + fileContent;
+ await writeFile(fileDest, fileContent, { encoding: 'utf-8' });
+ } else {
+ if (fileContent.includes('@import Firebase;')) {
+ fileContent = fileContent.replace('@import Firebase;', '#import ');
+ await writeFile(fileDest, fileContent, { encoding: 'utf-8' });
+ }
+ if (
+ fileContent.includes('[NSBundle bundleForClass:[self class]]') ||
+ fileContent.includes('[NSBundle bundleForClass:[CDVCapture class]]')
+ ) {
+ const bundleName = isSPM ? 'SWIFTPM_MODULE_BUNDLE' : '[NSBundle mainBundle]';
+ fileContent = fileContent.replace('[NSBundle bundleForClass:[self class]]', bundleName);
+ fileContent = fileContent.replace('[NSBundle bundleForClass:[CDVCapture class]]', bundleName);
+ await writeFile(fileDest, fileContent, { encoding: 'utf-8' });
+ }
+ if (isSPM && fileContent.includes('[NSBundle mainBundle] URLForResource')) {
+ fileContent = fileContent.replace(
+ '[NSBundle mainBundle] URLForResource',
+ 'SWIFTPM_MODULE_BUNDLE URLForResource',
+ );
+ await writeFile(fileDest, fileContent, { encoding: 'utf-8' });
+ }
+ if (fileContent.includes('[self.webView superview]') || fileContent.includes('self.webView.superview')) {
+ fileContent = fileContent.replace(/\[self.webView superview\]/g, 'self.viewController.view');
+ fileContent = fileContent.replace(/self.webView.superview/g, 'self.viewController.view');
+ await writeFile(fileDest, fileContent, { encoding: 'utf-8' });
+ }
+ }
+ }
+ }
+ const resourceFiles = getPlatformElement(p, platform, 'resource-file');
+ for (const resourceFile of resourceFiles) {
+ const fileName = resourceFile.$.src.split('/').pop();
+ const rootResFolder = isSPM ? sourcesFolder : config.ios.cordovaPluginsDirAbs;
+ await copy(getFilePath(config, p, resourceFile.$.src), join(rootResFolder, 'resources', fileName));
+ }
+ for (const framework of frameworks) {
+ if (framework.$.custom && framework.$.custom === 'true') {
+ await copy(getFilePath(config, p, framework.$.src), join(sourcesFolder, framework.$.src));
+ }
+ }
+ }
+}
+
+export async function removePluginsNativeFiles(config: Config): Promise {
+ await remove(config.ios.cordovaPluginsDirAbs);
+ if ((await config.ios.packageManager) === 'SPM') {
+ await remove(join(config.ios.nativeProjectDirAbs, 'CapApp-SPM', 'symlinks'));
+ }
+ await extractTemplate(config.cli.assets.ios.cordovaPluginsTemplateArchiveAbs, config.ios.cordovaPluginsDirAbs);
+}
+
+export function filterARCFiles(plugin: Plugin): boolean {
+ const sources = getPlatformElement(plugin, platform, 'source-file');
+ const sourcesARC = sources.filter(
+ (sourceFile: any) => sourceFile.$['compiler-flags'] && sourceFile.$['compiler-flags'] === '-fno-objc-arc',
+ );
+ return sourcesARC.length > 0;
+}
+
+function removeNoSystem(library: string, sourceFrameworks: string[]): boolean {
+ const libraries = sourceFrameworks.filter((framework) => framework.includes(library));
+ return libraries.length === 0;
+}
+
+async function replaceFrameworkVariables(config: Config, prefsArray: any[], frameworkString: string): Promise {
+ prefsArray.map((preference: any) => {
+ frameworkString = frameworkString.replace(
+ new RegExp(('$' + preference.$.name).replace('$', '\\$&'), 'g'),
+ preference.$.default,
+ );
+ });
+ return frameworkString;
+}
+
+function getFrameworkName(framework: any): string {
+ if (isFramework(framework)) {
+ if (framework.$.custom && framework.$.custom === 'true') {
+ return framework.$.src;
+ }
+ return framework.$.src.substr(0, framework.$.src.indexOf('.'));
+ }
+ return framework.$.src.substr(0, framework.$.src.indexOf('.')).replace('lib', '');
+}
+
+function isFramework(framework: any) {
+ return framework.$.src.split('.').pop().includes('framework');
+}
+
+export function cordovaPodfileLines(config: Config, plugins: Plugin[]): string[] {
+ const pods: string[] = [];
+
+ const cordovaPlugins = plugins.filter((p) => getPluginType(p, platform) === PluginType.Cordova);
+ cordovaPlugins.map(async (p) => {
+ const podspecs = getPlatformElement(p, platform, 'podspec');
+ podspecs.map((podspec: any) => {
+ podspec.pods.map((pPods: any) => {
+ pPods.pod.map((pod: any) => {
+ if (pod.$.git) {
+ let gitRef = '';
+ if (pod.$.tag) {
+ gitRef = `, :tag => '${pod.$.tag}'`;
+ } else if (pod.$.branch) {
+ gitRef = `, :branch => '${pod.$.branch}'`;
+ } else if (pod.$.commit) {
+ gitRef = `, :commit => '${pod.$.commit}'`;
+ }
+ pods.push(` pod '${pod.$.name}', :git => '${pod.$.git}'${gitRef}\n`);
+ }
+ });
+ });
+ });
+ });
+ const staticPlugins = cordovaPlugins.filter((p) => needsStaticPod(p));
+ const noStaticPlugins = cordovaPlugins.filter((el) => !staticPlugins.includes(el));
+ if (noStaticPlugins.length > 0) {
+ pods.push(` pod 'CordovaPlugins', :path => '../capacitor-cordova-ios-plugins'\n`);
+ }
+ if (staticPlugins.length > 0) {
+ pods.push(` pod 'CordovaPluginsStatic', :path => '../capacitor-cordova-ios-plugins'\n`);
+ }
+ const resourcesPlugins = cordovaPlugins.filter(filterResources);
+ if (resourcesPlugins.length > 0) {
+ pods.push(` pod 'CordovaPluginsResources', :path => '../capacitor-cordova-ios-plugins'\n`);
+ }
+
+ return pods;
+}
+
+function filterResources(plugin: Plugin) {
+ const resources = getPlatformElement(plugin, platform, 'resource-file');
+ return resources.length > 0;
+}
+
+export async function generateCordovaPackageFiles(cordovaPlugins: Plugin[], config: Config): Promise {
+ cordovaPlugins.map((plugin: any) => {
+ generateCordovaPackageFile(plugin, config);
+ });
+}
+
+export async function generateCordovaPackageFile(p: Plugin, config: Config): Promise {
+ const iosPlatformVersion = await getCapacitorPackageVersion(config, config.ios.name);
+ const iosVersion = getMajoriOSVersion(config);
+ const headerFiles = getPlatformElement(p, platform, 'header-file');
+ let headersText = '';
+ if (headerFiles.length > 0) {
+ headersText = `,
+ publicHeadersPath: "."`;
+ }
+
+ const platformTag = getPluginPlatform(p, platform);
+
+ if (platformTag.$?.package) {
+ const packageSwiftPath = join(p.rootPath, 'Package.swift');
+ let content = await readFile(packageSwiftPath, { encoding: 'utf-8' });
+ content = content.replace(`apache`, `ionic-team`).replaceAll(`cordova-ios`, `capacitor-swift-pm`);
+ content = setAllStringIn(
+ content,
+ `url: "https://github.com/ionic-team/capacitor-swift-pm.git",`,
+ `)`,
+ ` from: "${iosPlatformVersion}"`,
+ );
+ await writeFile(packageSwiftPath, content);
+ } else {
+ const content = `// swift-tools-version: 5.9
+
+import PackageDescription
+
+let package = Package(
+ name: "${p.name}",
+ platforms: [.iOS(.v${iosVersion})],
+ products: [
+ .library(
+ name: "${p.name}",
+ targets: ["${p.name}"]
+ )
+ ],
+ dependencies: [
+ .package(url: "https://github.com/ionic-team/capacitor-swift-pm.git", from: "${iosPlatformVersion}")
+ ],
+ targets: [
+ .target(
+ name: "${p.name}",
+ dependencies: [
+ .product(name: "Cordova", package: "capacitor-swift-pm")
+ ],
+ path: "."${headersText}
+ )
+ ]
+)`;
+ await writeFile(join(config.ios.cordovaPluginsDirAbs, 'sources', p.name, 'Package.swift'), content);
+ }
+}
diff --git a/cli/src/util/iosplugin.ts b/cli/src/util/iosplugin.ts
index 8ce42b35e7..ed4f4fd54b 100644
--- a/cli/src/util/iosplugin.ts
+++ b/cli/src/util/iosplugin.ts
@@ -68,6 +68,7 @@ export async function generateIOSPackageJSON(config: Config, plugins: Plugin[]):
const cordovaPlugins = await getCordovaPlugins(config, 'ios');
if (cordovaPlugins.length > 0) {
classList.push('CDVPlugin');
+ classList.push('CordovaPlugin');
}
writePluginJSON(config, classList);
}
diff --git a/cli/src/util/livereload.ts b/cli/src/util/livereload.ts
index 34d008a6ce..f447bec0a6 100644
--- a/cli/src/util/livereload.ts
+++ b/cli/src/util/livereload.ts
@@ -1,5 +1,4 @@
import { readJSONSync, writeJSONSync } from 'fs-extra';
-import { networkInterfaces } from 'os';
import { join } from 'path';
import type { Config } from '../definitions';
@@ -18,135 +17,7 @@ class CapLiveReload {
// nothing to do
}
- getIpAddress(name?: string, family?: any) {
- const interfaces: any = networkInterfaces() ?? {};
-
- const _normalizeFamily = (family?: any) => {
- if (family === 4) {
- return 'ipv4';
- }
- if (family === 6) {
- return 'ipv6';
- }
- return family ? family.toLowerCase() : 'ipv4';
- };
- const isLoopback = (addr: string) => {
- return (
- /^(::f{4}:)?127\.([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})/.test(addr) ||
- /^fe80::1$/.test(addr) ||
- /^::1$/.test(addr) ||
- /^::$/.test(addr)
- );
- };
- const isPrivate = (addr: string) => {
- return (
- /^(::f{4}:)?10\.([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})$/i.test(addr) ||
- /^(::f{4}:)?192\.168\.([0-9]{1,3})\.([0-9]{1,3})$/i.test(addr) ||
- /^(::f{4}:)?172\.(1[6-9]|2\d|30|31)\.([0-9]{1,3})\.([0-9]{1,3})$/i.test(addr) ||
- /^(::f{4}:)?127\.([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})$/i.test(addr) ||
- /^(::f{4}:)?169\.254\.([0-9]{1,3})\.([0-9]{1,3})$/i.test(addr) ||
- /^f[cd][0-9a-f]{2}:/i.test(addr) ||
- /^fe80:/i.test(addr) ||
- /^::1$/.test(addr) ||
- /^::$/.test(addr)
- );
- };
- const isPublic = (addr: string) => {
- return !isPrivate(addr);
- };
- const loopback = (family?: any) => {
- //
- // Default to `ipv4`
- //
- family = _normalizeFamily(family);
-
- if (family !== 'ipv4' && family !== 'ipv6') {
- throw new Error('family must be ipv4 or ipv6');
- }
-
- return family === 'ipv4' ? '127.0.0.1' : 'fe80::1';
- };
-
- //
- // Default to `ipv4`
- //
- family = _normalizeFamily(family);
-
- //
- // If a specific network interface has been named,
- // return the address.
- //
- if (name && name !== 'private' && name !== 'public') {
- const res = interfaces[name].filter((details: any) => {
- const itemFamily = _normalizeFamily(details.family);
- return itemFamily === family;
- });
- if (res.length === 0) {
- return undefined;
- }
- return res[0].address;
- }
-
- const all = Object.keys(interfaces)
- .map((nic) => {
- //
- // Note: name will only be `public` or `private`
- // when this is called.
- //
- const addresses = interfaces[nic].filter((details: any) => {
- details.family = _normalizeFamily(details.family);
- if (details.family !== family || isLoopback(details.address)) {
- return false;
- }
- if (!name) {
- return true;
- }
-
- return name === 'public' ? isPrivate(details.address) : isPublic(details.address);
- });
-
- return addresses.length ? addresses[0].address : undefined;
- })
- .filter(Boolean);
-
- return !all.length ? loopback(family) : all[0];
- }
-
- // TODO remove on next major as it's unused
- async editExtConfigForLiveReload(
- config: Config,
- platformName: string,
- options: RunCommandOptions,
- rootConfigChange = false,
- ): Promise {
- const platformAbsPath =
- platformName == config.ios.name
- ? config.ios.nativeTargetDirAbs
- : platformName == config.android.name
- ? config.android.assetsDirAbs
- : null;
- if (platformAbsPath == null) throw new Error('Platform not found.');
- const capConfigPath = rootConfigChange
- ? config.app.extConfigFilePath
- : join(platformAbsPath, 'capacitor.config.json');
-
- const configJson = { ...config.app.extConfig };
- this.configJsonToRevertTo.json = JSON.stringify(configJson, null, 2);
- this.configJsonToRevertTo.platformPath = capConfigPath;
- const url = `http://${options.host}:${options.port}`;
- configJson.server = {
- url,
- };
- return configJson;
- }
-
- // TODO remove rootConfigChange param on next major as it's unused
- async editCapConfigForLiveReload(
- config: Config,
- platformName: string,
- options: RunCommandOptions,
- rootConfigChange = false,
- ): Promise {
+ async editCapConfigForLiveReload(config: Config, platformName: string, options: RunCommandOptions): Promise {
const platformAbsPath =
platformName == config.ios.name
? config.ios.nativeTargetDirAbs
@@ -154,17 +25,14 @@ class CapLiveReload {
? config.android.assetsDirAbs
: null;
if (platformAbsPath == null) throw new Error('Platform not found.');
- const capConfigPath = rootConfigChange
- ? config.app.extConfigFilePath
- : join(platformAbsPath, 'capacitor.config.json');
+ const capConfigPath = join(platformAbsPath, 'capacitor.config.json');
const configJson = readJSONSync(capConfigPath);
this.configJsonToRevertTo.json = JSON.stringify(configJson, null, 2);
this.configJsonToRevertTo.platformPath = capConfigPath;
- const url = `${options.https ? 'https' : 'http'}://${options.host}${options.port ? `:${options.port}` : ''}`;
configJson.server = {
...configJson.server,
- url,
+ url: options.url,
};
writeJSONSync(capConfigPath, configJson, { spaces: '\t' });
}
diff --git a/cli/src/util/spm.ts b/cli/src/util/spm.ts
index b67a2d1919..6981f0ff5f 100644
--- a/cli/src/util/spm.ts
+++ b/cli/src/util/spm.ts
@@ -1,4 +1,4 @@
-import { pathExists, existsSync, readFileSync, writeFileSync, remove, move, mkdtemp } from 'fs-extra';
+import { ensureSymlink, pathExists, existsSync, readFileSync, writeFileSync, remove, move, mkdtemp } from 'fs-extra';
import { tmpdir } from 'os';
import { join, relative, resolve } from 'path';
import type { PlistObject } from 'plist';
@@ -6,6 +6,7 @@ import { build, parse } from 'plist';
import { extract } from 'tar';
import { getCapacitorPackageVersion } from '../common';
+import { getCordovaPlugins } from '../cordova';
import type { Config } from '../definitions';
import { fatal } from '../errors';
import { getMajoriOSVersion } from '../ios/common';
@@ -99,7 +100,10 @@ export async function removeCocoapodsFiles(config: Config): Promise {
export async function generatePackageText(config: Config, plugins: Plugin[]): Promise {
const iosPlatformVersion = await getCapacitorPackageVersion(config, config.ios.name);
const iosVersion = getMajoriOSVersion(config);
+ const cordovaPlugins = await getCordovaPlugins(config, 'ios');
+ const enableCordova = cordovaPlugins.length > 0;
const packageTraits = config.app.extConfig.experimental?.ios?.spm?.packageTraits ?? {};
+ const packageOptions = config.app.extConfig.experimental?.ios?.spm?.packageOptions ?? {};
const swiftToolsVersion = config.app.extConfig.experimental?.ios?.spm?.swiftToolsVersion ?? '5.9';
let packageSwiftText = `// swift-tools-version: ${swiftToolsVersion}
@@ -132,7 +136,13 @@ let package = Package(
packageSwiftText += `,\n .package(name: "${plugin.name}", path: "../../capacitor-cordova-ios-plugins/sources/${plugin.name}")`;
}
} else {
- const relPath = relative(config.ios.nativeXcodeProjDirAbs, plugin.rootPath);
+ const options = packageOptions[plugin.id];
+ const symlink = options?.symlink;
+ const symlinkFolder = join('symlinks', plugin.name);
+ const relPath = symlink ? symlinkFolder : relative(config.ios.nativeXcodeProjDirAbs, plugin.rootPath);
+ if (symlink) {
+ await ensureSymlink(plugin.rootPath, resolve(config.ios.nativeProjectDirAbs, 'CapApp-SPM', symlinkFolder));
+ }
const traits = packageTraits[plugin.id];
const traitsSuffix = traits?.length
? `, traits: [${traits
@@ -152,11 +162,22 @@ let package = Package(
.target(
name: "CapApp-SPM",
dependencies: [
- .product(name: "Capacitor", package: "capacitor-swift-pm"),
- .product(name: "Cordova", package: "capacitor-swift-pm")`;
+ .product(name: "Capacitor", package: "capacitor-swift-pm")`;
+
+ if (enableCordova) {
+ packageSwiftText += `,\n .product(name: "Cordova", package: "capacitor-swift-pm")`;
+ }
for (const plugin of plugins) {
- let pluginText = `,\n .product(name: "${plugin.ios?.name}", package: "${plugin.ios?.name}")`;
+ const aliases = Object.entries(packageOptions[plugin.id]?.moduleAliases ?? {});
+ const aliasText = aliases?.length
+ ? `, moduleAliases: [${aliases
+ .map(([target, replacement]) => {
+ return `"${target}": "${replacement}"`;
+ })
+ .join(', ')}]`
+ : '';
+ let pluginText = `,\n .product(name: "${plugin.ios?.name}", package: "${plugin.ios?.name}"${aliasText})`;
if (getPluginType(plugin, config.ios.name) === PluginType.Cordova) {
const platformTag = getPluginPlatform(plugin, config.ios.name);
if (platformTag.$?.package) {
diff --git a/cli/test/telemetry.spec.ts b/cli/test/telemetry.spec.ts
new file mode 100644
index 0000000000..412048527c
--- /dev/null
+++ b/cli/test/telemetry.spec.ts
@@ -0,0 +1,60 @@
+import { pathExists } from 'fs-extra';
+
+import type { Config, IOSConfig } from '../src/definitions';
+import { getIOSPackageManager } from '../src/telemetry';
+
+jest.mock('fs-extra', () => ({
+ pathExists: jest.fn(),
+}));
+
+const mockedPathExists = pathExists as unknown as jest.Mock;
+
+function makeConfig(ios: Partial): Config {
+ return { ios } as unknown as Config;
+}
+
+describe('getIOSPackageManager', () => {
+ beforeEach(() => {
+ mockedPathExists.mockReset();
+ });
+
+ it('returns "unknown" when the iOS platform directory does not exist', async () => {
+ mockedPathExists.mockResolvedValueOnce(false);
+
+ const result = await getIOSPackageManager(
+ makeConfig({
+ platformDirAbs: '/tmp/no-such-dir/ios',
+ packageManager: Promise.resolve('SPM'),
+ }),
+ );
+
+ expect(result).toBe('unknown');
+ expect(mockedPathExists).toHaveBeenCalledWith('/tmp/no-such-dir/ios');
+ });
+
+ it('returns the resolved package manager when iOS is present', async () => {
+ mockedPathExists.mockResolvedValueOnce(true);
+
+ const result = await getIOSPackageManager(
+ makeConfig({
+ platformDirAbs: '/tmp/app/ios',
+ packageManager: Promise.resolve('SPM'),
+ }),
+ );
+
+ expect(result).toBe('SPM');
+ });
+
+ it('returns "unknown" when packageManager resolution throws', async () => {
+ mockedPathExists.mockResolvedValueOnce(true);
+
+ const result = await getIOSPackageManager(
+ makeConfig({
+ platformDirAbs: '/tmp/app/ios',
+ packageManager: Promise.reject(new Error('boom')),
+ }),
+ );
+
+ expect(result).toBe('unknown');
+ });
+});
diff --git a/core/CHANGELOG.md b/core/CHANGELOG.md
index 3d48e81aaa..82a95241a6 100644
--- a/core/CHANGELOG.md
+++ b/core/CHANGELOG.md
@@ -3,164 +3,67 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
-## [8.3.4](https://github.com/Cap-go/capacitor-plus/compare/8.3.3...8.3.4) (2026-05-07)
+# [9.0.0-alpha.5](https://github.com/ionic-team/capacitor/compare/8.4.1...9.0.0-alpha.5) (2026-06-23)
-**Note:** Version bump only for package @capacitor-plus/core
+# [9.0.0-alpha.4](https://github.com/ionic-team/capacitor/compare/9.0.0-alpha.3...9.0.0-alpha.4) (2026-06-19)
+# [9.0.0-alpha.3](https://github.com/ionic-team/capacitor/compare/8.4.0...9.0.0-alpha.3) (2026-06-02)
+# [9.0.0-alpha.2](https://github.com/ionic-team/capacitor/compare/8.3.4...9.0.0-alpha.2) (2026-05-12)
+# [9.0.0-alpha.1](https://github.com/ionic-team/capacitor/compare/8.3.3...9.0.0-alpha.1) (2026-05-08)
-
-## [8.3.3](https://github.com/Cap-go/capacitor-plus/compare/8.3.2...8.3.3) (2026-05-06)
-
-**Note:** Version bump only for package @capacitor-plus/core
-
-
-
-
-
-## [8.3.2](https://github.com/Cap-go/capacitor-plus/compare/8.0.8...8.3.2) (2026-05-05)
-
+# [9.0.0-alpha.0](https://github.com/ionic-team/capacitor/compare/8.3.2...9.0.0-alpha.0) (2026-05-07)
### Bug Fixes
-* address follow-up review comments ([8bee786](https://github.com/Cap-go/capacitor-plus/commit/8bee786e2c68ca6c351e88f104b518291c1f81e3))
-* **cookies:** only send expires param on web if a date is set ([b10cd7f](https://github.com/Cap-go/capacitor-plus/commit/b10cd7ff15b010a76802374214f4e0cbd04abdab))
-* **core:** make SystemBars hide and show options optional ([#8305](https://github.com/Cap-go/capacitor-plus/issues/8305)) ([95dc7d8](https://github.com/Cap-go/capacitor-plus/commit/95dc7d8ace3aabdda7e325c4a8ef7d1432ad37e9))
-* **http:** handle URL objects on fetch ([#8386](https://github.com/Cap-go/capacitor-plus/issues/8386)) ([003099a](https://github.com/Cap-go/capacitor-plus/commit/003099aef246adfd76d890074d46b1484951824b))
-* resolve upstream sync conflicts ([75cbb30](https://github.com/Cap-go/capacitor-plus/commit/75cbb3097a7068bcb37313cbe6301628079101ca))
-* **SystemBars:** use native safe area insets on Android ([#8384](https://github.com/Cap-go/capacitor-plus/issues/8384)) ([4e99598](https://github.com/Cap-go/capacitor-plus/commit/4e99598a2a57ee97e82be1aaa09492744622fa60))
-
-
-### Reverts
-
-* revert version bump from [#8319](https://github.com/Cap-go/capacitor-plus/issues/8319) and [#8320](https://github.com/Cap-go/capacitor-plus/issues/8320) ([a48ebb6](https://github.com/Cap-go/capacitor-plus/commit/a48ebb622ea4ebe92927bf1756a4d8ac6012884b))
-
-
-
-
-
-## [8.0.8](https://github.com/Cap-go/capacitor-plus/compare/8.0.7...8.0.8) (2026-04-08)
-
-**Note:** Version bump only for package @capacitor-plus/core
-
-
-
-
-
-## [8.0.7](https://github.com/Cap-go/capacitor-plus/compare/8.0.6...8.0.7) (2026-01-12)
-
-**Note:** Version bump only for package @capacitor-plus/core
+- **http:** handle URL objects on fetch ([#8386](https://github.com/ionic-team/capacitor/issues/8386)) ([0aac1f0](https://github.com/ionic-team/capacitor/commit/0aac1f0aee8083dc5013f0d8e3c180eb02f21141))
+- **SystemBars:** use native safe area insets on Android ([#8384](https://github.com/ionic-team/capacitor/issues/8384)) ([d55f4f8](https://github.com/ionic-team/capacitor/commit/d55f4f859bd88fa5617699e874c48c451bcb5e5f))
+# [9.0.0-alpha.4](https://github.com/ionic-team/capacitor/compare/9.0.0-alpha.3...9.0.0-alpha.4) (2026-06-19)
+## [8.4.1](https://github.com/ionic-team/capacitor/compare/8.4.0...8.4.1) (2026-06-19)
+# [8.4.0](https://github.com/ionic-team/capacitor/compare/9.0.0-alpha.2...8.4.0) (2026-06-02)
+**Note:** Version bump only for package @capacitor/core
-## [8.0.6](https://github.com/Cap-go/capacitor-plus/compare/8.0.5...8.0.6) (2026-01-09)
-
-**Note:** Version bump only for package @capacitor-plus/core
-
-
-
-
-
-## [8.0.5](https://github.com/Cap-go/capacitor-plus/compare/8.0.4...8.0.5) (2026-01-08)
-
-**Note:** Version bump only for package @capacitor-plus/core
-
-
-
+# [9.0.0-alpha.3](https://github.com/ionic-team/capacitor/compare/9.0.0-alpha.2...9.0.0-alpha.3) (2026-06-02)
+# [8.4.0](https://github.com/ionic-team/capacitor/compare/8.3.4...8.4.0) (2026-06-02)
-## [8.0.4](https://github.com/Cap-go/capacitor-plus/compare/8.0.3...8.0.4) (2025-12-16)
+## [8.3.4](https://github.com/ionic-team/capacitor/compare/9.0.0-alpha.1...8.3.4) (2026-05-12)
-**Note:** Version bump only for package @capacitor-plus/core
+## [8.3.3](https://github.com/ionic-team/capacitor/compare/9.0.0-alpha.0...8.3.3) (2026-05-08)
+**Note:** Version bump only for package @capacitor/core
+# [9.0.0-alpha.2](https://github.com/ionic-team/capacitor/compare/9.0.0-alpha.1...9.0.0-alpha.2) (2026-05-12)
+**Note:** Version bump only for package @capacitor/core
+# [9.0.0-alpha.1](https://github.com/ionic-team/capacitor/compare/9.0.0-alpha.0...9.0.0-alpha.1) (2026-05-08)
-## [8.0.3](https://github.com/Cap-go/capacitor-plus/compare/8.0.2...8.0.3) (2025-12-16)
+**Note:** Version bump only for package @capacitor/core
+# [9.0.0-alpha.0](https://github.com/ionic-team/capacitor/compare/8.3.2...9.0.0-alpha.0) (2026-05-07)
### Bug Fixes
-* update homepage URL in package.json files for all platforms ([61ccdc4](https://github.com/Cap-go/capacitor-plus/commit/61ccdc4128a1ce2a7178eb0a195b188876ec0a9d))
-
-
-
-
+- **http:** handle URL objects on fetch ([#8386](https://github.com/ionic-team/capacitor/issues/8386)) ([0aac1f0](https://github.com/ionic-team/capacitor/commit/0aac1f0aee8083dc5013f0d8e3c180eb02f21141))
+- **SystemBars:** use native safe area insets on Android ([#8384](https://github.com/ionic-team/capacitor/issues/8384)) ([d55f4f8](https://github.com/ionic-team/capacitor/commit/d55f4f859bd88fa5617699e874c48c451bcb5e5f))
-## [8.0.2](https://github.com/Cap-go/capacitor-plus/compare/8.0.1...8.0.2) (2025-12-16)
+## [8.3.4](https://github.com/ionic-team/capacitor/compare/8.3.3...8.3.4) (2026-05-12)
+**Note:** Version bump only for package @capacitor/core
-### Features
+## [8.3.3](https://github.com/ionic-team/capacitor/compare/8.3.2...8.3.3) (2026-05-08)
-* add new workflows for testing and version bumping; update README files for all packages ([a01c2a8](https://github.com/Cap-go/capacitor-plus/commit/a01c2a842c363c2aa58e5681210fa62fac8e5de5))
-
-
-
-
-
-## [8.0.1](https://github.com/Cap-go/capacitor-plus/compare/3.3.4...8.0.1) (2025-12-16)
-
-### Bug Fixes
-
-- 204 http response ([#6266](https://github.com/Cap-go/capacitor-plus/issues/6266)) ([771f6ce](https://github.com/Cap-go/capacitor-plus/commit/771f6ce1f35159848db218a42dc4f56b5106f750))
-- add http method to prototype.open ([#6740](https://github.com/Cap-go/capacitor-plus/issues/6740)) ([1fd2d87](https://github.com/Cap-go/capacitor-plus/commit/1fd2d8762ff2341a8fe20eec9e774c6a29576e88))
-- **android:** make local urls use unpatched fetch ([#6953](https://github.com/Cap-go/capacitor-plus/issues/6953)) ([e50e56c](https://github.com/Cap-go/capacitor-plus/commit/e50e56c5231f230497d1bd420e02e2e065c38f86))
-- **cli:** signing type option issue ([#6716](https://github.com/Cap-go/capacitor-plus/issues/6716)) ([ee0f745](https://github.com/Cap-go/capacitor-plus/commit/ee0f7457e458ca4bb4eb74f67552ac2ace76016b))
-- **cookies:** hide httpOnly cookies from client ([0cc927e](https://github.com/Cap-go/capacitor-plus/commit/0cc927ef5f0f7076a6d486d666d78483f1d71c54))
-- **cookies:** make document.cookie setter synchronous ([2272abf](https://github.com/Cap-go/capacitor-plus/commit/2272abf3d3d9dc82d9ca0d03b17e2b78f11f61fc))
-- **cookies:** Use Set-Cookie headers to persist cookies ([57f8b39](https://github.com/Cap-go/capacitor-plus/commit/57f8b39d7f4c5ee0e5e5cb316913e9450a81d22b))
-- copy url from nativeResponse to response in native-bridge.ts ([#6397](https://github.com/Cap-go/capacitor-plus/issues/6397)) ([e81a2ff](https://github.com/Cap-go/capacitor-plus/commit/e81a2ff42ddd446f3004ab5af6e74209f7ff076a))
-- **core:** Exception object was not set on Cap ([#5917](https://github.com/Cap-go/capacitor-plus/issues/5917)) ([9ca27a4](https://github.com/Cap-go/capacitor-plus/commit/9ca27a4f8441b368f8bf9d97dda57b1a55ac0e4e))
-- **core:** make 'content-type' header count for XMLHttpRequest patch ([#7161](https://github.com/Cap-go/capacitor-plus/issues/7161)) ([26d7f68](https://github.com/Cap-go/capacitor-plus/commit/26d7f688284914c6ef795564ba424119efc32a1c))
-- **core:** Make cordova bridge use Promise instead of setTimeout ([#5586](https://github.com/Cap-go/capacitor-plus/issues/5586)) ([f35d96b](https://github.com/Cap-go/capacitor-plus/commit/f35d96b185f5890600a64b78e6bf939c336cbb2d))
-- **core:** Prevent error when hasListeners is empty ([#7975](https://github.com/Cap-go/capacitor-plus/issues/7975)) ([a4a0942](https://github.com/Cap-go/capacitor-plus/commit/a4a0942eddba068e078bd782bb093ed1ecff9e00))
-- **core:** use getPlatform instead of platform in cordova.js ([#7902](https://github.com/Cap-go/capacitor-plus/issues/7902)) ([277db7b](https://github.com/Cap-go/capacitor-plus/commit/277db7b48caaf870eefdf701ea99332c4338d7ed))
-- handle fetch headers that are Headers objects ([#6320](https://github.com/Cap-go/capacitor-plus/issues/6320)) ([cb00e49](https://github.com/Cap-go/capacitor-plus/commit/cb00e4952acca8e877555f30b2190f6685d25934))
-- http content headers not sent when using axios ([#8039](https://github.com/Cap-go/capacitor-plus/issues/8039)) ([67cac40](https://github.com/Cap-go/capacitor-plus/commit/67cac40660b3e8cc78d1d228b7c6915450948ef1))
-- **http:** add support for Request objects in fetch ([24b3cc1](https://github.com/Cap-go/capacitor-plus/commit/24b3cc113e3d8aae5d85dbf2d25bec0c35136477))
-- **http:** Add URLSearchParams support ([#7374](https://github.com/Cap-go/capacitor-plus/issues/7374)) ([9367ecc](https://github.com/Cap-go/capacitor-plus/commit/9367ecc56a0c78249dccdf95dca5006422144289))
-- **http:** boundary not added for Request objects ([#7897](https://github.com/Cap-go/capacitor-plus/issues/7897)) ([bdaa6f3](https://github.com/Cap-go/capacitor-plus/commit/bdaa6f3c38c33f3a021ac61f2de89101a5b66cff))
-- **http:** change proxy url generation ([#7354](https://github.com/Cap-go/capacitor-plus/issues/7354)) ([318c316](https://github.com/Cap-go/capacitor-plus/commit/318c316847c5b059fb88b46d4acd31e1ced477e5))
-- **http:** don't override readyState for non POST requests ([#7488](https://github.com/Cap-go/capacitor-plus/issues/7488)) ([30c13a8](https://github.com/Cap-go/capacitor-plus/commit/30c13a865e7710e6dc5f0ee014e951d52d030795))
-- **http:** don't throw errors when content-type is null on response ([#6627](https://github.com/Cap-go/capacitor-plus/issues/6627)) ([538821f](https://github.com/Cap-go/capacitor-plus/commit/538821f267aa3b79548fed6aaea8880ff949ffdd))
-- **http:** fire events in correct order when using xhr ([5ed3617](https://github.com/Cap-go/capacitor-plus/commit/5ed361787596bb5949f6ae5e366495f296352bf3))
-- **http:** fix local http requests on native platforms ([c4e040a](https://github.com/Cap-go/capacitor-plus/commit/c4e040a6f8c6b54bac6ae320e5f0f008604fe50f))
-- **http:** handle proxy urls with port ([#7273](https://github.com/Cap-go/capacitor-plus/issues/7273)) ([514409a](https://github.com/Cap-go/capacitor-plus/commit/514409aeb93ad65be105bbe2da8d2cd86ff159b0))
-- **http:** handle UInt8Array on body ([#7546](https://github.com/Cap-go/capacitor-plus/issues/7546)) ([cfb9ce1](https://github.com/Cap-go/capacitor-plus/commit/cfb9ce175615f69fe86b61af6d51ec2044d147cd))
-- **http:** inherit object properties on window.XMLHttpRequest ([91c11d0](https://github.com/Cap-go/capacitor-plus/commit/91c11d06f773c45a10f6f2d52f672ae6f189b162))
-- **http:** keep original URL properties on proxy ([#7329](https://github.com/Cap-go/capacitor-plus/issues/7329)) ([cbb6407](https://github.com/Cap-go/capacitor-plus/commit/cbb6407225b42a0d9db4f335a9766f119501021d))
-- **http:** Make proxy work with Request objects ([#7348](https://github.com/Cap-go/capacitor-plus/issues/7348)) ([7e68725](https://github.com/Cap-go/capacitor-plus/commit/7e6872573df03ab5cdc10a1a27db3e9fe81a141d))
-- **http:** parse readablestream data on fetch request objects ([#6919](https://github.com/Cap-go/capacitor-plus/issues/6919)) ([80ec3b7](https://github.com/Cap-go/capacitor-plus/commit/80ec3b73db18b7b6841bf90ed50a67389946ab87))
-- **http:** pass original url as query param on the proxy url ([#7527](https://github.com/Cap-go/capacitor-plus/issues/7527)) ([1da06e6](https://github.com/Cap-go/capacitor-plus/commit/1da06e66cb9cfbf5a5cc48ba6c23cdbe18bc8fc0))
-- **http:** prevent POST request from being proxied ([#7395](https://github.com/Cap-go/capacitor-plus/issues/7395)) ([7b8c352](https://github.com/Cap-go/capacitor-plus/commit/7b8c3523decd5610dcf09e926640bf35b382d61d))
-- **http:** return valid response for relative url xhr requests ([bde6569](https://github.com/Cap-go/capacitor-plus/commit/bde65696218f97a8328041f137457f46e5eb766a))
-- **http:** route get requests through custom handler ([#6818](https://github.com/Cap-go/capacitor-plus/issues/6818)) ([b853d06](https://github.com/Cap-go/capacitor-plus/commit/b853d065055b5a819949551be58b62d40b52e37c))
-- **http:** set formdata boundary and body when content-type not explicitly set ([0c2ccd9](https://github.com/Cap-go/capacitor-plus/commit/0c2ccd910a92ce3deaa67eb1819a4faa39c6af6e))
-- **http:** set port for proxy url ([#7341](https://github.com/Cap-go/capacitor-plus/issues/7341)) ([a3059dc](https://github.com/Cap-go/capacitor-plus/commit/a3059dca4a7746d9fb7102a7d41f4da80e2f48b4))
-- **ios:** Correctly Attach Headers to Request ([#6303](https://github.com/Cap-go/capacitor-plus/issues/6303)) ([a3f875c](https://github.com/Cap-go/capacitor-plus/commit/a3f875cf42e111fde07d6e87643264b19ed77573))
-- **ios:** crash when http headers contain numbers ([#6251](https://github.com/Cap-go/capacitor-plus/issues/6251)) ([028c556](https://github.com/Cap-go/capacitor-plus/commit/028c556a50b41ee99fe8f4f1aa2f42d3fd57f92d))
-- make Plugin.resolve act consistently ([#8225](https://github.com/Cap-go/capacitor-plus/issues/8225)) ([06aeb9e](https://github.com/Cap-go/capacitor-plus/commit/06aeb9e85d162d6be9d96820edcb2008cd74da84))
-- vue 3 log warning causes error on iOS ([#6993](https://github.com/Cap-go/capacitor-plus/issues/6993)) ([87271e2](https://github.com/Cap-go/capacitor-plus/commit/87271e2671013ad35d13b22f2e96d4fe8f4eeaf0))
-- **web:** Implement `retainUntilConsumed` on notifyListeners ([#7127](https://github.com/Cap-go/capacitor-plus/issues/7127)) ([526292e](https://github.com/Cap-go/capacitor-plus/commit/526292eb273ee7d8fa9a9912ce3b59e9a104c19e))
+**Note:** Version bump only for package @capacitor/core
-### Features
+## [8.3.2](https://github.com/ionic-team/capacitor/compare/8.3.1...8.3.2) (2026-05-07)
-- **android:** Add Optional Data Param for Error Object ([#5719](https://github.com/Cap-go/capacitor-plus/issues/5719)) ([174172b](https://github.com/Cap-go/capacitor-plus/commit/174172b6c64dc9117c48ed0e20c25e0b6c2fb625))
-- **android:** Improving SystemBars inset handling ([#8268](https://github.com/Cap-go/capacitor-plus/issues/8268)) ([81ae30a](https://github.com/Cap-go/capacitor-plus/commit/81ae30a503797e417dd125b06262dabc4696c88a))
-- **android:** Use addWebMessageListener where available ([#5427](https://github.com/Cap-go/capacitor-plus/issues/5427)) ([c2dfe80](https://github.com/Cap-go/capacitor-plus/commit/c2dfe808446717412b35e82713d123b7a052f264))
-- Capacitor Cookies & Capacitor Http core plugins ([d4047cf](https://github.com/Cap-go/capacitor-plus/commit/d4047cfa947676777f400389a8d65defae140b45))
-- **cookies:** add get cookies plugin method ([ba1e770](https://github.com/Cap-go/capacitor-plus/commit/ba1e7702a3338714aee24388c0afea39706c9341))
-- export buildRequestInit function so we can use for downloadFile ([95b0575](https://github.com/Cap-go/capacitor-plus/commit/95b0575e3fbc1b1408aa69b61c58e18bf8882cea))
-- **http:** Apply overrideUserAgent to requests ([#7906](https://github.com/Cap-go/capacitor-plus/issues/7906)) ([52482c9](https://github.com/Cap-go/capacitor-plus/commit/52482c9d3c575b737054b41f9d1730c70cc5f471))
-- **http:** support for FormData requests ([#6708](https://github.com/Cap-go/capacitor-plus/issues/6708)) ([849c564](https://github.com/Cap-go/capacitor-plus/commit/849c56458205bea3b078b1ee19807d7fd84c47b1))
-- Implement automated upstream sync and review process for Capacitor+ ([54a5dfb](https://github.com/Cap-go/capacitor-plus/commit/54a5dfbd1f81ca4144e13b3051bf592d3aaf1f4a))
-- System Bars Plugin ([#8180](https://github.com/Cap-go/capacitor-plus/issues/8180)) ([a32216a](https://github.com/Cap-go/capacitor-plus/commit/a32216ac0607172a3a9c7ae5cdbfc598769294a6))
-- Upgrade to Typescript 5.x ([#6433](https://github.com/Cap-go/capacitor-plus/issues/6433)) ([88d0ded](https://github.com/Cap-go/capacitor-plus/commit/88d0ded9e7356531ffc4563b9b81a0f3f069484b))
-- **webview:** add setServerAssetPath method ([881235b](https://github.com/Cap-go/capacitor-plus/commit/881235b14de23ef988746bfb89a5a0fc3c8d8466))
+**Note:** Version bump only for package @capacitor/core
## [8.3.1](https://github.com/ionic-team/capacitor/compare/8.3.0...8.3.1) (2026-04-16)
diff --git a/core/package.json b/core/package.json
index 267214634e..f1afefa86f 100644
--- a/core/package.json
+++ b/core/package.json
@@ -1,9 +1,9 @@
{
- "name": "@capacitor-plus/core",
- "version": "8.3.4",
- "description": "Capacitor+: Enhanced Capacitor with automated upstream sync - Cross-platform apps with JavaScript and the web",
- "homepage": "https://capgo.app/docs/plugins/capacitor-plus/",
- "author": "Capgo Team (https://capgo.app)",
+ "name": "@capacitor/core",
+ "version": "9.0.0-alpha.5",
+ "description": "Capacitor: Cross-platform apps with JavaScript and the web",
+ "homepage": "https://capacitorjs.com",
+ "author": "Ionic Team (https://ionic.io)",
"license": "MIT",
"repository": {
"type": "git",
diff --git a/ios-pods-template/App/App.xcodeproj/project.pbxproj b/ios-pods-template/App/App.xcodeproj/project.pbxproj
index 092f574919..f1ec6501e8 100644
--- a/ios-pods-template/App/App.xcodeproj/project.pbxproj
+++ b/ios-pods-template/App/App.xcodeproj/project.pbxproj
@@ -283,7 +283,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
- IPHONEOS_DEPLOYMENT_TARGET = 15.0;
+ IPHONEOS_DEPLOYMENT_TARGET = 16.0;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
@@ -334,7 +334,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
- IPHONEOS_DEPLOYMENT_TARGET = 15.0;
+ IPHONEOS_DEPLOYMENT_TARGET = 16.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
@@ -350,7 +350,7 @@
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
INFOPLIST_FILE = App/Info.plist;
- IPHONEOS_DEPLOYMENT_TARGET = 15.0;
+ IPHONEOS_DEPLOYMENT_TARGET = 16.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
MARKETING_VERSION = 1.0;
OTHER_SWIFT_FLAGS = "$(inherited) \"-D\" \"COCOAPODS\" \"-DDEBUG\"";
@@ -370,7 +370,7 @@
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
INFOPLIST_FILE = App/Info.plist;
- IPHONEOS_DEPLOYMENT_TARGET = 15.0;
+ IPHONEOS_DEPLOYMENT_TARGET = 16.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = com.getcapacitor.App;
diff --git a/ios-pods-template/App/App/AppDelegate.swift b/ios-pods-template/App/App/AppDelegate.swift
index c3cd83b5c0..0b31ad6866 100644
--- a/ios-pods-template/App/App/AppDelegate.swift
+++ b/ios-pods-template/App/App/AppDelegate.swift
@@ -1,7 +1,7 @@
import UIKit
import Capacitor
-@UIApplicationMain
+@main
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
diff --git a/ios-pods-template/App/Podfile b/ios-pods-template/App/Podfile
index 25801ecef7..b50444d463 100644
--- a/ios-pods-template/App/Podfile
+++ b/ios-pods-template/App/Podfile
@@ -1,6 +1,6 @@
require_relative '../../node_modules/@capacitor/ios/scripts/pods_helpers'
-platform :ios, '15.0'
+platform :ios, '16.0'
use_frameworks!
# workaround to avoid Xcode caching of Pods that requires
diff --git a/ios-spm-template/App/App.xcodeproj/project.pbxproj b/ios-spm-template/App/App.xcodeproj/project.pbxproj
index 46f934efd5..06959b343b 100644
--- a/ios-spm-template/App/App.xcodeproj/project.pbxproj
+++ b/ios-spm-template/App/App.xcodeproj/project.pbxproj
@@ -230,7 +230,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
- IPHONEOS_DEPLOYMENT_TARGET = 15.0;
+ IPHONEOS_DEPLOYMENT_TARGET = 16.0;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
@@ -281,7 +281,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
- IPHONEOS_DEPLOYMENT_TARGET = 15.0;
+ IPHONEOS_DEPLOYMENT_TARGET = 16.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
SWIFT_COMPILATION_MODE = wholemodule;
@@ -298,7 +298,7 @@
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
INFOPLIST_FILE = App/Info.plist;
- IPHONEOS_DEPLOYMENT_TARGET = 15.0;
+ IPHONEOS_DEPLOYMENT_TARGET = 16.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
@@ -320,7 +320,7 @@
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
INFOPLIST_FILE = App/Info.plist;
- IPHONEOS_DEPLOYMENT_TARGET = 15.0;
+ IPHONEOS_DEPLOYMENT_TARGET = 16.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
diff --git a/ios-spm-template/App/App/AppDelegate.swift b/ios-spm-template/App/App/AppDelegate.swift
index c3cd83b5c0..0b31ad6866 100644
--- a/ios-spm-template/App/App/AppDelegate.swift
+++ b/ios-spm-template/App/App/AppDelegate.swift
@@ -1,7 +1,7 @@
import UIKit
import Capacitor
-@UIApplicationMain
+@main
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
diff --git a/ios-spm-template/App/CapApp-SPM/Package.swift b/ios-spm-template/App/CapApp-SPM/Package.swift
index 5cde8b6645..e3309a275a 100644
--- a/ios-spm-template/App/CapApp-SPM/Package.swift
+++ b/ios-spm-template/App/CapApp-SPM/Package.swift
@@ -4,7 +4,7 @@ import PackageDescription
// DO NOT MODIFY THIS FILE - managed by Capacitor CLI commands
let package = Package(
name: "CapApp-SPM",
- platforms: [.iOS(.v15)],
+ platforms: [.iOS(.v16)],
products: [
.library(
name: "CapApp-SPM",
diff --git a/ios/CHANGELOG.md b/ios/CHANGELOG.md
index 11f26f1645..5fcfc0abae 100644
--- a/ios/CHANGELOG.md
+++ b/ios/CHANGELOG.md
@@ -3,234 +3,69 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
-## [8.3.4](https://github.com/Cap-go/capacitor-plus/compare/8.3.3...8.3.4) (2026-05-07)
+# [9.0.0-alpha.5](https://github.com/ionic-team/capacitor/compare/8.4.1...9.0.0-alpha.5) (2026-06-23)
-**Note:** Version bump only for package @capacitor-plus/ios
+# [9.0.0-alpha.4](https://github.com/ionic-team/capacitor/compare/9.0.0-alpha.3...9.0.0-alpha.4) (2026-06-19)
+# [9.0.0-alpha.3](https://github.com/ionic-team/capacitor/compare/8.4.0...9.0.0-alpha.3) (2026-06-02)
+# [9.0.0-alpha.2](https://github.com/ionic-team/capacitor/compare/8.3.4...9.0.0-alpha.2) (2026-05-12)
+# [9.0.0-alpha.1](https://github.com/ionic-team/capacitor/compare/8.3.3...9.0.0-alpha.1) (2026-05-08)
-
-## [8.3.3](https://github.com/Cap-go/capacitor-plus/compare/8.3.2...8.3.3) (2026-05-06)
-
-**Note:** Version bump only for package @capacitor-plus/ios
-
-
-
-
-
-## [8.3.2](https://github.com/Cap-go/capacitor-plus/compare/8.0.8...8.3.2) (2026-05-05)
-
+# [9.0.0-alpha.0](https://github.com/ionic-team/capacitor/compare/8.3.2...9.0.0-alpha.0) (2026-05-07)
### Bug Fixes
-* address follow-up review comments ([8bee786](https://github.com/Cap-go/capacitor-plus/commit/8bee786e2c68ca6c351e88f104b518291c1f81e3))
-* boundary value extraction for form-data requests ([#7518](https://github.com/Cap-go/capacitor-plus/issues/7518)) ([64ab854](https://github.com/Cap-go/capacitor-plus/commit/64ab854c12330804c24275d88d3a9f7c8e52a73d))
-* **http:** handle URL objects on fetch ([#8386](https://github.com/Cap-go/capacitor-plus/issues/8386)) ([003099a](https://github.com/Cap-go/capacitor-plus/commit/003099aef246adfd76d890074d46b1484951824b))
-* **ios:** make getArray accesible on Objective-C plugins ([#8392](https://github.com/Cap-go/capacitor-plus/issues/8392)) ([afb80f2](https://github.com/Cap-go/capacitor-plus/commit/afb80f2fecb4bf85dbebe25e815de2a5564264d6))
-* **ios:** remove tmpWindow usages on presentVC/dismissVC ([#8338](https://github.com/Cap-go/capacitor-plus/issues/8338)) ([fc9647f](https://github.com/Cap-go/capacitor-plus/commit/fc9647f26f08ff64f53b32c79fb19f153e3b0a24))
-* resolve upstream sync conflicts ([75cbb30](https://github.com/Cap-go/capacitor-plus/commit/75cbb3097a7068bcb37313cbe6301628079101ca))
-
-
-### Reverts
-
-* revert version bump from [#8319](https://github.com/Cap-go/capacitor-plus/issues/8319) and [#8320](https://github.com/Cap-go/capacitor-plus/issues/8320) ([a48ebb6](https://github.com/Cap-go/capacitor-plus/commit/a48ebb622ea4ebe92927bf1756a4d8ac6012884b))
-
-
-
-
-
-## [8.0.8](https://github.com/Cap-go/capacitor-plus/compare/8.0.7...8.0.8) (2026-04-08)
-
-**Note:** Version bump only for package @capacitor-plus/ios
-
-
-
-
-
-## [8.0.7](https://github.com/Cap-go/capacitor-plus/compare/8.0.6...8.0.7) (2026-01-12)
+- **http:** handle URL objects on fetch ([#8386](https://github.com/ionic-team/capacitor/issues/8386)) ([0aac1f0](https://github.com/ionic-team/capacitor/commit/0aac1f0aee8083dc5013f0d8e3c180eb02f21141))
+- **ios:** make getArray accesible on Objective-C plugins ([#8392](https://github.com/ionic-team/capacitor/issues/8392)) ([ef57c77](https://github.com/ionic-team/capacitor/commit/ef57c773e70af6b94685a2dc0f808db3ed4cda6e))
-**Note:** Version bump only for package @capacitor-plus/ios
+# [9.0.0-alpha.4](https://github.com/ionic-team/capacitor/compare/9.0.0-alpha.3...9.0.0-alpha.4) (2026-06-19)
+## [8.4.1](https://github.com/ionic-team/capacitor/compare/8.4.0...8.4.1) (2026-06-19)
+# [8.4.0](https://github.com/ionic-team/capacitor/compare/9.0.0-alpha.2...8.4.0) (2026-06-02)
+**Note:** Version bump only for package @capacitor/ios
+# [9.0.0-alpha.3](https://github.com/ionic-team/capacitor/compare/9.0.0-alpha.2...9.0.0-alpha.3) (2026-06-02)
-## [8.0.6](https://github.com/Cap-go/capacitor-plus/compare/8.0.5...8.0.6) (2026-01-09)
-
-**Note:** Version bump only for package @capacitor-plus/ios
-
-
-
-
-
-## [8.0.5](https://github.com/Cap-go/capacitor-plus/compare/8.0.4...8.0.5) (2026-01-08)
-
-**Note:** Version bump only for package @capacitor-plus/ios
-
-
-
+# [8.4.0](https://github.com/ionic-team/capacitor/compare/8.3.4...8.4.0) (2026-06-02)
+### Features
-## [8.0.4](https://github.com/Cap-go/capacitor-plus/compare/8.0.3...8.0.4) (2025-12-16)
+- add method getDouble to plugin config ([#7638](https://github.com/ionic-team/capacitor/issues/7638)) ([93c72de](https://github.com/ionic-team/capacitor/commit/93c72de40a2ec4c78b33659250cb08340083088e))
-**Note:** Version bump only for package @capacitor-plus/ios
+## [8.3.4](https://github.com/ionic-team/capacitor/compare/9.0.0-alpha.1...8.3.4) (2026-05-12)
+## [8.3.3](https://github.com/ionic-team/capacitor/compare/9.0.0-alpha.0...8.3.3) (2026-05-08)
+# [9.0.0-alpha.2](https://github.com/ionic-team/capacitor/compare/9.0.0-alpha.1...9.0.0-alpha.2) (2026-05-12)
+**Note:** Version bump only for package @capacitor/ios
+# [9.0.0-alpha.1](https://github.com/ionic-team/capacitor/compare/9.0.0-alpha.0...9.0.0-alpha.1) (2026-05-08)
-## [8.0.3](https://github.com/Cap-go/capacitor-plus/compare/8.0.2...8.0.3) (2025-12-16)
+**Note:** Version bump only for package @capacitor/ios
+# [9.0.0-alpha.0](https://github.com/ionic-team/capacitor/compare/8.3.2...9.0.0-alpha.0) (2026-05-07)
### Bug Fixes
-* update homepage URL in package.json files for all platforms ([61ccdc4](https://github.com/Cap-go/capacitor-plus/commit/61ccdc4128a1ce2a7178eb0a195b188876ec0a9d))
-
-
-
-
+- **http:** handle URL objects on fetch ([#8386](https://github.com/ionic-team/capacitor/issues/8386)) ([0aac1f0](https://github.com/ionic-team/capacitor/commit/0aac1f0aee8083dc5013f0d8e3c180eb02f21141))
+- **ios:** make getArray accesible on Objective-C plugins ([#8392](https://github.com/ionic-team/capacitor/issues/8392)) ([ef57c77](https://github.com/ionic-team/capacitor/commit/ef57c773e70af6b94685a2dc0f808db3ed4cda6e))
-## [8.0.2](https://github.com/Cap-go/capacitor-plus/compare/8.0.1...8.0.2) (2025-12-16)
+## [8.3.4](https://github.com/ionic-team/capacitor/compare/8.3.3...8.3.4) (2026-05-12)
+**Note:** Version bump only for package @capacitor/ios
-### Features
+## [8.3.3](https://github.com/ionic-team/capacitor/compare/8.3.2...8.3.3) (2026-05-08)
-* add new workflows for testing and version bumping; update README files for all packages ([a01c2a8](https://github.com/Cap-go/capacitor-plus/commit/a01c2a842c363c2aa58e5681210fa62fac8e5de5))
-
-
-
-
-
-## [8.0.1](https://github.com/Cap-go/capacitor-plus/compare/3.3.4...8.0.1) (2025-12-16)
-
-### Bug Fixes
-
-- 204 http response ([#6266](https://github.com/Cap-go/capacitor-plus/issues/6266)) ([771f6ce](https://github.com/Cap-go/capacitor-plus/commit/771f6ce1f35159848db218a42dc4f56b5106f750))
-- add http method to prototype.open ([#6740](https://github.com/Cap-go/capacitor-plus/issues/6740)) ([1fd2d87](https://github.com/Cap-go/capacitor-plus/commit/1fd2d8762ff2341a8fe20eec9e774c6a29576e88))
-- allow single parameter on setRequestBody ([#6728](https://github.com/Cap-go/capacitor-plus/issues/6728)) ([5343bdb](https://github.com/Cap-go/capacitor-plus/commit/5343bdb60d26849cd8f9c8ff28ba7d9ddbd05b26))
-- **android:** make local urls use unpatched fetch ([#6953](https://github.com/Cap-go/capacitor-plus/issues/6953)) ([e50e56c](https://github.com/Cap-go/capacitor-plus/commit/e50e56c5231f230497d1bd420e02e2e065c38f86))
-- **cli/ios:** Read handleApplicationNotifications configuration option ([#6030](https://github.com/Cap-go/capacitor-plus/issues/6030)) ([99ccf18](https://github.com/Cap-go/capacitor-plus/commit/99ccf181f6ee8a00ed97bdbf9076e2b2ea27cd57))
-- **cli:** signing type option issue ([#6716](https://github.com/Cap-go/capacitor-plus/issues/6716)) ([ee0f745](https://github.com/Cap-go/capacitor-plus/commit/ee0f7457e458ca4bb4eb74f67552ac2ace76016b))
-- **cookies:** hide httpOnly cookies from client ([0cc927e](https://github.com/Cap-go/capacitor-plus/commit/0cc927ef5f0f7076a6d486d666d78483f1d71c54))
-- **cookies:** make document.cookie setter synchronous ([2272abf](https://github.com/Cap-go/capacitor-plus/commit/2272abf3d3d9dc82d9ca0d03b17e2b78f11f61fc))
-- **cookies:** sanitize url before retrieving/setting cookies ([ca40634](https://github.com/Cap-go/capacitor-plus/commit/ca4063471f215d3f7525e51592d9c72138a52855))
-- **cookies:** Use Set-Cookie headers to persist cookies ([57f8b39](https://github.com/Cap-go/capacitor-plus/commit/57f8b39d7f4c5ee0e5e5cb316913e9450a81d22b))
-- **core:** Exception object was not set on Cap ([#5917](https://github.com/Cap-go/capacitor-plus/issues/5917)) ([9ca27a4](https://github.com/Cap-go/capacitor-plus/commit/9ca27a4f8441b368f8bf9d97dda57b1a55ac0e4e))
-- **core:** make 'content-type' header count for XMLHttpRequest patch ([#7161](https://github.com/Cap-go/capacitor-plus/issues/7161)) ([26d7f68](https://github.com/Cap-go/capacitor-plus/commit/26d7f688284914c6ef795564ba424119efc32a1c))
-- handle fetch headers that are Headers objects ([#6320](https://github.com/Cap-go/capacitor-plus/issues/6320)) ([cb00e49](https://github.com/Cap-go/capacitor-plus/commit/cb00e4952acca8e877555f30b2190f6685d25934))
-- http content headers not sent when using axios ([#8039](https://github.com/Cap-go/capacitor-plus/issues/8039)) ([67cac40](https://github.com/Cap-go/capacitor-plus/commit/67cac40660b3e8cc78d1d228b7c6915450948ef1))
-- **http:** add support for Request objects in fetch ([24b3cc1](https://github.com/Cap-go/capacitor-plus/commit/24b3cc113e3d8aae5d85dbf2d25bec0c35136477))
-- **http:** Add URLSearchParams support ([#7374](https://github.com/Cap-go/capacitor-plus/issues/7374)) ([9367ecc](https://github.com/Cap-go/capacitor-plus/commit/9367ecc56a0c78249dccdf95dca5006422144289))
-- **http:** boundary not added for Request objects ([#7897](https://github.com/Cap-go/capacitor-plus/issues/7897)) ([bdaa6f3](https://github.com/Cap-go/capacitor-plus/commit/bdaa6f3c38c33f3a021ac61f2de89101a5b66cff))
-- **http:** change proxy url generation ([#7354](https://github.com/Cap-go/capacitor-plus/issues/7354)) ([318c316](https://github.com/Cap-go/capacitor-plus/commit/318c316847c5b059fb88b46d4acd31e1ced477e5))
-- **http:** don't override readyState for non POST requests ([#7488](https://github.com/Cap-go/capacitor-plus/issues/7488)) ([30c13a8](https://github.com/Cap-go/capacitor-plus/commit/30c13a865e7710e6dc5f0ee014e951d52d030795))
-- **http:** don't throw errors when content-type is null on response ([#6627](https://github.com/Cap-go/capacitor-plus/issues/6627)) ([538821f](https://github.com/Cap-go/capacitor-plus/commit/538821f267aa3b79548fed6aaea8880ff949ffdd))
-- **http:** fire events in correct order when using xhr ([5ed3617](https://github.com/Cap-go/capacitor-plus/commit/5ed361787596bb5949f6ae5e366495f296352bf3))
-- **http:** fix local http requests on native platforms ([c4e040a](https://github.com/Cap-go/capacitor-plus/commit/c4e040a6f8c6b54bac6ae320e5f0f008604fe50f))
-- **http:** handle proxy urls with port ([#7273](https://github.com/Cap-go/capacitor-plus/issues/7273)) ([514409a](https://github.com/Cap-go/capacitor-plus/commit/514409aeb93ad65be105bbe2da8d2cd86ff159b0))
-- **http:** handle UInt8Array on body ([#7546](https://github.com/Cap-go/capacitor-plus/issues/7546)) ([cfb9ce1](https://github.com/Cap-go/capacitor-plus/commit/cfb9ce175615f69fe86b61af6d51ec2044d147cd))
-- **http:** inherit object properties on window.XMLHttpRequest ([91c11d0](https://github.com/Cap-go/capacitor-plus/commit/91c11d06f773c45a10f6f2d52f672ae6f189b162))
-- **http:** keep original URL properties on proxy ([#7329](https://github.com/Cap-go/capacitor-plus/issues/7329)) ([cbb6407](https://github.com/Cap-go/capacitor-plus/commit/cbb6407225b42a0d9db4f335a9766f119501021d))
-- **http:** Make proxy work with Request objects ([#7348](https://github.com/Cap-go/capacitor-plus/issues/7348)) ([7e68725](https://github.com/Cap-go/capacitor-plus/commit/7e6872573df03ab5cdc10a1a27db3e9fe81a141d))
-- **http:** parse readablestream data on fetch request objects ([#6919](https://github.com/Cap-go/capacitor-plus/issues/6919)) ([80ec3b7](https://github.com/Cap-go/capacitor-plus/commit/80ec3b73db18b7b6841bf90ed50a67389946ab87))
-- **http:** pass original url as query param on the proxy url ([#7527](https://github.com/Cap-go/capacitor-plus/issues/7527)) ([1da06e6](https://github.com/Cap-go/capacitor-plus/commit/1da06e66cb9cfbf5a5cc48ba6c23cdbe18bc8fc0))
-- **http:** prevent POST request from being proxied ([#7395](https://github.com/Cap-go/capacitor-plus/issues/7395)) ([7b8c352](https://github.com/Cap-go/capacitor-plus/commit/7b8c3523decd5610dcf09e926640bf35b382d61d))
-- **http:** Properly URL-encode key and values during `x-www-form-urlencoded` POSTs ([#8037](https://github.com/Cap-go/capacitor-plus/issues/8037)) ([87b4641](https://github.com/Cap-go/capacitor-plus/commit/87b4641d1fa32b78e6fc2e87ee7b2c49b625b213))
-- **http:** return valid response for relative url xhr requests ([bde6569](https://github.com/Cap-go/capacitor-plus/commit/bde65696218f97a8328041f137457f46e5eb766a))
-- **http:** route get requests through custom handler ([#6818](https://github.com/Cap-go/capacitor-plus/issues/6818)) ([b853d06](https://github.com/Cap-go/capacitor-plus/commit/b853d065055b5a819949551be58b62d40b52e37c))
-- **http:** set port for proxy url ([#7341](https://github.com/Cap-go/capacitor-plus/issues/7341)) ([a3059dc](https://github.com/Cap-go/capacitor-plus/commit/a3059dca4a7746d9fb7102a7d41f4da80e2f48b4))
-- inject cordova files if a cordova plugin is present ([#7363](https://github.com/Cap-go/capacitor-plus/issues/7363)) ([ce9d505](https://github.com/Cap-go/capacitor-plus/commit/ce9d50585b1cab183245197878bf625cf0289275))
-- **ios/android:** better http error handling ([#6208](https://github.com/Cap-go/capacitor-plus/issues/6208)) ([7d4d70a](https://github.com/Cap-go/capacitor-plus/commit/7d4d70a0500b7996c710c0762907f44bdf27c92b))
-- **ios/android:** copy url from nativeResponse to response ([#6482](https://github.com/Cap-go/capacitor-plus/issues/6482)) ([828fb71](https://github.com/Cap-go/capacitor-plus/commit/828fb71ebb52c0655d5879ad0edaac7368ab2b96))
-- **ios:** Add check for both serverURL and localURL in navigation ([#5736](https://github.com/Cap-go/capacitor-plus/issues/5736)) ([8e824f3](https://github.com/Cap-go/capacitor-plus/commit/8e824f33ad4df898fb8c0936a8f5e9041832a5c5))
-- **ios:** Add Codable folder to podspec source_files ([#7131](https://github.com/Cap-go/capacitor-plus/issues/7131)) ([04d1d55](https://github.com/Cap-go/capacitor-plus/commit/04d1d557b51fcac31281a3f547300f06c6dacfb2))
-- **ios:** add some new cordova-ios classes used by Cordova plugins ([#7096](https://github.com/Cap-go/capacitor-plus/issues/7096)) ([3db9051](https://github.com/Cap-go/capacitor-plus/commit/3db9051eb015cf5f402f81b4cbaa7b27a5c9477a))
-- **ios:** also call bridge.reset() on webViewWebContentProcessDidTerminate ([#8143](https://github.com/Cap-go/capacitor-plus/issues/8143)) ([1de1f15](https://github.com/Cap-go/capacitor-plus/commit/1de1f157169bc0e23060ffabf044c6d391b98efe))
-- **ios:** Avoid double encoding on http urls ([#6288](https://github.com/Cap-go/capacitor-plus/issues/6288)) ([4768085](https://github.com/Cap-go/capacitor-plus/commit/4768085414768bb2c013afcc6c645664893cd297))
-- **ios:** CapacitorHttp cannot use delete method ([#6220](https://github.com/Cap-go/capacitor-plus/issues/6220)) ([4d238a9](https://github.com/Cap-go/capacitor-plus/commit/4d238a9e0dcf1e3e8c105c3aa4c7361abf16398e))
-- **ios:** check if urlSchemeTask is stopped before calling its methods ([#7482](https://github.com/Cap-go/capacitor-plus/issues/7482)) ([b32b5b1](https://github.com/Cap-go/capacitor-plus/commit/b32b5b17ed14bd43c846b3fcb930bfd88e245e40))
-- **ios:** Correctly Attach Headers to Request ([#6303](https://github.com/Cap-go/capacitor-plus/issues/6303)) ([a3f875c](https://github.com/Cap-go/capacitor-plus/commit/a3f875cf42e111fde07d6e87643264b19ed77573))
-- **ios:** crash when http headers contain numbers ([#6251](https://github.com/Cap-go/capacitor-plus/issues/6251)) ([028c556](https://github.com/Cap-go/capacitor-plus/commit/028c556a50b41ee99fe8f4f1aa2f42d3fd57f92d))
-- **ios:** don't check isMediaExtension on range requests ([#7868](https://github.com/Cap-go/capacitor-plus/issues/7868)) ([028caa5](https://github.com/Cap-go/capacitor-plus/commit/028caa5378d359fb1004098aa93a24ad0f49a4ae))
-- **ios:** encode whitespace in http plugin urls ([#6169](https://github.com/Cap-go/capacitor-plus/issues/6169)) ([dccb0a9](https://github.com/Cap-go/capacitor-plus/commit/dccb0a99850c7c878906156a509ecd675836ef1a))
-- **ios:** error data is optional ([#5782](https://github.com/Cap-go/capacitor-plus/issues/5782)) ([da48d79](https://github.com/Cap-go/capacitor-plus/commit/da48d798c3463de9de188ae6a6475fd6afba6091))
-- **ios:** Event listeners were unexpectedly nil ([#6445](https://github.com/Cap-go/capacitor-plus/issues/6445)) ([209d4ed](https://github.com/Cap-go/capacitor-plus/commit/209d4edace610b00e689440a5c08e72f5da60cc2))
-- **ios:** fix retain cycle caused by CDVPluginManager ([#7692](https://github.com/Cap-go/capacitor-plus/issues/7692)) ([02bdb3d](https://github.com/Cap-go/capacitor-plus/commit/02bdb3d1d15907dcc577f16b7f2e22050e54ffef))
-- **ios:** listen for CapacitorViewDidAppear ([#7850](https://github.com/Cap-go/capacitor-plus/issues/7850)) ([e24ffb7](https://github.com/Cap-go/capacitor-plus/commit/e24ffb7d4de0bf3d53e92537f21c864f121c1fad))
-- **ios:** Make Bridge webView first responder ([#7753](https://github.com/Cap-go/capacitor-plus/issues/7753)) ([77e4668](https://github.com/Cap-go/capacitor-plus/commit/77e4668fa8dbb24b4561387e101547f74e37538e))
-- **ios:** make removeAllListeners accessible from javascript ([#7566](https://github.com/Cap-go/capacitor-plus/issues/7566)) ([388a822](https://github.com/Cap-go/capacitor-plus/commit/388a8223c60e8eac8437ca4cb26a93ab359f53ad))
-- **ios:** make removeAllListeners return a promise ([#5526](https://github.com/Cap-go/capacitor-plus/issues/5526)) ([815f71b](https://github.com/Cap-go/capacitor-plus/commit/815f71b6b62f6c4d5f66e6a36c190bb00a96fdcc))
-- **ios:** move PrivacyInfo.xcprivacy to resource_bundles to fix build… ([#8264](https://github.com/Cap-go/capacitor-plus/issues/8264)) ([e6f50b8](https://github.com/Cap-go/capacitor-plus/commit/e6f50b8c0c41acaaa21af373e195751508c37e9d))
-- **ios:** Moves `updateBinaryVersion` call to the end of `loadView`. ([#7226](https://github.com/Cap-go/capacitor-plus/issues/7226)) ([7724760](https://github.com/Cap-go/capacitor-plus/commit/77247602ac150797d2375118f702cf9ba39ea957))
-- **ios:** overwrite CORS headers on livereload ([#7339](https://github.com/Cap-go/capacitor-plus/issues/7339)) ([0c8d69b](https://github.com/Cap-go/capacitor-plus/commit/0c8d69b7f9c163730e7d74bb0147b61742c61676))
-- **ios:** Prevent Xcode 14 warning on CAPWebView ([#5821](https://github.com/Cap-go/capacitor-plus/issues/5821)) ([66954ef](https://github.com/Cap-go/capacitor-plus/commit/66954ef6bc93f2038d85a386ef2f8b582af11bc3))
-- **ios:** properly deliver retained events after listener re-add [#5732](https://github.com/Cap-go/capacitor-plus/issues/5732) ([c5d6328](https://github.com/Cap-go/capacitor-plus/commit/c5d632831924a1bcc868bc46b42f7ff619408752))
-- **ios:** publish Podfile script ([#5799](https://github.com/Cap-go/capacitor-plus/issues/5799)) ([604f03a](https://github.com/Cap-go/capacitor-plus/commit/604f03a29bc500d2841987d0a0f1b20d34fba7d6))
-- **ios:** Reload webView on webViewWebContentProcessDidTerminate ([#5391](https://github.com/Cap-go/capacitor-plus/issues/5391)) ([beebff4](https://github.com/Cap-go/capacitor-plus/commit/beebff4550575c28c233937a11a8eacf5a76411c))
-- **ios:** Remove CocoaPods Xcode 15 workaround that causes issues ([#7059](https://github.com/Cap-go/capacitor-plus/issues/7059)) ([043a8db](https://github.com/Cap-go/capacitor-plus/commit/043a8dba4059e33c7445696c186110bef1130e16))
-- **ios:** Remove Cordova as an embedded framework ([#5709](https://github.com/Cap-go/capacitor-plus/issues/5709)) ([bbf6d24](https://github.com/Cap-go/capacitor-plus/commit/bbf6d248bf9217a5c5c6c15c7bcfeda209aba5b1))
-- **ios:** Remove Cordova UIView extension ([#8189](https://github.com/Cap-go/capacitor-plus/issues/8189)) ([0c7bcd3](https://github.com/Cap-go/capacitor-plus/commit/0c7bcd3d10f3e3d5a1259f5096879771f8e26436))
-- **ios:** replace deprecation warnings ([#8156](https://github.com/Cap-go/capacitor-plus/issues/8156)) ([e76b29b](https://github.com/Cap-go/capacitor-plus/commit/e76b29b77a7d71ef2341dd3aa530c5d9f291a941))
-- **ios:** Reset plugin listeners when WebView process is terminated ([#7905](https://github.com/Cap-go/capacitor-plus/issues/7905)) ([d039157](https://github.com/Cap-go/capacitor-plus/commit/d0391576726955b2c1b484f1ca9a03465b9ef67e))
-- **ios:** respect shouldEncodeUrlParams value ([#7931](https://github.com/Cap-go/capacitor-plus/issues/7931)) ([4fb12a0](https://github.com/Cap-go/capacitor-plus/commit/4fb12a03a92c0f38b0d48b114252342f4bdc17bf))
-- **ios:** Return proper MIME Type for local WASM files ([#6675](https://github.com/Cap-go/capacitor-plus/issues/6675)) ([d7856de](https://github.com/Cap-go/capacitor-plus/commit/d7856de62a4c058ac474ae91a5fd221dabf99c0a))
-- **ios:** return proper mimeType on M1 x86_64 simulators ([#5853](https://github.com/Cap-go/capacitor-plus/issues/5853)) ([325b6fe](https://github.com/Cap-go/capacitor-plus/commit/325b6fe83939efaaef44c7e8624e33de742a57e2)), closes [#5793](https://github.com/Cap-go/capacitor-plus/issues/5793)
-- **ios:** Revert server url addition for CAPWebView. ([#6705](https://github.com/Cap-go/capacitor-plus/issues/6705)) ([1b8352d](https://github.com/Cap-go/capacitor-plus/commit/1b8352dc5124dc3f57d7881d619537cbf8c3674b))
-- **iOS:** Separate cookies by `; ` rather than `;` when accessing through `document.cookie` ([#6313](https://github.com/Cap-go/capacitor-plus/issues/6313)) ([beade60](https://github.com/Cap-go/capacitor-plus/commit/beade6020e25dc405e796e1b06bf6dd90b217693))
-- **ios:** set cors headers in asset handler for live reload ([e5a1c81](https://github.com/Cap-go/capacitor-plus/commit/e5a1c81fe81904dfd7e3f5100a04088173effc1c))
-- **ios:** Silence WKProcessPool warning ([#8184](https://github.com/Cap-go/capacitor-plus/issues/8184)) ([b6abcb7](https://github.com/Cap-go/capacitor-plus/commit/b6abcb7d656ee24e48a5d0dc7b68888b0318fe5d))
-- **ios:** Use `URL(fileURLWithPath:)` instead of `URL(string:)` ([#5603](https://github.com/Cap-go/capacitor-plus/issues/5603)) ([5fac1b2](https://github.com/Cap-go/capacitor-plus/commit/5fac1b2da5aa5882087716cb2aa862d89173f4a1))
-- **ios:** use ReturnPromise for SystemBars returnType ([#8239](https://github.com/Cap-go/capacitor-plus/issues/8239)) ([eb51288](https://github.com/Cap-go/capacitor-plus/commit/eb5128866953281dc7bed88bd734fc3804b3a702))
-- make Plugin.resolve act consistently ([#8225](https://github.com/Cap-go/capacitor-plus/issues/8225)) ([06aeb9e](https://github.com/Cap-go/capacitor-plus/commit/06aeb9e85d162d6be9d96820edcb2008cd74da84))
-- Remove all plugin listeners in bridge reset ([#7962](https://github.com/Cap-go/capacitor-plus/issues/7962)) ([06aeea9](https://github.com/Cap-go/capacitor-plus/commit/06aeea973aa56ac2fb791f893ebd899253ee65f9))
-- remove duplicates from auto registration array using set ([#7192](https://github.com/Cap-go/capacitor-plus/issues/7192)) ([c4984ae](https://github.com/Cap-go/capacitor-plus/commit/c4984ae4433602dbe028f72736cb6e56e8f92bf9))
-- stop crashing from `objc_getClassList` ([#7187](https://github.com/Cap-go/capacitor-plus/issues/7187)) ([e148db7](https://github.com/Cap-go/capacitor-plus/commit/e148db7758e4186ad45fd74185a10fb757ff9b29))
-- vue 3 log warning causes error on iOS ([#6993](https://github.com/Cap-go/capacitor-plus/issues/6993)) ([87271e2](https://github.com/Cap-go/capacitor-plus/commit/87271e2671013ad35d13b22f2e96d4fe8f4eeaf0))
+**Note:** Version bump only for package @capacitor/ios
-### Features
+## [8.3.2](https://github.com/ionic-team/capacitor/compare/8.3.1...8.3.2) (2026-05-07)
-- Add CapWebView ([#5715](https://github.com/Cap-go/capacitor-plus/issues/5715)) ([143d266](https://github.com/Cap-go/capacitor-plus/commit/143d266ef0a818bac59dbbdaeda3b5c382ebfa1d))
-- Add function to inject external JS into WebView before document load ([#7864](https://github.com/Cap-go/capacitor-plus/issues/7864)) ([ec0954c](https://github.com/Cap-go/capacitor-plus/commit/ec0954c197543e913939f3ab9c4bcb172bfa3530))
-- Add global initialFocus configuration ([#7775](https://github.com/Cap-go/capacitor-plus/issues/7775)) ([61d0165](https://github.com/Cap-go/capacitor-plus/commit/61d01653685d8e3594d2d8a6bd870fa9643ba95c))
-- Add option for custom error page ([#5723](https://github.com/Cap-go/capacitor-plus/issues/5723)) ([e8bdef3](https://github.com/Cap-go/capacitor-plus/commit/e8bdef3b4634e4ad45fa8fc34c7c0ab8dfa383f3))
-- Add XCFrameworks ([#7020](https://github.com/Cap-go/capacitor-plus/issues/7020)) ([5306095](https://github.com/Cap-go/capacitor-plus/commit/53060955dc83cdbfda66bed60c2efcba395a9ca8))
-- **android:** Add Optional Data Param for Error Object ([#5719](https://github.com/Cap-go/capacitor-plus/issues/5719)) ([174172b](https://github.com/Cap-go/capacitor-plus/commit/174172b6c64dc9117c48ed0e20c25e0b6c2fb625))
-- **android:** Improving SystemBars inset handling ([#8268](https://github.com/Cap-go/capacitor-plus/issues/8268)) ([81ae30a](https://github.com/Cap-go/capacitor-plus/commit/81ae30a503797e417dd125b06262dabc4696c88a))
-- **android:** Use addWebMessageListener where available ([#5427](https://github.com/Cap-go/capacitor-plus/issues/5427)) ([c2dfe80](https://github.com/Cap-go/capacitor-plus/commit/c2dfe808446717412b35e82713d123b7a052f264))
-- Capacitor Cookies & Capacitor Http core plugins ([d4047cf](https://github.com/Cap-go/capacitor-plus/commit/d4047cfa947676777f400389a8d65defae140b45))
-- **cookies:** add get cookies plugin method ([ba1e770](https://github.com/Cap-go/capacitor-plus/commit/ba1e7702a3338714aee24388c0afea39706c9341))
-- **core:** expose `methodName` via `CAPPluginCall` ([#7641](https://github.com/Cap-go/capacitor-plus/issues/7641)) ([df109aa](https://github.com/Cap-go/capacitor-plus/commit/df109aa1cfa1ea824e22feecbd2b7183a57fc693))
-- expose `appStartPath` on cap config server configuration ([#8019](https://github.com/Cap-go/capacitor-plus/issues/8019)) ([a274fef](https://github.com/Cap-go/capacitor-plus/commit/a274fef069176a8e528a22f4734d1e29a539709c))
-- **http:** Apply overrideUserAgent to requests ([#7906](https://github.com/Cap-go/capacitor-plus/issues/7906)) ([52482c9](https://github.com/Cap-go/capacitor-plus/commit/52482c9d3c575b737054b41f9d1730c70cc5f471))
-- **http:** support for FormData requests ([#6708](https://github.com/Cap-go/capacitor-plus/issues/6708)) ([849c564](https://github.com/Cap-go/capacitor-plus/commit/849c56458205bea3b078b1ee19807d7fd84c47b1))
-- Implement automated upstream sync and review process for Capacitor+ ([54a5dfb](https://github.com/Cap-go/capacitor-plus/commit/54a5dfbd1f81ca4144e13b3051bf592d3aaf1f4a))
-- **iOS, Android:** add AppUUID Lib for plugins ([#5690](https://github.com/Cap-go/capacitor-plus/issues/5690)) ([05e76cf](https://github.com/Cap-go/capacitor-plus/commit/05e76cf526a44e07fa75f9482fa2223a13918638))
-- **ios:** Add `setServerBasePath(_:)` to CAPBridgeProtocol ([#5860](https://github.com/Cap-go/capacitor-plus/issues/5860)) ([76f28e7](https://github.com/Cap-go/capacitor-plus/commit/76f28e70a5c0a03e4c6b9a93a0c068666a2c38ff))
-- **ios:** Add `setServerBasePath(path:)` to CAPWebView ([#5742](https://github.com/Cap-go/capacitor-plus/issues/5742)) ([1afbf8a](https://github.com/Cap-go/capacitor-plus/commit/1afbf8a9dd0b8f7b1ac439d24e5d8ba26f786318))
-- **ios:** Add Codable support for CAPPluginCall and JSValueContainer ([#7119](https://github.com/Cap-go/capacitor-plus/issues/7119)) ([af417e0](https://github.com/Cap-go/capacitor-plus/commit/af417e0cbbb1a3a7b3b62756eebb8d1dc0952cc4))
-- **ios:** add getConfig to CAPPlugin ([#5495](https://github.com/Cap-go/capacitor-plus/issues/5495)) ([224a9d0](https://github.com/Cap-go/capacitor-plus/commit/224a9d075629d9c9da9ddc658eb282617fc46d09))
-- **ios:** Add new iOS 15 Motion permission delegate ([#5317](https://github.com/Cap-go/capacitor-plus/issues/5317)) ([c05a3cb](https://github.com/Cap-go/capacitor-plus/commit/c05a3cbbf02217e3972d5e067970cae18bff3faa))
-- **ios:** Add new iOS15 media capture permission delegate ([#5196](https://github.com/Cap-go/capacitor-plus/issues/5196)) ([d8b54ac](https://github.com/Cap-go/capacitor-plus/commit/d8b54ac23414bfe56e50e1254066630a6f87eb0e))
-- **ios:** Add overrideable router var for CAPWebView. ([#5743](https://github.com/Cap-go/capacitor-plus/issues/5743)) ([c1de1c0](https://github.com/Cap-go/capacitor-plus/commit/c1de1c0138aad188a760118e35983d10d257f8e7))
-- **ios:** Add overrideable routing for CAPBridgeViewController subclasses ([#5546](https://github.com/Cap-go/capacitor-plus/issues/5546)) ([8875d5e](https://github.com/Cap-go/capacitor-plus/commit/8875d5e2721e8a8ee763ce70cb672db383f36efa))
-- **ios:** Add preferredContentMode configuration option ([#5583](https://github.com/Cap-go/capacitor-plus/issues/5583)) ([5b6dfa3](https://github.com/Cap-go/capacitor-plus/commit/5b6dfa3fe29c85632546b299f03cc04a77cf7475))
-- **ios:** add webContentsDebuggingEnabled configuration ([#6495](https://github.com/Cap-go/capacitor-plus/issues/6495)) ([c691e4a](https://github.com/Cap-go/capacitor-plus/commit/c691e4aecbfb7a45ce0465d1fe9020ab715815d3))
-- **iOS:** Allow plugins to hook into handling WebView URL authentication challenges ([#8216](https://github.com/Cap-go/capacitor-plus/issues/8216)) ([e8507cf](https://github.com/Cap-go/capacitor-plus/commit/e8507cfe4d93337ddee8ab6597aab5209ebb4858))
-- **ios:** Allow to configure popover size ([#5717](https://github.com/Cap-go/capacitor-plus/issues/5717)) ([ca1a125](https://github.com/Cap-go/capacitor-plus/commit/ca1a125e5ab05d6066dd303bc75e99dfe21f210a))
-- **ios:** Alternative debug config for SPM ([#7982](https://github.com/Cap-go/capacitor-plus/issues/7982)) ([a054aa5](https://github.com/Cap-go/capacitor-plus/commit/a054aa5bb4d5eabe5da5d42a380bd51b8785958c))
-- **ios:** CAPPluginMethod selector-based initializer ([#7412](https://github.com/Cap-go/capacitor-plus/issues/7412)) ([44c5b55](https://github.com/Cap-go/capacitor-plus/commit/44c5b55e36b85471a85ee5a1af47bdb1a5d83a8b))
-- **ios:** Enable Fullscreen API on WebView ([#7909](https://github.com/Cap-go/capacitor-plus/issues/7909)) ([172638e](https://github.com/Cap-go/capacitor-plus/commit/172638ec7b6eb67bf25f8dac2818122ba31c2c91))
-- **ios:** JSValueEncoder/Decoder feature parity with JSONEncoder/Decoder ([#7647](https://github.com/Cap-go/capacitor-plus/issues/7647)) ([410249b](https://github.com/Cap-go/capacitor-plus/commit/410249b6c626e67235f25b466ed4969d52148bd1)), closes [#7576](https://github.com/Cap-go/capacitor-plus/issues/7576)
-- **ios:** Makes CapacitorBridge, WebViewAssetHandler, and WebViewDelegationHandler open classes, along with several of their methods ([#7009](https://github.com/Cap-go/capacitor-plus/issues/7009)) ([40d62cb](https://github.com/Cap-go/capacitor-plus/commit/40d62cbce950c2f3972764fe134cc37f2343f33d))
-- **ios:** Plugin Registration and Plugin Instance Support ([#6072](https://github.com/Cap-go/capacitor-plus/issues/6072)) ([9f1d863](https://github.com/Cap-go/capacitor-plus/commit/9f1d863c1222096334a0dd05f39ce7f984a2763a))
-- **iOS:** post install script for deployment target ([#5783](https://github.com/Cap-go/capacitor-plus/issues/5783)) ([f5afa94](https://github.com/Cap-go/capacitor-plus/commit/f5afa94b3b9c246d87b2af03359840f503bace90))
-- **ios:** Replace usage of UserDefaults with KeyValueStore. ([#7191](https://github.com/Cap-go/capacitor-plus/issues/7191)) ([cd58ba2](https://github.com/Cap-go/capacitor-plus/commit/cd58ba2a654f40bf72616f430d7b9604b283e23d))
-- **ios:** Support of range requests on WebViewAssetHandler ([#5659](https://github.com/Cap-go/capacitor-plus/issues/5659)) ([348c08d](https://github.com/Cap-go/capacitor-plus/commit/348c08d511e9d57a1b2ecedc3290c65fa9ba3924))
-- modify package.swift on update and sync ([#7042](https://github.com/Cap-go/capacitor-plus/issues/7042)) ([24573fb](https://github.com/Cap-go/capacitor-plus/commit/24573fb864c43551e2ce42721b45ff901155627d))
-- retain multiple calls per event until consumed ([#6419](https://github.com/Cap-go/capacitor-plus/issues/6419)) ([5aba2cb](https://github.com/Cap-go/capacitor-plus/commit/5aba2cbe29bdbab2a7af861c65d8323acf9c54a6))
-- System Bars Plugin ([#8180](https://github.com/Cap-go/capacitor-plus/issues/8180)) ([a32216a](https://github.com/Cap-go/capacitor-plus/commit/a32216ac0607172a3a9c7ae5cdbfc598769294a6))
-- **webview:** add setServerAssetPath method ([881235b](https://github.com/Cap-go/capacitor-plus/commit/881235b14de23ef988746bfb89a5a0fc3c8d8466))
+**Note:** Version bump only for package @capacitor/ios
## [8.3.1](https://github.com/ionic-team/capacitor/compare/8.3.0...8.3.1) (2026-04-16)
diff --git a/ios/Capacitor.podspec b/ios/Capacitor.podspec
index 9d392728d2..01ce20591e 100644
--- a/ios/Capacitor.podspec
+++ b/ios/Capacitor.podspec
@@ -12,13 +12,12 @@ Pod::Spec.new do |s|
s.summary = 'Capacitor for iOS'
s.license = 'MIT'
s.homepage = 'https://capacitorjs.com/'
- s.ios.deployment_target = '15.0'
+ s.ios.deployment_target = '16.0'
s.authors = { 'Ionic Team' => 'hi@ionicframework.com' }
s.source = { git: 'https://github.com/ionic-team/capacitor.git', tag: package['version'] }
s.source_files = "#{prefix}Capacitor/Capacitor/**/*.{swift,h,m}"
s.module_map = "#{prefix}Capacitor/Capacitor/Capacitor.modulemap"
s.resources = ["#{prefix}Capacitor/Capacitor/assets/native-bridge.js"]
s.resource_bundles = { 'Capacitor' => ["#{prefix}Capacitor/Capacitor/PrivacyInfo.xcprivacy"] }
- s.dependency 'CapacitorCordova'
s.swift_version = '5.1'
end
diff --git a/ios/Capacitor/Capacitor.xcodeproj/project.pbxproj b/ios/Capacitor/Capacitor.xcodeproj/project.pbxproj
index b060d9f7d0..8c67100745 100644
--- a/ios/Capacitor/Capacitor.xcodeproj/project.pbxproj
+++ b/ios/Capacitor/Capacitor.xcodeproj/project.pbxproj
@@ -9,8 +9,6 @@
/* Begin PBXBuildFile section */
0F83E885285A332E006C43CB /* AppUUID.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0F83E884285A332D006C43CB /* AppUUID.swift */; };
0F8F33B327DA980A003F49D6 /* PluginConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0F8F33B127DA980A003F49D6 /* PluginConfig.swift */; };
- 2F81F5C926FB7CB400DD35BE /* CAPBridgeViewController+CDVScreenOrientationDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = 2F81F5C726FB7CB400DD35BE /* CAPBridgeViewController+CDVScreenOrientationDelegate.h */; };
- 2F81F5CA26FB7CB400DD35BE /* CAPBridgeViewController+CDVScreenOrientationDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 2F81F5C826FB7CB400DD35BE /* CAPBridgeViewController+CDVScreenOrientationDelegate.m */; };
373A69C1255C9360000A6F44 /* NotificationHandlerProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 373A69C0255C9360000A6F44 /* NotificationHandlerProtocol.swift */; };
373A69F2255C95D0000A6F44 /* NotificationRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 373A69F1255C95D0000A6F44 /* NotificationRouter.swift */; };
501CBAA71FC0A723009B0D4D /* WebKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 501CBAA61FC0A723009B0D4D /* WebKit.framework */; };
@@ -52,14 +50,12 @@
62959B3A2524DA7800A3D7F1 /* CAPLog.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62959B082524DA7700A3D7F1 /* CAPLog.swift */; };
62959B3B2524DA7800A3D7F1 /* CAPPluginMethod.h in Headers */ = {isa = PBXBuildFile; fileRef = 62959B092524DA7700A3D7F1 /* CAPPluginMethod.h */; settings = {ATTRIBUTES = (Public, ); }; };
62959B3C2524DA7800A3D7F1 /* CAPBridgeDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62959B0A2524DA7700A3D7F1 /* CAPBridgeDelegate.swift */; };
- 62959B402524DA7800A3D7F1 /* TmpViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62959B0E2524DA7700A3D7F1 /* TmpViewController.swift */; };
62959B412524DA7800A3D7F1 /* Capacitor.h in Headers */ = {isa = PBXBuildFile; fileRef = 62959B0F2524DA7700A3D7F1 /* Capacitor.h */; settings = {ATTRIBUTES = (Public, ); }; };
62959B422524DA7800A3D7F1 /* DocLinks.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62959B102524DA7700A3D7F1 /* DocLinks.swift */; };
62959B432524DA7800A3D7F1 /* Data+Capacitor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62959B112524DA7700A3D7F1 /* Data+Capacitor.swift */; };
62959B452524DA7800A3D7F1 /* CAPPlugin.h in Headers */ = {isa = PBXBuildFile; fileRef = 62959B132524DA7700A3D7F1 /* CAPPlugin.h */; settings = {ATTRIBUTES = (Public, ); }; };
62959B462524DA7800A3D7F1 /* CAPBridge.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62959B142524DA7700A3D7F1 /* CAPBridge.swift */; };
62959B472524DA7800A3D7F1 /* CAPNotifications.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62959B152524DA7700A3D7F1 /* CAPNotifications.swift */; };
- 62959BA52526475A00A3D7F1 /* Cordova.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 62959BA02526474300A3D7F1 /* Cordova.framework */; };
6296A77E253A2E49005A202A /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6296A77D253A2E49005A202A /* AppDelegate.swift */; };
6296A782253A2E49005A202A /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6296A781253A2E49005A202A /* ViewController.swift */; };
6296A785253A2E49005A202A /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 6296A783253A2E49005A202A /* Main.storyboard */; };
@@ -158,8 +154,6 @@
/* Begin PBXFileReference section */
0F83E884285A332D006C43CB /* AppUUID.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppUUID.swift; sourceTree = ""; };
0F8F33B127DA980A003F49D6 /* PluginConfig.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PluginConfig.swift; sourceTree = ""; };
- 2F81F5C726FB7CB400DD35BE /* CAPBridgeViewController+CDVScreenOrientationDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "CAPBridgeViewController+CDVScreenOrientationDelegate.h"; sourceTree = ""; };
- 2F81F5C826FB7CB400DD35BE /* CAPBridgeViewController+CDVScreenOrientationDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "CAPBridgeViewController+CDVScreenOrientationDelegate.m"; sourceTree = ""; };
373A69C0255C9360000A6F44 /* NotificationHandlerProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationHandlerProtocol.swift; sourceTree = ""; };
373A69F1255C95D0000A6F44 /* NotificationRouter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationRouter.swift; sourceTree = ""; };
501CBAA61FC0A723009B0D4D /* WebKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = WebKit.framework; path = System/Library/Frameworks/WebKit.framework; sourceTree = SDKROOT; };
@@ -204,7 +198,6 @@
62959B082524DA7700A3D7F1 /* CAPLog.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CAPLog.swift; sourceTree = ""; };
62959B092524DA7700A3D7F1 /* CAPPluginMethod.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CAPPluginMethod.h; sourceTree = ""; };
62959B0A2524DA7700A3D7F1 /* CAPBridgeDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CAPBridgeDelegate.swift; sourceTree = ""; };
- 62959B0E2524DA7700A3D7F1 /* TmpViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TmpViewController.swift; sourceTree = ""; };
62959B0F2524DA7700A3D7F1 /* Capacitor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Capacitor.h; sourceTree = ""; };
62959B102524DA7700A3D7F1 /* DocLinks.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DocLinks.swift; sourceTree = ""; };
62959B112524DA7700A3D7F1 /* Data+Capacitor.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Data+Capacitor.swift"; sourceTree = ""; };
@@ -270,7 +263,6 @@
buildActionMask = 2147483647;
files = (
501CBAA71FC0A723009B0D4D /* WebKit.framework in Frameworks */,
- 62959BA52526475A00A3D7F1 /* Cordova.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -395,7 +387,6 @@
6214934625509C3F006C36F9 /* CAPInstanceConfiguration.swift */,
62959B082524DA7700A3D7F1 /* CAPLog.swift */,
62959AE72524DA7700A3D7F1 /* CAPFile.swift */,
- 62959B0E2524DA7700A3D7F1 /* TmpViewController.swift */,
62959B102524DA7700A3D7F1 /* DocLinks.swift */,
62959B152524DA7700A3D7F1 /* CAPNotifications.swift */,
62959B072524DA7700A3D7F1 /* CapacitorExtension.swift */,
@@ -403,8 +394,6 @@
62FABD1925AE5C01007B3814 /* Array+Capacitor.swift */,
62D43AEF2581817500673C24 /* WKWebView+Capacitor.swift */,
62D43B642582A13D00673C24 /* WKWebView+Capacitor.m */,
- 2F81F5C726FB7CB400DD35BE /* CAPBridgeViewController+CDVScreenOrientationDelegate.h */,
- 2F81F5C826FB7CB400DD35BE /* CAPBridgeViewController+CDVScreenOrientationDelegate.m */,
62959AE92524DA7700A3D7F1 /* UIColor.swift */,
62959AFE2524DA7700A3D7F1 /* UIStatusBarManager+CAPHandleTapAction.m */,
62959B122524DA7700A3D7F1 /* Info.plist */,
@@ -515,7 +504,6 @@
623D6909254C6FDF002D01D1 /* CAPInstanceDescriptor.h in Headers */,
62959B192524DA7800A3D7F1 /* CAPBridgedPlugin.h in Headers */,
621ECCB82542045900D3D615 /* CAPBridgedJSTypes.h in Headers */,
- 2F81F5C926FB7CB400DD35BE /* CAPBridgeViewController+CDVScreenOrientationDelegate.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -710,7 +698,6 @@
A7D9312F2B23710300FF59A2 /* JSValueDecoder.swift in Sources */,
62959B362524DA7800A3D7F1 /* CAPBridgeViewController.swift in Sources */,
621ECCB72542045900D3D615 /* CAPBridgedJSTypes.m in Sources */,
- 62959B402524DA7800A3D7F1 /* TmpViewController.swift in Sources */,
621ECCD6254205BD00D3D615 /* CAPBridgeProtocol.swift in Sources */,
62D43AF02581817500673C24 /* WKWebView+Capacitor.swift in Sources */,
62959B432524DA7800A3D7F1 /* Data+Capacitor.swift in Sources */,
@@ -728,7 +715,6 @@
62959B1D2524DA7800A3D7F1 /* UIColor.swift in Sources */,
62959B332524DA7800A3D7F1 /* CAPPlugin.m in Sources */,
62959B1C2524DA7800A3D7F1 /* CAPPluginMethod.m in Sources */,
- 2F81F5CA26FB7CB400DD35BE /* CAPBridgeViewController+CDVScreenOrientationDelegate.m in Sources */,
62ADC0CA25CB678000E914DE /* PluginCallResult.swift in Sources */,
62959B472524DA7800A3D7F1 /* CAPNotifications.swift in Sources */,
62D43B652582A13D00673C24 /* WKWebView+Capacitor.m in Sources */,
@@ -893,7 +879,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
- IPHONEOS_DEPLOYMENT_TARGET = 15.0;
+ IPHONEOS_DEPLOYMENT_TARGET = 16.0;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
@@ -951,7 +937,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
- IPHONEOS_DEPLOYMENT_TARGET = 15.0;
+ IPHONEOS_DEPLOYMENT_TARGET = 16.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
@@ -978,7 +964,7 @@
);
INFOPLIST_FILE = Capacitor/Info.plist;
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
- IPHONEOS_DEPLOYMENT_TARGET = 15.0;
+ IPHONEOS_DEPLOYMENT_TARGET = 16.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
MODULEMAP_FILE = Capacitor/Capacitor.modulemap;
PRODUCT_BUNDLE_IDENTIFIER = com.capacitorjs.ios.Capacitor;
@@ -1008,7 +994,7 @@
);
INFOPLIST_FILE = Capacitor/Info.plist;
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
- IPHONEOS_DEPLOYMENT_TARGET = 15.0;
+ IPHONEOS_DEPLOYMENT_TARGET = 16.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
MODULEMAP_FILE = Capacitor/Capacitor.modulemap;
PRODUCT_BUNDLE_IDENTIFIER = com.capacitorjs.ios.Capacitor;
@@ -1072,7 +1058,7 @@
CODE_SIGN_STYLE = Automatic;
DEVELOPMENT_TEAM = "";
INFOPLIST_FILE = TestsHostApp/Info.plist;
- IPHONEOS_DEPLOYMENT_TARGET = 15.0;
+ IPHONEOS_DEPLOYMENT_TARGET = 16.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES;
@@ -1095,7 +1081,7 @@
CODE_SIGN_STYLE = Automatic;
DEVELOPMENT_TEAM = "";
INFOPLIST_FILE = TestsHostApp/Info.plist;
- IPHONEOS_DEPLOYMENT_TARGET = 15.0;
+ IPHONEOS_DEPLOYMENT_TARGET = 16.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
MTL_FAST_MATH = YES;
PRODUCT_BUNDLE_IDENTIFIER = com.capacitorjs.ios.TestsHostApp;
@@ -1118,7 +1104,7 @@
ENABLE_USER_SCRIPT_SANDBOXING = YES;
GCC_C_LANGUAGE_STANDARD = gnu17;
GENERATE_INFOPLIST_FILE = YES;
- IPHONEOS_DEPLOYMENT_TARGET = 15.0;
+ IPHONEOS_DEPLOYMENT_TARGET = 16.0;
LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
MARKETING_VERSION = 1.0;
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
@@ -1145,7 +1131,7 @@
ENABLE_USER_SCRIPT_SANDBOXING = YES;
GCC_C_LANGUAGE_STANDARD = gnu17;
GENERATE_INFOPLIST_FILE = YES;
- IPHONEOS_DEPLOYMENT_TARGET = 15.0;
+ IPHONEOS_DEPLOYMENT_TARGET = 16.0;
LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
MARKETING_VERSION = 1.0;
MTL_FAST_MATH = YES;
diff --git a/ios/Capacitor/Capacitor/CAPApplicationDelegateProxy.swift b/ios/Capacitor/Capacitor/CAPApplicationDelegateProxy.swift
index 7f510bc5ac..d687953fea 100644
--- a/ios/Capacitor/Capacitor/CAPApplicationDelegateProxy.swift
+++ b/ios/Capacitor/Capacitor/CAPApplicationDelegateProxy.swift
@@ -11,7 +11,6 @@ public class ApplicationDelegateProxy: NSObject, UIApplicationDelegate {
"url": url,
"options": options
])
- NotificationCenter.default.post(name: NSNotification.Name.CDVPluginHandleOpenURL, object: url)
lastURL = url
return true
}
diff --git a/ios/Capacitor/Capacitor/CAPBridgeProtocol.swift b/ios/Capacitor/Capacitor/CAPBridgeProtocol.swift
index 24ee52a75d..98ac66d965 100644
--- a/ios/Capacitor/Capacitor/CAPBridgeProtocol.swift
+++ b/ios/Capacitor/Capacitor/CAPBridgeProtocol.swift
@@ -79,6 +79,9 @@ import WebKit
func registerPluginType(_ pluginType: CAPPlugin.Type)
func registerPluginInstance(_ pluginInstance: CAPPlugin)
+ // MARK: - Interceptors
+ func registerCallInterceptor(_ name: String, handler: @escaping ([String: Any]) -> Void)
+
// MARK: - View Presentation
func showAlertWith(title: String, message: String, buttonTitle: String)
@available(*, deprecated, message: "Use self?.bridge?.viewController?.present")
diff --git a/ios/Capacitor/Capacitor/CAPBridgeViewController+CDVScreenOrientationDelegate.h b/ios/Capacitor/Capacitor/CAPBridgeViewController+CDVScreenOrientationDelegate.h
deleted file mode 100644
index aeda727d5f..0000000000
--- a/ios/Capacitor/Capacitor/CAPBridgeViewController+CDVScreenOrientationDelegate.h
+++ /dev/null
@@ -1,6 +0,0 @@
-#import
-
-@interface CAPBridgeViewController (CDVScreenOrientationDelegate)
-
-@end
-
diff --git a/ios/Capacitor/Capacitor/CAPBridgeViewController+CDVScreenOrientationDelegate.m b/ios/Capacitor/Capacitor/CAPBridgeViewController+CDVScreenOrientationDelegate.m
deleted file mode 100644
index 94c169a0cc..0000000000
--- a/ios/Capacitor/Capacitor/CAPBridgeViewController+CDVScreenOrientationDelegate.m
+++ /dev/null
@@ -1,5 +0,0 @@
-#import "CAPBridgeViewController+CDVScreenOrientationDelegate.h"
-
-@implementation CAPBridgeViewController (CDVScreenOrientationDelegate)
-
-@end
diff --git a/ios/Capacitor/Capacitor/CAPBridgeViewController.swift b/ios/Capacitor/Capacitor/CAPBridgeViewController.swift
index a7285213d8..33f17be66c 100644
--- a/ios/Capacitor/Capacitor/CAPBridgeViewController.swift
+++ b/ios/Capacitor/Capacitor/CAPBridgeViewController.swift
@@ -1,6 +1,5 @@
import UIKit
import WebKit
-import Cordova
@objc open class CAPBridgeViewController: UIViewController {
private var capacitorBridge: CapacitorBridge?
@@ -47,10 +46,10 @@ import Cordova
// create the bridge
capacitorBridge = CapacitorBridge(with: configuration,
delegate: self,
- cordovaConfiguration: configDescriptor.cordovaConfiguration,
assetHandler: assetHandler,
delegationHandler: delegationHandler)
capacitorDidLoad()
+ updateAppLocationIfNeeded()
if configDescriptor.instanceType == .fixed {
updateBinaryVersion()
@@ -89,18 +88,25 @@ import Cordova
- Note: This is called early in the View Controller's lifecycle. Not all properties will be set at invocation.
*/
open func instanceDescriptor() -> InstanceDescriptor {
- let descriptor = InstanceDescriptor.init()
- if !isNewBinary && !descriptor.cordovaDeployDisabled {
+ return InstanceDescriptor()
+ }
+
+ /// This function must be called after plugins are loaded or it will have no effect.
+ open func updateAppLocationIfNeeded() {
+ let cordovaPlugin = bridge?.plugin(withName: "__CordovaPlugin")
+ let cordovaDeployDisabled = cordovaPlugin?.perform(Selector(("cordovaDeployDisabled"))).takeUnretainedValue() as? Bool ?? false
+
+ if !isNewBinary && !cordovaDeployDisabled {
if let persistedPath = KeyValueStore.standard["serverBasePath", as: String.self], !persistedPath.isEmpty {
if let libPath = NSSearchPathForDirectoriesInDomains(.libraryDirectory, .userDomainMask, true).first {
- descriptor.appLocation = URL(fileURLWithPath: libPath, isDirectory: true)
+ let serverBasePath = URL(fileURLWithPath: libPath, isDirectory: true)
.appendingPathComponent("NoCloud")
.appendingPathComponent("ionic_built_snapshots")
.appendingPathComponent(URL(fileURLWithPath: persistedPath, isDirectory: true).lastPathComponent)
+ setServerBasePath(path: serverBasePath.path)
}
}
}
- return descriptor
}
open func router() -> Router {
@@ -124,9 +130,7 @@ import Cordova
webViewConfiguration.allowsAirPlayForMediaPlayback = true
webViewConfiguration.mediaTypesRequiringUserActionForPlayback = []
webViewConfiguration.limitsNavigationsToAppBoundDomains = instanceConfiguration.limitsNavigationsToAppBoundDomains
- if #available(iOS 15.4, *) {
- webViewConfiguration.preferences.isElementFullscreenEnabled = true
- }
+ webViewConfiguration.preferences.isElementFullscreenEnabled = true
if let appendUserAgent = instanceConfiguration.appendedUserAgentString {
if let appName = webViewConfiguration.applicationNameForUserAgent {
webViewConfiguration.applicationNameForUserAgent = "\(appName) \(appendUserAgent)"
diff --git a/ios/Capacitor/Capacitor/CAPInstanceDescriptor.h b/ios/Capacitor/Capacitor/CAPInstanceDescriptor.h
index f477ef55be..3ca447e6f8 100644
--- a/ios/Capacitor/Capacitor/CAPInstanceDescriptor.h
+++ b/ios/Capacitor/Capacitor/CAPInstanceDescriptor.h
@@ -2,7 +2,7 @@
#define CAPInstanceDescriptor_h
@import UIKit;
-@import Cordova;
+
typedef NS_ENUM(NSInteger, CAPInstanceType) {
CAPInstanceTypeFixed NS_SWIFT_NAME(fixed),
@@ -137,7 +137,7 @@ NS_SWIFT_NAME(InstanceDescriptor)
/**
@brief The parser used to load the cofiguration for Cordova plugins.
*/
-@property (nonatomic, copy, nonnull) CDVConfigParser *cordovaConfiguration;
+@property (nonatomic, copy, nonnull) NSObject *cordovaConfiguration;
/**
@brief Warnings generated during initialization.
*/
diff --git a/ios/Capacitor/Capacitor/CAPInstanceDescriptor.m b/ios/Capacitor/Capacitor/CAPInstanceDescriptor.m
index 2d7a4fba91..acdbc08caf 100644
--- a/ios/Capacitor/Capacitor/CAPInstanceDescriptor.m
+++ b/ios/Capacitor/Capacitor/CAPInstanceDescriptor.m
@@ -45,7 +45,6 @@ - (void)_setDefaultsWithAppLocation:(NSURL*)location {
_contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;
_appLocation = location;
_limitsNavigationsToAppBoundDomains = FALSE;
- _cordovaConfiguration = [[CDVConfigParser alloc] init];
_warnings = 0;
if (location == nil) {
_warnings |= CAPInstanceWarningMissingAppDir;
diff --git a/ios/Capacitor/Capacitor/CAPInstanceDescriptor.swift b/ios/Capacitor/Capacitor/CAPInstanceDescriptor.swift
index a7eff5f623..495de0634d 100644
--- a/ios/Capacitor/Capacitor/CAPInstanceDescriptor.swift
+++ b/ios/Capacitor/Capacitor/CAPInstanceDescriptor.swift
@@ -52,23 +52,6 @@ internal extension InstanceDescriptor {
warnings.update(with: .missingFile)
}
- // parse the cordova configuration
- var configParser: XMLParser?
- if let cordovaURL = cordovaURL,
- FileManager.default.fileExists(atPath: cordovaURL.path, isDirectory: &isDirectory),
- isDirectory.boolValue == false {
- configParser = XMLParser(contentsOf: cordovaURL)
- } else {
- warnings.update(with: .missingCordovaFile)
- // we don't want to break up string literals
- // swiftlint:disable:next line_length
- if let cordovaXML = "".data(using: .utf8) {
- configParser = XMLParser(data: cordovaXML)
- }
- }
- configParser?.delegate = cordovaConfiguration
- configParser?.parse()
-
// extract our configuration values
if let config = config {
// to be removed
@@ -160,7 +143,7 @@ internal extension InstanceDescriptor {
extension InstanceDescriptor {
@objc public var cordovaDeployDisabled: Bool {
- return (cordovaConfiguration.settings?["DisableDeploy".lowercased()] as? NSString)?.boolValue ?? false
+ return false
}
@objc public func normalize() {
diff --git a/ios/Capacitor/Capacitor/CapacitorBridge.swift b/ios/Capacitor/Capacitor/CapacitorBridge.swift
index 7b8b9b99dc..de2beb22e3 100644
--- a/ios/Capacitor/Capacitor/CapacitorBridge.swift
+++ b/ios/Capacitor/Capacitor/CapacitorBridge.swift
@@ -1,12 +1,11 @@
import Foundation
import Dispatch
import WebKit
-import Cordova
internal typealias CapacitorPlugin = CAPPlugin & CAPBridgedPlugin
struct RegistrationList: Codable {
- let packageClassList: Set
+ var packageClassList: Set
}
/**
@@ -93,10 +92,6 @@ open class CapacitorBridge: NSObject, CAPBridgeProtocol {
}
}
}
- @available(*, deprecated, message: "obsolete")
- var tmpWindow: UIWindow?
- @available(*, deprecated, message: "obsolete")
- static let tmpVCAppeared = Notification(name: Notification.Name(rawValue: "tmpViewControllerAppeared"))
public static let capacitorSite = "https://capacitorjs.com/"
public static let fileStartIdentifier = "/_capacitor_file_"
public static let httpInterceptorStartIdentifier = "/_capacitor_http_interceptor_"
@@ -117,18 +112,16 @@ open class CapacitorBridge: NSObject, CAPBridgeProtocol {
@objc public var config: InstanceConfiguration
// Map of all loaded and instantiated plugins by pluginId -> instance
var plugins = [String: CapacitorPlugin]()
- // Manager for getting Cordova plugins
- var cordovaPluginManager: CDVPluginManager?
// Calls we are storing to resolve later
var storedCalls = ConcurrentDictionary()
// Whether to inject the Cordova files
- private var injectCordovaFiles = false
- private var cordovaParser: CDVConfigParser?
+ private var cordovaIsPresent = false
private var injectMiscFiles: [String] = []
private var canInjectJS: Bool = true
// Background dispatch queue for plugin calls
open private(set) var dispatchQueue = DispatchQueue(label: "bridge")
+ internal private(set) var callInterceptors: [String: ([String: Any]) -> Void] = [:]
// Array of block based observers
var observers: [NSObjectProtocol] = []
@@ -205,12 +198,17 @@ open class CapacitorBridge: NSObject, CAPBridgeProtocol {
// MARK: - Initialization
- public init(with configuration: InstanceConfiguration, delegate bridgeDelegate: CAPBridgeDelegate, cordovaConfiguration: CDVConfigParser, assetHandler: WebViewAssetHandler, delegationHandler: WebViewDelegationHandler, autoRegisterPlugins: Bool = true) {
+ @available(*, deprecated, renamed: "init", message: "Use different init")
+ public convenience init(with configuration: InstanceConfiguration, delegate bridgeDelegate: CAPBridgeDelegate, cordovaConfiguration: Any, assetHandler: WebViewAssetHandler, delegationHandler: WebViewDelegationHandler, autoRegisterPlugins: Bool = true) {
+ self.init(with: configuration, delegate: bridgeDelegate, assetHandler: assetHandler, delegationHandler: delegationHandler, autoRegisterPlugins: autoRegisterPlugins)
+ }
+
+ public init(with configuration: InstanceConfiguration, delegate bridgeDelegate: CAPBridgeDelegate, assetHandler: WebViewAssetHandler, delegationHandler: WebViewDelegationHandler, autoRegisterPlugins: Bool = true) {
+
self.bridgeDelegate = bridgeDelegate
self.webViewAssetHandler = assetHandler
self.webViewDelegationHandler = delegationHandler
self.config = configuration
- self.cordovaParser = cordovaConfiguration
self.notificationRouter = NotificationRouter()
self.notificationRouter.handleApplicationNotifications = configuration.handleApplicationNotifications
self.autoRegisterPlugins = autoRegisterPlugins
@@ -220,12 +218,9 @@ open class CapacitorBridge: NSObject, CAPBridgeProtocol {
exportCoreJS(localUrl: configuration.localURL.absoluteString)
registerPlugins()
- setupCordovaCompatibility()
+ setupListeners()
exportMiscJS()
canInjectJS = false
- observers.append(NotificationCenter.default.addObserver(forName: type(of: self).tmpVCAppeared.name, object: .none, queue: .none) { [weak self] _ in
- self?.tmpWindow = nil
- })
self.setupWebDebugging(configuration: configuration)
}
@@ -262,31 +257,27 @@ open class CapacitorBridge: NSObject, CAPBridgeProtocol {
injectMiscFiles.removeAll()
}
- /**
- Set up our Cordova compat by loading all known Cordova plugins and injecting their JS.
- */
- func setupCordovaCompatibility() {
- if injectCordovaFiles {
- exportCordovaJS()
- registerCordovaPlugins()
- } else {
- observers.append(NotificationCenter.default.addObserver(forName: UIApplication.willEnterForegroundNotification, object: nil, queue: OperationQueue.main) { [weak self] (_) in
- self?.triggerDocumentJSEvent(eventName: "resume")
- })
- observers.append(NotificationCenter.default.addObserver(forName: UIApplication.didEnterBackgroundNotification, object: nil, queue: OperationQueue.main) { [weak self] (_) in
- self?.triggerDocumentJSEvent(eventName: "pause")
- })
- }
- }
-
- /**
- Export the core Cordova JS runtime
- */
- func exportCordovaJS() {
- do {
- try JSExport.exportCordovaJS(userContentController: webViewDelegationHandler.contentController)
- } catch {
- type(of: self).fatalError(error, error)
+ func setupListeners() {
+ if !cordovaIsPresent {
+ observers.append(
+ NotificationCenter.default.addObserver(
+ forName: UIApplication.willEnterForegroundNotification,
+ object: nil,
+ queue: .main
+ ) { [weak self] _ in
+ self?.triggerDocumentJSEvent(eventName: "resume")
+ }
+ )
+
+ observers.append(
+ NotificationCenter.default.addObserver(
+ forName: UIApplication.didEnterBackgroundNotification,
+ object: nil,
+ queue: .main
+ ) { [weak self] _ in
+ self?.triggerDocumentJSEvent(eventName: "pause")
+ }
+ )
}
}
@@ -309,14 +300,13 @@ open class CapacitorBridge: NSObject, CAPBridgeProtocol {
do {
if let pluginJSON = Bundle.main.url(forResource: "capacitor.config", withExtension: "json") {
let pluginData = try Data(contentsOf: pluginJSON)
- let registrationList = try JSONDecoder().decode(RegistrationList.self, from: pluginData)
+ var registrationList = try JSONDecoder().decode(RegistrationList.self, from: pluginData)
for plugin in registrationList.packageClassList {
- if let pluginClass = NSClassFromString(plugin) {
- if pluginClass == CDVPlugin.self {
- injectCordovaFiles = true
- } else {
- pluginList.append(pluginClass)
+ if let pluginClass = NSClassFromString(plugin), pluginClass is CAPPlugin.Type {
+ pluginList.append(pluginClass)
+ if plugin == "CordovaPlugin" {
+ cordovaIsPresent = true
}
}
}
@@ -393,6 +383,10 @@ open class CapacitorBridge: NSObject, CAPBridgeProtocol {
// MARK: - CAPBridgeProtocol: Call Management
+ public func registerCallInterceptor(_ name: String, handler: @escaping ([String: Any]) -> Void) {
+ callInterceptors[name] = handler
+ }
+
@objc public func saveCall(_ call: CAPPluginCall) {
storedCalls[call.callbackId] = call
}
@@ -425,23 +419,6 @@ open class CapacitorBridge: NSObject, CAPBridgeProtocol {
return self.dispatchQueue
}
- func registerCordovaPlugins() {
- guard let cordovaParser = cordovaParser else {
- return
- }
- cordovaPluginManager = CDVPluginManager.init(parser: cordovaParser, viewController: self.viewController, webView: self.getWebView())
- if cordovaParser.startupPluginNames.count > 0 {
- for pluginName in cordovaParser.startupPluginNames {
- _ = cordovaPluginManager?.getCommandInstance(pluginName as? String)
- }
- }
- do {
- try JSExport.exportCordovaPluginsJS(userContentController: webViewDelegationHandler.contentController)
- } catch {
- type(of: self).fatalError(error, error)
- }
- }
-
func reload() {
self.getWebView()?.reload()
}
@@ -540,34 +517,6 @@ open class CapacitorBridge: NSObject, CAPBridgeProtocol {
}
}
- /**
- Handle a Cordova call from JavaScript. First, find the corresponding plugin,
- construct a selector, and perform that selector on the plugin instance.
- */
- func handleCordovaJSCall(call: JSCall) {
- // Create a selector to send to the plugin
-
- if let plugin = self.cordovaPluginManager?.getCommandInstance(call.pluginId.lowercased()) {
- let selector = NSSelectorFromString("\(call.method):")
- if !plugin.responds(to: selector) {
- CAPLog.print("Error: Plugin \(plugin.className ?? "") does not respond to method call \(selector).")
- CAPLog.print("Ensure plugin method exists and uses @objc in its declaration")
- return
- }
-
- let arguments: [Any] = call.options["options"] as? [Any] ?? []
- let pluginCall = CDVInvokedUrlCommand(arguments: arguments,
- callbackId: call.callbackId,
- className: plugin.className,
- methodName: call.method)
- plugin.perform(selector, with: pluginCall)
-
- } else {
- CAPLog.print("Error: Cordova Plugin mapping not found")
- return
- }
- }
-
func removeAllPluginListeners() {
for plugin in plugins.values {
plugin.perform(#selector(CAPPlugin.removeAllListeners(_:)), with: nil)
diff --git a/ios/Capacitor/Capacitor/JS.swift b/ios/Capacitor/Capacitor/JS.swift
index 46972c48a5..b1198b1786 100644
--- a/ios/Capacitor/Capacitor/JS.swift
+++ b/ios/Capacitor/Capacitor/JS.swift
@@ -14,11 +14,11 @@ public typealias JSResultBody = [String: Any]
/**
* A call originating from JavaScript land
*/
-internal struct JSCall {
- let options: [String: Any]
- let pluginId: String
- let method: String
- let callbackId: String
+public struct JSCall {
+ public let options: [String: Any]
+ public let pluginId: String
+ public let method: String
+ public let callbackId: String
}
internal protocol JSResultProtocol {
diff --git a/ios/Capacitor/Capacitor/JSExport.swift b/ios/Capacitor/Capacitor/JSExport.swift
index f6934c17a7..c51da733df 100644
--- a/ios/Capacitor/Capacitor/JSExport.swift
+++ b/ios/Capacitor/Capacitor/JSExport.swift
@@ -35,24 +35,6 @@ internal class JSExport {
}
}
- static func exportCordovaJS(userContentController: WKUserContentController) throws {
- guard let cordovaUrl = Bundle.main.url(forResource: "public/cordova", withExtension: "js") else {
- CAPLog.print("ERROR: Required cordova.js file not found. Cordova plugins will not function!")
- throw CapacitorBridgeError.errorExportingCoreJS
- }
- guard let cordovaPluginsUrl = Bundle.main.url(forResource: "public/cordova_plugins", withExtension: "js") else {
- CAPLog.print("ERROR: Required cordova_plugins.js file not found. Cordova plugins will not function!")
- throw CapacitorBridgeError.errorExportingCoreJS
- }
- do {
- try self.injectFile(fileURL: cordovaUrl, userContentController: userContentController)
- try self.injectFile(fileURL: cordovaPluginsUrl, userContentController: userContentController)
- } catch {
- CAPLog.print("ERROR: Unable to read required cordova files. Cordova plugins will not function!")
- throw CapacitorBridgeError.errorExportingCoreJS
- }
- }
-
static func exportMiscFileJS(paths: [String], userContentController: WKUserContentController) {
for path in paths {
if let miscJSFilePath = Bundle.main.url(forResource: "public/\(path.replacingOccurrences(of: ".js", with: ""))", withExtension: "js") {
@@ -184,28 +166,6 @@ internal class JSExport {
return lines.joined(separator: "\n")
}
- static func exportCordovaPluginsJS(userContentController: WKUserContentController) throws {
- if let pluginsJSFolder = Bundle.main.url(forResource: "public/plugins", withExtension: nil) {
- self.injectFilesForFolder(folder: pluginsJSFolder, userContentController: userContentController)
- }
- }
-
- static func injectFilesForFolder(folder: URL, userContentController: WKUserContentController) {
- let fileManager = FileManager.default
- do {
- let fileURLs = try fileManager.contentsOfDirectory(at: folder, includingPropertiesForKeys: nil, options: [])
- for fileURL in fileURLs {
- if fileURL.hasDirectoryPath {
- injectFilesForFolder(folder: fileURL, userContentController: userContentController)
- } else {
- try self.injectFile(fileURL: fileURL, userContentController: userContentController)
- }
- }
- } catch {
- CAPLog.print("Error while enumerating files")
- }
- }
-
static func injectFile(fileURL: URL, userContentController: WKUserContentController) throws {
do {
let data = try String(contentsOf: fileURL, encoding: .utf8)
diff --git a/ios/Capacitor/Capacitor/PluginConfig.swift b/ios/Capacitor/Capacitor/PluginConfig.swift
index f2461e102d..8d73bc1def 100644
--- a/ios/Capacitor/Capacitor/PluginConfig.swift
+++ b/ios/Capacitor/Capacitor/PluginConfig.swift
@@ -30,6 +30,13 @@ import Foundation
return defaultValue
}
+ @objc public func getDouble(_ configKey: String, _ defaultValue: Double) -> Double {
+ if let val = (self.config)[keyPath: KeyPath(configKey)] as? Double {
+ return val
+ }
+ return defaultValue
+ }
+
public func getArray(_ configKey: String, _ defaultValue: JSArray? = nil) -> JSArray? {
if let val = (self.config)[keyPath: KeyPath(configKey)] as? JSArray {
return val
diff --git a/ios/Capacitor/Capacitor/TmpViewController.swift b/ios/Capacitor/Capacitor/TmpViewController.swift
deleted file mode 100644
index 3511d18aed..0000000000
--- a/ios/Capacitor/Capacitor/TmpViewController.swift
+++ /dev/null
@@ -1,8 +0,0 @@
-import UIKit
-
-internal class TmpViewController: UIViewController {
- override func viewDidAppear(_ animated: Bool) {
- super.viewDidAppear(animated)
- NotificationCenter.default.post(CapacitorBridge.tmpVCAppeared)
- }
-}
diff --git a/ios/Capacitor/Capacitor/WebViewDelegationHandler.swift b/ios/Capacitor/Capacitor/WebViewDelegationHandler.swift
index 2b4a256d00..37deace97b 100644
--- a/ios/Capacitor/Capacitor/WebViewDelegationHandler.swift
+++ b/ios/Capacitor/Capacitor/WebViewDelegationHandler.swift
@@ -208,17 +208,8 @@ open class WebViewDelegationHandler: NSObject, WKNavigationDelegate, WKUIDelegat
}
bridge.handleJSCall(call: JSCall(options: options, pluginId: pluginId, method: method, callbackId: callbackId))
- } else if type == "cordova" {
- let pluginId = dict["service"] as? String ?? ""
- let method = dict["action"] as? String ?? ""
- let callbackId = dict["callbackId"] as? String ?? ""
-
- let args = dict["actionArgs"] as? Array ?? []
- let options = ["options": args]
-
- CAPLog.print("To Native Cordova -> ", pluginId, method, callbackId, options)
-
- bridge.handleCordovaJSCall(call: JSCall(options: options, pluginId: pluginId, method: method, callbackId: callbackId))
+ } else if let handler = bridge.callInterceptors[type] {
+ handler(dict)
}
}
}
diff --git a/ios/Capacitor/CapacitorTests/ConfigurationTests.swift b/ios/Capacitor/CapacitorTests/ConfigurationTests.swift
index 778bfd688d..177f211e7d 100644
--- a/ios/Capacitor/CapacitorTests/ConfigurationTests.swift
+++ b/ios/Capacitor/CapacitorTests/ConfigurationTests.swift
@@ -33,7 +33,6 @@ class ConfigurationTests: XCTestCase {
let descriptor = InstanceDescriptor.init()
XCTAssertTrue(descriptor.warnings.contains(.missingAppDir))
XCTAssertTrue(descriptor.warnings.contains(.missingFile))
- XCTAssertTrue(descriptor.warnings.contains(.missingCordovaFile))
}
func testMissingAppDetection() throws {
diff --git a/ios/Capacitor/CapacitorTests/PluginCallAccessorTests.m b/ios/Capacitor/CapacitorTests/PluginCallAccessorTests.m
index 0295cfa822..4d665aeec1 100644
--- a/ios/Capacitor/CapacitorTests/PluginCallAccessorTests.m
+++ b/ios/Capacitor/CapacitorTests/PluginCallAccessorTests.m
@@ -21,7 +21,7 @@ - (void)setUp {
@"testDateString": [formatter stringFromDate:date],
@"testBoolTrue": @TRUE,
@"testBoolFalse": @FALSE};
- [self setCall:[[CAPPluginCall alloc] initWithCallbackId:@"test" options:options success:NULL error:NULL]];
+ [self setCall:[[CAPPluginCall alloc] initWithCallbackId:@"test" methodName:@"test" options:options success:NULL error:NULL]];
}
- (void)testStringAccessor {
diff --git a/ios/CapacitorCordova.podspec b/ios/CapacitorCordova.podspec
index 65fcce86d7..98f6bc3474 100644
--- a/ios/CapacitorCordova.podspec
+++ b/ios/CapacitorCordova.podspec
@@ -15,12 +15,13 @@ Pod::Spec.new do |s|
s.license = 'MIT'
s.authors = { 'Ionic Team' => 'hi@ionicframework.com' }
s.source = { git: 'https://github.com/ionic-team/capacitor', tag: s.version.to_s }
- s.platform = :ios, 15.0
- s.source_files = "#{prefix}CapacitorCordova/CapacitorCordova/**/*.{h,m}"
+ s.platform = :ios, 16.0
+ s.source_files = "#{prefix}CapacitorCordova/CapacitorCordova/**/*.{h,m,swift}"
s.public_header_files = "#{prefix}CapacitorCordova/CapacitorCordova/Classes/Public/*.h",
"#{prefix}CapacitorCordova/CapacitorCordova/CapacitorCordova.h"
s.module_map = "#{prefix}CapacitorCordova/CapacitorCordova/CapacitorCordova.modulemap"
s.resource_bundles = { 'CapacitorCordova' => ["#{prefix}CapacitorCordova/CapacitorCordova/PrivacyInfo.xcprivacy"] }
s.requires_arc = true
+ s.dependency 'Capacitor', s.version.to_s
s.framework = 'WebKit'
end
diff --git a/ios/CapacitorCordova/CapacitorCordova.xcodeproj/project.pbxproj b/ios/CapacitorCordova/CapacitorCordova.xcodeproj/project.pbxproj
index 3f9ef4c65c..e95b03f613 100644
--- a/ios/CapacitorCordova/CapacitorCordova.xcodeproj/project.pbxproj
+++ b/ios/CapacitorCordova/CapacitorCordova.xcodeproj/project.pbxproj
@@ -328,7 +328,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
- IPHONEOS_DEPLOYMENT_TARGET = 15.0;
+ IPHONEOS_DEPLOYMENT_TARGET = 16.0;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
@@ -383,7 +383,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
- IPHONEOS_DEPLOYMENT_TARGET = 15.0;
+ IPHONEOS_DEPLOYMENT_TARGET = 16.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
VALIDATE_PRODUCT = YES;
diff --git a/ios/CapacitorCordova/CapacitorCordova/Classes/Public/Plugin.swift b/ios/CapacitorCordova/CapacitorCordova/Classes/Public/Plugin.swift
new file mode 100644
index 0000000000..d58c4ca33f
--- /dev/null
+++ b/ios/CapacitorCordova/CapacitorCordova/Classes/Public/Plugin.swift
@@ -0,0 +1,126 @@
+import Capacitor
+
+@objc(CordovaPlugin)
+public class CordovaPlugin: CAPPlugin, CAPBridgedPlugin {
+ public let jsName = "__CordovaPlugin"
+ public let pluginMethods: [CAPPluginMethod] = []
+ public var identifier: String { jsName }
+
+ private var _cordovaDeployDisabled = false
+
+ override public func load() {
+ injectJavascript()
+ configureRuntime()
+ }
+
+ func configureRuntime() {
+ guard let configURL = Bundle.main.url(forResource: "config", withExtension: "xml") else { fatalError() }
+ guard let bridge, let webView = bridge.webView else { return }
+
+ let cordovaConfigParser = CDVConfigParser()
+
+ let xmlParser = XMLParser(contentsOf: configURL)
+ xmlParser?.delegate = cordovaConfigParser
+ xmlParser?.parse()
+
+ guard let pluginManager = CDVPluginManager(
+ parser: cordovaConfigParser,
+ viewController: bridge.viewController,
+ webView: bridge.webView
+ ) else { return }
+
+ for plugin in cordovaConfigParser.startupPluginNames.compactMap({ $0 as? String }) {
+ _ = pluginManager.getCommandInstance(plugin)
+ }
+
+ exportCordovaPluginsJS(userContentController: webView.configuration.userContentController)
+
+ bridge.registerCallInterceptor("cordova") { [pluginManager] dict in
+ let pluginId = dict["service"] as? String ?? ""
+ let method = dict["action"] as? String ?? ""
+ let callbackId = dict["callbackId"] as? String ?? ""
+
+ let args = dict["actionArgs"] as? Array ?? []
+ let options = ["options": args]
+
+ CAPLog.print("To Native Cordova -> ", pluginId, method, callbackId, options)
+
+ if let plugin = pluginManager.getCommandInstance(pluginId.lowercased()) {
+ let selector = NSSelectorFromString("\(method):")
+ if !plugin.responds(to: selector) {
+ CAPLog.print("Error: Plugin \(plugin.className ?? "") does not respond to method call \(selector).")
+ CAPLog.print("Ensure plugin method exists and uses @objc in its declaration")
+ return
+ }
+
+ let arguments = options["options"] ?? []
+ let pluginCall = CDVInvokedUrlCommand(
+ arguments: arguments,
+ callbackId: callbackId,
+ className: plugin.className,
+ methodName: method
+ )
+
+ plugin.perform(selector, with: pluginCall)
+
+ } else {
+ CAPLog.print("Error: Cordova Plugin mapping not found")
+ return
+ }
+ }
+
+ _cordovaDeployDisabled = (cordovaConfigParser.settings?["DisableDeploy".lowercased()] as? NSString)?.boolValue ?? false
+ }
+
+ @objc
+ func cordovaDeployDisabled() -> NSNumber {
+ return _cordovaDeployDisabled as NSNumber
+ }
+
+ func injectJavascript() {
+ guard let cordovaUrl = Bundle.main.url(forResource: "public/cordova", withExtension: "js") else {
+ fatalError("ERROR: Required cordova.js file not found. Cordova plugins will not function!")
+ }
+
+ guard let cordovaPluginsUrl = Bundle.main.url(forResource: "public/cordova_plugins", withExtension: "js") else {
+ fatalError("ERROR: Required cordova_plugins.js file not found. Cordova plugins will not function!")
+ }
+
+ guard let webView = bridge?.webView else { return }
+
+ injectFile(fileURL: cordovaUrl, userContentController: webView.configuration.userContentController)
+ injectFile(fileURL: cordovaPluginsUrl, userContentController: webView.configuration.userContentController)
+ }
+
+ func exportCordovaPluginsJS(userContentController: WKUserContentController) {
+ if let pluginsJSFolder = Bundle.main.url(forResource: "public/plugins", withExtension: nil) {
+ injectFilesForFolder(folder: pluginsJSFolder, userContentController: userContentController)
+ }
+ }
+
+ func injectFile(fileURL: URL, userContentController: WKUserContentController) {
+ do {
+ let data = try String(contentsOf: fileURL, encoding: .utf8)
+ let userScript = WKUserScript(source: data, injectionTime: .atDocumentStart, forMainFrameOnly: true)
+ userContentController.addUserScript(userScript)
+ } catch {
+ fatalError("Unable to inject js file")
+ }
+ }
+
+ func injectFilesForFolder(folder: URL, userContentController: WKUserContentController) {
+ let fileManager = FileManager.default
+ do {
+ let fileURLs = try fileManager.contentsOfDirectory(at: folder, includingPropertiesForKeys: nil, options: [])
+ for fileURL in fileURLs {
+ if fileURL.hasDirectoryPath {
+ injectFilesForFolder(folder: fileURL, userContentController: userContentController)
+ } else {
+ injectFile(fileURL: fileURL, userContentController: userContentController)
+ }
+ }
+ } catch {
+ CAPLog.print("Error while enumerating files")
+ }
+ }
+}
diff --git a/ios/package.json b/ios/package.json
index 74aeb2a2f3..783ccc9c15 100644
--- a/ios/package.json
+++ b/ios/package.json
@@ -1,9 +1,9 @@
{
- "name": "@capacitor-plus/ios",
- "version": "8.3.4",
- "description": "Capacitor+: Enhanced Capacitor with automated upstream sync - Cross-platform apps with JavaScript and the web",
- "homepage": "https://capgo.app/docs/plugins/capacitor-plus/",
- "author": "Capgo Team (https://capgo.app)",
+ "name": "@capacitor/ios",
+ "version": "9.0.0-alpha.5",
+ "description": "Capacitor: Cross-platform apps with JavaScript and the web",
+ "homepage": "https://capacitorjs.com",
+ "author": "Ionic Team (https://ionic.io)",
"license": "MIT",
"repository": {
"type": "git",
@@ -25,8 +25,7 @@
"xc:build:CapacitorCordova": "cd CapacitorCordova && xcodebuild && cd .."
},
"peerDependencies": {
- "@capacitor-plus/core": "^8.3.0",
- "@capacitor/core": "^8.3.0"
+ "@capacitor/core": "^9.0.0-alpha.5"
},
"publishConfig": {
"access": "public"
diff --git a/ios/scripts/pods_helpers.rb b/ios/scripts/pods_helpers.rb
index 7a240db461..42335c2072 100644
--- a/ios/scripts/pods_helpers.rb
+++ b/ios/scripts/pods_helpers.rb
@@ -1,11 +1,11 @@
def assertDeploymentTarget(installer)
installer.pods_project.targets.each do |target|
target.build_configurations.each do |config|
- # ensure IPHONEOS_DEPLOYMENT_TARGET is at least 15.0
+ # ensure IPHONEOS_DEPLOYMENT_TARGET is at least 16.0
deployment_target = config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'].to_f
- should_upgrade = deployment_target < 15.0 && deployment_target != 0.0
+ should_upgrade = deployment_target < 16.0 && deployment_target != 0.0
if should_upgrade
- config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '15.0'
+ config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '16.0'
end
end
end
diff --git a/lerna.json b/lerna.json
index a64c4e93ae..55aa96b3f6 100644
--- a/lerna.json
+++ b/lerna.json
@@ -4,15 +4,12 @@
"hoist": true
},
"version": {
- "allowBranch": [
- "main",
- "plus"
- ],
+ "allowBranch": "next",
"conventionalCommits": true,
"message": "chore(release): %s",
"tagVersionPrefix": ""
}
},
- "version": "8.3.4",
+ "version": "9.0.0-alpha.5",
"$schema": "node_modules/lerna/schemas/lerna-schema.json"
}
diff --git a/scripts/publish-android.sh b/scripts/publish-android.sh
index b9b39c9aa8..58c4ddfb94 100644
--- a/scripts/publish-android.sh
+++ b/scripts/publish-android.sh
@@ -24,7 +24,7 @@ else
printf %"s\n" "Publishing $CAP_VERSION to MavenCentral production..."
# Build and publish
- $DIR/gradlew clean build publishReleasePublicationToSonatypeRepository closeAndReleaseSonatypeStagingRepository --max-workers 1 -b $DIR/capacitor/build.gradle -Pandroid.useAndroidX=true > $LOG_OUTPUT 2>&1
+ $DIR/gradlew :capacitor-android:clean :capacitor-android:build :capacitor-android:publishReleasePublicationToSonatypeRepository closeAndReleaseSonatypeStagingRepository --max-workers 1 -Pandroid.useAndroidX=true > $LOG_OUTPUT 2>&1
echo $RESULT