diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml
index b041f6e067..a2be826965 100644
--- a/.github/ISSUE_TEMPLATE/config.yml
+++ b/.github/ISSUE_TEMPLATE/config.yml
@@ -1,5 +1,8 @@
blank_issues_enabled: false
contact_links:
+ - name: Feature Request
+ url: https://outsystems.canny.io/capacitor-feature-requests
+ about: Request a new feature
- name: ⚙️ Request a new plugin
url: https://github.com/capacitor-community/proposals
about: Propose a new plugin or platform to the Capacitor community
diff --git a/.github/ISSUE_TEMPLATE/feature-request.yml b/.github/ISSUE_TEMPLATE/feature-request.yml
deleted file mode 100644
index fc6d66e90a..0000000000
--- a/.github/ISSUE_TEMPLATE/feature-request.yml
+++ /dev/null
@@ -1,50 +0,0 @@
-name: Feature Request
-description: Request a new feature
-title: "[Feature]: "
-labels: ["triage"]
-body:
- - type: markdown
- attributes:
- value: |
- ## Thanks for your input on enhancements to Capacitor!
- - type: input
- id: Description
- attributes:
- label: Description
- description: "A short description of your requested feature"
- validations:
- required: true
- - type: checkboxes
- id: platforms
- attributes:
- label: Platforms
- description: "Check the platforms that will need this feature"
- options:
- - label: iOS
- required: false
- - label: Android
- required: false
- - label: Web
- required: false
- - type: textarea
- id: requested-feature
- attributes:
- label: Request or proposed solution
- description: "Describe the feature you are looking for in detail and any Preferred Solution you have"
- placeholder: "This new thing would be great!"
- validations:
- required: true
- - type: textarea
- id: alternatives
- attributes:
- label: Alternatives
- description: "Describe some alternatives, if any"
- placeholder: "Some other ideas!"
- validations:
- required: false
- - type: textarea
- id: additional-info
- attributes:
- label: Additional Information
- description: "Anything else we need to know to help? Include it here."
- placeholder: "Tell us anything!"
diff --git a/.github/ionic-issue-bot.yml b/.github/ionic-issue-bot.yml
index fef86a40f0..7adf8c4573 100644
--- a/.github/ionic-issue-bot.yml
+++ b/.github/ionic-issue-bot.yml
@@ -20,7 +20,7 @@ comment:
message: >
This issue needs more information before it can be addressed.
In particular, the reporter needs to provide a minimal sample app that demonstrates the issue.
- If no sample app is provided within 15 days, the issue will be closed.
+ If no sample app is provided within 7 days, the issue will be closed.
Please see the Contributing Guide for [how to create a Sample App](https://github.com/ionic-team/capacitor/blob/HEAD/CONTRIBUTING.md#creating-a-code-reproduction).
diff --git a/.github/workflows/needs-reply.yml b/.github/workflows/needs-reply.yml
new file mode 100644
index 0000000000..c4fd4a7444
--- /dev/null
+++ b/.github/workflows/needs-reply.yml
@@ -0,0 +1,21 @@
+name: Close old issues that need reply
+
+on:
+ schedule:
+ - cron: "0 0 * * *"
+
+jobs:
+ build:
+ runs-on: ubuntu-latest
+ steps:
+ - name: Close old issues that need reply
+ uses: imhoffd/needs-reply@v2
+ with:
+ repo-token: ${{ secrets.BOT_TOKEN }}
+ issue-label: 'needs reply'
+ days-before-close: 7
+ close-message: |
+ It looks like this issue didn't get the information it needed, so I'll close it for now. If I made a mistake, sorry! I am just a bot.
+
+ Have a great day!
+ Ionitron 💙
diff --git a/.github/workflows/publish-ios.yml b/.github/workflows/publish-ios.yml
new file mode 100644
index 0000000000..e5e6447767
--- /dev/null
+++ b/.github/workflows/publish-ios.yml
@@ -0,0 +1,30 @@
+name: Publish Native iOS Library
+
+on:
+ workflow_call:
+ secrets:
+ COCOAPODS_TRUNK_TOKEN:
+ required: true
+ workflow_dispatch:
+
+jobs:
+ publish-ios:
+ runs-on: macos-15
+ timeout-minutes: 30
+ steps:
+ - run: sudo xcode-select --switch /Applications/Xcode_26.0.app
+ - run: xcrun simctl list > /dev/null
+ - run: xcodebuild -downloadPlatform iOS
+ - uses: actions/setup-node@v6
+ with:
+ node-version: 22.x
+ - uses: actions/checkout@v5
+ with:
+ fetch-depth: 0
+ ref: 'main'
+ - name: Install Cocoapods
+ run: gem install cocoapods
+ - name: Deploy to Cocoapods
+ run: sh ./scripts/native-podspec.sh publish
+ env:
+ COCOAPODS_TRUNK_TOKEN: ${{ secrets.COCOAPODS_TRUNK_TOKEN }}
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index 6e88826b57..dc1d09f292 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -25,7 +25,7 @@ jobs:
fi
setup:
runs-on: ubuntu-latest
- timeout-minutes: 30
+ timeout-minutes: 60
steps:
- name: Get Latest
uses: actions/setup-node@v6
@@ -39,7 +39,7 @@ jobs:
key: ${{ runner.OS }}-dependencies-cache-${{ hashFiles('**/package.json') }}
lint:
runs-on: macos-15
- timeout-minutes: 30
+ timeout-minutes: 60
steps:
- uses: actions/setup-node@v6
with:
@@ -55,7 +55,7 @@ jobs:
- run: npm run lint
test-cli:
runs-on: macos-15
- timeout-minutes: 30
+ timeout-minutes: 60
needs:
- setup
- lint
@@ -76,7 +76,7 @@ jobs:
working-directory: ./cli
test-core:
runs-on: ubuntu-latest
- timeout-minutes: 30
+ timeout-minutes: 60
needs:
- setup
- lint
@@ -97,7 +97,7 @@ jobs:
working-directory: ./core
test-ios:
runs-on: macos-15
- timeout-minutes: 30
+ timeout-minutes: 60
needs:
- setup
- lint
@@ -107,6 +107,8 @@ jobs:
- /Applications/Xcode_26.0.app
steps:
- run: sudo xcode-select --switch ${{ matrix.xcode }}
+ - run: xcrun simctl list > /dev/null
+ - run: xcodebuild -downloadPlatform iOS
- uses: actions/setup-node@v6
with:
node-version: 22.x
@@ -123,7 +125,7 @@ jobs:
run: sh ./scripts/native-podspec.sh lint
test-android:
runs-on: ubuntu-latest
- timeout-minutes: 30
+ timeout-minutes: 60
needs:
- setup
- lint
diff --git a/CHANGELOG.md b/CHANGELOG.md
index d83d979b48..036539bc09 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -3,6 +3,7 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
+<<<<<<< HEAD
## [8.0.8](https://github.com/Cap-go/capacitor-plus/compare/8.0.7...8.0.8) (2026-04-08)
@@ -453,6 +454,73 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline
- update sync branches when upstream PRs have new commits ([5f80078](https://github.com/Cap-go/capacitor-plus/commit/5f80078db201099c6bf75b9e40a6efd1c3d8ac46))
- 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))
+=======
+# [8.3.0](https://github.com/ionic-team/capacitor/compare/8.2.0...8.3.0) (2026-03-25)
+
+### Bug Fixes
+
+- **android:** correctly parsing `server.url` when they include paths ([#8391](https://github.com/ionic-team/capacitor/issues/8391)) ([a9f2181](https://github.com/ionic-team/capacitor/commit/a9f218179b60555d86b44bf2b33354da3e64e98c))
+- **cli:** inline CSS sourcemaps in addition to JS sourcemaps ([#8377](https://github.com/ionic-team/capacitor/issues/8377)) ([69476ab](https://github.com/ionic-team/capacitor/commit/69476ab9c0b47911a14d2482cab53a877a5ae784))
+- **http:** handle URL objects on fetch ([#8386](https://github.com/ionic-team/capacitor/issues/8386)) ([003099a](https://github.com/ionic-team/capacitor/commit/003099aef246adfd76d890074d46b1484951824b))
+- **ios:** make getArray accesible on Objective-C plugins ([#8392](https://github.com/ionic-team/capacitor/issues/8392)) ([afb80f2](https://github.com/ionic-team/capacitor/commit/afb80f2fecb4bf85dbebe25e815de2a5564264d6))
+- **SystemBars:** use native safe area insets on Android ([#8384](https://github.com/ionic-team/capacitor/issues/8384)) ([4e99598](https://github.com/ionic-team/capacitor/commit/4e99598a2a57ee97e82be1aaa09492744622fa60))
+
+### Features
+
+- **cli:** Experimental config for swift-tools-version in SPM apps ([#8372](https://github.com/ionic-team/capacitor/issues/8372)) ([d2ee84f](https://github.com/ionic-team/capacitor/commit/d2ee84f8186909b142b418c02fc19f79d3c6a6ed))
+- **cli:** support SPM package traits in generated Package.swift ([#8351](https://github.com/ionic-team/capacitor/issues/8351)) ([27e6aa8](https://github.com/ionic-team/capacitor/commit/27e6aa89cf22e0b1a6d46710faed9aa8899600b0))
+
+# [8.2.0](https://github.com/ionic-team/capacitor/compare/8.1.0...8.2.0) (2026-03-06)
+
+### Bug Fixes
+
+- **android:** Add missing null checks in BridgeActivity ([#8185](https://github.com/ionic-team/capacitor/issues/8185)) ([bd29b99](https://github.com/ionic-team/capacitor/commit/bd29b9913a9279de26fc21c6cb0b93b8f5e5433a))
+- **android:** Concurrent Range Requests for assets ([#8357](https://github.com/ionic-team/capacitor/issues/8357)) ([5e82c89](https://github.com/ionic-team/capacitor/commit/5e82c89f1bff6d0e9ccea2554007aacb920d4c58))
+- **android:** handle lowercase range header ([#8368](https://github.com/ionic-team/capacitor/issues/8368)) ([ae0e2dd](https://github.com/ionic-team/capacitor/commit/ae0e2ddccb2904ee4b3d47d4be1f7556ac7000a1))
+- **android:** invalid http range seeking ([#8369](https://github.com/ionic-team/capacitor/issues/8369)) ([3109d22](https://github.com/ionic-team/capacitor/commit/3109d22547253ed44293777c60652f14cf83e416))
+- **cli:** Allow to run update on non macOS ([#8344](https://github.com/ionic-team/capacitor/issues/8344)) ([a441280](https://github.com/ionic-team/capacitor/commit/a441280d7c6b310ca516d6fb2736c09525987774))
+- **cli:** Don't overwrite config.server section with `--live-reload` ([#7528](https://github.com/ionic-team/capacitor/issues/7528)) ([782b9d9](https://github.com/ionic-team/capacitor/commit/782b9d9c26dcf1282b918996becb0224c0baca1d))
+- **cli:** use 8.0.0 as default Capacitor SPM dependency version ([#8341](https://github.com/ionic-team/capacitor/issues/8341)) ([a55dc5e](https://github.com/ionic-team/capacitor/commit/a55dc5ee4dfeab861cde1e11c9063aefea91006b))
+- **docs:** fix typo in CapApp-SPM README ([#8348](https://github.com/ionic-team/capacitor/issues/8348)) ([7d001ac](https://github.com/ionic-team/capacitor/commit/7d001ac4c58757fba922ea50f5bf5233ce217490))
+- **ios:** remove tmpWindow usages on presentVC/dismissVC ([#8338](https://github.com/ionic-team/capacitor/issues/8338)) ([fc9647f](https://github.com/ionic-team/capacitor/commit/fc9647f26f08ff64f53b32c79fb19f153e3b0a24))
+
+### Features
+
+- **cli:** Add --https option for --live-reload ([#8194](https://github.com/ionic-team/capacitor/issues/8194)) ([5db81e6](https://github.com/ionic-team/capacitor/commit/5db81e68c67652e9d2b29d7ad30629b423d2ad30))
+
+# [8.1.0](https://github.com/ionic-team/capacitor/compare/8.0.2...8.1.0) (2026-02-11)
+
+### Bug Fixes
+
+- **cookies:** only send expires param on web if a date is set ([b10cd7f](https://github.com/ionic-team/capacitor/commit/b10cd7ff15b010a76802374214f4e0cbd04abdab))
+
+### Features
+
+- **cli:** Add packageManager to iOS config ([#8321](https://github.com/ionic-team/capacitor/issues/8321)) ([a125498](https://github.com/ionic-team/capacitor/commit/a1254983bbb9dcb273d93f3c5f639b792e516406))
+
+### Reverts
+
+- revert version bump from [#8319](https://github.com/ionic-team/capacitor/issues/8319) and [#8320](https://github.com/ionic-team/capacitor/issues/8320) ([a48ebb6](https://github.com/ionic-team/capacitor/commit/a48ebb622ea4ebe92927bf1756a4d8ac6012884b))
+
+## [8.0.2](https://github.com/ionic-team/capacitor/compare/8.0.1...8.0.2) (2026-01-27)
+
+### Bug Fixes
+
+- **android:** AGP 9.0 no longer supports `proguard-android.txt` ([#8315](https://github.com/ionic-team/capacitor/issues/8315)) ([dcc76c3](https://github.com/ionic-team/capacitor/commit/dcc76c37508a9b71fb36d95707748c2dd115cf52))
+- **cli:** Update tar package ([#8311](https://github.com/ionic-team/capacitor/issues/8311)) ([0969c5c](https://github.com/ionic-team/capacitor/commit/0969c5cd0b16cf23d2489a85a3b8fa1bee2ebf3b))
+- **core:** make SystemBars hide and show options optional ([#8305](https://github.com/ionic-team/capacitor/issues/8305)) ([95dc7d8](https://github.com/ionic-team/capacitor/commit/95dc7d8ace3aabdda7e325c4a8ef7d1432ad37e9))
+- **SystemBars:** get correct style on handleOnConfigurationChanged ([#8295](https://github.com/ionic-team/capacitor/issues/8295)) ([2a66b44](https://github.com/ionic-team/capacitor/commit/2a66b44915895f971e4a26a8612798aa2f95ea11))
+- **SystemBars:** Set window background color according to theme ([#8306](https://github.com/ionic-team/capacitor/issues/8306)) ([6037e38](https://github.com/ionic-team/capacitor/commit/6037e3836ec24c9ddf26e74e5fbec20ab506adfd))
+- **SystemBars:** Skipping margin manipulation when on a fixed WebView ([#8309](https://github.com/ionic-team/capacitor/issues/8309)) ([53c33b6](https://github.com/ionic-team/capacitor/commit/53c33b614218bf635322fbdf9a38038a7964e3d4))
+
+## [8.0.1](https://github.com/ionic-team/capacitor/compare/8.0.0...8.0.1) (2026-01-13)
+
+### Bug Fixes
+
+- **android:** Remove calculated bottom inset if keyboard is visible ([#8280](https://github.com/ionic-team/capacitor/issues/8280)) ([196b642](https://github.com/ionic-team/capacitor/commit/196b642236d293a5012e3c307fcd942766e56cce))
+- **cli:** Support wireless iOS devices in `cap run` ([#8301](https://github.com/ionic-team/capacitor/issues/8301)) ([dcb368c](https://github.com/ionic-team/capacitor/commit/dcb368c33555487f1b6f46a6d8e30736bdd78955))
+- **cli:** use latest native-run ([#8296](https://github.com/ionic-team/capacitor/issues/8296)) ([121d830](https://github.com/ionic-team/capacitor/commit/121d83013f39e25009121533a2c3ad86e428d6b2))
+>>>>>>> upstream/main
# [8.0.0](https://github.com/ionic-team/capacitor/compare/8.0.0-beta.0...8.0.0) (2025-12-08)
diff --git a/android/CHANGELOG.md b/android/CHANGELOG.md
index c4a1cdd0b2..704d8e1f6a 100644
--- a/android/CHANGELOG.md
+++ b/android/CHANGELOG.md
@@ -3,6 +3,7 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
+<<<<<<< HEAD
## [8.0.8](https://github.com/Cap-go/capacitor-plus/compare/8.0.7...8.0.8) (2026-04-08)
@@ -210,6 +211,45 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline
- 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))
+=======
+# [8.3.0](https://github.com/ionic-team/capacitor/compare/8.2.0...8.3.0) (2026-03-25)
+
+### Bug Fixes
+
+- **android:** correctly parsing `server.url` when they include paths ([#8391](https://github.com/ionic-team/capacitor/issues/8391)) ([a9f2181](https://github.com/ionic-team/capacitor/commit/a9f218179b60555d86b44bf2b33354da3e64e98c))
+- **http:** handle URL objects on fetch ([#8386](https://github.com/ionic-team/capacitor/issues/8386)) ([003099a](https://github.com/ionic-team/capacitor/commit/003099aef246adfd76d890074d46b1484951824b))
+- **SystemBars:** use native safe area insets on Android ([#8384](https://github.com/ionic-team/capacitor/issues/8384)) ([4e99598](https://github.com/ionic-team/capacitor/commit/4e99598a2a57ee97e82be1aaa09492744622fa60))
+
+# [8.2.0](https://github.com/ionic-team/capacitor/compare/8.1.0...8.2.0) (2026-03-06)
+
+### Bug Fixes
+
+- **android:** Add missing null checks in BridgeActivity ([#8185](https://github.com/ionic-team/capacitor/issues/8185)) ([bd29b99](https://github.com/ionic-team/capacitor/commit/bd29b9913a9279de26fc21c6cb0b93b8f5e5433a))
+- **android:** Concurrent Range Requests for assets ([#8357](https://github.com/ionic-team/capacitor/issues/8357)) ([5e82c89](https://github.com/ionic-team/capacitor/commit/5e82c89f1bff6d0e9ccea2554007aacb920d4c58))
+- **android:** handle lowercase range header ([#8368](https://github.com/ionic-team/capacitor/issues/8368)) ([ae0e2dd](https://github.com/ionic-team/capacitor/commit/ae0e2ddccb2904ee4b3d47d4be1f7556ac7000a1))
+- **android:** invalid http range seeking ([#8369](https://github.com/ionic-team/capacitor/issues/8369)) ([3109d22](https://github.com/ionic-team/capacitor/commit/3109d22547253ed44293777c60652f14cf83e416))
+
+# [8.1.0](https://github.com/ionic-team/capacitor/compare/8.0.2...8.1.0) (2026-02-11)
+
+### Reverts
+
+- revert version bump from [#8319](https://github.com/ionic-team/capacitor/issues/8319) and [#8320](https://github.com/ionic-team/capacitor/issues/8320) ([a48ebb6](https://github.com/ionic-team/capacitor/commit/a48ebb622ea4ebe92927bf1756a4d8ac6012884b))
+
+## [8.0.2](https://github.com/ionic-team/capacitor/compare/8.0.1...8.0.2) (2026-01-27)
+
+### Bug Fixes
+
+- **android:** AGP 9.0 no longer supports `proguard-android.txt` ([#8315](https://github.com/ionic-team/capacitor/issues/8315)) ([dcc76c3](https://github.com/ionic-team/capacitor/commit/dcc76c37508a9b71fb36d95707748c2dd115cf52))
+- **SystemBars:** get correct style on handleOnConfigurationChanged ([#8295](https://github.com/ionic-team/capacitor/issues/8295)) ([2a66b44](https://github.com/ionic-team/capacitor/commit/2a66b44915895f971e4a26a8612798aa2f95ea11))
+- **SystemBars:** Set window background color according to theme ([#8306](https://github.com/ionic-team/capacitor/issues/8306)) ([6037e38](https://github.com/ionic-team/capacitor/commit/6037e3836ec24c9ddf26e74e5fbec20ab506adfd))
+- **SystemBars:** Skipping margin manipulation when on a fixed WebView ([#8309](https://github.com/ionic-team/capacitor/issues/8309)) ([53c33b6](https://github.com/ionic-team/capacitor/commit/53c33b614218bf635322fbdf9a38038a7964e3d4))
+
+## [8.0.1](https://github.com/ionic-team/capacitor/compare/8.0.0...8.0.1) (2026-01-13)
+
+### Bug Fixes
+
+- **android:** Remove calculated bottom inset if keyboard is visible ([#8280](https://github.com/ionic-team/capacitor/issues/8280)) ([196b642](https://github.com/ionic-team/capacitor/commit/196b642236d293a5012e3c307fcd942766e56cce))
+>>>>>>> upstream/main
# [8.0.0](https://github.com/ionic-team/capacitor/compare/8.0.0-beta.0...8.0.0) (2025-12-08)
diff --git a/android/capacitor/src/main/assets/native-bridge.js b/android/capacitor/src/main/assets/native-bridge.js
index 40daf2a484..f5e7cc4403 100644
--- a/android/capacitor/src/main/assets/native-bridge.js
+++ b/android/capacitor/src/main/assets/native-bridge.js
@@ -505,6 +505,10 @@ var nativeBridge = (function (exports) {
if (typeof resource === 'string') {
return await win.CapacitorWebFetch(createProxyUrl(resource, win), options);
}
+ else if (resource instanceof URL) {
+ const modifiedURL = new URL(createProxyUrl(resource.toString(), win));
+ return await win.CapacitorWebFetch(modifiedURL, options);
+ }
else if (resource instanceof Request) {
const modifiedRequest = new Request(createProxyUrl(resource.url, win), resource);
return await win.CapacitorWebFetch(modifiedRequest, options);
diff --git a/android/capacitor/src/main/java/com/getcapacitor/Bridge.java b/android/capacitor/src/main/java/com/getcapacitor/Bridge.java
index 2a72a4304a..de1bad88ba 100644
--- a/android/capacitor/src/main/java/com/getcapacitor/Bridge.java
+++ b/android/capacitor/src/main/java/com/getcapacitor/Bridge.java
@@ -628,11 +628,11 @@ private void initWebView() {
try {
URL appUrlObject = new URL(appUrlConfig);
authorities.add(appUrlObject.getAuthority());
+ localUrl = appUrlObject.getProtocol() + "://" + appUrlObject.getAuthority();
} catch (Exception ex) {
Logger.error("Provided server url is invalid: " + ex.getMessage());
return;
}
- localUrl = appUrlConfig;
appUrl = appUrlConfig;
} else {
appUrl = localUrl;
diff --git a/android/capacitor/src/main/java/com/getcapacitor/BridgeActivity.java b/android/capacitor/src/main/java/com/getcapacitor/BridgeActivity.java
index c3779a5488..bfd532c4d2 100644
--- a/android/capacitor/src/main/java/com/getcapacitor/BridgeActivity.java
+++ b/android/capacitor/src/main/java/com/getcapacitor/BridgeActivity.java
@@ -66,7 +66,9 @@ public Bridge getBridge() {
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
- bridge.saveInstanceState(outState);
+ if (bridge != null) {
+ bridge.saveInstanceState(outState);
+ }
}
@Override
@@ -82,8 +84,10 @@ public void onStart() {
@Override
public void onRestart() {
super.onRestart();
- this.bridge.onRestart();
- Logger.debug("App restarted");
+ if (this.bridge != null) {
+ this.bridge.onRestart();
+ Logger.debug("App restarted");
+ }
}
@Override
@@ -131,7 +135,9 @@ public void onDestroy() {
@Override
public void onDetachedFromWindow() {
super.onDetachedFromWindow();
- this.bridge.onDetachedFromWindow();
+ if (this.bridge != null) {
+ this.bridge.onDetachedFromWindow();
+ }
}
/**
diff --git a/android/capacitor/src/main/java/com/getcapacitor/WebViewLocalServer.java b/android/capacitor/src/main/java/com/getcapacitor/WebViewLocalServer.java
index a044bfbe6d..a39483de91 100755
--- a/android/capacitor/src/main/java/com/getcapacitor/WebViewLocalServer.java
+++ b/android/capacitor/src/main/java/com/getcapacitor/WebViewLocalServer.java
@@ -128,9 +128,22 @@ 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);
+ }
}
WebViewLocalServer(Context context, Bridge bridge, JSInjector jsInjector, ArrayList authorities, boolean html5mode) {
@@ -326,14 +339,16 @@ private WebResourceResponse handleCapacitorHttpRequest(WebResourceRequest reques
private WebResourceResponse handleLocalRequest(WebResourceRequest request, PathHandler handler) {
String path = request.getUrl().getPath();
- if (request.getRequestHeaders().get("Range") != null) {
+ Map requestHeaders = request.getRequestHeaders();
+ String rangeString = requestHeaders.get("Range") != null ? requestHeaders.get("Range") : requestHeaders.get("range");
+
+ if (rangeString != null) {
InputStream responseStream = new LollipopLazyInputStream(handler, request);
String mimeType = getMimeType(path, responseStream);
- Map tempResponseHeaders = handler.getResponseHeaders();
+ Map tempResponseHeaders = handler.buildDefaultResponseHeaders();
int statusCode = 206;
try {
int totalRange = responseStream.available();
- String rangeString = request.getRequestHeaders().get("Range");
String[] parts = rangeString.split("=");
String[] streamParts = parts[1].split("-");
String fromRange = streamParts[0];
@@ -365,7 +380,7 @@ private WebResourceResponse handleLocalRequest(WebResourceRequest request, PathH
handler.getEncoding(),
statusCode,
handler.getReasonPhrase(),
- handler.getResponseHeaders(),
+ handler.buildDefaultResponseHeaders(),
responseStream
);
}
@@ -376,7 +391,7 @@ private WebResourceResponse handleLocalRequest(WebResourceRequest request, PathH
handler.getEncoding(),
handler.getStatusCode(),
handler.getReasonPhrase(),
- handler.getResponseHeaders(),
+ handler.buildDefaultResponseHeaders(),
null
);
}
@@ -411,7 +426,7 @@ private WebResourceResponse handleLocalRequest(WebResourceRequest request, PathH
handler.getEncoding(),
statusCode,
handler.getReasonPhrase(),
- handler.getResponseHeaders(),
+ handler.buildDefaultResponseHeaders(),
responseStream
);
}
@@ -442,7 +457,7 @@ private WebResourceResponse handleLocalRequest(WebResourceRequest request, PathH
handler.getEncoding(),
statusCode,
handler.getReasonPhrase(),
- handler.getResponseHeaders(),
+ handler.buildDefaultResponseHeaders(),
responseStream
);
}
@@ -517,7 +532,7 @@ private WebResourceResponse handleProxyRequest(WebResourceRequest request, PathH
handler.getEncoding(),
handler.getStatusCode(),
handler.getReasonPhrase(),
- handler.getResponseHeaders(),
+ handler.buildDefaultResponseHeaders(),
responseStream
);
}
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 affb414a7b..fbfb6b5e21 100644
--- a/android/capacitor/src/main/java/com/getcapacitor/plugin/SystemBars.java
+++ b/android/capacitor/src/main/java/com/getcapacitor/plugin/SystemBars.java
@@ -1,9 +1,12 @@
package com.getcapacitor.plugin;
+import android.content.Context;
+import android.content.pm.PackageInfo;
import android.content.res.Configuration;
+import android.content.res.Resources;
import android.os.Build;
+import android.util.TypedValue;
import android.view.View;
-import android.view.ViewGroup;
import android.view.Window;
import android.webkit.JavascriptInterface;
import android.webkit.WebView;
@@ -12,6 +15,7 @@
import androidx.core.view.WindowCompat;
import androidx.core.view.WindowInsetsCompat;
import androidx.core.view.WindowInsetsControllerCompat;
+import androidx.webkit.WebViewCompat;
import com.getcapacitor.Plugin;
import com.getcapacitor.PluginCall;
import com.getcapacitor.PluginMethod;
@@ -31,6 +35,11 @@ public class SystemBars extends Plugin {
static final String INSETS_HANDLING_CSS = "css";
static final String INSETS_HANDLING_DISABLE = "disable";
+ // https://issues.chromium.org/issues/40699457
+ private static final int WEBVIEW_VERSION_WITH_SAFE_AREA_FIX = 140;
+ // https://issues.chromium.org/issues/457682720
+ private static final int WEBVIEW_VERSION_WITH_SAFE_AREA_KEYBOARD_FIX = 144;
+
static final String viewportMetaJSFunction = """
function capacitorSystemBarsCheckMetaViewport() {
const meta = document.querySelectorAll("meta[name=viewport]");
@@ -47,6 +56,9 @@ function capacitorSystemBarsCheckMetaViewport() {
private boolean insetHandlingEnabled = true;
private boolean hasViewportCover = false;
+ private String currentStatusBarStyle = STYLE_DEFAULT;
+ private String currentGestureBarStyle = STYLE_DEFAULT;
+
@Override
public void load() {
getBridge().getWebView().addJavascriptInterface(this, "CapacitorSystemBarsAndroidInterface");
@@ -73,7 +85,9 @@ public void onPageCommitVisible(WebView view, String url) {
@Override
protected void handleOnConfigurationChanged(Configuration newConfig) {
super.handleOnConfigurationChanged(newConfig);
- setStyle(STYLE_DEFAULT, "");
+
+ setStyle(currentGestureBarStyle, BAR_GESTURE_BAR);
+ setStyle(currentStatusBarStyle, BAR_STATUS_BAR);
}
private void initSystemBars() {
@@ -86,7 +100,7 @@ private void initSystemBars() {
}
initWindowInsetsListener();
- initSafeAreaInsets();
+ initSafeAreaCSSVariables();
getBridge().executeOnMainThread(() -> {
setStyle(style, "");
@@ -143,10 +157,13 @@ public void onDOMReady() {
private Insets calcSafeAreaInsets(WindowInsetsCompat insets) {
Insets safeArea = insets.getInsets(WindowInsetsCompat.Type.systemBars() | WindowInsetsCompat.Type.displayCutout());
+ if (insets.isVisible(WindowInsetsCompat.Type.ime())) {
+ return Insets.of(safeArea.left, safeArea.top, safeArea.right, 0);
+ }
return Insets.of(safeArea.left, safeArea.top, safeArea.right, safeArea.bottom);
}
- private void initSafeAreaInsets() {
+ 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);
@@ -158,37 +175,57 @@ private void initSafeAreaInsets() {
}
private void initWindowInsetsListener() {
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.VANILLA_ICE_CREAM && insetHandlingEnabled) {
- ViewCompat.setOnApplyWindowInsetsListener((View) getBridge().getWebView().getParent(), (v, insets) -> {
- if (hasViewportCover) {
- Insets safeAreaInsets = calcSafeAreaInsets(insets);
- boolean keyboardVisible = insets.isVisible(WindowInsetsCompat.Type.ime());
+ ViewCompat.setOnApplyWindowInsetsListener((View) getBridge().getWebView().getParent(), (v, insets) -> {
+ boolean shouldPassthroughInsets = getWebViewMajorVersion() >= WEBVIEW_VERSION_WITH_SAFE_AREA_FIX && hasViewportCover;
- if (keyboardVisible) {
- safeAreaInsets = Insets.of(safeAreaInsets.left, safeAreaInsets.top, safeAreaInsets.right, 0);
+ Insets systemBarsInsets = insets.getInsets(WindowInsetsCompat.Type.systemBars() | WindowInsetsCompat.Type.displayCutout());
+ Insets imeInsets = insets.getInsets(WindowInsetsCompat.Type.ime());
+ boolean keyboardVisible = insets.isVisible(WindowInsetsCompat.Type.ime());
- Insets imeInsets = insets.getInsets(WindowInsetsCompat.Type.ime());
- setViewMargins(v, Insets.of(0, 0, 0, imeInsets.bottom));
- } else {
- setViewMargins(v, Insets.NONE);
- }
+ if (shouldPassthroughInsets) {
+ // 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);
- return WindowInsetsCompat.CONSUMED;
}
- return insets;
- });
- }
- }
+ return new WindowInsetsCompat.Builder(insets)
+ .setInsets(
+ WindowInsetsCompat.Type.systemBars() | WindowInsetsCompat.Type.displayCutout(),
+ Insets.of(
+ systemBarsInsets.left,
+ systemBarsInsets.top,
+ systemBarsInsets.right,
+ getBottomInset(systemBarsInsets, keyboardVisible)
+ )
+ )
+ .build();
+ }
- private void setViewMargins(View v, Insets insets) {
- ViewGroup.MarginLayoutParams mlp = (ViewGroup.MarginLayoutParams) v.getLayoutParams();
- mlp.leftMargin = insets.left;
- mlp.bottomMargin = insets.bottom;
- mlp.rightMargin = insets.right;
- mlp.topMargin = insets.top;
- v.setLayoutParams(mlp);
+ // We need to correct for a possible shown IME
+ v.setPadding(
+ systemBarsInsets.left,
+ systemBarsInsets.top,
+ systemBarsInsets.right,
+ keyboardVisible ? imeInsets.bottom : systemBarsInsets.bottom
+ );
+
+ // Returning `WindowInsetsCompat.CONSUMED` breaks recalculation of safe area insets
+ // So we have to explicitly set insets to `0`
+ // See: https://issues.chromium.org/issues/461332423
+ WindowInsetsCompat newInsets = new WindowInsetsCompat.Builder(insets)
+ .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);
+ }
+
+ return newInsets;
+ });
}
private void injectSafeAreaCSS(int top, int right, int bottom, int left) {
@@ -231,12 +268,16 @@ private void setStyle(String style, String bar) {
Window window = getActivity().getWindow();
WindowInsetsControllerCompat windowInsetsControllerCompat = WindowCompat.getInsetsController(window, window.getDecorView());
if (bar.isEmpty() || bar.equals(BAR_STATUS_BAR)) {
+ currentStatusBarStyle = style;
windowInsetsControllerCompat.setAppearanceLightStatusBars(!style.equals(STYLE_DARK));
}
if (bar.isEmpty() || bar.equals(BAR_GESTURE_BAR)) {
+ currentGestureBarStyle = style;
windowInsetsControllerCompat.setAppearanceLightNavigationBars(!style.equals(STYLE_DARK));
}
+
+ getActivity().getWindow().getDecorView().setBackgroundColor(getThemeColor(getContext(), android.R.attr.windowBackground));
}
private void setHidden(boolean hide, String bar) {
@@ -268,4 +309,36 @@ private String getStyleForTheme() {
}
return STYLE_DARK;
}
+
+ public int getThemeColor(Context context, int attrRes) {
+ TypedValue typedValue = new TypedValue();
+
+ Resources.Theme theme = context.getTheme();
+ theme.resolveAttribute(attrRes, typedValue, true);
+ return typedValue.data;
+ }
+
+ private Integer getWebViewMajorVersion() {
+ PackageInfo info = WebViewCompat.getCurrentWebViewPackage(getContext());
+ if (info != null && info.versionName != null) {
+ String[] versionSegments = info.versionName.split("\\.");
+ return Integer.valueOf(versionSegments[0]);
+ }
+
+ return 0;
+ }
+
+ private int getBottomInset(Insets systemBarsInsets, boolean keyboardVisible) {
+ if (getWebViewMajorVersion() < WEBVIEW_VERSION_WITH_SAFE_AREA_KEYBOARD_FIX) {
+ // This is a workaround for webview versions that have a bug
+ // that causes the bottom inset to be incorrect if the IME is visible
+ // See: https://issues.chromium.org/issues/457682720
+
+ if (keyboardVisible) {
+ return 0;
+ }
+ }
+
+ return systemBarsInsets.bottom;
+ }
}
diff --git a/android/package.json b/android/package.json
index ed0e3c097f..54c7240108 100644
--- a/android/package.json
+++ b/android/package.json
@@ -1,9 +1,17 @@
{
+<<<<<<< HEAD
"name": "@capacitor-plus/android",
"version": "8.0.8",
"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": "8.3.0",
+ "description": "Capacitor: Cross-platform apps with JavaScript and the web",
+ "homepage": "https://capacitorjs.com",
+ "author": "Ionic Team (https://ionic.io)",
+>>>>>>> upstream/main
"license": "MIT",
"repository": {
"type": "git",
@@ -23,8 +31,12 @@
"verify": "./gradlew clean lint build test -b capacitor/build.gradle"
},
"peerDependencies": {
+<<<<<<< HEAD
"@capacitor-plus/core": "^8.0.0",
"@capacitor/core": "^8.0.0"
+=======
+ "@capacitor/core": "^8.3.0"
+>>>>>>> upstream/main
},
"publishConfig": {
"access": "public"
diff --git a/cli/CHANGELOG.md b/cli/CHANGELOG.md
index de8843a888..9ffff28fb2 100644
--- a/cli/CHANGELOG.md
+++ b/cli/CHANGELOG.md
@@ -3,6 +3,7 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
+<<<<<<< HEAD
## [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
@@ -230,6 +231,53 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline
- 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))
+=======
+# [8.3.0](https://github.com/ionic-team/capacitor/compare/8.2.0...8.3.0) (2026-03-25)
+
+### Bug Fixes
+
+- **cli:** inline CSS sourcemaps in addition to JS sourcemaps ([#8377](https://github.com/ionic-team/capacitor/issues/8377)) ([69476ab](https://github.com/ionic-team/capacitor/commit/69476ab9c0b47911a14d2482cab53a877a5ae784))
+- **SystemBars:** use native safe area insets on Android ([#8384](https://github.com/ionic-team/capacitor/issues/8384)) ([4e99598](https://github.com/ionic-team/capacitor/commit/4e99598a2a57ee97e82be1aaa09492744622fa60))
+
+### Features
+
+- **cli:** Experimental config for swift-tools-version in SPM apps ([#8372](https://github.com/ionic-team/capacitor/issues/8372)) ([d2ee84f](https://github.com/ionic-team/capacitor/commit/d2ee84f8186909b142b418c02fc19f79d3c6a6ed))
+- **cli:** support SPM package traits in generated Package.swift ([#8351](https://github.com/ionic-team/capacitor/issues/8351)) ([27e6aa8](https://github.com/ionic-team/capacitor/commit/27e6aa89cf22e0b1a6d46710faed9aa8899600b0))
+
+# [8.2.0](https://github.com/ionic-team/capacitor/compare/8.1.0...8.2.0) (2026-03-06)
+
+### Bug Fixes
+
+- **cli:** Allow to run update on non macOS ([#8344](https://github.com/ionic-team/capacitor/issues/8344)) ([a441280](https://github.com/ionic-team/capacitor/commit/a441280d7c6b310ca516d6fb2736c09525987774))
+- **cli:** Don't overwrite config.server section with `--live-reload` ([#7528](https://github.com/ionic-team/capacitor/issues/7528)) ([782b9d9](https://github.com/ionic-team/capacitor/commit/782b9d9c26dcf1282b918996becb0224c0baca1d))
+
+### Features
+
+- **cli:** Add --https option for --live-reload ([#8194](https://github.com/ionic-team/capacitor/issues/8194)) ([5db81e6](https://github.com/ionic-team/capacitor/commit/5db81e68c67652e9d2b29d7ad30629b423d2ad30))
+
+# [8.1.0](https://github.com/ionic-team/capacitor/compare/8.0.2...8.1.0) (2026-02-11)
+
+### Features
+
+- **cli:** Add packageManager to iOS config ([#8321](https://github.com/ionic-team/capacitor/issues/8321)) ([a125498](https://github.com/ionic-team/capacitor/commit/a1254983bbb9dcb273d93f3c5f639b792e516406))
+
+### Reverts
+
+- revert version bump from [#8319](https://github.com/ionic-team/capacitor/issues/8319) and [#8320](https://github.com/ionic-team/capacitor/issues/8320) ([a48ebb6](https://github.com/ionic-team/capacitor/commit/a48ebb622ea4ebe92927bf1756a4d8ac6012884b))
+
+## [8.0.2](https://github.com/ionic-team/capacitor/compare/8.0.1...8.0.2) (2026-01-27)
+
+### Bug Fixes
+
+- **cli:** Update tar package ([#8311](https://github.com/ionic-team/capacitor/issues/8311)) ([0969c5c](https://github.com/ionic-team/capacitor/commit/0969c5cd0b16cf23d2489a85a3b8fa1bee2ebf3b))
+
+## [8.0.1](https://github.com/ionic-team/capacitor/compare/8.0.0...8.0.1) (2026-01-13)
+
+### Bug Fixes
+
+- **cli:** Support wireless iOS devices in `cap run` ([#8301](https://github.com/ionic-team/capacitor/issues/8301)) ([dcb368c](https://github.com/ionic-team/capacitor/commit/dcb368c33555487f1b6f46a6d8e30736bdd78955))
+- **cli:** use latest native-run ([#8296](https://github.com/ionic-team/capacitor/issues/8296)) ([121d830](https://github.com/ionic-team/capacitor/commit/121d83013f39e25009121533a2c3ad86e428d6b2))
+>>>>>>> upstream/main
# [8.0.0](https://github.com/ionic-team/capacitor/compare/8.0.0-beta.0...8.0.0) (2025-12-08)
diff --git a/cli/package.json b/cli/package.json
index 30862c5d48..2f649d7692 100644
--- a/cli/package.json
+++ b/cli/package.json
@@ -1,9 +1,17 @@
{
+<<<<<<< HEAD
"name": "@capacitor-plus/cli",
"version": "8.0.8",
"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": "8.3.0",
+ "description": "Capacitor: Cross-platform apps with JavaScript and the web",
+ "homepage": "https://capacitorjs.com",
+ "author": "Ionic Team (https://ionic.io)",
+>>>>>>> upstream/main
"license": "MIT",
"repository": {
"type": "git",
@@ -58,7 +66,7 @@
"prompts": "^2.4.2",
"rimraf": "^6.0.1",
"semver": "^7.6.3",
- "tar": "^6.1.11",
+ "tar": "^7.5.3",
"tslib": "^2.8.1",
"xml2js": "^0.6.2"
},
@@ -69,7 +77,6 @@
"@types/plist": "^3.0.5",
"@types/prompts": "^2.4.9",
"@types/semver": "^7.5.8",
- "@types/tar": "^6.1.1",
"@types/tmp": "^0.2.6",
"@types/xml2js": "0.4.5",
"jest": "^29.7.0",
diff --git a/cli/src/config.ts b/cli/src/config.ts
index c6800dd936..0ce16244a7 100644
--- a/cli/src/config.ts
+++ b/cli/src/config.ts
@@ -1,5 +1,5 @@
import Debug from 'debug';
-import { pathExists, readFile, readJSON, writeFile, writeJSON } from 'fs-extra';
+import { existsSync, pathExists, readFile, readJSON, writeFile, writeJSON } from 'fs-extra';
import { dirname, extname, join, relative, resolve } from 'path';
import c from './colors';
@@ -13,6 +13,7 @@ import type {
IOSConfig,
WebConfig,
XcodeExportMethod,
+ PackageManager,
} from './definitions';
import { OS } from './definitions';
import { fatal, isFatal } from './errors';
@@ -22,7 +23,7 @@ import { formatJSObject } from './util/js';
import { findNXMonorepoRoot, isNXMonorepo } from './util/monorepotools';
import { requireTS, resolveNode } from './util/node';
import { lazy } from './util/promise';
-import { getCommandOutput } from './util/subprocess';
+import { getCommandOutput, isInstalled } from './util/subprocess';
const debug = Debug('capacitor:config');
@@ -273,7 +274,8 @@ async function loadIOSConfig(rootDir: string, extConfig: ExternalConfig): Promis
const nativeXcodeProjDir = `${nativeProjectDir}/App.xcodeproj`;
const nativeXcodeProjDirAbs = resolve(platformDirAbs, nativeXcodeProjDir);
const nativeXcodeWorkspaceDirAbs = lazy(() => determineXcodeWorkspaceDirAbs(nativeProjectDirAbs));
- const podPath = lazy(() => determineGemfileOrCocoapodPath(rootDir, platformDirAbs, nativeProjectDirAbs));
+ const podPath = lazy(() => determineCocoapodPath());
+ const packageManager = lazy(() => determinePackageManager(rootDir, platformDirAbs, nativeProjectDirAbs));
const webDirAbs = lazy(() => determineIOSWebDirAbs(nativeProjectDirAbs, nativeTargetDirAbs, nativeXcodeProjDirAbs));
const cordovaPluginsDir = 'capacitor-cordova-ios-plugins';
const buildOptions = {
@@ -301,6 +303,7 @@ async function loadIOSConfig(rootDir: string, extConfig: ExternalConfig): Promis
webDir: lazy(async () => relative(platformDirAbs, await webDirAbs)),
webDirAbs,
podPath,
+ packageManager,
buildOptions,
};
}
@@ -415,13 +418,24 @@ async function determineAndroidStudioPath(os: OS): Promise {
return '';
}
-async function determineGemfileOrCocoapodPath(
+async function determineCocoapodPath(): Promise {
+ if (process.env.CAPACITOR_COCOAPODS_PATH) {
+ return process.env.CAPACITOR_COCOAPODS_PATH;
+ }
+ return 'pod';
+}
+
+async function determinePackageManager(
rootDir: string,
platformDir: any,
nativeProjectDirAbs: string,
-): Promise {
+): Promise {
+ if (existsSync(resolve(nativeProjectDirAbs, 'CapApp-SPM'))) {
+ return 'SPM';
+ }
+
if (process.env.CAPACITOR_COCOAPODS_PATH) {
- return process.env.CAPACITOR_COCOAPODS_PATH;
+ return 'Cocoapods';
}
let gemfilePath = '';
@@ -450,17 +464,17 @@ async function determineGemfileOrCocoapodPath(
try {
const gemfileText = (await readFile(gemfilePath)).toString();
if (!gemfileText) {
- return 'pod';
+ return 'Cocoapods';
}
const cocoapodsInGemfile = new RegExp(/gem\s+['"]cocoapods/).test(gemfileText);
- if (cocoapodsInGemfile) {
- return 'bundle exec pod';
+ if (cocoapodsInGemfile && (await isInstalled('bundle'))) {
+ return 'bundler';
} else {
- return 'pod';
+ return 'Cocoapods';
}
} catch {
- return 'pod';
+ return 'Cocoapods';
}
}
diff --git a/cli/src/declarations.ts b/cli/src/declarations.ts
index 6612eec777..6c8645406d 100644
--- a/cli/src/declarations.ts
+++ b/cli/src/declarations.ts
@@ -509,6 +509,60 @@ export interface CapacitorConfig {
};
};
+ experimental?: {
+ /**
+ * Experimental iOS-specific configuration.
+ *
+ * These options may change or be removed in future versions.
+ *
+ * @since 8.2.0
+ */
+ ios?: {
+ /**
+ * Swift Package Manager (SPM) specific configuration.
+ *
+ * @since 8.2.0
+ */
+ spm?: {
+ /**
+ * Swift tools version to use in Package.swift header.
+ *
+ * Defines the minimum version of the Swift compiler version required to build your app.
+ * For more information check the [swift documentation](https://docs.swift.org/swiftpm/documentation/packagemanagerdocs/settingswifttoolsversion/)
+ *
+ * Warning: Capacitor does not officially support Swift 6 yet.
+ * Setting this property to 6.0 or higher may cause issues.
+ * If you need to set this property to 6.0 or higher, make sure to throughrouly test your iOS app.
+ *
+ * This setting may graduate to `ios.spm.swiftToolsVersion` in a future major release.
+ *
+ * @since 8.3.0
+ * @default '5.9'
+ * @example '6.1'
+ */
+ swiftToolsVersion?: string;
+
+ /**
+ * Define package traits for SPM plugin dependencies.
+ *
+ * This requires explicitly setting experimental.ios.spm.swiftToolsVersion
+ * to '6.1' or higher.
+ *
+ * The key is the plugin ID (e.g. `@capacitor-firebase/analytics`)
+ * and the value is an array of trait names.
+ *
+ * Packages can have default traits. If you use this property, and
+ * want to preserve the defaults, include ".defaults" in the array.
+ *
+ * This setting may graduate to `ios.spm.packageTraits` in a future major release.
+ *
+ * @since 8.3.0
+ */
+ packageTraits?: { [pluginId: string]: string[] };
+ };
+ };
+ };
+
server?: {
/**
* Configure the local hostname of the device.
@@ -713,7 +767,7 @@ export interface PluginsConfig {
*
* `css` = Injects CSS variables (`--safe-area-inset-*`) containing correct safe area inset values into the webview.
*
- * `disable` = Disable all inset handling.
+ * `disable` = Disable CSS variables injection.
*
* @default "css"
*/
diff --git a/cli/src/definitions.ts b/cli/src/definitions.ts
index 893a9d0300..2df6398e97 100644
--- a/cli/src/definitions.ts
+++ b/cli/src/definitions.ts
@@ -3,6 +3,7 @@ import type { CapacitorConfig, PluginsConfig } from './declarations';
type DeepReadonly = { readonly [P in keyof T]: DeepReadonly };
export type ExternalConfig = DeepReadonly;
+export type Writable = T extends object ? { -readonly [K in keyof T]: Writable } : T;
export const enum OS {
Unknown = 'unknown',
@@ -11,6 +12,8 @@ export const enum OS {
Linux = 'linux',
}
+export type PackageManager = 'Cocoapods' | 'bundler' | 'SPM';
+
export interface PackageJson {
readonly name: string;
readonly version: string;
@@ -116,6 +119,7 @@ export interface IOSConfig extends PlatformConfig {
readonly cordovaPluginsDirAbs: string;
readonly minVersion: string;
readonly podPath: Promise;
+ readonly packageManager: Promise;
readonly scheme: string;
readonly webDir: Promise;
readonly webDirAbs: Promise;
diff --git a/cli/src/index.ts b/cli/src/index.ts
index 999fb0c1af..fb70e1039b 100644
--- a/cli/src/index.ts
+++ b/cli/src/index.ts
@@ -3,7 +3,7 @@ import { resolve } from 'path';
import c from './colors';
import { loadConfig } from './config';
-import type { Config } from './definitions';
+import type { Config, PackageManager, Writable } from './definitions';
import { fatal, isFatal } from './errors';
import { receive } from './ipc';
import { logger, output } from './log';
@@ -11,8 +11,6 @@ import { telemetryAction } from './telemetry';
import { wrapAction } from './util/cli';
import { emoji as _e } from './util/emoji';
-type Writable = T extends object ? { -readonly [K in keyof T]: Writable } : T;
-
process.on('unhandledRejection', (error) => {
console.error(c.failure('[fatal]'), error);
});
@@ -29,6 +27,16 @@ export async function run(): Promise {
}
}
+async function getPackageManager(config: Config, packageManager: any): Promise {
+ if (packageManager === 'cocoapods') {
+ if ((await config.ios.packageManager) === 'bundler') {
+ return 'bundler';
+ }
+ return 'Cocoapods';
+ }
+ return 'SPM';
+}
+
export function runProgram(config: Config): void {
program.version(config.cli.package.version);
@@ -241,10 +249,11 @@ 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', 'Enable Live Reload')
- .option('--host ', 'Host used for live reload')
- .option('--port ', 'Port used for live reload')
+ .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('--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(
@@ -265,6 +274,7 @@ export function runProgram(config: Config): void {
host,
port,
configuration,
+ https,
},
) => {
const { runCommand } = await import('./tasks/run');
@@ -282,6 +292,7 @@ export function runProgram(config: Config): void {
host,
port,
configuration,
+ https,
});
},
),
@@ -313,6 +324,7 @@ export function runProgram(config: Config): void {
const { addCommand } = await import('./tasks/add');
const configWritable: Writable = config as Writable;
+ configWritable.ios.packageManager = getPackageManager(config, packagemanager?.toLowerCase());
if (packagemanager?.toLowerCase() === 'CocoaPods'.toLowerCase()) {
configWritable.cli.assets.ios.platformTemplateArchive = 'ios-pods-template.tar.gz';
configWritable.cli.assets.ios.platformTemplateArchiveAbs = resolve(
diff --git a/cli/src/ios/build.ts b/cli/src/ios/build.ts
index 982e30c337..83485f913a 100644
--- a/cli/src/ios/build.ts
+++ b/cli/src/ios/build.ts
@@ -6,18 +6,15 @@ import { runTask } from '../common';
import { XcodeExportMethod, type Config } from '../definitions';
import { logSuccess } from '../log';
import { type BuildCommandOptions } from '../tasks/build';
-import { checkPackageManager } from '../util/spm';
import { runCommand } from '../util/subprocess';
export async function buildiOS(config: Config, buildOptions: BuildCommandOptions): Promise {
const theScheme = buildOptions.scheme ?? 'App';
- const packageManager = await checkPackageManager(config);
-
let typeOfBuild: string;
let projectName: string;
- if (packageManager == 'Cocoapods') {
+ if ((await config.ios.packageManager) !== 'SPM') {
typeOfBuild = '-workspace';
projectName = basename(await config.ios.nativeXcodeWorkspaceDirAbs);
} else {
diff --git a/cli/src/ios/common.ts b/cli/src/ios/common.ts
index 5e805ffeec..701e4a0500 100644
--- a/cli/src/ios/common.ts
+++ b/cli/src/ios/common.ts
@@ -4,12 +4,14 @@ import { join, resolve } from 'path';
import c from '../colors';
import { checkCapacitorPlatform } from '../common';
+import type { CheckFunction } from '../common';
import { getIncompatibleCordovaPlugins } from '../cordova';
import { OS } from '../definitions';
import type { Config } from '../definitions';
import { logger } from '../log';
import { PluginType, getPluginPlatform } from '../plugin';
import type { Plugin } from '../plugin';
+import { checkPackageTraitsRequirements, checkSwiftToolsVersion } from '../util/spm';
import { isInstalled, runCommand } from '../util/subprocess';
export async function checkIOSPackage(config: Config): Promise {
@@ -25,6 +27,22 @@ function execBundler() {
}
}
+export async function getCommonChecks(config: Config): Promise {
+ const checks: CheckFunction[] = [];
+ if ((await config.ios.packageManager) === 'bundler') {
+ checks.push(() => checkBundler(config));
+ } else if ((await config.ios.packageManager) === 'Cocoapods') {
+ checks.push(() => checkCocoaPods(config));
+ } else if ((await config.ios.packageManager) === 'SPM') {
+ const swiftToolsVersion = config.app.extConfig.experimental?.ios?.spm?.swiftToolsVersion;
+ if (swiftToolsVersion) {
+ checks.push(() => checkSwiftToolsVersion(config, swiftToolsVersion));
+ }
+ checks.push(() => checkPackageTraitsRequirements(config));
+ }
+ return checks;
+}
+
export async function checkBundler(config: Config): Promise {
if (config.cli.os === OS.Mac) {
let bundlerResult = execBundler();
diff --git a/cli/src/ios/doctor.ts b/cli/src/ios/doctor.ts
index 77d9b8b175..87bb3911f5 100644
--- a/cli/src/ios/doctor.ts
+++ b/cli/src/ios/doctor.ts
@@ -4,7 +4,7 @@ import { fatal } from '../errors';
import { logSuccess } from '../log';
import { isInstalled } from '../util/subprocess';
-import { checkBundler, checkCocoaPods } from './common';
+import { getCommonChecks } from './common';
export async function doctorIOS(config: Config): Promise {
// DOCTOR ideas for iOS:
@@ -19,7 +19,7 @@ export async function doctorIOS(config: Config): Promise {
// check online datebase of common errors
// check if www folder is empty (index.html does not exist)
try {
- await check([() => checkBundler(config) || checkCocoaPods(config), () => checkWebDir(config), checkXcode]);
+ await check([() => checkWebDir(config), checkXcode, ...(await getCommonChecks(config))]);
logSuccess('iOS looking great! 👌');
} catch (e: any) {
fatal(e.stack ?? e);
diff --git a/cli/src/ios/open.ts b/cli/src/ios/open.ts
index ea115ca0f2..3652b9eeac 100644
--- a/cli/src/ios/open.ts
+++ b/cli/src/ios/open.ts
@@ -2,10 +2,9 @@ import open from 'open';
import { wait } from '../common';
import type { Config } from '../definitions';
-import { checkPackageManager } from '../util/spm';
export async function openIOS(config: Config): Promise {
- if ((await checkPackageManager(config)) == 'SPM') {
+ if ((await config.ios.packageManager) == 'SPM') {
await open(config.ios.nativeXcodeProjDirAbs, { wait: false });
} else {
await open(await config.ios.nativeXcodeWorkspaceDirAbs, { wait: false });
diff --git a/cli/src/ios/run.ts b/cli/src/ios/run.ts
index 13a031f395..d893f8cf1e 100644
--- a/cli/src/ios/run.ts
+++ b/cli/src/ios/run.ts
@@ -6,7 +6,6 @@ import { promptForPlatformTarget, runTask } from '../common';
import type { Config } from '../definitions';
import type { RunCommandOptions } from '../tasks/run';
import { runNativeRun, getPlatformTargets } from '../util/native-run';
-import { checkPackageManager } from '../util/spm';
import { runCommand } from '../util/subprocess';
const debug = Debug('capacitor:ios:run');
@@ -33,12 +32,12 @@ export async function runIOS(
const derivedDataPath = resolve(config.ios.platformDirAbs, 'DerivedData', target.id);
- const packageManager = await checkPackageManager(config);
+ const packageManager = await config.ios.packageManager;
let typeOfBuild: string;
let projectName: string;
- if (packageManager == 'Cocoapods') {
+ if (packageManager !== 'SPM') {
typeOfBuild = '-workspace';
projectName = basename(await config.ios.nativeXcodeWorkspaceDirAbs);
} else {
diff --git a/cli/src/ios/update.ts b/cli/src/ios/update.ts
index 3fbc6472d6..9d3c1b2335 100644
--- a/cli/src/ios/update.ts
+++ b/cli/src/ios/update.ts
@@ -21,7 +21,7 @@ import { copy as copyTask } from '../tasks/copy';
import { convertToUnixPath } from '../util/fs';
import { generateIOSPackageJSON } from '../util/iosplugin';
import { resolveNode } from '../util/node';
-import { checkPackageManager, generatePackageFile, checkPluginsForPackageSwift } from '../util/spm';
+import { generatePackageFile, checkPluginsForPackageSwift } from '../util/spm';
import { runCommand, isInstalled } from '../util/subprocess';
import { extractTemplate } from '../util/template';
@@ -51,7 +51,7 @@ async function updatePluginFiles(config: Config, plugins: Plugin[], deployment:
}
await handleCordovaPluginsJS(cordovaPlugins, config, platform);
await checkPluginDependencies(plugins, platform, config.app.extConfig.cordova?.failOnUninstalledPlugins);
- if ((await checkPackageManager(config)) === 'SPM') {
+ if ((await config.ios.packageManager) === 'SPM') {
await generateCordovaPackageFiles(cordovaPlugins, config);
const validSPMPackages = await checkPluginsForPackageSwift(config, plugins);
@@ -131,18 +131,15 @@ async function updatePodfile(config: Config, plugins: Plugin[], deployment: bool
await writeFile(podfilePath, podfileContent, { encoding: 'utf-8' });
const podPath = await config.ios.podPath;
- const useBundler = podPath.startsWith('bundle') && (await isInstalled('bundle'));
- const podCommandExists = await isInstalled('pod');
- if (useBundler || podCommandExists) {
- if (useBundler) {
- await runCommand('bundle', ['exec', 'pod', 'install', ...(deployment ? ['--deployment'] : [])], {
- cwd: config.ios.nativeProjectDirAbs,
- });
- } else {
- await runCommand(podPath, ['install', ...(deployment ? ['--deployment'] : [])], {
- cwd: config.ios.nativeProjectDirAbs,
- });
- }
+ const useBundler = (await config.ios.packageManager) === 'bundler';
+ if (useBundler) {
+ await runCommand('bundle', ['exec', 'pod', 'install', ...(deployment ? ['--deployment'] : [])], {
+ cwd: config.ios.nativeProjectDirAbs,
+ });
+ } else if (await isInstalled('pod')) {
+ await runCommand(podPath, ['install', ...(deployment ? ['--deployment'] : [])], {
+ cwd: config.ios.nativeProjectDirAbs,
+ });
} else {
logger.warn('Skipping pod install because CocoaPods is not installed');
}
diff --git a/cli/src/tasks/add.ts b/cli/src/tasks/add.ts
index f849132bf4..f45b0c363c 100644
--- a/cli/src/tasks/add.ts
+++ b/cli/src/tasks/add.ts
@@ -22,7 +22,7 @@ import type { CheckFunction } from '../common';
import type { Config } from '../definitions';
import { fatal, isFatal } from '../errors';
import { addIOS } from '../ios/add';
-import { editProjectSettingsIOS, checkBundler, checkCocoaPods, checkIOSPackage } from '../ios/common';
+import { editProjectSettingsIOS, checkIOSPackage, getCommonChecks } from '../ios/common';
import { logger, logSuccess, output } from '../log';
import { sync } from './sync';
@@ -75,7 +75,7 @@ export async function addCommand(config: Config, selectedPlatformName: string):
}
try {
- await check([() => checkPackage(), () => checkAppConfig(config), ...addChecks(config, platformName)]);
+ await check([() => checkPackage(), () => checkAppConfig(config), ...(await getAddChecks(config, platformName))]);
await doAdd(config, platformName);
await editPlatforms(config, platformName);
@@ -110,9 +110,9 @@ function printNextSteps(platformName: string) {
);
}
-function addChecks(config: Config, platformName: string): CheckFunction[] {
+async function getAddChecks(config: Config, platformName: string): Promise {
if (platformName === config.ios.name) {
- return [() => checkIOSPackage(config), () => checkBundler(config) || checkCocoaPods(config)];
+ return [() => checkIOSPackage(config), ...(await getCommonChecks(config))];
} else if (platformName === config.android.name) {
return [() => checkAndroidPackage(config)];
} else if (platformName === config.web.name) {
diff --git a/cli/src/tasks/migrate-spm.ts b/cli/src/tasks/migrate-spm.ts
index f59a069a2b..a99f5cb591 100644
--- a/cli/src/tasks/migrate-spm.ts
+++ b/cli/src/tasks/migrate-spm.ts
@@ -1,8 +1,9 @@
-import type { Config } from '../definitions';
+import { check } from '../common';
+import type { Config, Writable } from '../definitions';
import { fatal } from '../errors';
+import { getCommonChecks } from '../ios/common';
import { logger } from '../log';
import {
- checkPackageManager,
extractSPMPackageDirectory,
removeCocoapodsFiles,
runCocoapodsDeintegrate,
@@ -12,16 +13,17 @@ import {
import { update } from './update';
export async function migrateToSPM(config: Config): Promise {
- if ((await checkPackageManager(config)) == 'SPM') {
+ if ((await config.ios.packageManager) == 'SPM') {
fatal('Capacitor project is already using SPM, exiting.');
}
-
+ await check(await getCommonChecks(config));
await extractSPMPackageDirectory(config);
await runCocoapodsDeintegrate(config);
await removeCocoapodsFiles(config);
await addInfoPlistDebugIfNeeded(config);
- await update(config, 'ios', true);
-
+ const configWritable: Writable = config as Writable;
+ configWritable.ios.packageManager = Promise.resolve('SPM');
+ await update(configWritable as Config, 'ios', false);
logger.info(
'To complete migration follow the manual steps at https://capacitorjs.com/docs/ios/spm#using-our-migration-tool',
);
diff --git a/cli/src/tasks/migrate.ts b/cli/src/tasks/migrate.ts
index 9aab32cafa..c2325ebab4 100644
--- a/cli/src/tasks/migrate.ts
+++ b/cli/src/tasks/migrate.ts
@@ -10,7 +10,6 @@ import { fatal } from '../errors';
import { getMajoriOSVersion } from '../ios/common';
import { logger, logPrompt, logSuccess } from '../log';
import { deleteFolderRecursive } from '../util/fs';
-import { checkPackageManager } from '../util/spm';
import { runCommand } from '../util/subprocess';
import { extractTemplate } from '../util/template';
@@ -198,7 +197,7 @@ export async function migrateCommand(config: Config, noprompt: boolean, packagem
);
});
- if ((await checkPackageManager(config)) === 'Cocoapods') {
+ if ((await config.ios.packageManager) !== 'SPM') {
// Update Podfile
await runTask(`Migrating Podfile to ${iOSVersion}.0.`, () => {
return updateFile(
diff --git a/cli/src/tasks/run.ts b/cli/src/tasks/run.ts
index 97413cb098..2abdb9cd2c 100644
--- a/cli/src/tasks/run.ts
+++ b/cli/src/tasks/run.ts
@@ -34,6 +34,7 @@ export interface RunCommandOptions {
host?: string;
port?: string;
configuration?: string;
+ https?: boolean;
}
export async function runCommand(
@@ -42,7 +43,9 @@ export async function runCommand(
options: RunCommandOptions,
): Promise {
options.host = options.host ?? CapLiveReloadHelper.getIpAddress() ?? 'localhost';
- options.port = options.port ?? '3000';
+ if (!options.https && !options.port) {
+ options.port = '3000';
+ }
if (selectedPlatformName && !(await isValidPlatform(selectedPlatformName))) {
const platformDir = resolvePlatform(config, selectedPlatformName);
if (platformDir) {
@@ -108,7 +111,7 @@ export async function runCommand(
})
.then(() => process.exit());
logger.info(
- `App running with live reload listing for: http://${options.host}:${options.port}. Press Ctrl+C to quit.`,
+ `App running with live reload listing for: ${options.https ? 'https' : 'http'}://${options.host}${options.port ? `:${options.port}` : ''}. Press Ctrl+C to quit.`,
);
await sleepForever();
}
diff --git a/cli/src/tasks/sourcemaps.ts b/cli/src/tasks/sourcemaps.ts
index b460972f02..070cd5b3cb 100644
--- a/cli/src/tasks/sourcemaps.ts
+++ b/cli/src/tasks/sourcemaps.ts
@@ -12,7 +12,7 @@ function walkDirectory(dirPath: string) {
walkDirectory(targetFile);
} else {
const mapFile = join(dirPath, `${file}.map`);
- if (extname(file) === '.js' && existsSync(mapFile)) {
+ if ((extname(file) === '.js' || extname(file) === '.css') && existsSync(mapFile)) {
const bufMap = readFileSync(mapFile).toString('base64');
const bufFile = readFileSync(targetFile, 'utf8');
const result = bufFile.replace(
diff --git a/cli/src/tasks/sync.ts b/cli/src/tasks/sync.ts
index 98660e8b8c..e76ecaac87 100644
--- a/cli/src/tasks/sync.ts
+++ b/cli/src/tasks/sync.ts
@@ -5,7 +5,7 @@ import { logger } from '../log';
import { allSerial } from '../util/promise';
import { copy, copyCommand } from './copy';
-import { update, updateChecks, updateCommand } from './update';
+import { addUpdateChecks, update, updateCommand } from './update';
/**
* Sync is a copy and an update in one.
@@ -27,7 +27,7 @@ export async function syncCommand(
const then = +new Date();
const platforms = await selectPlatforms(config, selectedPlatformName);
try {
- await check([() => checkPackage(), () => checkWebDir(config), ...updateChecks(config, platforms)]);
+ await check([() => checkPackage(), () => checkWebDir(config), ...(await addUpdateChecks(config, platforms))]);
await allSerial(platforms.map((platformName) => () => sync(config, platformName, deployment, inline)));
const now = +new Date();
const diff = (now - then) / 1000;
diff --git a/cli/src/tasks/update.ts b/cli/src/tasks/update.ts
index a2b6cbe0d6..362a20aa70 100644
--- a/cli/src/tasks/update.ts
+++ b/cli/src/tasks/update.ts
@@ -13,7 +13,7 @@ import {
import type { CheckFunction } from '../common';
import type { Config } from '../definitions';
import { fatal, isFatal } from '../errors';
-import { checkBundler, checkCocoaPods } from '../ios/common';
+import { checkBundler, checkCocoaPods, getCommonChecks } from '../ios/common';
import { updateIOS } from '../ios/update';
import { logger } from '../log';
import { allSerial } from '../util/promise';
@@ -30,8 +30,7 @@ export async function updateCommand(config: Config, selectedPlatformName: string
const then = +new Date();
const platforms = await selectPlatforms(config, selectedPlatformName);
try {
- await check([() => checkPackage(), ...updateChecks(config, platforms)]);
-
+ await check([() => checkPackage(), ...(await addUpdateChecks(config, platforms))]);
await allSerial(platforms.map((platformName) => async () => await update(config, platformName, deployment)));
const now = +new Date();
const diff = (now - then) / 1000;
@@ -46,6 +45,28 @@ export async function updateCommand(config: Config, selectedPlatformName: string
}
}
+export async function addUpdateChecks(config: Config, platforms: string[]): Promise {
+ let checks: CheckFunction[] = [];
+ for (const platformName of platforms) {
+ if (platformName === config.ios.name) {
+ checks = await getCommonChecks(config);
+ } else if (platformName === config.android.name) {
+ continue;
+ } else if (platformName === config.web.name) {
+ continue;
+ } else {
+ throw `Platform ${platformName} is not valid.`;
+ }
+ }
+ return checks;
+}
+
+/**
+ * @deprecated use addUpdateChecks
+ * @param config
+ * @param platforms
+ * @returns
+ */
export function updateChecks(config: Config, platforms: string[]): CheckFunction[] {
const checks: CheckFunction[] = [];
for (const platformName of platforms) {
diff --git a/cli/src/util/livereload.ts b/cli/src/util/livereload.ts
index c3b15ee9fa..34d008a6ce 100644
--- a/cli/src/util/livereload.ts
+++ b/cli/src/util/livereload.ts
@@ -161,8 +161,9 @@ class CapLiveReload {
const configJson = readJSONSync(capConfigPath);
this.configJsonToRevertTo.json = JSON.stringify(configJson, null, 2);
this.configJsonToRevertTo.platformPath = capConfigPath;
- const url = `http://${options.host}:${options.port}`;
+ const url = `${options.https ? 'https' : 'http'}://${options.host}${options.port ? `:${options.port}` : ''}`;
configJson.server = {
+ ...configJson.server,
url,
};
writeJSONSync(capConfigPath, configJson, { spaces: '\t' });
diff --git a/cli/src/util/spm.ts b/cli/src/util/spm.ts
index 72f4903f1c..f3723b4590 100644
--- a/cli/src/util/spm.ts
+++ b/cli/src/util/spm.ts
@@ -12,13 +12,18 @@ import { getMajorMinoriOSVersion } from '../ios/common';
import { logger } from '../log';
import type { Plugin } from '../plugin';
import { getPluginType, PluginType } from '../plugin';
-import { runCommand, isInstalled } from '../util/subprocess';
+import { runCommand } from '../util/subprocess';
export interface SwiftPlugin {
name: string;
path: string;
}
+/**
+ * @deprecated use config.ios.packageManager
+ * @param config
+ * @returns 'Cocoapods' | 'SPM'
+ */
export async function checkPackageManager(config: Config): Promise<'Cocoapods' | 'SPM'> {
const iosDirectory = config.ios.nativeProjectDirAbs;
if (existsSync(resolve(iosDirectory, 'CapApp-SPM'))) {
@@ -92,9 +97,15 @@ export async function removeCocoapodsFiles(config: Config): Promise {
export async function generatePackageText(config: Config, plugins: Plugin[]): Promise {
const iosPlatformVersion = await getCapacitorPackageVersion(config, config.ios.name);
+<<<<<<< HEAD
const iosVersion = getMajorMinoriOSVersion(config);
+=======
+ const iosVersion = getMajoriOSVersion(config);
+ const packageTraits = config.app.extConfig.experimental?.ios?.spm?.packageTraits ?? {};
+ const swiftToolsVersion = config.app.extConfig.experimental?.ios?.spm?.swiftToolsVersion ?? '5.9';
+>>>>>>> upstream/main
- let packageSwiftText = `// swift-tools-version: 5.9
+ let packageSwiftText = `// swift-tools-version: ${swiftToolsVersion}
import PackageDescription
// DO NOT MODIFY THIS FILE - managed by Capacitor CLI commands
@@ -114,7 +125,16 @@ 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);
- packageSwiftText += `,\n .package(name: "${plugin.ios?.name}", path: "${relPath}")`;
+ const traits = packageTraits[plugin.id];
+ const traitsSuffix = traits?.length
+ ? `, traits: [${traits
+ .map((t) => {
+ // Any trait is written with quotes, with the exception of .defaults
+ return /^\.?defaults?$/i.test(t) ? '.defaults' : `"${t}"`;
+ })
+ .join(', ')}]`
+ : '';
+ packageSwiftText += `,\n .package(name: "${plugin.ios?.name}", path: "${relPath}"${traitsSuffix})`;
}
}
@@ -144,25 +164,19 @@ let package = Package(
export async function runCocoapodsDeintegrate(config: Config): Promise {
const podPath = await config.ios.podPath;
const projectFileName = config.ios.nativeXcodeProjDirAbs;
- const useBundler = podPath.startsWith('bundle') && (await isInstalled('bundle'));
- const podCommandExists = await isInstalled('pod');
-
- if (useBundler) logger.info('Found bundler, using it to run CocoaPods.');
+ const useBundler = (await config.ios.packageManager) === 'bundler';
logger.info('Running pod deintegrate on project ' + projectFileName);
- if (useBundler || podCommandExists) {
- if (useBundler) {
- await runCommand('bundle', ['exec', 'pod', 'deintegrate', projectFileName], {
- cwd: config.ios.nativeProjectDirAbs,
- });
- } else {
- await runCommand(podPath, ['deintegrate', projectFileName], {
- cwd: config.ios.nativeProjectDirAbs,
- });
- }
+ if (useBundler) {
+ logger.info('Found bundler, using it to run CocoaPods.');
+ await runCommand('bundle', ['exec', 'pod', 'deintegrate', projectFileName], {
+ cwd: config.ios.nativeProjectDirAbs,
+ });
} else {
- logger.warn('Skipping pod deintegrate because CocoaPods is not installed - migration will be incomplete');
+ await runCommand(podPath, ['deintegrate', projectFileName], {
+ cwd: config.ios.nativeProjectDirAbs,
+ });
}
}
@@ -189,6 +203,54 @@ export async function addInfoPlistDebugIfNeeded(config: Config): Promise {
}
}
+export async function checkSwiftToolsVersion(config: Config, version: string | undefined): Promise {
+ if (!version) {
+ return null;
+ }
+
+ const swiftToolsVersionRegex = /^[0-9]+\.[0-9]+(\.[0-9]+)?$/;
+
+ if (!swiftToolsVersionRegex.test(version)) {
+ return (
+ `Invalid Swift tools version: "${version}".\n` +
+ `The Swift tools version must be in major.minor or major.minor.patch format (e.g., "5.9", "6.0", "5.9.2").`
+ );
+ }
+
+ return null;
+}
+
+export async function checkPackageTraitsRequirements(config: Config): Promise {
+ const packageTraits = config.app.extConfig.experimental?.ios?.spm?.packageTraits;
+ const swiftToolsVersion = config.app.extConfig.experimental?.ios?.spm?.swiftToolsVersion;
+
+ const hasPackageTraits = packageTraits && Object.keys(packageTraits).some((key) => packageTraits[key]?.length > 0);
+
+ if (!hasPackageTraits) {
+ return null;
+ }
+
+ if (!swiftToolsVersion) {
+ return (
+ `Package traits require an explicit Swift tools version of 6.1 or higher.\n` +
+ `Set experimental.ios.spm.swiftToolsVersion to '6.1' or higher in your Capacitor configuration.`
+ );
+ }
+
+ const versionParts = swiftToolsVersion.split('.').map((part) => parseInt(part, 10));
+ const major = versionParts[0] || 0;
+ const minor = versionParts[1] || 0;
+
+ if (major < 6 || (major === 6 && minor < 1)) {
+ return (
+ `Package traits require Swift tools version 6.1 or higher, but "${swiftToolsVersion}" was specified.\n` +
+ `Update experimental.ios.spm.swiftToolsVersion to '6.1' or higher in your Capacitor configuration.`
+ );
+ }
+
+ return null;
+}
+
// Private Functions
async function pluginsWithPackageSwift(plugins: Plugin[]): Promise {
diff --git a/cli/src/util/template.ts b/cli/src/util/template.ts
index 76b699ee26..dd36751cf0 100644
--- a/cli/src/util/template.ts
+++ b/cli/src/util/template.ts
@@ -1,7 +1,7 @@
import { mkdirp } from 'fs-extra';
-import tar from 'tar';
+import { extract } from 'tar';
export async function extractTemplate(src: string, dir: string): Promise {
await mkdirp(dir);
- await tar.extract({ file: src, cwd: dir });
+ await extract({ file: src, cwd: dir });
}
diff --git a/core/CHANGELOG.md b/core/CHANGELOG.md
index fcd6a8c50e..9aac25935b 100644
--- a/core/CHANGELOG.md
+++ b/core/CHANGELOG.md
@@ -3,6 +3,7 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
+<<<<<<< HEAD
## [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
@@ -124,6 +125,38 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline
- 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))
+=======
+# [8.3.0](https://github.com/ionic-team/capacitor/compare/8.2.0...8.3.0) (2026-03-25)
+
+### Bug Fixes
+
+- **http:** handle URL objects on fetch ([#8386](https://github.com/ionic-team/capacitor/issues/8386)) ([003099a](https://github.com/ionic-team/capacitor/commit/003099aef246adfd76d890074d46b1484951824b))
+- **SystemBars:** use native safe area insets on Android ([#8384](https://github.com/ionic-team/capacitor/issues/8384)) ([4e99598](https://github.com/ionic-team/capacitor/commit/4e99598a2a57ee97e82be1aaa09492744622fa60))
+
+# [8.2.0](https://github.com/ionic-team/capacitor/compare/8.1.0...8.2.0) (2026-03-06)
+
+**Note:** Version bump only for package @capacitor/core
+
+# [8.1.0](https://github.com/ionic-team/capacitor/compare/8.0.2...8.1.0) (2026-02-11)
+
+### Bug Fixes
+
+- **cookies:** only send expires param on web if a date is set ([b10cd7f](https://github.com/ionic-team/capacitor/commit/b10cd7ff15b010a76802374214f4e0cbd04abdab))
+
+### Reverts
+
+- revert version bump from [#8319](https://github.com/ionic-team/capacitor/issues/8319) and [#8320](https://github.com/ionic-team/capacitor/issues/8320) ([a48ebb6](https://github.com/ionic-team/capacitor/commit/a48ebb622ea4ebe92927bf1756a4d8ac6012884b))
+
+## [8.0.2](https://github.com/ionic-team/capacitor/compare/8.0.1...8.0.2) (2026-01-27)
+
+### Bug Fixes
+
+- **core:** make SystemBars hide and show options optional ([#8305](https://github.com/ionic-team/capacitor/issues/8305)) ([95dc7d8](https://github.com/ionic-team/capacitor/commit/95dc7d8ace3aabdda7e325c4a8ef7d1432ad37e9))
+
+## [8.0.1](https://github.com/ionic-team/capacitor/compare/8.0.0...8.0.1) (2026-01-13)
+
+**Note:** Version bump only for package @capacitor/core
+>>>>>>> upstream/main
# [8.0.0](https://github.com/ionic-team/capacitor/compare/8.0.0-beta.0...8.0.0) (2025-12-08)
diff --git a/core/native-bridge.ts b/core/native-bridge.ts
index f988399be8..4fc028f379 100644
--- a/core/native-bridge.ts
+++ b/core/native-bridge.ts
@@ -532,6 +532,9 @@ const initBridge = (w: any): void => {
if (typeof resource === 'string') {
return await win.CapacitorWebFetch(createProxyUrl(resource, win), options);
+ } else if (resource instanceof URL) {
+ const modifiedURL = new URL(createProxyUrl(resource.toString(), win));
+ return await win.CapacitorWebFetch(modifiedURL, options);
} else if (resource instanceof Request) {
const modifiedRequest = new Request(createProxyUrl(resource.url, win), resource);
return await win.CapacitorWebFetch(modifiedRequest, options);
diff --git a/core/package.json b/core/package.json
index c927292328..4d20252286 100644
--- a/core/package.json
+++ b/core/package.json
@@ -1,9 +1,17 @@
{
+<<<<<<< HEAD
"name": "@capacitor-plus/core",
"version": "8.0.8",
"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": "8.3.0",
+ "description": "Capacitor: Cross-platform apps with JavaScript and the web",
+ "homepage": "https://capacitorjs.com",
+ "author": "Ionic Team (https://ionic.io)",
+>>>>>>> upstream/main
"license": "MIT",
"repository": {
"type": "git",
diff --git a/core/src/core-plugins.ts b/core/src/core-plugins.ts
index 8a4bd755f3..a1efe9c901 100644
--- a/core/src/core-plugins.ts
+++ b/core/src/core-plugins.ts
@@ -110,7 +110,7 @@ export class CapacitorCookiesPluginWeb extends WebPlugin implements CapacitorCoo
const encodedValue = encode(options.value);
// Clean & sanitize options
- const expires = `; expires=${(options.expires || '').replace('expires=', '')}`; // Default is "; expires="
+ const expires = options.expires ? `; expires=${options.expires.replace('expires=', '')}` : '';
const path = (options.path || '/').replace('path=', ''); // Default is "path=/"
const domain = options.url != null && options.url.length > 0 ? `domain=${options.url}` : '';
@@ -617,14 +617,14 @@ export interface SystemBarsPlugin {
*
* @since 8.0.0
*/
- show(options: SystemBarsVisibilityOptions): Promise;
+ show(options?: SystemBarsVisibilityOptions): Promise;
/**
* Hide the system bars.
*
* @since 8.0.0
*/
- hide(options: SystemBarsVisibilityOptions): Promise;
+ hide(options?: SystemBarsVisibilityOptions): Promise;
/**
* Set the animation to use when showing / hiding the status bar.
diff --git a/core/system-bars.md b/core/system-bars.md
index 2f9b78603f..67275077af 100644
--- a/core/system-bars.md
+++ b/core/system-bars.md
@@ -39,7 +39,7 @@ To control this behavior, use the `insetsHandling` configuration setting.
## Example
```typescript
-import { SystemBars, SystemBarsStyle } from '@capacitor/core';
+import { SystemBars, SystemBarsStyle, SystemBarType } from '@capacitor/core';
const setSystemBarStyleDark = async () => {
await SystemBars.setStyle({ style: SystemBarsStyle.Dark });
@@ -73,7 +73,7 @@ const setStatusBarAnimation = async () => {
## Configuration
| Prop | Type | Description | Default |
| ------------- | -------------------- | ------------------------------------------------------------------------- | ------------------ |
-| **`insetsHandling`** | string | Specifies how to handle problematic insets on Android. This option is only supported on Android.
`css` = Injects CSS variables (`--safe-area-inset-*`) containing correct safe area inset values into the webview.
`disable` = Disable all inset handling. | css |
+| **`insetsHandling`** | string | Specifies how to handle problematic insets on Android. This option is only supported on Android.
`css` = Injects CSS variables (`--safe-area-inset-*`) containing correct safe area inset values into the webview.
`disable` = Disable CSS variables injection. | css |
| **`style`** | string | The style of the text and icons of the system bars. | DEFAULT |
| **`hidden`** | boolean | Hide the system bars on start. | false |
| **`animation`** | string | The type of status bar animation used when showing or hiding. This option is only supported on iOS. | FADE |
@@ -152,7 +152,7 @@ Set the current style of the system bars.
### show(...)
```typescript
-show(options: SystemBarsVisibilityOptions) => Promise
+show(options?: SystemBarsVisibilityOptions) => Promise
```
Show the system bars.
@@ -169,7 +169,7 @@ Show the system bars.
### hide(...)
```typescript
-hide(options: SystemBarsVisibilityOptions) => Promise
+hide(options?: SystemBarsVisibilityOptions) => Promise
```
Hide the system bars.
diff --git a/ios-spm-template/App/CapApp-SPM/README.md b/ios-spm-template/App/CapApp-SPM/README.md
index 5e22a2f8a0..03964db900 100644
--- a/ios-spm-template/App/CapApp-SPM/README.md
+++ b/ios-spm-template/App/CapApp-SPM/README.md
@@ -1,5 +1,5 @@
# CapApp-SPM
-This SPM is used to host SPM dependencies for you Capacitor project
+This package is used to host SPM dependencies for your Capacitor project
Do not modify the contents of it or there may be unintended consequences.
diff --git a/ios/CHANGELOG.md b/ios/CHANGELOG.md
index db07ef6337..c2915f8e61 100644
--- a/ios/CHANGELOG.md
+++ b/ios/CHANGELOG.md
@@ -3,6 +3,7 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
+<<<<<<< HEAD
## [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
@@ -194,6 +195,34 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline
- 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))
+=======
+# [8.3.0](https://github.com/ionic-team/capacitor/compare/8.2.0...8.3.0) (2026-03-25)
+
+### Bug Fixes
+
+- **http:** handle URL objects on fetch ([#8386](https://github.com/ionic-team/capacitor/issues/8386)) ([003099a](https://github.com/ionic-team/capacitor/commit/003099aef246adfd76d890074d46b1484951824b))
+- **ios:** make getArray accesible on Objective-C plugins ([#8392](https://github.com/ionic-team/capacitor/issues/8392)) ([afb80f2](https://github.com/ionic-team/capacitor/commit/afb80f2fecb4bf85dbebe25e815de2a5564264d6))
+
+# [8.2.0](https://github.com/ionic-team/capacitor/compare/8.1.0...8.2.0) (2026-03-06)
+
+### Bug Fixes
+
+- **ios:** remove tmpWindow usages on presentVC/dismissVC ([#8338](https://github.com/ionic-team/capacitor/issues/8338)) ([fc9647f](https://github.com/ionic-team/capacitor/commit/fc9647f26f08ff64f53b32c79fb19f153e3b0a24))
+
+# [8.1.0](https://github.com/ionic-team/capacitor/compare/8.0.2...8.1.0) (2026-02-11)
+
+### Reverts
+
+- revert version bump from [#8319](https://github.com/ionic-team/capacitor/issues/8319) and [#8320](https://github.com/ionic-team/capacitor/issues/8320) ([a48ebb6](https://github.com/ionic-team/capacitor/commit/a48ebb622ea4ebe92927bf1756a4d8ac6012884b))
+
+## [8.0.2](https://github.com/ionic-team/capacitor/compare/8.0.1...8.0.2) (2026-01-27)
+
+**Note:** Version bump only for package @capacitor/ios
+
+## [8.0.1](https://github.com/ionic-team/capacitor/compare/8.0.0...8.0.1) (2026-01-13)
+
+**Note:** Version bump only for package @capacitor/ios
+>>>>>>> upstream/main
# [8.0.0](https://github.com/ionic-team/capacitor/compare/8.0.0-beta.0...8.0.0) (2025-12-08)
diff --git a/ios/Capacitor/Capacitor/CAPBridgeProtocol.swift b/ios/Capacitor/Capacitor/CAPBridgeProtocol.swift
index f86b914f8e..24ee52a75d 100644
--- a/ios/Capacitor/Capacitor/CAPBridgeProtocol.swift
+++ b/ios/Capacitor/Capacitor/CAPBridgeProtocol.swift
@@ -81,7 +81,9 @@ import WebKit
// MARK: - View Presentation
func showAlertWith(title: String, message: String, buttonTitle: String)
+ @available(*, deprecated, message: "Use self?.bridge?.viewController?.present")
func presentVC(_ viewControllerToPresent: UIViewController, animated flag: Bool, completion: (() -> Void)?)
+ @available(*, deprecated, message: "Use self?.bridge?.viewController?.dismiss")
func dismissVC(animated flag: Bool, completion: (() -> Void)?)
}
diff --git a/ios/Capacitor/Capacitor/CAPBridgedJSTypes.h b/ios/Capacitor/Capacitor/CAPBridgedJSTypes.h
index 516c8648b8..67f8a9501d 100644
--- a/ios/Capacitor/Capacitor/CAPBridgedJSTypes.h
+++ b/ios/Capacitor/Capacitor/CAPBridgedJSTypes.h
@@ -10,6 +10,7 @@
- (NSString * _Nullable)getString:(NSString * _Nonnull)key defaultValue:(NSString * _Nullable)defaultValue;
- (NSDate * _Nullable)getDate:(NSString * _Nonnull)key defaultValue:(NSDate * _Nullable)defaultValue;
- (NSDictionary * _Nullable)getObject:(NSString * _Nonnull)key defaultValue:(NSDictionary * _Nullable)defaultValue;
+- (NSArray * _Nullable)getArray:(NSString * _Nonnull)key defaultValue:(NSArray * _Nullable)defaultValue;
- (NSNumber * _Nullable)getNumber:(NSString * _Nonnull)key defaultValue:(NSNumber * _Nullable)defaultValue;
- (BOOL)getBool:(NSString * _Nonnull)key defaultValue:(BOOL)defaultValue;
@end
diff --git a/ios/Capacitor/Capacitor/CAPBridgedJSTypes.m b/ios/Capacitor/Capacitor/CAPBridgedJSTypes.m
index fb6da4586f..c8ec07da7f 100644
--- a/ios/Capacitor/Capacitor/CAPBridgedJSTypes.m
+++ b/ios/Capacitor/Capacitor/CAPBridgedJSTypes.m
@@ -29,6 +29,14 @@ - (NSDictionary * _Nullable)getObject:(NSString * _Nonnull)key defaultValue:(NSD
return defaultValue;
}
+- (NSArray * _Nullable)getArray:(NSString * _Nonnull)key defaultValue:(NSArray * _Nullable)defaultValue; {
+ id value = [[self dictionaryRepresentation] objectForKey:key];
+ if (value != nil && [value isKindOfClass:[NSArray class]]) {
+ return value;
+ }
+ return defaultValue;
+}
+
- (NSNumber * _Nullable)getNumber:(NSString * _Nonnull)key defaultValue:(NSNumber * _Nullable)defaultValue {
id value = [[self dictionaryRepresentation] objectForKey:key];
if (value != nil && [value isKindOfClass:[NSNumber class]]) {
diff --git a/ios/Capacitor/Capacitor/CapacitorBridge.swift b/ios/Capacitor/Capacitor/CapacitorBridge.swift
index 8b0026ad98..7b8b9b99dc 100644
--- a/ios/Capacitor/Capacitor/CapacitorBridge.swift
+++ b/ios/Capacitor/Capacitor/CapacitorBridge.swift
@@ -93,8 +93,9 @@ 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_"
@@ -747,22 +748,10 @@ open class CapacitorBridge: NSObject, CAPBridgeProtocol {
}
@objc open func presentVC(_ viewControllerToPresent: UIViewController, animated flag: Bool, completion: (() -> Void)? = nil) {
- if viewControllerToPresent.modalPresentationStyle == .popover {
- self.viewController?.present(viewControllerToPresent, animated: flag, completion: completion)
- } else {
- self.tmpWindow = UIWindow.init(frame: UIScreen.main.bounds)
- self.tmpWindow?.rootViewController = TmpViewController.init()
- self.tmpWindow?.makeKeyAndVisible()
- self.tmpWindow?.rootViewController?.present(viewControllerToPresent, animated: flag, completion: completion)
- }
+ self.viewController?.present(viewControllerToPresent, animated: flag, completion: completion)
}
@objc open func dismissVC(animated flag: Bool, completion: (() -> Void)? = nil) {
- if self.tmpWindow == nil {
- self.viewController?.dismiss(animated: flag, completion: completion)
- } else {
- self.tmpWindow?.rootViewController?.dismiss(animated: flag, completion: completion)
- self.tmpWindow = nil
- }
+ self.viewController?.dismiss(animated: flag, completion: completion)
}
}
diff --git a/ios/Capacitor/Capacitor/assets/native-bridge.js b/ios/Capacitor/Capacitor/assets/native-bridge.js
index 40daf2a484..f5e7cc4403 100644
--- a/ios/Capacitor/Capacitor/assets/native-bridge.js
+++ b/ios/Capacitor/Capacitor/assets/native-bridge.js
@@ -505,6 +505,10 @@ var nativeBridge = (function (exports) {
if (typeof resource === 'string') {
return await win.CapacitorWebFetch(createProxyUrl(resource, win), options);
}
+ else if (resource instanceof URL) {
+ const modifiedURL = new URL(createProxyUrl(resource.toString(), win));
+ return await win.CapacitorWebFetch(modifiedURL, options);
+ }
else if (resource instanceof Request) {
const modifiedRequest = new Request(createProxyUrl(resource.url, win), resource);
return await win.CapacitorWebFetch(modifiedRequest, options);
diff --git a/ios/package.json b/ios/package.json
index 7a0a2a4f0a..1d00acc4ff 100644
--- a/ios/package.json
+++ b/ios/package.json
@@ -1,9 +1,17 @@
{
+<<<<<<< HEAD
"name": "@capacitor-plus/ios",
"version": "8.0.8",
"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": "8.3.0",
+ "description": "Capacitor: Cross-platform apps with JavaScript and the web",
+ "homepage": "https://capacitorjs.com",
+ "author": "Ionic Team (https://ionic.io)",
+>>>>>>> upstream/main
"license": "MIT",
"repository": {
"type": "git",
@@ -21,12 +29,16 @@
],
"scripts": {
"verify": "npm run xc:build:Capacitor && npm run xc:build:CapacitorCordova",
- "xc:build:Capacitor": "cd Capacitor && xcodebuild clean test -workspace Capacitor.xcworkspace -scheme Capacitor -destination 'platform=iOS Simulator,name=iPhone 16,OS=26.0.1' && cd ..",
+ "xc:build:Capacitor": "cd Capacitor && xcodebuild clean test -workspace Capacitor.xcworkspace -scheme Capacitor -destination 'platform=iOS Simulator,name=iPhone 17,OS=26.0.1' && cd ..",
"xc:build:CapacitorCordova": "cd CapacitorCordova && xcodebuild && cd .."
},
"peerDependencies": {
+<<<<<<< HEAD
"@capacitor-plus/core": "^8.0.0",
"@capacitor/core": "^8.0.0"
+=======
+ "@capacitor/core": "^8.3.0"
+>>>>>>> upstream/main
},
"publishConfig": {
"access": "public"
diff --git a/lerna.json b/lerna.json
index a3c96f424c..9aba74e108 100644
--- a/lerna.json
+++ b/lerna.json
@@ -13,6 +13,10 @@
"tagVersionPrefix": ""
}
},
+<<<<<<< HEAD
"version": "8.0.8",
+=======
+ "version": "8.3.0",
+>>>>>>> upstream/main
"$schema": "node_modules/lerna/schemas/lerna-schema.json"
}
diff --git a/package.json b/package.json
index b933a118c4..079eb7aa7a 100644
--- a/package.json
+++ b/package.json
@@ -32,17 +32,26 @@
"@ionic/eslint-config": "^0.4.0",
"@ionic/prettier-config": "^4.0.0",
"@ionic/swiftlint-config": "^2.0.0",
+<<<<<<< HEAD
"@types/node": "^24.10.1",
"@types/tar": "^6.1.2",
"eslint": "^8.57.1",
"eslint-plugin-import": "^2.31.0",
+=======
+ "@types/node": "18.18.6",
+ "eslint": "^8.57.0",
+>>>>>>> upstream/main
"lerna": "^7.1.3",
"prettier": "^3.6.2",
"prettier-plugin-java": "^2.7.7",
"rimraf": "^6.1.0",
"semver": "^7.3.7",
"swiftlint": "^2.0.0",
+<<<<<<< HEAD
"tar": "^6.1.11",
"prettier-pretty-check": "^0.2.0"
+=======
+ "tar": "^7.5.3"
+>>>>>>> upstream/main
}
}
diff --git a/scripts/pack-cli-assets.mjs b/scripts/pack-cli-assets.mjs
index 99dae12e65..20df223c12 100644
--- a/scripts/pack-cli-assets.mjs
+++ b/scripts/pack-cli-assets.mjs
@@ -1,5 +1,5 @@
import { resolve } from 'path';
-import tar from 'tar';
+import { create } from 'tar';
import { execute } from './lib/cli.mjs';
import { mkdir } from './lib/fs.mjs';
@@ -25,7 +25,7 @@ execute(async () => {
const files = await lsfiles(templatePath, { cwd: templatePath });
- await tar.create({ gzip: true, file: dest, cwd: templatePath }, files);
+ await create({ gzip: true, file: dest, cwd: templatePath }, files);
console.log(`Packed ${dest}!`);
}