diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 80a064c68a..ea338db0f9 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -21,7 +21,7 @@ concurrency: jobs: setup: runs-on: ubuntu-latest - timeout-minutes: 10 + timeout-minutes: 30 steps: - name: Get Latest uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 @@ -38,7 +38,7 @@ jobs: key: ${{ runner.OS }}-bun-dependencies-cache-${{ hashFiles('bun.lock') }} lint: runs-on: macos-15 - timeout-minutes: 10 + timeout-minutes: 30 steps: - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 with: @@ -57,7 +57,7 @@ jobs: - run: bun run lint test-cli: runs-on: macos-15 - timeout-minutes: 10 + timeout-minutes: 30 needs: - setup - lint @@ -81,7 +81,7 @@ jobs: working-directory: ./cli test-core: runs-on: ubuntu-latest - timeout-minutes: 10 + timeout-minutes: 30 needs: - setup - lint @@ -105,7 +105,7 @@ jobs: working-directory: ./core test-ios: runs-on: macos-15 - timeout-minutes: 10 + timeout-minutes: 30 needs: - setup - lint @@ -136,7 +136,7 @@ jobs: run: sh ./scripts/native-podspec.sh lint test-android: runs-on: ubuntu-latest - timeout-minutes: 10 + timeout-minutes: 30 needs: - setup - lint diff --git a/CHANGELOG.md b/CHANGELOG.md index 5064d193a9..af861c6a95 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,33 +3,13 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. -## [8.5.2](https://github.com/Cap-go/capacitor-plus/compare/8.5.1...8.5.2) (2026-08-26) - -**Note:** Version bump only for package capacitor - - - - - -## [8.5.1](https://github.com/Cap-go/capacitor-plus/compare/8.3.12...8.5.1) (2026-08-25) - - -### Bug Fixes - -* **ci:** fetch upstream objects so plus branch sync works ([#109](https://github.com/Cap-go/capacitor-plus/issues/109)) ([1fa7eee](https://github.com/Cap-go/capacitor-plus/commit/1fa7eeeff9494e9b32afb20a9850389b79d6bcec)) -* **ci:** resolve modify/delete conflicts in sync conflict PRs ([#110](https://github.com/Cap-go/capacitor-plus/issues/110)) ([5c29fb9](https://github.com/Cap-go/capacitor-plus/commit/5c29fb9af001b9aafdcde7b7054585e093f44431)) - - - - - # [8.5.0](https://github.com/ionic-team/capacitor/compare/8.4.2...8.5.0) (2026-07-31) -## Bug Fixes +### Bug Fixes - **cli:** support TypeScript 7 when loading capacitor.config.ts ([#8534](https://github.com/ionic-team/capacitor/issues/8534)) ([4c1c870](https://github.com/ionic-team/capacitor/commit/4c1c8709413b9c19b008c99122ca330cc3c90e6f)) -## Features +### Features - **cli:** add migrator functionality for adopting UIScene ([#8544](https://github.com/ionic-team/capacitor/issues/8544)) ([984fa85](https://github.com/ionic-team/capacitor/commit/984fa85ba0adab0aacf895aed6323bf4b503dccb)) - **ios:** UIScene Support ([#8536](https://github.com/ionic-team/capacitor/issues/8536)) ([3fa04a3](https://github.com/ionic-team/capacitor/commit/3fa04a357c92af34cd6fccb8124791963804a9dc)) @@ -49,14 +29,14 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline # [8.4.0](https://github.com/ionic-team/capacitor/compare/8.3.4...8.4.0) (2026-06-02) -## Bug Fixes +### Bug Fixes - **android:** show only the requested system bar ([#8480](https://github.com/ionic-team/capacitor/issues/8480)) ([4c6c321](https://github.com/ionic-team/capacitor/commit/4c6c3219afb5223211e857457e46283c37eb9424)) - **cli:** revert live reload config on failure ([#8485](https://github.com/ionic-team/capacitor/issues/8485)) ([1d031a4](https://github.com/ionic-team/capacitor/commit/1d031a4abec2c793079ba8897ad2e40c4cc6c7f9)) - **SystemBars:** make `safe-area-inset-x` available on API <= 34 ([#8424](https://github.com/ionic-team/capacitor/issues/8424)) ([e456de0](https://github.com/ionic-team/capacitor/commit/e456de083e19644f484bec5a5359cb67960ac8bc)) - **SystemBars:** respect `insetsHandling` disable ([#8481](https://github.com/ionic-team/capacitor/issues/8481)) ([d4ad7ff](https://github.com/ionic-team/capacitor/commit/d4ad7ffe39daf66e0cfc63af9028d5c05543bde7)) -## Features +### Features - add method getDouble to plugin config ([#7638](https://github.com/ionic-team/capacitor/issues/7638)) ([93c72de](https://github.com/ionic-team/capacitor/commit/93c72de40a2ec4c78b33659250cb08340083088e)) - **cli:** add experimental packageOptions ([#8471](https://github.com/ionic-team/capacitor/issues/8471)) ([258867b](https://github.com/ionic-team/capacitor/commit/258867b7bf37b1837b99b02ec9638e5a6df08d97)) diff --git a/android/CHANGELOG.md b/android/CHANGELOG.md index a6ec97e3ba..d324013f33 100644 --- a/android/CHANGELOG.md +++ b/android/CHANGELOG.md @@ -3,22 +3,6 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. -## [8.5.2](https://github.com/Cap-go/capacitor-plus/compare/8.5.1...8.5.2) (2026-08-26) - -**Note:** Version bump only for package @capacitor-plus/android - - - - - -## [8.5.1](https://github.com/Cap-go/capacitor-plus/compare/8.3.12...8.5.1) (2026-08-25) - -**Note:** Version bump only for package @capacitor-plus/android - - - - - # [8.5.0](https://github.com/ionic-team/capacitor/compare/8.4.2...8.5.0) (2026-07-31) **Note:** Version bump only for package @capacitor/android diff --git a/android/capacitor/src/main/java/com/getcapacitor/BridgeWebChromeClient.java b/android/capacitor/src/main/java/com/getcapacitor/BridgeWebChromeClient.java index c2075811a0..bac57209fa 100644 --- a/android/capacitor/src/main/java/com/getcapacitor/BridgeWebChromeClient.java +++ b/android/capacitor/src/main/java/com/getcapacitor/BridgeWebChromeClient.java @@ -412,12 +412,6 @@ private boolean showImageCapturePicker(final ValueCallback filePathCallba } takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, imageFileUri); takePictureIntent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION | Intent.FLAG_GRANT_READ_URI_PERMISSION); - - // Store in static variables to survive activity recreation - pendingFilePathCallback = filePathCallback; - pendingImageFileUri = imageFileUri; - pendingFileChooserType = FileChooserType.IMAGE_CAPTURE; - activityListener = (activityResult) -> { Uri[] result = null; if (activityResult.getResultCode() == Activity.RESULT_OK) { diff --git a/android/capacitor/src/main/java/com/getcapacitor/WebViewLocalServer.java b/android/capacitor/src/main/java/com/getcapacitor/WebViewLocalServer.java index 016609ce3a..4724ab075e 100755 --- a/android/capacitor/src/main/java/com/getcapacitor/WebViewLocalServer.java +++ b/android/capacitor/src/main/java/com/getcapacitor/WebViewLocalServer.java @@ -756,48 +756,6 @@ public long skip(long n) throws IOException { } } - /** - * An InputStream wrapper that limits the number of bytes that can be read. - */ - static class BoundedInputStream extends InputStream { - - private final InputStream in; - private long remaining; - - public BoundedInputStream(InputStream in, long limit) { - this.in = in; - this.remaining = limit; - } - - @Override - public int available() throws IOException { - int available = in.available(); - return (int) Math.min(available, remaining); - } - - @Override - public int read() throws IOException { - if (remaining <= 0) return -1; - int result = in.read(); - if (result != -1) remaining--; - return result; - } - - @Override - public int read(byte[] b, int off, int len) throws IOException { - if (remaining <= 0) return -1; - int toRead = (int) Math.min(len, remaining); - int result = in.read(b, off, toRead); - if (result > 0) remaining -= result; - return result; - } - - @Override - public void close() throws IOException { - in.close(); - } - } - // For L and above. private static class LollipopLazyInputStream extends LazyInputStream { diff --git a/android/capacitor/src/main/java/com/getcapacitor/cordova/MockCordovaWebViewImpl.java b/android/capacitor/src/main/java/com/getcapacitor/cordova/MockCordovaWebViewImpl.java index 1115429d7b..020c1457a1 100644 --- a/android/capacitor/src/main/java/com/getcapacitor/cordova/MockCordovaWebViewImpl.java +++ b/android/capacitor/src/main/java/com/getcapacitor/cordova/MockCordovaWebViewImpl.java @@ -70,14 +70,12 @@ public CapacitorEvalBridgeMode(WebView webView, CordovaInterface cordova) { @Override public void onNativeToJsMessageAvailable(final NativeToJsMessageQueue queue) { - cordova - .getActivity() - .runOnUiThread(() -> { - String js = queue.popAndEncodeAsJs(); - if (js != null) { - webView.evaluateJavascript(js, null); - } - }); + cordova.getActivity().runOnUiThread(() -> { + String js = queue.popAndEncodeAsJs(); + if (js != null) { + webView.evaluateJavascript(js, null); + } + }); } } diff --git a/android/capacitor/src/main/java/com/getcapacitor/plugin/SystemBars.java b/android/capacitor/src/main/java/com/getcapacitor/plugin/SystemBars.java index 84a4bfa8a3..9a50858f40 100644 --- a/android/capacitor/src/main/java/com/getcapacitor/plugin/SystemBars.java +++ b/android/capacitor/src/main/java/com/getcapacitor/plugin/SystemBars.java @@ -44,17 +44,17 @@ public class SystemBars extends Plugin { 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]"); - if (meta.length == 0) { - return false; - } - // get the last found meta viewport tag - const metaContent = meta[meta.length - 1].content; - return metaContent.includes("viewport-fit=cover"); + function capacitorSystemBarsCheckMetaViewport() { + const meta = document.querySelectorAll("meta[name=viewport]"); + if (meta.length == 0) { + return false; } - capacitorSystemBarsCheckMetaViewport(); - """; + // get the last found meta viewport tag + const metaContent = meta[meta.length - 1].content; + return metaContent.includes("viewport-fit=cover"); + } + capacitorSystemBarsCheckMetaViewport(); + """; private String insetsHandling = INSETS_HANDLING_CSS; private boolean hasViewportCover = false; @@ -272,7 +272,7 @@ private void initWindowInsetsListener() { // We need to correct for a possible shown IME v.setPadding(0, 0, 0, keyboardVisible ? imeInsets.bottom : 0); - Insets safeAreaInsets = calcSafeAreaInsets(safeAreaSource); + Insets safeAreaInsets = calcSafeAreaInsets(insets); injectSafeAreaCSS(safeAreaInsets.top, safeAreaInsets.right, safeAreaInsets.bottom, safeAreaInsets.left); return new WindowInsetsCompat.Builder(insets) @@ -297,7 +297,7 @@ private void initWindowInsetsListener() { .setInsets(WindowInsetsCompat.Type.systemBars() | WindowInsetsCompat.Type.displayCutout(), Insets.of(0, 0, 0, 0)) .build(); - Insets safeAreaInsets = calcSafeAreaInsets(safeAreaSource); + Insets safeAreaInsets = calcSafeAreaInsets(newInsets); injectSafeAreaCSS(safeAreaInsets.top, safeAreaInsets.right, safeAreaInsets.bottom, safeAreaInsets.left); return newInsets; @@ -364,7 +364,6 @@ private void setHidden(boolean hide, String bar) { if (hide) { if (bar.isEmpty()) { windowInsetsControllerCompat.hide(WindowInsetsCompat.Type.systemBars()); - navBarVisible = false; } else if (bar.equals(BAR_STATUS_BAR)) { windowInsetsControllerCompat.hide(WindowInsetsCompat.Type.statusBars()); } else if (bar.equals(BAR_GESTURE_BAR)) { @@ -376,7 +375,6 @@ private void setHidden(boolean hide, String bar) { if (bar.isEmpty()) { windowInsetsControllerCompat.show(WindowInsetsCompat.Type.systemBars()); - navBarVisible = true; } else if (bar.equals(BAR_STATUS_BAR)) { windowInsetsControllerCompat.show(WindowInsetsCompat.Type.statusBars()); } else if (bar.equals(BAR_GESTURE_BAR)) { diff --git a/android/capacitor/src/test/java/com/getcapacitor/plugin/SystemBarsTest.java b/android/capacitor/src/test/java/com/getcapacitor/plugin/SystemBarsTest.java index 0ea955ae88..f72373a88e 100644 --- a/android/capacitor/src/test/java/com/getcapacitor/plugin/SystemBarsTest.java +++ b/android/capacitor/src/test/java/com/getcapacitor/plugin/SystemBarsTest.java @@ -1,7 +1,5 @@ package com.getcapacitor.plugin; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mockStatic; import static org.mockito.Mockito.never; @@ -15,7 +13,6 @@ import androidx.core.view.WindowInsetsCompat; import androidx.core.view.WindowInsetsControllerCompat; import com.getcapacitor.Bridge; -import java.lang.reflect.Field; import java.lang.reflect.Method; import org.junit.Test; import org.mockito.MockedStatic; @@ -49,66 +46,8 @@ public void showWithNavigationBarShowsOnlyNavigationBars() throws Exception { verify(controller, never()).show(WindowInsetsCompat.Type.statusBars()); } - @Test - public void hideWithEmptyBarHidesSystemBars() throws Exception { - WindowInsetsControllerCompat controller = invokeSetHidden(new SystemBars(), true, ""); - - verify(controller).hide(WindowInsetsCompat.Type.systemBars()); - verify(controller, never()).hide(WindowInsetsCompat.Type.statusBars()); - verify(controller, never()).hide(WindowInsetsCompat.Type.navigationBars()); - } - - @Test - public void hideWithStatusBarHidesOnlyStatusBars() throws Exception { - WindowInsetsControllerCompat controller = invokeSetHidden(new SystemBars(), true, "StatusBar"); - - verify(controller).hide(WindowInsetsCompat.Type.statusBars()); - verify(controller, never()).hide(WindowInsetsCompat.Type.systemBars()); - verify(controller, never()).hide(WindowInsetsCompat.Type.navigationBars()); - } - - @Test - public void togglingNavigationBarTracksNavBarVisible() throws Exception { - SystemBars plugin = new SystemBars(); - - invokeSetHidden(plugin, true, "NavigationBar"); - assertFalse(navBarVisible(plugin)); - - invokeSetHidden(plugin, false, "NavigationBar"); - assertTrue(navBarVisible(plugin)); - } - - @Test - public void togglingAllBarsTracksNavBarVisible() throws Exception { - SystemBars plugin = new SystemBars(); - - invokeSetHidden(plugin, true, ""); - assertFalse(navBarVisible(plugin)); - - invokeSetHidden(plugin, false, ""); - assertTrue(navBarVisible(plugin)); - } - - @Test - public void hidingOnlyStatusBarLeavesNavBarVisible() throws Exception { - SystemBars plugin = new SystemBars(); - - invokeSetHidden(plugin, true, "StatusBar"); - - assertTrue(navBarVisible(plugin)); - } - - private boolean navBarVisible(SystemBars plugin) throws Exception { - Field field = SystemBars.class.getDeclaredField("navBarVisible"); - field.setAccessible(true); - return field.getBoolean(plugin); - } - private WindowInsetsControllerCompat invokeSetHidden(String bar) throws Exception { - return invokeSetHidden(new SystemBars(), false, bar); - } - - private WindowInsetsControllerCompat invokeSetHidden(SystemBars plugin, boolean hide, String bar) throws Exception { + SystemBars plugin = new SystemBars(); Bridge bridge = mock(Bridge.class); AppCompatActivity activity = mock(AppCompatActivity.class); Window window = mock(Window.class); @@ -126,7 +65,7 @@ private WindowInsetsControllerCompat invokeSetHidden(SystemBars plugin, boolean Method setHidden = SystemBars.class.getDeclaredMethod("setHidden", boolean.class, String.class); setHidden.setAccessible(true); - setHidden.invoke(plugin, hide, bar); + setHidden.invoke(plugin, false, bar); } return controller; diff --git a/android/capacitor/src/test/java/com/getcapacitor/plugin/util/HttpRequestHandlerTest.java b/android/capacitor/src/test/java/com/getcapacitor/plugin/util/HttpRequestHandlerTest.java index fd8b686ee6..1006721235 100644 --- a/android/capacitor/src/test/java/com/getcapacitor/plugin/util/HttpRequestHandlerTest.java +++ b/android/capacitor/src/test/java/com/getcapacitor/plugin/util/HttpRequestHandlerTest.java @@ -11,8 +11,8 @@ public class HttpRequestHandlerTest { static final String BASE_URL = "https://httpbin.org/get"; static final String PARAMS_JSON = """ - {"k": "a&b"} - """; + {"k": "a&b"} + """; @Test public void testHttpURLConnectionBuilderSetUrlParamsEncoded() throws Exception { diff --git a/android/package.json b/android/package.json index f42e65913d..1148b0e4a9 100644 --- a/android/package.json +++ b/android/package.json @@ -1,9 +1,9 @@ { - "name": "@capacitor-plus/android", - "version": "8.5.2", - "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.5.0", + "description": "Capacitor: Cross-platform apps with JavaScript and the web", + "homepage": "https://capacitorjs.com", + "author": "Ionic Team (https://ionic.io)", "license": "MIT", "repository": { "type": "git", @@ -23,7 +23,6 @@ "verify": "./gradlew clean lint build test -b capacitor/build.gradle" }, "peerDependencies": { - "@capacitor-plus/core": "^8.5.0", "@capacitor/core": "^8.5.0" }, "publishConfig": { diff --git a/cli/CHANGELOG.md b/cli/CHANGELOG.md index 64ffed5668..950f3335df 100644 --- a/cli/CHANGELOG.md +++ b/cli/CHANGELOG.md @@ -3,29 +3,13 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. -## [8.5.2](https://github.com/Cap-go/capacitor-plus/compare/8.5.1...8.5.2) (2026-08-26) - -**Note:** Version bump only for package @capacitor-plus/cli - - - - - -## [8.5.1](https://github.com/Cap-go/capacitor-plus/compare/8.3.12...8.5.1) (2026-08-25) - -**Note:** Version bump only for package @capacitor-plus/cli - - - - - # [8.5.0](https://github.com/ionic-team/capacitor/compare/8.4.2...8.5.0) (2026-07-31) -## Bug Fixes +### Bug Fixes - **cli:** support TypeScript 7 when loading capacitor.config.ts ([#8534](https://github.com/ionic-team/capacitor/issues/8534)) ([4c1c870](https://github.com/ionic-team/capacitor/commit/4c1c8709413b9c19b008c99122ca330cc3c90e6f)) -## Features +### Features - **cli:** add migrator functionality for adopting UIScene ([#8544](https://github.com/ionic-team/capacitor/issues/8544)) ([984fa85](https://github.com/ionic-team/capacitor/commit/984fa85ba0adab0aacf895aed6323bf4b503dccb)) @@ -42,11 +26,11 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline # [8.4.0](https://github.com/ionic-team/capacitor/compare/8.3.4...8.4.0) (2026-06-02) -## Bug Fixes +### Bug Fixes - **cli:** revert live reload config on failure ([#8485](https://github.com/ionic-team/capacitor/issues/8485)) ([1d031a4](https://github.com/ionic-team/capacitor/commit/1d031a4abec2c793079ba8897ad2e40c4cc6c7f9)) -## Features +### Features - **cli:** add experimental packageOptions ([#8471](https://github.com/ionic-team/capacitor/issues/8471)) ([258867b](https://github.com/ionic-team/capacitor/commit/258867b7bf37b1837b99b02ec9638e5a6df08d97)) - **cli:** capture ios_package_manager in telemetry ([#8482](https://github.com/ionic-team/capacitor/issues/8482)) ([b4b297a](https://github.com/ionic-team/capacitor/commit/b4b297a52f8732659662d5e5aaeff81c0f7d9835)) diff --git a/cli/package.json b/cli/package.json index f7ee82153a..9387c3facc 100644 --- a/cli/package.json +++ b/cli/package.json @@ -1,9 +1,9 @@ { - "name": "@capacitor-plus/cli", - "version": "8.5.2", - "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.5.0", + "description": "Capacitor: Cross-platform apps with JavaScript and the web", + "homepage": "https://capacitorjs.com", + "author": "Ionic Team (https://ionic.io)", "license": "MIT", "repository": { "type": "git", @@ -60,7 +60,6 @@ "semver": "^7.6.3", "tar": "^7.5.3", "tslib": "^2.8.1", - "typescript": "~5.0.2", "xcode": "^3.0.1", "xml2js": "^0.6.2" }, diff --git a/cli/src/ios/update.ts b/cli/src/ios/update.ts index 8d28888330..8790c9ca35 100644 --- a/cli/src/ios/update.ts +++ b/cli/src/ios/update.ts @@ -1,6 +1,6 @@ import { copy, remove, pathExists, readFile, realpath, writeFile } from 'fs-extra'; import { basename, dirname, join, relative } from 'path'; -import { major, prerelease, valid } from 'semver'; +import { major, prerelease } from 'semver'; import c from '../colors'; import { checkPlatformVersions, getCapacitorPackageVersion, runTask } from '../common'; @@ -59,6 +59,30 @@ async function updatePluginFiles(config: Config, plugins: Plugin[], deployment: await generateCordovaPackageFiles(cordovaPlugins, config); const validSPMPackages = await checkPluginsForPackageSwift(config, plugins); + await Promise.all( + validSPMPackages.map(async (plugin) => { + const iosPlatformVersion = await getCapacitorPackageVersion(config, config.ios.name); + const packageSwiftPath = join(plugin.rootPath, 'Package.swift'); + let content = await readFile(packageSwiftPath, { encoding: 'utf-8' }); + const regex = new RegExp( + 'url:\\s*"https://github.com/ionic-team/capacitor-swift-pm\\.git",\\s*from:\\s*"([^"]+)"', + ); + const version = content.match(regex)?.[1]; + const majorCapVersion = major(iosPlatformVersion); + if (version && major(version) != majorCapVersion) { + const preCapVersion = prerelease(iosPlatformVersion); + const forceVersion = preCapVersion ? iosPlatformVersion : `${majorCapVersion}.0.0`; + content = setAllStringIn( + content, + `url: "https://github.com/ionic-team/capacitor-swift-pm.git",`, + `)`, + ` from: "${forceVersion}"`, + ); + await writeFile(packageSwiftPath, content); + logger.warn(`${plugin.id} is built for Capacitor ${major(version)}, it might cause issues`); + } + }), + ); await generatePackageFile(config, validSPMPackages.concat(cordovaPlugins)); diff --git a/cli/src/tasks/migrate-uiscene.ts b/cli/src/tasks/migrate-uiscene.ts index 40b0bc4200..9f6dfa2789 100644 --- a/cli/src/tasks/migrate-uiscene.ts +++ b/cli/src/tasks/migrate-uiscene.ts @@ -134,125 +134,21 @@ async function scanAndWarn(config: Config): Promise { } } -function findMatchingBrace(source: string, openIdx: number): number | null { +function hasCustomDelegateBody(source: string, sigRegex: RegExp): boolean { + const match = source.match(sigRegex); + if (!match || match.index === undefined) return false; + const openIdx = source.indexOf('{', match.index); + if (openIdx === -1) return false; let depth = 1; let i = openIdx + 1; - let inLineComment = false; - let blockCommentDepth = 0; - let inString: '"' | '"""' | null = null; - let stringHashes = 0; - while (i < source.length && depth > 0) { const ch = source[i]; - const next = source[i + 1]; - - if (inLineComment) { - if (ch === '\n') inLineComment = false; - i++; - continue; - } - - if (blockCommentDepth > 0) { - if (ch === '*' && next === '/') { - blockCommentDepth--; - i += 2; - continue; - } - if (ch === '/' && next === '*') { - blockCommentDepth++; - i += 2; - continue; - } - i++; - continue; - } - - if (inString === '"') { - if (stringHashes === 0 && ch === '\\') { - i += 2; - continue; - } - if (ch === '"') { - let closingHashes = 0; - while (source[i + 1 + closingHashes] === '#') { - closingHashes++; - } - if (closingHashes === stringHashes) { - i += 1 + closingHashes; - inString = null; - stringHashes = 0; - continue; - } - } - i++; - continue; - } - - if (inString === '"""') { - if (ch === '"' && source[i + 1] === '"' && source[i + 2] === '"') { - let closingHashes = 0; - while (source[i + 3 + closingHashes] === '#') { - closingHashes++; - } - if (closingHashes === stringHashes) { - i += 3 + closingHashes; - inString = null; - stringHashes = 0; - continue; - } - } - i++; - continue; - } - - if (ch === '/' && next === '/') { - inLineComment = true; - i += 2; - continue; - } - - if (ch === '/' && next === '*') { - blockCommentDepth++; - i += 2; - continue; - } - - if (ch === '#' || ch === '"') { - let hashes = 0; - while (source[i + hashes] === '#') { - hashes++; - } - const quoteIdx = i + hashes; - if (source[quoteIdx] === '"') { - if (source[quoteIdx + 1] === '"' && source[quoteIdx + 2] === '"') { - inString = '"""'; - stringHashes = hashes; - i = quoteIdx + 3; - continue; - } - inString = '"'; - stringHashes = hashes; - i = quoteIdx + 1; - continue; - } - } - if (ch === '{') depth++; else if (ch === '}') depth--; i++; } - - return depth === 0 ? i - 1 : null; -} - -function hasCustomDelegateBody(source: string, sigRegex: RegExp): boolean { - const match = source.match(sigRegex); - if (!match || match.index === undefined) return false; - const openIdx = source.indexOf('{', match.index); - if (openIdx === -1) return false; - const closeIdx = findMatchingBrace(source, openIdx); - if (closeIdx === null) return false; - const body = source.slice(openIdx + 1, closeIdx); + if (depth !== 0) return false; + const body = source.slice(openIdx + 1, i - 1); const codeLines = body .split('\n') .map((l) => l.trim()) @@ -329,11 +225,18 @@ function extractConfigurationForConnecting(appDelegateSource: string): string | if (openIdx === -1) { return null; } - const closeIdx = findMatchingBrace(appDelegateSource, openIdx); - if (closeIdx === null) { + let depth = 1; + let i = openIdx + 1; + while (i < appDelegateSource.length && depth > 0) { + const ch = appDelegateSource[i]; + if (ch === '{') depth++; + else if (ch === '}') depth--; + i++; + } + if (depth !== 0) { return null; } - return '\n' + appDelegateSource.slice(sigMatch.index, closeIdx + 1) + '\n'; + return '\n' + appDelegateSource.slice(sigMatch.index, i) + '\n'; } function insertBeforeAppDelegateClassEnd(source: string, snippet: string): string | null { @@ -343,10 +246,18 @@ function insertBeforeAppDelegateClassEnd(source: string, snippet: string): strin return null; } const openIdx = source.indexOf('{', match.index); - const closeIdx = findMatchingBrace(source, openIdx); - if (closeIdx === null) { + let depth = 1; + let i = openIdx + 1; + while (i < source.length && depth > 0) { + const ch = source[i]; + if (ch === '{') depth++; + else if (ch === '}') depth--; + i++; + } + if (depth !== 0) { return null; } + const closeIdx = i - 1; return source.slice(0, closeIdx) + snippet + source.slice(closeIdx); } @@ -387,7 +298,6 @@ function describeSignals({ export const __testables = { classify, describeSignals, - findMatchingBrace, insertBeforeAppDelegateClassEnd, extractConfigurationForConnecting, hasCustomDelegateBody, diff --git a/cli/src/tasks/migrate.ts b/cli/src/tasks/migrate.ts index ca6f1e7f0c..8631897294 100644 --- a/cli/src/tasks/migrate.ts +++ b/cli/src/tasks/migrate.ts @@ -446,7 +446,7 @@ async function writeBreakingChanges() { )}.`, ); } - if (allDependencies['@capacitor/ios'] || allDependencies['@capacitor-plus/ios']) { + if (allDependencies['@capacitor/ios']) { logger.info( 'IMPORTANT: Capacitor 8.5 adopts UIScene on iOS. ' + 'See https://capacitorjs.com/docs/updating/8-5 for the full 8.4 → 8.5 migration guide.', diff --git a/cli/src/tasks/run.ts b/cli/src/tasks/run.ts index 780c8130e0..2fef2989f7 100644 --- a/cli/src/tasks/run.ts +++ b/cli/src/tasks/run.ts @@ -121,9 +121,6 @@ export async function runCommand( } catch (e: any) { if (options.liveReload) { await CapLiveReloadHelper.revertCapConfigForLiveReload(); - if (liveReloadManifestUpdated && platformName === config.android.name && cordovaPlugins) { - await writeCordovaAndroidManifest(cordovaPlugins, config, platformName, false); - } } if (!isFatal(e)) { fatal(e.stack ?? e); diff --git a/cli/src/util/node.ts b/cli/src/util/node.ts index 5600b5cad5..2967816113 100644 --- a/cli/src/util/node.ts +++ b/cli/src/util/node.ts @@ -30,7 +30,27 @@ const dynamicImport: (specifier: string) => Promise = new Function('specifi /** * @see https://github.com/ionic-team/stencil/blob/HEAD/src/compiler/sys/node-require.ts */ -function loadWithClassicCompiler(ts: typeof typescript, id: string): unknown { +export const requireTS = async (ts: typeof typescript, p: string): Promise => { + const id = resolve(p); + + if (!hasClassicCompilerAPI(ts)) { + // Node has its own built-in TypeScript syntax stripping (stable since Node 23.6, and + // available behind --experimental-strip-types since Node 22.6), so we can load the file + // directly via the native ESM loader instead of transpiling it ourselves. + try { + return await dynamicImport(pathToFileURL(id).href); + } catch (e: any) { + if (e?.code === 'ERR_UNKNOWN_FILE_EXTENSION') { + throw new Error( + `Your installed version of TypeScript (${ts.version}) no longer provides the compiler API Capacitor previously used to load .ts config files, ` + + `and your Node.js runtime (${process.version}) doesn't support loading them natively either.\n` + + 'Upgrade to Node.js 22.6+ (running with --experimental-strip-types), or Node.js 23.6+, to continue using capacitor.config.ts.', + ); + } + throw e; + } + } + delete require.cache[id]; require.extensions['.ts'] = (module: NodeModuleWithCompile, fileName: string) => { diff --git a/cli/src/util/spm.ts b/cli/src/util/spm.ts index 8c0ee028cd..9f623b7e0f 100644 --- a/cli/src/util/spm.ts +++ b/cli/src/util/spm.ts @@ -137,9 +137,9 @@ let package = Package( const options = packageOptions[plugin.id]; const symlink = options?.symlink; const symlinkFolder = join('symlinks', plugin.name); - const relPath = convertToUnixPath( - symlink ? symlinkFolder : relative(config.ios.nativeXcodeProjDirAbs, plugin.rootPath), - ); + const relPath = symlink + ? symlinkFolder + : convertToUnixPath(relative(config.ios.nativeXcodeProjDirAbs, plugin.rootPath)); if (symlink) { await ensureSymlink(plugin.rootPath, resolve(config.ios.nativeProjectDirAbs, 'CapApp-SPM', symlinkFolder)); } @@ -275,6 +275,7 @@ export async function addSceneManifestIfNeeded(config: Config): Promise { { UISceneConfigurationName: 'Default Configuration', UISceneDelegateClassName: '$(PRODUCT_MODULE_NAME).SceneDelegate', + UISceneStoryboardFile: 'Main', }, ], }, diff --git a/cli/src/util/xcode.ts b/cli/src/util/xcode.ts index 86a9707e9e..64ab836a34 100644 --- a/cli/src/util/xcode.ts +++ b/cli/src/util/xcode.ts @@ -1,5 +1,4 @@ import { writeFileSync } from 'fs-extra'; -import { basename } from 'path'; import { project as loadXcodeProject } from 'xcode'; import type { XcodeProject } from 'xcode'; @@ -21,8 +20,7 @@ export function addSwiftFileToAppTarget( const project = loadXcodeProject(pbxprojPath); project.parseSync(); - const targetUuid = project.getFirstTarget().uuid; - if (project.hasFile(fileRelPath) && isSwiftFileInTargetSources(project, fileRelPath, targetUuid)) { + if (project.hasFile(fileRelPath)) { return { added: false }; } @@ -31,31 +29,7 @@ export function addSwiftFileToAppTarget( throw new Error(`Could not find PBXGroup with comment "${groupName}" in ${pbxprojPath}`); } - if (project.hasFile(fileRelPath) && !isSwiftFileInTargetSources(project, fileRelPath, targetUuid)) { - const fileRefUuid = findFileRefUuid(project, fileRelPath); - if (!fileRefUuid) { - throw new Error(`Could not find PBXFileReference for ${fileRelPath} in ${pbxprojPath}`); - } - - const group = project.getPBXGroupByKey(groupUuid); - if (group && !group.children.some((child: { comment?: string }) => child.comment === fileRelPath)) { - group.children.push({ value: fileRefUuid, comment: fileRelPath }); - } - - const file = { - fileRef: fileRefUuid, - path: fileRelPath, - basename: basename(fileRelPath), - group: 'Sources', - target: targetUuid, - uuid: project.generateUuid(), - }; - (project as XcodeProject & { addToPbxBuildFileSection: (file: unknown) => void }).addToPbxBuildFileSection(file); - (project as XcodeProject & { addToPbxSourcesBuildPhase: (file: unknown) => void }).addToPbxSourcesBuildPhase(file); - writeFileSync(pbxprojPath, project.writeSync(), 'utf-8'); - return { added: true }; - } - + const targetUuid = project.getFirstTarget().uuid; const result = project.addSourceFile(fileRelPath, { target: targetUuid }, groupUuid); if (!result) { throw new Error(`Failed to register ${fileRelPath} in ${pbxprojPath}`); @@ -65,38 +39,6 @@ export function addSwiftFileToAppTarget( return { added: true }; } -function fileReferenceMatchesPath(ref: { path?: string }, fileRelPath: string): boolean { - const path = ref.path; - return path === fileRelPath || path === `"${fileRelPath}"`; -} - -function findFileRefUuid(project: XcodeProject, fileRelPath: string): string | null { - const objects = project.hash.project.objects; - const fileRefs = Object.entries(objects.PBXFileReference).filter(([k]) => !k.endsWith('_comment')); - const fileRefEntry = fileRefs.find( - ([, ref]) => typeof ref === 'object' && fileReferenceMatchesPath(ref as { path?: string }, fileRelPath), - ); - return fileRefEntry?.[0] ?? null; -} - -function isSwiftFileInTargetSources(project: XcodeProject, fileRelPath: string, targetUuid: string): boolean { - const fileRefUuid = findFileRefUuid(project, fileRelPath); - if (!fileRefUuid) { - return false; - } - - const objects = project.hash.project.objects; - const sourcesPhase = project.pbxSourcesBuildPhaseObj(targetUuid); - if (!sourcesPhase?.files) { - return false; - } - - return sourcesPhase.files.some((file: { value?: string }) => { - const buildFile = objects.PBXBuildFile[file.value ?? '']; - return typeof buildFile === 'object' && buildFile?.fileRef === fileRefUuid; - }); -} - // Exported for tests. export function findGroupUuidByComment(project: XcodeProject, comment: string): string | null { const groups = project.hash.project.objects.PBXGroup; diff --git a/cli/test/migrate-uiscene-plist.spec.ts b/cli/test/migrate-uiscene-plist.spec.ts index f07dded8c0..dc3bd25135 100644 --- a/cli/test/migrate-uiscene-plist.spec.ts +++ b/cli/test/migrate-uiscene-plist.spec.ts @@ -81,7 +81,7 @@ describe('addSceneManifestIfNeeded', () => { expect(roleArray).toHaveLength(1); expect(roleArray[0]['UISceneConfigurationName']).toBe('Default Configuration'); expect(roleArray[0]['UISceneDelegateClassName']).toBe('$(PRODUCT_MODULE_NAME).SceneDelegate'); - expect(roleArray[0]['UISceneStoryboardFile']).toBeUndefined(); + expect(roleArray[0]['UISceneStoryboardFile']).toBe('Main'); }); it('preserves sibling keys', async () => { diff --git a/cli/test/migrate-uiscene-scan.spec.ts b/cli/test/migrate-uiscene-scan.spec.ts index 7fa3f84e34..c0d7964ddf 100644 --- a/cli/test/migrate-uiscene-scan.spec.ts +++ b/cli/test/migrate-uiscene-scan.spec.ts @@ -7,7 +7,7 @@ import { __testables } from '../src/tasks/migrate-uiscene'; import { mktmp } from './util'; -const { hasCustomDelegateBody, scanAndWarn, findMatchingBrace } = __testables; +const { hasCustomDelegateBody, scanAndWarn } = __testables; const OPEN_URL_SIG = /func application\([^)]*\bopen url:/; const CONTINUE_SIG = /func application\([^)]*\bcontinue userActivity:/; @@ -82,26 +82,6 @@ class AppDelegate: UIResponder, UIApplicationDelegate { }); }); -describe('findMatchingBrace', () => { - it('ignores braces inside ordinary string literals', () => { - const source = 'class AppDelegate {\n let payload = "{\\"a\\":1}"\n}'; - const openIdx = source.indexOf('{'); - expect(findMatchingBrace(source, openIdx)).toBe(source.length - 1); - }); - - it('ignores braces inside raw string literals', () => { - const source = 'class AppDelegate {\n let payload = #"}"#\n}'; - const openIdx = source.indexOf('{'); - expect(findMatchingBrace(source, openIdx)).toBe(source.length - 1); - }); - - it('ignores braces inside multiline string literals', () => { - const source = 'class AppDelegate {\n let payload = """\n }\n """\n}'; - const openIdx = source.indexOf('{'); - expect(findMatchingBrace(source, openIdx)).toBe(source.length - 1); - }); -}); - describe('scanAndWarn', () => { let tmpDir: any; let iosDir: string; @@ -172,19 +152,13 @@ describe('scanAndWarn', () => { expect(warnSpy).not.toHaveBeenCalled(); }); - it('skips Pods/, build/, DerivedData/, and .build/ directories', async () => { + it('skips Pods/, build/, and DerivedData/ directories', async () => { const podsDir = join(iosDir, 'App', 'Pods'); const buildDir = join(iosDir, 'App', 'build'); - const derivedDataDir = join(iosDir, 'App', 'DerivedData'); - const dotBuildDir = join(iosDir, 'App', '.build'); await mkdirp(podsDir); await mkdirp(buildDir); - await mkdirp(derivedDataDir); - await mkdirp(dotBuildDir); writeFileSync(join(podsDir, 'ThirdParty.swift'), `let x = UIApplication.shared.applicationState\n`); writeFileSync(join(buildDir, 'Generated.swift'), `class TmpViewController {}\n`); - writeFileSync(join(derivedDataDir, 'BuildOutput.swift'), `class TmpViewController {}\n`); - writeFileSync(join(dotBuildDir, 'Artifact.swift'), `class TmpViewController {}\n`); await scanAndWarn(makeConfig()); diff --git a/cli/test/xcode.spec.ts b/cli/test/xcode.spec.ts index 6071945ab4..e6aa083570 100644 --- a/cli/test/xcode.spec.ts +++ b/cli/test/xcode.spec.ts @@ -23,11 +23,8 @@ describe('findGroupUuidByComment', () => { const uuid = findGroupUuidByComment(project, 'App'); - if (!uuid) { - throw new Error('Expected App group UUID'); - } expect(uuid).toMatch(/^[A-F0-9]{24}$/); - const group = project.getPBXGroupByKey(uuid); + const group = project.getPBXGroupByKey(uuid!); expect(group).toBeDefined(); expect(group?.path).toBe('App'); }); @@ -41,7 +38,7 @@ describe('findGroupUuidByComment', () => { }); describe('addSwiftFileToAppTarget', () => { - let tmpDir: Awaited> | undefined; + let tmpDir: any; let pbxprojPath: string; beforeEach(async () => { @@ -50,8 +47,7 @@ describe('addSwiftFileToAppTarget', () => { }); afterEach(() => { - const cleanup = tmpDir?.cleanupCallback as unknown as (() => void) | undefined; - cleanup?.(); + tmpDir.cleanupCallback(); }); it('registers a new Swift file in all four pbxproj sections', () => { @@ -78,14 +74,11 @@ describe('addSwiftFileToAppTarget', () => { buildFiles.some(([k]) => (objects.PBXBuildFile as any)[`${k}_comment`]?.includes('SceneDelegate.swift')), ).toBe(true); - const appGroupUuid = findGroupUuidByComment(project, 'App'); - if (!appGroupUuid) { - throw new Error('Expected App group UUID'); - } - const appGroup = project.getPBXGroupByKey(appGroupUuid); - expect(appGroup?.children.some((c: any) => c.comment === 'SceneDelegate.swift')).toBe(true); + const appGroupUuid = findGroupUuidByComment(project, 'App')!; + const appGroup = project.getPBXGroupByKey(appGroupUuid)!; + expect(appGroup.children.some((c: any) => c.comment === 'SceneDelegate.swift')).toBe(true); - const sourcesPhase = objects.PBXSourcesBuildPhase ?? {}; + const sourcesPhase = objects.PBXSourcesBuildPhase!; const sourcesEntries = Object.entries(sourcesPhase).filter(([k]) => !k.endsWith('_comment')); const [, sourcesObj] = sourcesEntries[0]; expect((sourcesObj as any).files.some((f: any) => f.comment?.includes('SceneDelegate.swift'))).toBe(true); diff --git a/core/CHANGELOG.md b/core/CHANGELOG.md index 067d0aa2ee..ddc7db3339 100644 --- a/core/CHANGELOG.md +++ b/core/CHANGELOG.md @@ -3,22 +3,6 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. -## [8.5.2](https://github.com/Cap-go/capacitor-plus/compare/8.5.1...8.5.2) (2026-08-26) - -**Note:** Version bump only for package @capacitor-plus/core - - - - - -## [8.5.1](https://github.com/Cap-go/capacitor-plus/compare/8.3.12...8.5.1) (2026-08-25) - -**Note:** Version bump only for package @capacitor-plus/core - - - - - # [8.5.0](https://github.com/ionic-team/capacitor/compare/8.4.2...8.5.0) (2026-07-31) **Note:** Version bump only for package @capacitor/core diff --git a/core/package.json b/core/package.json index 48d3934ba6..1b364837c7 100644 --- a/core/package.json +++ b/core/package.json @@ -1,9 +1,9 @@ { - "name": "@capacitor-plus/core", - "version": "8.5.2", - "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.5.0", + "description": "Capacitor: Cross-platform apps with JavaScript and the web", + "homepage": "https://capacitorjs.com", + "author": "Ionic Team (https://ionic.io)", "license": "MIT", "repository": { "type": "git", diff --git a/ios-pods-template/App/App/Info.plist b/ios-pods-template/App/App/Info.plist index 485f40e314..f8c8a57659 100644 --- a/ios-pods-template/App/App/Info.plist +++ b/ios-pods-template/App/App/Info.plist @@ -25,19 +25,21 @@ UIApplicationSceneManifest UIApplicationSupportsMultipleScenes - - UISceneConfigurations - - UIWindowSceneSessionRoleApplication - - - UISceneConfigurationName - Default Configuration - UISceneDelegateClassName - $(PRODUCT_MODULE_NAME).SceneDelegate - - - + + UISceneConfigurations + + UIWindowSceneSessionRoleApplication + + + UISceneConfigurationName + Default Configuration + UISceneDelegateClassName + $(PRODUCT_MODULE_NAME).SceneDelegate + UISceneStoryboardFile + Main + + + UILaunchStoryboardName LaunchScreen diff --git a/ios-spm-template/App/App/Info.plist b/ios-spm-template/App/App/Info.plist index bdf2461d53..fc41ce69bc 100644 --- a/ios-spm-template/App/App/Info.plist +++ b/ios-spm-template/App/App/Info.plist @@ -27,19 +27,21 @@ UIApplicationSceneManifest UIApplicationSupportsMultipleScenes - - UISceneConfigurations - - UIWindowSceneSessionRoleApplication - - - UISceneConfigurationName - Default Configuration - UISceneDelegateClassName - $(PRODUCT_MODULE_NAME).SceneDelegate - - - + + UISceneConfigurations + + UIWindowSceneSessionRoleApplication + + + UISceneConfigurationName + Default Configuration + UISceneDelegateClassName + $(PRODUCT_MODULE_NAME).SceneDelegate + UISceneStoryboardFile + Main + + + UILaunchStoryboardName LaunchScreen diff --git a/ios/CHANGELOG.md b/ios/CHANGELOG.md index 7886796ba7..e0cd1e8e87 100644 --- a/ios/CHANGELOG.md +++ b/ios/CHANGELOG.md @@ -3,25 +3,9 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. -## [8.5.2](https://github.com/Cap-go/capacitor-plus/compare/8.5.1...8.5.2) (2026-08-26) - -**Note:** Version bump only for package @capacitor-plus/ios - - - - - -## [8.5.1](https://github.com/Cap-go/capacitor-plus/compare/8.3.12...8.5.1) (2026-08-25) - -**Note:** Version bump only for package @capacitor-plus/ios - - - - - # [8.5.0](https://github.com/ionic-team/capacitor/compare/8.4.2...8.5.0) (2026-07-31) -## Features +### Features - **ios:** UIScene Support ([#8536](https://github.com/ionic-team/capacitor/issues/8536)) ([3fa04a3](https://github.com/ionic-team/capacitor/commit/3fa04a357c92af34cd6fccb8124791963804a9dc)) @@ -35,7 +19,7 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline # [8.4.0](https://github.com/ionic-team/capacitor/compare/8.3.4...8.4.0) (2026-06-02) -## Features +### Features - add method getDouble to plugin config ([#7638](https://github.com/ionic-team/capacitor/issues/7638)) ([93c72de](https://github.com/ionic-team/capacitor/commit/93c72de40a2ec4c78b33659250cb08340083088e)) diff --git a/ios/Capacitor/Capacitor/CAPSceneDelegateProxy.swift b/ios/Capacitor/Capacitor/CAPSceneDelegateProxy.swift index 6ef6235e92..782efe4cff 100644 --- a/ios/Capacitor/Capacitor/CAPSceneDelegateProxy.swift +++ b/ios/Capacitor/Capacitor/CAPSceneDelegateProxy.swift @@ -7,7 +7,6 @@ // import Foundation -import UIKit @objc(CAPSceneDelegateProxy) public class SceneDelegateProxy: NSObject, UISceneDelegate { @@ -22,12 +21,10 @@ public class SceneDelegateProxy: NSObject, UISceneDelegate { // missed. Deliver them on the first capacitorViewDidAppear, once plugins are // registered. var token: NSObjectProtocol? - token = NotificationCenter.default.addObserver(forName: .capacitorViewDidAppear, object: nil, queue: .main) { [weak self] _ in - guard let self, Self.isBridgeReady(for: scene) else { return } + token = NotificationCenter.default.addObserver(forName: .capacitorViewDidAppear, object: nil, queue: .main) { _ in if let token { NotificationCenter.default.removeObserver(token) } - token = nil if !connectionOptions.urlContexts.isEmpty { self.scene(scene, openURLContexts: connectionOptions.urlContexts) } @@ -37,41 +34,6 @@ public class SceneDelegateProxy: NSObject, UISceneDelegate { } } - private static func isBridgeReady(for scene: UIScene) -> Bool { - guard let windowScene = scene as? UIWindowScene else { - return false - } - - for window in windowScene.windows { - guard let bridge = findBridge(in: window.rootViewController) else { - continue - } - if bridge.isViewLoaded && bridge.view.window != nil { - return true - } - } - - return false - } - - private static func findBridge(in viewController: UIViewController?) -> CAPBridgeViewController? { - if let bridge = viewController as? CAPBridgeViewController { - return bridge - } - if let navigationController = viewController as? UINavigationController { - return findBridge(in: navigationController.visibleViewController) - } - if let tabBarController = viewController as? UITabBarController { - return findBridge(in: tabBarController.selectedViewController) - } - for child in viewController?.children ?? [] { - if let bridge = findBridge(in: child) { - return bridge - } - } - return nil - } - public func scene(_ scene: UIScene, openURLContexts URLContexts: Set) { for context in URLContexts { lastURL = context.url diff --git a/ios/Capacitor/Capacitor/CapacitorBridge.swift b/ios/Capacitor/Capacitor/CapacitorBridge.swift index 4251102e4b..65679fa2b3 100644 --- a/ios/Capacitor/Capacitor/CapacitorBridge.swift +++ b/ios/Capacitor/Capacitor/CapacitorBridge.swift @@ -263,13 +263,16 @@ open class CapacitorBridge: NSObject, CAPBridgeProtocol { exportCordovaJS() registerCordovaPlugins() } else { - observers.append(NotificationCenter.default.addObserver(forName: UIApplication.willEnterForegroundNotification, object: nil, queue: OperationQueue.main) { [weak self] _ in - guard self?.viewController?.view.window?.windowScene == nil else { return } - self?.triggerDocumentJSEvent(eventName: "resume") + observers.append(NotificationCenter.default.addObserver(forName: UIScene.willEnterForegroundNotification, object: nil, queue: OperationQueue.main) { [weak self] notification in + if let scene = notification.object as? UIWindowScene, scene === self?.viewController?.view.window?.windowScene { + self?.triggerDocumentJSEvent(eventName: "resume") + } + }) - observers.append(NotificationCenter.default.addObserver(forName: UIApplication.didEnterBackgroundNotification, object: nil, queue: OperationQueue.main) { [weak self] _ in - guard self?.viewController?.view.window?.windowScene == nil else { return } - self?.triggerDocumentJSEvent(eventName: "pause") + observers.append(NotificationCenter.default.addObserver(forName: UIScene.didEnterBackgroundNotification, object: nil, queue: OperationQueue.main) { [weak self] notification in + if let scene = notification.object as? UIWindowScene, scene === self?.viewController?.view.window?.windowScene { + self?.triggerDocumentJSEvent(eventName: "pause") + } }) observers.append(NotificationCenter.default.addObserver(forName: UIScene.willEnterForegroundNotification, object: nil, queue: OperationQueue.main) { [weak self] notification in if let scene = notification.object as? UIWindowScene, scene === self?.viewController?.view.window?.windowScene { diff --git a/ios/package.json b/ios/package.json index 0925b653eb..7c87d8f35e 100644 --- a/ios/package.json +++ b/ios/package.json @@ -1,9 +1,9 @@ { - "name": "@capacitor-plus/ios", - "version": "8.5.2", - "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.5.0", + "description": "Capacitor: Cross-platform apps with JavaScript and the web", + "homepage": "https://capacitorjs.com", + "author": "Ionic Team (https://ionic.io)", "license": "MIT", "repository": { "type": "git", @@ -25,7 +25,6 @@ "xc:build:CapacitorCordova": "cd CapacitorCordova && xcodebuild && cd .." }, "peerDependencies": { - "@capacitor-plus/core": "^8.5.0", "@capacitor/core": "^8.5.0" }, "publishConfig": { diff --git a/lerna.json b/lerna.json index 06ff51191c..168f7298a5 100644 --- a/lerna.json +++ b/lerna.json @@ -13,6 +13,6 @@ "tagVersionPrefix": "" } }, - "version": "8.5.2", + "version": "8.5.0", "$schema": "node_modules/lerna/schemas/lerna-schema.json" }