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}!`); }