diff --git a/.eslintignore b/.eslintignore index 4a1df4e690..abf24cdbf6 100644 --- a/.eslintignore +++ b/.eslintignore @@ -3,6 +3,6 @@ cli/assets dist types android/capacitor/src/main/assets/native-bridge.js -ios/Capacitor/Capacitor/assets/native-bridge.js +ios/Sources/Capacitor/assets/native-bridge.js ios/Frameworks/Capacitor.xcframework/ios-arm64_x86_64-simulator/Capacitor.framework/native-bridge.js ios/Frameworks/Capacitor.xcframework/ios-arm64/Capacitor.framework/native-bridge.js diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 471e939ec8..a3d35a1919 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -89,7 +89,7 @@ jobs: - run: npm test working-directory: ./core test-ios: - runs-on: macos-15 + runs-on: macos-26 timeout-minutes: 30 needs: - setup @@ -97,7 +97,7 @@ jobs: strategy: matrix: xcode: - - /Applications/Xcode_26.0.app + - /Applications/Xcode_26.6.app steps: - run: sudo xcode-select --switch ${{ matrix.xcode }} - run: xcrun simctl list > /dev/null diff --git a/.gitignore b/.gitignore index 0968d10c62..703a749612 100644 --- a/.gitignore +++ b/.gitignore @@ -10,6 +10,7 @@ Pods/ Podfile.lock Build/* build/ +.build Index/ .*.sw* android-template.iml diff --git a/.prettierignore b/.prettierignore index 143c857005..bc26e51947 100644 --- a/.prettierignore +++ b/.prettierignore @@ -3,6 +3,6 @@ core/types cli/assets dist android/capacitor/src/main/assets/native-bridge.js -ios/Capacitor/Capacitor/assets/native-bridge.js +ios/Sources/Capacitor/assets/native-bridge.js ios/Frameworks/Capacitor.xcframework/ios-arm64_x86_64-simulator/Capacitor.framework/native-bridge.js ios/Frameworks/Capacitor.xcframework/ios-arm64/Capacitor.framework/native-bridge.js diff --git a/CHANGELOG.md b/CHANGELOG.md index 23c60e63ed..865f96f3e4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. # [9.0.0-alpha.6](https://github.com/ionic-team/capacitor/compare/9.0.0-alpha.5...9.0.0-alpha.6) (2026-07-14) +## [8.4.1](https://github.com/ionic-team/capacitor/compare/8.4.0...8.4.1) (2026-06-19) + +### Bug Fixes + +- **cli:** make SPM dependency patch work on prereleases ([#8508](https://github.com/ionic-team/capacitor/issues/8508)) ([6048e90](https://github.com/ionic-team/capacitor/commit/6048e90171afa0229a3c25b52a23c377c6bb804c)) +- **cli:** patch Capacitor SPM dependency version in plugins ([#8492](https://github.com/ionic-team/capacitor/issues/8492)) ([28bb2c6](https://github.com/ionic-team/capacitor/commit/28bb2c687069dfdd6aa7abc866004a1c6388d103)) + +# [8.4.0](https://github.com/ionic-team/capacitor/compare/8.3.4...8.4.0) (2026-06-02) ### Bug Fixes diff --git a/Package.swift b/Package.swift new file mode 100644 index 0000000000..dc0383f631 --- /dev/null +++ b/Package.swift @@ -0,0 +1,62 @@ +// swift-tools-version: 6.3 +import PackageDescription + +let package = Package( + name: "Capacitor", + platforms: [.iOS(.v16)], + products: [ + .library( + name: "Capacitor", + targets: ["Capacitor"] + ), + .library( + name: "Cordova", + targets: ["Cordova"] + ), + .library( + name: "CapacitorCordova", + targets: ["Cordova", "CapacitorCordova"] + ) + ], + targets: [ + .target( + name: "Capacitor", + path: "ios/Sources/Capacitor", + resources: [.copy("assets")], + swiftSettings: [ + .swiftLanguageMode(.v5) + ], + + ), + .target( + name: "Cordova", + path: "ios/Sources/Cordova", + publicHeadersPath: "include", + cSettings: [ + .headerSearchPath("include"), + ], + linkerSettings: [ + .linkedFramework("UIKit"), + .linkedFramework("WebKit"), + .linkedFramework("MobileCoreServices"), + .linkedFramework("CFNetwork") + ] + ), + .target( + name: "CapacitorCordova", + dependencies: ["Capacitor", "Cordova"], + path: "ios/Sources/CapacitorCordova", + ), + .testTarget( + name: "CapacitorTests", + dependencies: [ + "Capacitor" + ], + path: "ios/Tests/CapacitorTests", + resources: [ + .copy("Resources/configurations") + ] + ) + ], + swiftLanguageModes: [.v5] +) diff --git a/android/CHANGELOG.md b/android/CHANGELOG.md index 0a30c257f2..b08ea428a1 100644 --- a/android/CHANGELOG.md +++ b/android/CHANGELOG.md @@ -31,6 +31,10 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline # [9.0.0-alpha.3](https://github.com/ionic-team/capacitor/compare/8.4.0...9.0.0-alpha.3) (2026-06-02) +## [8.4.1](https://github.com/ionic-team/capacitor/compare/8.4.0...8.4.1) (2026-06-19) + +**Note:** Version bump only for package @capacitor/android + # [8.4.0](https://github.com/ionic-team/capacitor/compare/8.3.4...8.4.0) (2026-06-02) ### Bug Fixes diff --git a/cli/src/ios/update.ts b/cli/src/ios/update.ts index 93a1ad4b55..3f4f009a1b 100644 --- a/cli/src/ios/update.ts +++ b/cli/src/ios/update.ts @@ -65,13 +65,18 @@ async function updatePluginFiles(config: Config, plugins: Plugin[], deployment: await Promise.all( validSPMPackages.map(async (plugin) => { const iosPlatformVersion = await getCapacitorPackageVersion(config, config.ios.name); + const majorCapVersion = major(iosPlatformVersion); + if (majorCapVersion >= 9) { + // Capacitor 9+ uses a branch-based dependency, so there's no version to reconcile. + return; + } + 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`; diff --git a/cli/src/util/cordova-ios.ts b/cli/src/util/cordova-ios.ts index 371bd96d33..f097d4ed29 100644 --- a/cli/src/util/cordova-ios.ts +++ b/cli/src/util/cordova-ios.ts @@ -1,5 +1,6 @@ import { copy, readFile, writeFile, remove } from 'fs-extra'; import { join } from 'path'; +import { major } from 'semver'; import { getCapacitorPackageVersion } from '../common'; import { needsStaticPod } from '../cordova'; @@ -353,18 +354,26 @@ export async function generateCordovaPackageFile(p: Plugin, config: Config): Pro publicHeadersPath: "."`; } + const useSourceSPM = major(iosPlatformVersion) >= 9; + const capacitorPackageName = useSourceSPM ? 'capacitor' : 'capacitor-swift-pm'; + const capacitorPackageUrl = useSourceSPM + ? 'https://github.com/ionic-team/capacitor' + : 'https://github.com/ionic-team/capacitor-swift-pm.git'; + const capacitorPackageVersionSuffix = useSourceSPM + ? ` branch: "feature/source-spm"` + : ` from: "${iosPlatformVersion}"`; + const platformTag = getPluginPlatform(p, platform); if (platformTag.$?.package) { const packageSwiftPath = join(p.rootPath, 'Package.swift'); let content = await readFile(packageSwiftPath, { encoding: 'utf-8' }); - content = content.replace(`apache`, `ionic-team`).replaceAll(`cordova-ios`, `capacitor-swift-pm`); - content = setAllStringIn( - content, - `url: "https://github.com/ionic-team/capacitor-swift-pm.git",`, - `)`, - ` from: "${iosPlatformVersion}"`, - ); + content = content.replace(`apache`, `ionic-team`); + // The source repo is referenced as "cordova-ios.git" in URLs; source-SPM's package has no .git suffix. + content = useSourceSPM + ? content.replaceAll(`cordova-ios.git`, capacitorPackageName).replaceAll(`cordova-ios`, capacitorPackageName) + : content.replaceAll(`cordova-ios`, capacitorPackageName); + content = setAllStringIn(content, `url: "${capacitorPackageUrl}",`, `)`, capacitorPackageVersionSuffix); await writeFile(packageSwiftPath, content); } else { const content = `// swift-tools-version: 5.9 @@ -381,13 +390,13 @@ let package = Package( ) ], dependencies: [ - .package(url: "https://github.com/ionic-team/capacitor-swift-pm.git", from: "${iosPlatformVersion}") + .package(url: "${capacitorPackageUrl}",${capacitorPackageVersionSuffix}) ], targets: [ .target( name: "${p.name}", dependencies: [ - .product(name: "Cordova", package: "capacitor-swift-pm") + .product(name: "Cordova", package: "${capacitorPackageName}") ], path: "."${headersText} ) diff --git a/cli/src/util/spm.ts b/cli/src/util/spm.ts index 2c8cacc672..9245abc3cd 100644 --- a/cli/src/util/spm.ts +++ b/cli/src/util/spm.ts @@ -3,6 +3,7 @@ import { tmpdir } from 'os'; import { join, relative, resolve } from 'path'; import type { PlistObject } from 'plist'; import { build, parse } from 'plist'; +import { major } from 'semver'; import { extract } from 'tar'; import { getCapacitorPackageVersion } from '../common'; @@ -105,7 +106,12 @@ export async function generatePackageText(config: Config, plugins: Plugin[]): Pr const enableCordova = cordovaPlugins.length > 0; const packageTraits = config.app.extConfig.experimental?.ios?.spm?.packageTraits ?? {}; const packageOptions = config.app.extConfig.experimental?.ios?.spm?.packageOptions ?? {}; - const swiftToolsVersion = config.app.extConfig.experimental?.ios?.spm?.swiftToolsVersion ?? '5.9'; + const swiftToolsVersion = config.app.extConfig.experimental?.ios?.spm?.swiftToolsVersion ?? '6.3'; + const useSourceSPM = major(iosPlatformVersion) >= 9; + const capacitorPackageName = useSourceSPM ? 'capacitor' : 'capacitor-swift-pm'; + const capacitorPackageDependency = useSourceSPM + ? `.package(url: "https://github.com/ionic-team/capacitor", branch: "next")` + : `.package(url: "https://github.com/ionic-team/capacitor-swift-pm.git", exact: "${iosPlatformVersion}")`; let packageSwiftText = `// swift-tools-version: ${swiftToolsVersion} import PackageDescription @@ -120,7 +126,7 @@ let package = Package( targets: ["CapApp-SPM"]) ], dependencies: [ - .package(url: "https://github.com/ionic-team/capacitor-swift-pm.git", exact: "${iosPlatformVersion}")`; + ${capacitorPackageDependency}`; for (const plugin of plugins) { if (getPluginType(plugin, config.ios.name) === PluginType.Cordova) { @@ -165,10 +171,10 @@ let package = Package( .target( name: "CapApp-SPM", dependencies: [ - .product(name: "Capacitor", package: "capacitor-swift-pm")`; + .product(name: "Capacitor", package: "${capacitorPackageName}")`; if (enableCordova) { - packageSwiftText += `,\n .product(name: "Cordova", package: "capacitor-swift-pm")`; + packageSwiftText += `,\n .product(name: "Cordova", package: "${capacitorPackageName}")`; } for (const plugin of plugins) { diff --git a/core/rollup.bridge.config.js b/core/rollup.bridge.config.js index 9f8d90e97d..d741e5dcc5 100644 --- a/core/rollup.bridge.config.js +++ b/core/rollup.bridge.config.js @@ -17,7 +17,7 @@ export default { sourcemap: false, }, { - file: '../ios/Capacitor/Capacitor/assets/native-bridge.js', + file: '../ios/Sources/Capacitor/assets/native-bridge.js', format: 'iife', name: 'nativeBridge', preferConst: true, diff --git a/ios-pods-template/App/App.xcodeproj/project.pbxproj b/ios-pods-template/App/App.xcodeproj/project.pbxproj index 026cbd4583..88d1ad2041 100644 --- a/ios-pods-template/App/App.xcodeproj/project.pbxproj +++ b/ios-pods-template/App/App.xcodeproj/project.pbxproj @@ -9,12 +9,12 @@ /* Begin PBXBuildFile section */ 2FAD9763203C412B000D30F8 /* config.xml in Resources */ = {isa = PBXBuildFile; fileRef = 2FAD9762203C412B000D30F8 /* config.xml */; }; 50379B232058CBB4000EE86E /* capacitor.config.json in Resources */ = {isa = PBXBuildFile; fileRef = 50379B222058CBB4000EE86E /* capacitor.config.json */; }; - 504EC3081FED79650016851F /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 504EC3071FED79650016851F /* AppDelegate.swift */; }; - 504EC30D1FED79650016851F /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 504EC30B1FED79650016851F /* Main.storyboard */; }; 504EC30F1FED79650016851F /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 504EC30E1FED79650016851F /* Assets.xcassets */; }; 504EC3121FED79650016851F /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 504EC3101FED79650016851F /* LaunchScreen.storyboard */; }; 50B271D11FEDC1A000F3C39B /* public in Resources */ = {isa = PBXBuildFile; fileRef = 50B271D01FEDC1A000F3C39B /* public */; }; - 9582B6852FE996820072D4E8 /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9582B6842FE996800072D4E8 /* SceneDelegate.swift */; }; + 952C1C64302642D6000D0FF6 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 952C1C63302642D3000D0FF6 /* AppDelegate.swift */; }; + 9582B68A2FE9ABF30072D4E8 /* App.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9582B6892FE9ABF10072D4E8 /* App.swift */; }; + 9582B68C2FE9ACC30072D4E8 /* CapacitorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9582B68B2FE9ACBE0072D4E8 /* CapacitorView.swift */; }; A084ECDBA7D38E1E42DFC39D /* Pods_App.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AF277DCFFFF123FFC6DF26C7 /* Pods_App.framework */; }; /* End PBXBuildFile section */ @@ -22,13 +22,13 @@ 2FAD9762203C412B000D30F8 /* config.xml */ = {isa = PBXFileReference; lastKnownFileType = text.xml; path = config.xml; sourceTree = ""; }; 50379B222058CBB4000EE86E /* capacitor.config.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = capacitor.config.json; sourceTree = ""; }; 504EC3041FED79650016851F /* App.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = App.app; sourceTree = BUILT_PRODUCTS_DIR; }; - 504EC3071FED79650016851F /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; - 504EC30C1FED79650016851F /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 504EC30E1FED79650016851F /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 504EC3111FED79650016851F /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 504EC3131FED79650016851F /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 50B271D01FEDC1A000F3C39B /* public */ = {isa = PBXFileReference; lastKnownFileType = folder; path = public; sourceTree = ""; }; - 9582B6842FE996800072D4E8 /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = ""; }; + 952C1C63302642D3000D0FF6 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 9582B6892FE9ABF10072D4E8 /* App.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = App.swift; sourceTree = ""; }; + 9582B68B2FE9ACBE0072D4E8 /* CapacitorView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CapacitorView.swift; sourceTree = ""; }; AF277DCFFFF123FFC6DF26C7 /* Pods_App.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_App.framework; sourceTree = BUILT_PRODUCTS_DIR; }; AF51FD2D460BCFE21FA515B2 /* Pods-App.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App.release.xcconfig"; path = "Pods/Target Support Files/Pods-App/Pods-App.release.xcconfig"; sourceTree = ""; }; FC68EB0AF532CFC21C3344DD /* Pods-App.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App.debug.xcconfig"; path = "Pods/Target Support Files/Pods-App/Pods-App.debug.xcconfig"; sourceTree = ""; }; @@ -75,10 +75,10 @@ 504EC3061FED79650016851F /* App */ = { isa = PBXGroup; children = ( - 9582B6842FE996800072D4E8 /* SceneDelegate.swift */, + 952C1C63302642D3000D0FF6 /* AppDelegate.swift */, + 9582B68B2FE9ACBE0072D4E8 /* CapacitorView.swift */, + 9582B6892FE9ABF10072D4E8 /* App.swift */, 50379B222058CBB4000EE86E /* capacitor.config.json */, - 504EC3071FED79650016851F /* AppDelegate.swift */, - 504EC30B1FED79650016851F /* Main.storyboard */, 504EC30E1FED79650016851F /* Assets.xcassets */, 504EC3101FED79650016851F /* LaunchScreen.storyboard */, 504EC3131FED79650016851F /* Info.plist */, @@ -164,7 +164,6 @@ 50B271D11FEDC1A000F3C39B /* public in Resources */, 504EC30F1FED79650016851F /* Assets.xcassets in Resources */, 50379B232058CBB4000EE86E /* capacitor.config.json in Resources */, - 504EC30D1FED79650016851F /* Main.storyboard in Resources */, 2FAD9763203C412B000D30F8 /* config.xml in Resources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -212,22 +211,15 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 504EC3081FED79650016851F /* AppDelegate.swift in Sources */, - 9582B6852FE996820072D4E8 /* SceneDelegate.swift in Sources */, + 952C1C64302642D6000D0FF6 /* AppDelegate.swift in Sources */, + 9582B68A2FE9ABF30072D4E8 /* App.swift in Sources */, + 9582B68C2FE9ACC30072D4E8 /* CapacitorView.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXSourcesBuildPhase section */ /* Begin PBXVariantGroup section */ - 504EC30B1FED79650016851F /* Main.storyboard */ = { - isa = PBXVariantGroup; - children = ( - 504EC30C1FED79650016851F /* Base */, - ); - name = Main.storyboard; - sourceTree = ""; - }; 504EC3101FED79650016851F /* LaunchScreen.storyboard */ = { isa = PBXVariantGroup; children = ( diff --git a/ios-pods-template/App/App/App.swift b/ios-pods-template/App/App/App.swift new file mode 100644 index 0000000000..23b0a8cc18 --- /dev/null +++ b/ios-pods-template/App/App/App.swift @@ -0,0 +1,20 @@ +import SwiftUI +import Capacitor + +@main +struct CapacitorApp: App { + @UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate + + var body: some Scene { + WindowGroup { + CapacitorView() + .ignoresSafeArea() + .onOpenURL { url in + SceneDelegateProxy.shared.handle(openURL: url) + } + .onContinueUserActivity(NSUserActivityTypeBrowsingWeb) { activity in + SceneDelegateProxy.shared.handle(userActivity: activity) + } + } + } +} diff --git a/ios-pods-template/App/App/AppDelegate.swift b/ios-pods-template/App/App/AppDelegate.swift index 1dfbed0901..99ba4ab96e 100644 --- a/ios-pods-template/App/App/AppDelegate.swift +++ b/ios-pods-template/App/App/AppDelegate.swift @@ -1,58 +1,9 @@ +import Foundation import UIKit -import Capacitor - -@main -class AppDelegate: UIResponder, UIApplicationDelegate { - - var window: UIWindow? +class AppDelegate: NSObject, UIApplicationDelegate { func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { - // Override point for customization after application launch. return true } - - func applicationWillResignActive(_ application: UIApplication) { - // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. - // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game. - } - - func applicationDidEnterBackground(_ application: UIApplication) { - // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. - // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. - } - - func applicationWillEnterForeground(_ application: UIApplication) { - // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background. - } - - func applicationDidBecomeActive(_ application: UIApplication) { - // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. - } - - func applicationWillTerminate(_ application: UIApplication) { - // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. - } - - func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey: Any] = [:]) -> Bool { - // Called when the app was launched with a url. Feel free to add additional processing here, - // but if you want the App API to support tracking app url opens, make sure to keep this call - return ApplicationDelegateProxy.shared.application(app, open: url, options: options) - } - - func application(_ application: UIApplication, continue userActivity: NSUserActivity, restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void) -> Bool { - // Called when the app was launched with an activity, including Universal Links. - // Feel free to add additional processing here, but if you want the App API to support - // tracking app url opens, make sure to keep this call - return ApplicationDelegateProxy.shared.application(application, continue: userActivity, restorationHandler: restorationHandler) - } - - func application(_ application: UIApplication, - configurationForConnecting connectingSceneSession: UISceneSession, - options: UIScene.ConnectionOptions) -> UISceneConfiguration { - - let config = UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role) - config.delegateClass = SceneDelegate.self - return config - } - } + diff --git a/ios-pods-template/App/App/Base.lproj/Main.storyboard b/ios-pods-template/App/App/Base.lproj/Main.storyboard deleted file mode 100644 index b44df7be8f..0000000000 --- a/ios-pods-template/App/App/Base.lproj/Main.storyboard +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - - - - - - - - - - - - - - diff --git a/ios-pods-template/App/App/CapacitorView.swift b/ios-pods-template/App/App/CapacitorView.swift new file mode 100644 index 0000000000..12575c875b --- /dev/null +++ b/ios-pods-template/App/App/CapacitorView.swift @@ -0,0 +1,10 @@ +import SwiftUI +import Capacitor + +public struct CapacitorView: UIViewControllerRepresentable { + public func makeUIViewController(context: Context) -> CAPBridgeViewController { + CAPBridgeViewController() + } + + public func updateUIViewController(_ vc: CAPBridgeViewController, context: Context) {} +} diff --git a/ios-pods-template/App/App/Info.plist b/ios-pods-template/App/App/Info.plist index f8c8a57659..23320dae5e 100644 --- a/ios-pods-template/App/App/Info.plist +++ b/ios-pods-template/App/App/Info.plist @@ -25,26 +25,10 @@ UIApplicationSceneManifest UIApplicationSupportsMultipleScenes - - UISceneConfigurations - - UIWindowSceneSessionRoleApplication - - - UISceneConfigurationName - Default Configuration - UISceneDelegateClassName - $(PRODUCT_MODULE_NAME).SceneDelegate - UISceneStoryboardFile - Main - - - + UILaunchStoryboardName LaunchScreen - UIMainStoryboardFile - Main UIRequiredDeviceCapabilities armv7 diff --git a/ios-pods-template/App/App/SceneDelegate.swift b/ios-pods-template/App/App/SceneDelegate.swift deleted file mode 100644 index f352e1e959..0000000000 --- a/ios-pods-template/App/App/SceneDelegate.swift +++ /dev/null @@ -1,24 +0,0 @@ -import UIKit -import Capacitor - -class SceneDelegate: UIResponder, UIWindowSceneDelegate { - var window: UIWindow? - - func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) { - guard let windowScene = scene as? UIWindowScene else { return } - - window = UIWindow(windowScene: windowScene) - window?.rootViewController = CAPBridgeViewController() - window?.makeKeyAndVisible() - - SceneDelegateProxy.shared.scene(scene, willConnectTo: session, options: connectionOptions) - } - - func scene(_ scene: UIScene, openURLContexts URLContexts: Set) { - SceneDelegateProxy.shared.scene(scene, openURLContexts: URLContexts) - } - - func scene(_ scene: UIScene, continue userActivity: NSUserActivity) { - SceneDelegateProxy.shared.scene(scene, continue: userActivity) - } -} diff --git a/ios-spm-template/App/App.xcodeproj/project.pbxproj b/ios-spm-template/App/App.xcodeproj/project.pbxproj index 87225f719f..269623b05a 100644 --- a/ios-spm-template/App/App.xcodeproj/project.pbxproj +++ b/ios-spm-template/App/App.xcodeproj/project.pbxproj @@ -15,7 +15,8 @@ 504EC30F1FED79650016851F /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 504EC30E1FED79650016851F /* Assets.xcassets */; }; 504EC3121FED79650016851F /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 504EC3101FED79650016851F /* LaunchScreen.storyboard */; }; 50B271D11FEDC1A000F3C39B /* public in Resources */ = {isa = PBXBuildFile; fileRef = 50B271D01FEDC1A000F3C39B /* public */; }; - 9582B6832FE993A70072D4E8 /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9582B6822FE993A50072D4E8 /* SceneDelegate.swift */; }; + 9575E845302683A8004C1ED7 /* App.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9575E844302683A6004C1ED7 /* App.swift */; }; + 9575E847302683C1004C1ED7 /* CapacitorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9575E846302683BC004C1ED7 /* CapacitorView.swift */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ @@ -28,7 +29,8 @@ 504EC3111FED79650016851F /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 504EC3131FED79650016851F /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 50B271D01FEDC1A000F3C39B /* public */ = {isa = PBXFileReference; lastKnownFileType = folder; path = public; sourceTree = ""; }; - 9582B6822FE993A50072D4E8 /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = ""; }; + 9575E844302683A6004C1ED7 /* App.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = App.swift; sourceTree = ""; }; + 9575E846302683BC004C1ED7 /* CapacitorView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CapacitorView.swift; sourceTree = ""; }; 958DCC722DB07C7200EA8C5F /* debug.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = debug.xcconfig; path = ../debug.xcconfig; sourceTree = SOURCE_ROOT; }; /* End PBXFileReference section */ @@ -64,7 +66,8 @@ 504EC3061FED79650016851F /* App */ = { isa = PBXGroup; children = ( - 9582B6822FE993A50072D4E8 /* SceneDelegate.swift */, + 9575E846302683BC004C1ED7 /* CapacitorView.swift */, + 9575E844302683A6004C1ED7 /* App.swift */, 50379B222058CBB4000EE86E /* capacitor.config.json */, 504EC3071FED79650016851F /* AppDelegate.swift */, 504EC30B1FED79650016851F /* Main.storyboard */, @@ -158,8 +161,9 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 9575E845302683A8004C1ED7 /* App.swift in Sources */, 504EC3081FED79650016851F /* AppDelegate.swift in Sources */, - 9582B6832FE993A70072D4E8 /* SceneDelegate.swift in Sources */, + 9575E847302683C1004C1ED7 /* CapacitorView.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/ios-spm-template/App/App/App.swift b/ios-spm-template/App/App/App.swift new file mode 100644 index 0000000000..fec128fcef --- /dev/null +++ b/ios-spm-template/App/App/App.swift @@ -0,0 +1,21 @@ +import SwiftUI +import Capacitor + +@main +struct CapacitorApp: App { + @UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate + + var body: some Scene { + WindowGroup { + CapacitorView() + .ignoresSafeArea() + .onOpenURL { url in + SceneDelegateProxy.shared.handle(openURL: url) + } + .onContinueUserActivity(NSUserActivityTypeBrowsingWeb) { activity in + SceneDelegateProxy.shared.handle(userActivity: activity) + } + } + } +} + diff --git a/ios-spm-template/App/App/AppDelegate.swift b/ios-spm-template/App/App/AppDelegate.swift index 7fe69b516a..5fb4c09fbe 100644 --- a/ios-spm-template/App/App/AppDelegate.swift +++ b/ios-spm-template/App/App/AppDelegate.swift @@ -1,44 +1,7 @@ import UIKit -import Capacitor - -@main -class AppDelegate: UIResponder, UIApplicationDelegate { - - var window: UIWindow? +class AppDelegate: NSObject, UIApplicationDelegate { func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { - // Override point for customization after application launch. return true } - - func applicationWillResignActive(_ application: UIApplication) { - // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. - // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game. - } - - func applicationDidEnterBackground(_ application: UIApplication) { - // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. - // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. - } - - func applicationWillEnterForeground(_ application: UIApplication) { - // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background. - } - - func applicationDidBecomeActive(_ application: UIApplication) { - // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. - } - - func applicationWillTerminate(_ application: UIApplication) { - // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. - } - - func application(_ application: UIApplication, - configurationForConnecting connectingSceneSession: UISceneSession, - options: UIScene.ConnectionOptions) -> UISceneConfiguration { - let config = UISceneConfiguration(name: "Default Configuration", - sessionRole: connectingSceneSession.role) - config.delegateClass = SceneDelegate.self - return config - } } diff --git a/ios-spm-template/App/App/CapacitorView.swift b/ios-spm-template/App/App/CapacitorView.swift new file mode 100644 index 0000000000..bae562243f --- /dev/null +++ b/ios-spm-template/App/App/CapacitorView.swift @@ -0,0 +1,11 @@ +import SwiftUI +import Capacitor + +public struct CapacitorView: UIViewControllerRepresentable { + public func makeUIViewController(context: Context) -> CAPBridgeViewController { + CAPBridgeViewController() + } + + public func updateUIViewController(_ vc: CAPBridgeViewController, context: Context) {} +} + diff --git a/ios-spm-template/App/App/SceneDelegate.swift b/ios-spm-template/App/App/SceneDelegate.swift deleted file mode 100644 index f352e1e959..0000000000 --- a/ios-spm-template/App/App/SceneDelegate.swift +++ /dev/null @@ -1,24 +0,0 @@ -import UIKit -import Capacitor - -class SceneDelegate: UIResponder, UIWindowSceneDelegate { - var window: UIWindow? - - func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) { - guard let windowScene = scene as? UIWindowScene else { return } - - window = UIWindow(windowScene: windowScene) - window?.rootViewController = CAPBridgeViewController() - window?.makeKeyAndVisible() - - SceneDelegateProxy.shared.scene(scene, willConnectTo: session, options: connectionOptions) - } - - func scene(_ scene: UIScene, openURLContexts URLContexts: Set) { - SceneDelegateProxy.shared.scene(scene, openURLContexts: URLContexts) - } - - func scene(_ scene: UIScene, continue userActivity: NSUserActivity) { - SceneDelegateProxy.shared.scene(scene, continue: userActivity) - } -} diff --git a/ios-spm-template/App/CapApp-SPM/Package.swift b/ios-spm-template/App/CapApp-SPM/Package.swift index e3309a275a..b46d6e9560 100644 --- a/ios-spm-template/App/CapApp-SPM/Package.swift +++ b/ios-spm-template/App/CapApp-SPM/Package.swift @@ -1,4 +1,4 @@ -// swift-tools-version: 5.9 +// swift-tools-version: 6.3 import PackageDescription // DO NOT MODIFY THIS FILE - managed by Capacitor CLI commands @@ -11,14 +11,14 @@ let package = Package( targets: ["CapApp-SPM"]) ], dependencies: [ - .package(url: "https://github.com/ionic-team/capacitor-swift-pm.git", from: "8.0.0") + .package(url: "https://github.com/ionic-team/capacitor", branch: "next") ], targets: [ .target( name: "CapApp-SPM", dependencies: [ - .product(name: "Capacitor", package: "capacitor-swift-pm"), - .product(name: "Cordova", package: "capacitor-swift-pm") + .product(name: "Capacitor", package: "capacitor"), + .product(name: "Cordova", package: "capacitor") ] ) ] diff --git a/ios/CHANGELOG.md b/ios/CHANGELOG.md index c0eb3e1de5..ff21df1e13 100644 --- a/ios/CHANGELOG.md +++ b/ios/CHANGELOG.md @@ -27,6 +27,10 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline # [9.0.0-alpha.3](https://github.com/ionic-team/capacitor/compare/8.4.0...9.0.0-alpha.3) (2026-06-02) +## [8.4.1](https://github.com/ionic-team/capacitor/compare/8.4.0...8.4.1) (2026-06-19) + +**Note:** Version bump only for package @capacitor/ios + # [8.4.0](https://github.com/ionic-team/capacitor/compare/8.3.4...8.4.0) (2026-06-02) ### Features diff --git a/ios/Capacitor.podspec b/ios/Capacitor.podspec index 01ce20591e..4d9a20601b 100644 --- a/ios/Capacitor.podspec +++ b/ios/Capacitor.podspec @@ -15,9 +15,8 @@ Pod::Spec.new do |s| s.ios.deployment_target = '16.0' s.authors = { 'Ionic Team' => 'hi@ionicframework.com' } s.source = { git: 'https://github.com/ionic-team/capacitor.git', tag: package['version'] } - s.source_files = "#{prefix}Capacitor/Capacitor/**/*.{swift,h,m}" - s.module_map = "#{prefix}Capacitor/Capacitor/Capacitor.modulemap" - s.resources = ["#{prefix}Capacitor/Capacitor/assets/native-bridge.js"] - s.resource_bundles = { 'Capacitor' => ["#{prefix}Capacitor/Capacitor/PrivacyInfo.xcprivacy"] } + s.source_files = "#{prefix}Sources/Capacitor/**/*.{swift,h,m}" + s.resources = ["#{prefix}Sources/Capacitor/assets/native-bridge.js"] + s.resource_bundles = { 'Capacitor' => ["#{prefix}Sources/Capacitor/PrivacyInfo.xcprivacy"] } s.swift_version = '5.1' end diff --git a/ios/Capacitor/Capacitor.xcodeproj/project.pbxproj b/ios/Capacitor/Capacitor.xcodeproj/project.pbxproj deleted file mode 100644 index ebaa6b5be1..0000000000 --- a/ios/Capacitor/Capacitor.xcodeproj/project.pbxproj +++ /dev/null @@ -1,1162 +0,0 @@ -// !$*UTF8*$! -{ - archiveVersion = 1; - classes = { - }; - objectVersion = 48; - objects = { - -/* Begin PBXBuildFile section */ - 0F83E885285A332E006C43CB /* AppUUID.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0F83E884285A332D006C43CB /* AppUUID.swift */; }; - 0F8F33B327DA980A003F49D6 /* PluginConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0F8F33B127DA980A003F49D6 /* PluginConfig.swift */; }; - 373A69C1255C9360000A6F44 /* NotificationHandlerProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 373A69C0255C9360000A6F44 /* NotificationHandlerProtocol.swift */; }; - 373A69F2255C95D0000A6F44 /* NotificationRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 373A69F1255C95D0000A6F44 /* NotificationRouter.swift */; }; - 501CBAA71FC0A723009B0D4D /* WebKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 501CBAA61FC0A723009B0D4D /* WebKit.framework */; }; - 50503EE91FC08595003606DC /* Capacitor.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 50503EDF1FC08594003606DC /* Capacitor.framework */; }; - 50503EEE1FC08595003606DC /* CapacitorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50503EED1FC08595003606DC /* CapacitorTests.swift */; }; - 6214934725509C3F006C36F9 /* CAPInstanceConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6214934625509C3F006C36F9 /* CAPInstanceConfiguration.swift */; }; - 621ECCB72542045900D3D615 /* CAPBridgedJSTypes.m in Sources */ = {isa = PBXBuildFile; fileRef = 621ECCB42542045900D3D615 /* CAPBridgedJSTypes.m */; }; - 621ECCB82542045900D3D615 /* CAPBridgedJSTypes.h in Headers */ = {isa = PBXBuildFile; fileRef = 621ECCB62542045900D3D615 /* CAPBridgedJSTypes.h */; settings = {ATTRIBUTES = (Private, ); }; }; - 621ECCBC2542046400D3D615 /* JSTypes.swift in Sources */ = {isa = PBXBuildFile; fileRef = 621ECCBB2542046400D3D615 /* JSTypes.swift */; }; - 621ECCC3254204B700D3D615 /* BridgedTypesTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 621ECCC2254204B700D3D615 /* BridgedTypesTests.swift */; }; - 621ECCC8254204BE00D3D615 /* JSONSerializationWrapper.m in Sources */ = {isa = PBXBuildFile; fileRef = 621ECCC6254204BE00D3D615 /* JSONSerializationWrapper.m */; }; - 621ECCD6254205BD00D3D615 /* CAPBridgeProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 621ECCD4254205BD00D3D615 /* CAPBridgeProtocol.swift */; }; - 621ECCDA254205C400D3D615 /* CapacitorBridge.swift in Sources */ = {isa = PBXBuildFile; fileRef = 621ECCD9254205C400D3D615 /* CapacitorBridge.swift */; }; - 621ECCE3254206A600D3D615 /* CAPApplicationDelegateProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 621ECCE2254206A600D3D615 /* CAPApplicationDelegateProxy.swift */; }; - 623D68FA254C5037002D01D1 /* KeyPath.swift in Sources */ = {isa = PBXBuildFile; fileRef = 623D68F9254C5037002D01D1 /* KeyPath.swift */; }; - 623D6909254C6FDF002D01D1 /* CAPInstanceDescriptor.h in Headers */ = {isa = PBXBuildFile; fileRef = 623D6907254C6FDF002D01D1 /* CAPInstanceDescriptor.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 623D690A254C6FDF002D01D1 /* CAPInstanceDescriptor.m in Sources */ = {isa = PBXBuildFile; fileRef = 623D6908254C6FDF002D01D1 /* CAPInstanceDescriptor.m */; }; - 623D6914254C7030002D01D1 /* CAPInstanceDescriptor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 623D6913254C7030002D01D1 /* CAPInstanceDescriptor.swift */; }; - 623D691D254C7462002D01D1 /* CAPInstanceConfiguration.h in Headers */ = {isa = PBXBuildFile; fileRef = 623D691B254C7462002D01D1 /* CAPInstanceConfiguration.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 623D691E254C7462002D01D1 /* CAPInstanceConfiguration.m in Sources */ = {isa = PBXBuildFile; fileRef = 623D691C254C7462002D01D1 /* CAPInstanceConfiguration.m */; }; - 625AF1ED258963C700869675 /* WebViewAssetHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 625AF1EC258963C700869675 /* WebViewAssetHandler.swift */; }; - 6263686025F6EC0100576C1C /* PluginCallAccessorTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 6263685F25F6EC0100576C1C /* PluginCallAccessorTests.m */; }; - 626D2D992613B61E0046CE81 /* hidinglogs.json in CopyFiles */ = {isa = PBXBuildFile; fileRef = 626D2D902613B4BB0046CE81 /* hidinglogs.json */; }; - 62959B162524DA7800A3D7F1 /* CAPPluginCall.h in Headers */ = {isa = PBXBuildFile; fileRef = 62959AE22524DA7700A3D7F1 /* CAPPluginCall.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 62959B172524DA7800A3D7F1 /* JSExport.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62959AE32524DA7700A3D7F1 /* JSExport.swift */; }; - 62959B192524DA7800A3D7F1 /* CAPBridgedPlugin.h in Headers */ = {isa = PBXBuildFile; fileRef = 62959AE52524DA7700A3D7F1 /* CAPBridgedPlugin.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 62959B1A2524DA7800A3D7F1 /* CAPPluginCall.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62959AE62524DA7700A3D7F1 /* CAPPluginCall.swift */; }; - 62959B1C2524DA7800A3D7F1 /* CAPPluginMethod.m in Sources */ = {isa = PBXBuildFile; fileRef = 62959AE82524DA7700A3D7F1 /* CAPPluginMethod.m */; }; - 62959B1D2524DA7800A3D7F1 /* UIColor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62959AE92524DA7700A3D7F1 /* UIColor.swift */; }; - 62959B222524DA7800A3D7F1 /* Console.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62959AEF2524DA7700A3D7F1 /* Console.swift */; }; - 62959B262524DA7800A3D7F1 /* WebView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62959AF32524DA7700A3D7F1 /* WebView.swift */; }; - 62959B302524DA7800A3D7F1 /* UIStatusBarManager+CAPHandleTapAction.m in Sources */ = {isa = PBXBuildFile; fileRef = 62959AFE2524DA7700A3D7F1 /* UIStatusBarManager+CAPHandleTapAction.m */; }; - 62959B312524DA7800A3D7F1 /* JS.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62959AFF2524DA7700A3D7F1 /* JS.swift */; }; - 62959B332524DA7800A3D7F1 /* CAPPlugin.m in Sources */ = {isa = PBXBuildFile; fileRef = 62959B012524DA7700A3D7F1 /* CAPPlugin.m */; }; - 62959B362524DA7800A3D7F1 /* CAPBridgeViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62959B042524DA7700A3D7F1 /* CAPBridgeViewController.swift */; }; - 62959B382524DA7800A3D7F1 /* CAPPluginCall.m in Sources */ = {isa = PBXBuildFile; fileRef = 62959B062524DA7700A3D7F1 /* CAPPluginCall.m */; }; - 62959B392524DA7800A3D7F1 /* CapacitorExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62959B072524DA7700A3D7F1 /* CapacitorExtension.swift */; }; - 62959B3A2524DA7800A3D7F1 /* CAPLog.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62959B082524DA7700A3D7F1 /* CAPLog.swift */; }; - 62959B3B2524DA7800A3D7F1 /* CAPPluginMethod.h in Headers */ = {isa = PBXBuildFile; fileRef = 62959B092524DA7700A3D7F1 /* CAPPluginMethod.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 62959B3C2524DA7800A3D7F1 /* CAPBridgeDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62959B0A2524DA7700A3D7F1 /* CAPBridgeDelegate.swift */; }; - 62959B412524DA7800A3D7F1 /* Capacitor.h in Headers */ = {isa = PBXBuildFile; fileRef = 62959B0F2524DA7700A3D7F1 /* Capacitor.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 62959B422524DA7800A3D7F1 /* DocLinks.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62959B102524DA7700A3D7F1 /* DocLinks.swift */; }; - 62959B432524DA7800A3D7F1 /* Data+Capacitor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62959B112524DA7700A3D7F1 /* Data+Capacitor.swift */; }; - 62959B452524DA7800A3D7F1 /* CAPPlugin.h in Headers */ = {isa = PBXBuildFile; fileRef = 62959B132524DA7700A3D7F1 /* CAPPlugin.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 62959B472524DA7800A3D7F1 /* CAPNotifications.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62959B152524DA7700A3D7F1 /* CAPNotifications.swift */; }; - 6296A77E253A2E49005A202A /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6296A77D253A2E49005A202A /* AppDelegate.swift */; }; - 6296A782253A2E49005A202A /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6296A781253A2E49005A202A /* ViewController.swift */; }; - 6296A7A0253A2E49005A202A /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6296A7A1253A2E49005A202A /* SceneDelegate.swift */; }; - 6296A785253A2E49005A202A /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 6296A783253A2E49005A202A /* Main.storyboard */; }; - 6296A787253A2E49005A202A /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 6296A786253A2E49005A202A /* Assets.xcassets */; }; - 6296A78A253A2E49005A202A /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 6296A788253A2E49005A202A /* LaunchScreen.storyboard */; }; - 62A91C3425535F5700861508 /* ConfigurationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62A91C3325535F5700861508 /* ConfigurationTests.swift */; }; - 62A91C3F2553710E00861508 /* nonjson.json in CopyFiles */ = {isa = PBXBuildFile; fileRef = 62A91C392553710300861508 /* nonjson.json */; }; - 62ADC0CA25CB678000E914DE /* PluginCallResult.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62ADC0C925CB678000E914DE /* PluginCallResult.swift */; }; - 62D43AF02581817500673C24 /* WKWebView+Capacitor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62D43AEF2581817500673C24 /* WKWebView+Capacitor.swift */; }; - 62D43B652582A13D00673C24 /* WKWebView+Capacitor.m in Sources */ = {isa = PBXBuildFile; fileRef = 62D43B642582A13D00673C24 /* WKWebView+Capacitor.m */; }; - 62E0736125535E8700BAAADB /* server.json in CopyFiles */ = {isa = PBXBuildFile; fileRef = 62E0735225535E6500BAAADB /* server.json */; }; - 62E0736225535E8700BAAADB /* bad.json in CopyFiles */ = {isa = PBXBuildFile; fileRef = 62E0735325535E6500BAAADB /* bad.json */; }; - 62E0736325535E8700BAAADB /* flat.json in CopyFiles */ = {isa = PBXBuildFile; fileRef = 62E0735425535E6500BAAADB /* flat.json */; }; - 62E0736425535E8700BAAADB /* hierarchy.json in CopyFiles */ = {isa = PBXBuildFile; fileRef = 62E0735525535E6500BAAADB /* hierarchy.json */; }; - 62E207AE2588234500A78983 /* WebViewDelegationHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62E207AD2588234500A78983 /* WebViewDelegationHandler.swift */; }; - 62E79C722638B23300414164 /* JSExportTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62E79C712638B23300414164 /* JSExportTests.swift */; }; - 62E79CD7263A178B00414164 /* native-bridge.js in Resources */ = {isa = PBXBuildFile; fileRef = 62E79C572638AF7500414164 /* native-bridge.js */; }; - 62FABD1A25AE5C01007B3814 /* Array+Capacitor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62FABD1925AE5C01007B3814 /* Array+Capacitor.swift */; }; - 62FABD2325AE60BA007B3814 /* BridgedTypesTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 62FABD2225AE60BA007B3814 /* BridgedTypesTests.m */; }; - 62FABD2B25AE6182007B3814 /* BridgedTypesHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62FABD2A25AE6182007B3814 /* BridgedTypesHelper.swift */; }; - 952707712FD9DD2D0079E5D3 /* CAPSceneDelegateProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9527076F2FD9DD260079E5D3 /* CAPSceneDelegateProxy.swift */; }; - 957BD9402E78A4A50056874C /* SystemBars.swift in Sources */ = {isa = PBXBuildFile; fileRef = 957BD93E2E78A4A20056874C /* SystemBars.swift */; }; - A327E6B628DB8B2900CA8B0A /* HttpRequestHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = A327E6B228DB8B2800CA8B0A /* HttpRequestHandler.swift */; }; - A327E6B728DB8B2900CA8B0A /* CapacitorHttp.swift in Sources */ = {isa = PBXBuildFile; fileRef = A327E6B428DB8B2900CA8B0A /* CapacitorHttp.swift */; }; - A327E6B828DB8B2900CA8B0A /* CapacitorUrlRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = A327E6B528DB8B2900CA8B0A /* CapacitorUrlRequest.swift */; }; - A38C3D7728484E76004B3680 /* CapacitorCookies.swift in Sources */ = {isa = PBXBuildFile; fileRef = A38C3D7628484E76004B3680 /* CapacitorCookies.swift */; }; - A38C3D7B2848BE6F004B3680 /* CapacitorCookieManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = A38C3D7A2848BE6F004B3680 /* CapacitorCookieManager.swift */; }; - A71289E627F380A500DADDF3 /* Router.swift in Sources */ = {isa = PBXBuildFile; fileRef = A71289E527F380A500DADDF3 /* Router.swift */; }; - A71289EB27F380FD00DADDF3 /* RouterTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A71289EA27F380FD00DADDF3 /* RouterTests.swift */; }; - A7187FD22BD1CB7D00093C45 /* CAPPluginMethod.swift in Sources */ = {isa = PBXBuildFile; fileRef = A7187FD12BD1CB7D00093C45 /* CAPPluginMethod.swift */; }; - A76739792B98E09700795F7B /* PrivacyInfo.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = A76739782B98E09700795F7B /* PrivacyInfo.xcprivacy */; }; - A771ADEE2C8B845000AF234D /* DateCodableTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A771ADED2C8B845000AF234D /* DateCodableTests.swift */; }; - A771ADF12C8B909100AF234D /* URLCodableTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A771ADF02C8B909100AF234D /* URLCodableTests.swift */; }; - A7BE62CC2B486A5400165ACB /* KeyValueStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = A7BE62CB2B486A5400165ACB /* KeyValueStore.swift */; }; - A7D474D52C8BA8E8005620A8 /* DataCodableTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A7D474D42C8BA8E8005620A8 /* DataCodableTests.swift */; }; - A7D474D82C8BA8FD005620A8 /* NonconformingFloatCodableTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A7D474D72C8BA8FD005620A8 /* NonconformingFloatCodableTests.swift */; }; - A7D8B3522B238A840003FAD6 /* JSValueEncoder.swift in Sources */ = {isa = PBXBuildFile; fileRef = A7D8B3512B238A840003FAD6 /* JSValueEncoder.swift */; }; - A7D8B3632B263B8D0003FAD6 /* NestedCodableTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A7D8B3622B263B8D0003FAD6 /* NestedCodableTests.swift */; }; - A7D8B3642B263B8D0003FAD6 /* Capacitor.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 50503EDF1FC08594003606DC /* Capacitor.framework */; }; - A7D8B36A2B263B990003FAD6 /* CodableTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A7D8B3562B23B2110003FAD6 /* CodableTests.swift */; }; - A7D8B36E2B2692300003FAD6 /* SuperCodableTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A7D8B36D2B2692300003FAD6 /* SuperCodableTests.swift */; }; - A7D9312F2B23710300FF59A2 /* JSValueDecoder.swift in Sources */ = {isa = PBXBuildFile; fileRef = A7D9312E2B23710300FF59A2 /* JSValueDecoder.swift */; }; - A7DB03AC29B001E300888AE9 /* CAPBridgedPlugin+getMethod.swift in Sources */ = {isa = PBXBuildFile; fileRef = A7DB03AB29B001E300888AE9 /* CAPBridgedPlugin+getMethod.swift */; }; - A7F7EDCD291EC75C0015B73B /* CAPPlugin+LoadInstance.swift in Sources */ = {isa = PBXBuildFile; fileRef = A7F7EDCC291EC75C0015B73B /* CAPPlugin+LoadInstance.swift */; }; - A7F7EDD5292BE8520015B73B /* CAPInstancePlugin.swift in Sources */ = {isa = PBXBuildFile; fileRef = A7F7EDD4292BE8520015B73B /* CAPInstancePlugin.swift */; }; -/* End PBXBuildFile section */ - -/* Begin PBXContainerItemProxy section */ - 50503EEA1FC08595003606DC /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 50503ED61FC08594003606DC /* Project object */; - proxyType = 1; - remoteGlobalIDString = 50503EDE1FC08594003606DC; - remoteInfo = Avocado; - }; - 6296A796253A2EAE005A202A /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 50503ED61FC08594003606DC /* Project object */; - proxyType = 1; - remoteGlobalIDString = 6296A77A253A2E49005A202A; - remoteInfo = TestsHostApp; - }; - A7D8B3652B263B8D0003FAD6 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 50503ED61FC08594003606DC /* Project object */; - proxyType = 1; - remoteGlobalIDString = 50503EDE1FC08594003606DC; - remoteInfo = Capacitor; - }; -/* End PBXContainerItemProxy section */ - -/* Begin PBXCopyFilesBuildPhase section */ - 622BB9C32541FE1900A5DBCA /* CopyFiles */ = { - isa = PBXCopyFilesBuildPhase; - buildActionMask = 2147483647; - dstPath = configurations; - dstSubfolderSpec = 1; - files = ( - 626D2D992613B61E0046CE81 /* hidinglogs.json in CopyFiles */, - 62A91C3F2553710E00861508 /* nonjson.json in CopyFiles */, - 62E0736125535E8700BAAADB /* server.json in CopyFiles */, - 62E0736225535E8700BAAADB /* bad.json in CopyFiles */, - 62E0736325535E8700BAAADB /* flat.json in CopyFiles */, - 62E0736425535E8700BAAADB /* hierarchy.json in CopyFiles */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXCopyFilesBuildPhase section */ - -/* Begin PBXFileReference section */ - 0F83E884285A332D006C43CB /* AppUUID.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppUUID.swift; sourceTree = ""; }; - 0F8F33B127DA980A003F49D6 /* PluginConfig.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PluginConfig.swift; sourceTree = ""; }; - 373A69C0255C9360000A6F44 /* NotificationHandlerProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationHandlerProtocol.swift; sourceTree = ""; }; - 373A69F1255C95D0000A6F44 /* NotificationRouter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationRouter.swift; sourceTree = ""; }; - 501CBAA61FC0A723009B0D4D /* WebKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = WebKit.framework; path = System/Library/Frameworks/WebKit.framework; sourceTree = SDKROOT; }; - 50503EDF1FC08594003606DC /* Capacitor.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Capacitor.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 50503EE81FC08595003606DC /* CapacitorTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = CapacitorTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; - 50503EED1FC08595003606DC /* CapacitorTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CapacitorTests.swift; sourceTree = ""; }; - 6214934625509C3F006C36F9 /* CAPInstanceConfiguration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CAPInstanceConfiguration.swift; sourceTree = ""; }; - 621ECCB42542045900D3D615 /* CAPBridgedJSTypes.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CAPBridgedJSTypes.m; sourceTree = ""; }; - 621ECCB62542045900D3D615 /* CAPBridgedJSTypes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CAPBridgedJSTypes.h; sourceTree = ""; }; - 621ECCBB2542046400D3D615 /* JSTypes.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = JSTypes.swift; sourceTree = ""; }; - 621ECCC2254204B700D3D615 /* BridgedTypesTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BridgedTypesTests.swift; sourceTree = ""; }; - 621ECCC6254204BE00D3D615 /* JSONSerializationWrapper.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JSONSerializationWrapper.m; sourceTree = ""; }; - 621ECCC7254204BE00D3D615 /* JSONSerializationWrapper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSONSerializationWrapper.h; sourceTree = ""; }; - 621ECCCD254204C400D3D615 /* CapacitorTests-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "CapacitorTests-Bridging-Header.h"; sourceTree = ""; }; - 621ECCD4254205BD00D3D615 /* CAPBridgeProtocol.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CAPBridgeProtocol.swift; sourceTree = ""; }; - 621ECCD9254205C400D3D615 /* CapacitorBridge.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CapacitorBridge.swift; sourceTree = ""; }; - 621ECCE2254206A600D3D615 /* CAPApplicationDelegateProxy.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CAPApplicationDelegateProxy.swift; sourceTree = ""; }; - 623D68F9254C5037002D01D1 /* KeyPath.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeyPath.swift; sourceTree = ""; }; - 623D6907254C6FDF002D01D1 /* CAPInstanceDescriptor.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CAPInstanceDescriptor.h; sourceTree = ""; }; - 623D6908254C6FDF002D01D1 /* CAPInstanceDescriptor.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = CAPInstanceDescriptor.m; sourceTree = ""; }; - 623D6913254C7030002D01D1 /* CAPInstanceDescriptor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CAPInstanceDescriptor.swift; sourceTree = ""; }; - 623D691B254C7462002D01D1 /* CAPInstanceConfiguration.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CAPInstanceConfiguration.h; sourceTree = ""; }; - 623D691C254C7462002D01D1 /* CAPInstanceConfiguration.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = CAPInstanceConfiguration.m; sourceTree = ""; }; - 625AF1EC258963C700869675 /* WebViewAssetHandler.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WebViewAssetHandler.swift; sourceTree = ""; }; - 6263685F25F6EC0100576C1C /* PluginCallAccessorTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = PluginCallAccessorTests.m; sourceTree = ""; }; - 626D2D902613B4BB0046CE81 /* hidinglogs.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = hidinglogs.json; sourceTree = ""; }; - 62959AE22524DA7700A3D7F1 /* CAPPluginCall.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CAPPluginCall.h; sourceTree = ""; }; - 62959AE32524DA7700A3D7F1 /* JSExport.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = JSExport.swift; sourceTree = ""; }; - 62959AE52524DA7700A3D7F1 /* CAPBridgedPlugin.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CAPBridgedPlugin.h; sourceTree = ""; }; - 62959AE62524DA7700A3D7F1 /* CAPPluginCall.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CAPPluginCall.swift; sourceTree = ""; }; - 62959AE82524DA7700A3D7F1 /* CAPPluginMethod.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CAPPluginMethod.m; sourceTree = ""; }; - 62959AE92524DA7700A3D7F1 /* UIColor.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UIColor.swift; sourceTree = ""; }; - 62959AEF2524DA7700A3D7F1 /* Console.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Console.swift; sourceTree = ""; }; - 62959AF32524DA7700A3D7F1 /* WebView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WebView.swift; sourceTree = ""; }; - 62959AFE2524DA7700A3D7F1 /* UIStatusBarManager+CAPHandleTapAction.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIStatusBarManager+CAPHandleTapAction.m"; sourceTree = ""; }; - 62959AFF2524DA7700A3D7F1 /* JS.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = JS.swift; sourceTree = ""; }; - 62959B012524DA7700A3D7F1 /* CAPPlugin.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CAPPlugin.m; sourceTree = ""; }; - 62959B042524DA7700A3D7F1 /* CAPBridgeViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CAPBridgeViewController.swift; sourceTree = ""; }; - 62959B062524DA7700A3D7F1 /* CAPPluginCall.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CAPPluginCall.m; sourceTree = ""; }; - 62959B072524DA7700A3D7F1 /* CapacitorExtension.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CapacitorExtension.swift; sourceTree = ""; }; - 62959B082524DA7700A3D7F1 /* CAPLog.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CAPLog.swift; sourceTree = ""; }; - 62959B092524DA7700A3D7F1 /* CAPPluginMethod.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CAPPluginMethod.h; sourceTree = ""; }; - 62959B0A2524DA7700A3D7F1 /* CAPBridgeDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CAPBridgeDelegate.swift; sourceTree = ""; }; - 62959B0F2524DA7700A3D7F1 /* Capacitor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Capacitor.h; sourceTree = ""; }; - 62959B102524DA7700A3D7F1 /* DocLinks.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DocLinks.swift; sourceTree = ""; }; - 62959B112524DA7700A3D7F1 /* Data+Capacitor.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Data+Capacitor.swift"; sourceTree = ""; }; - 62959B122524DA7700A3D7F1 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 62959B132524DA7700A3D7F1 /* CAPPlugin.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CAPPlugin.h; sourceTree = ""; }; - 62959B152524DA7700A3D7F1 /* CAPNotifications.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CAPNotifications.swift; sourceTree = ""; }; - 62959B8225253A9500A3D7F1 /* Capacitor.modulemap */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.module-map"; path = Capacitor.modulemap; sourceTree = ""; }; - 62959BBD2526510200A3D7F1 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 6296A77B253A2E49005A202A /* TestsHostApp.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = TestsHostApp.app; sourceTree = BUILT_PRODUCTS_DIR; }; - 6296A77D253A2E49005A202A /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; - 6296A781253A2E49005A202A /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; - 6296A7A1253A2E49005A202A /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = ""; }; - 6296A784253A2E49005A202A /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; - 6296A786253A2E49005A202A /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; - 6296A789253A2E49005A202A /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; - 6296A78B253A2E49005A202A /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 62A91C3325535F5700861508 /* ConfigurationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConfigurationTests.swift; sourceTree = ""; }; - 62A91C392553710300861508 /* nonjson.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = nonjson.json; sourceTree = ""; }; - 62ADC0C925CB678000E914DE /* PluginCallResult.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PluginCallResult.swift; sourceTree = ""; }; - 62D43AEF2581817500673C24 /* WKWebView+Capacitor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "WKWebView+Capacitor.swift"; sourceTree = ""; }; - 62D43B642582A13D00673C24 /* WKWebView+Capacitor.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "WKWebView+Capacitor.m"; sourceTree = ""; }; - 62E0735225535E6500BAAADB /* server.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = server.json; sourceTree = ""; }; - 62E0735325535E6500BAAADB /* bad.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = bad.json; sourceTree = ""; }; - 62E0735425535E6500BAAADB /* flat.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = flat.json; sourceTree = ""; }; - 62E0735525535E6500BAAADB /* hierarchy.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = hierarchy.json; sourceTree = ""; }; - 62E207AD2588234500A78983 /* WebViewDelegationHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WebViewDelegationHandler.swift; sourceTree = ""; }; - 62E79C572638AF7500414164 /* native-bridge.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = "native-bridge.js"; sourceTree = ""; }; - 62E79C712638B23300414164 /* JSExportTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JSExportTests.swift; sourceTree = ""; }; - 62FABD1925AE5C01007B3814 /* Array+Capacitor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Array+Capacitor.swift"; sourceTree = ""; }; - 62FABD2225AE60BA007B3814 /* BridgedTypesTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = BridgedTypesTests.m; sourceTree = ""; }; - 62FABD2A25AE6182007B3814 /* BridgedTypesHelper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BridgedTypesHelper.swift; sourceTree = ""; }; - 9527076F2FD9DD260079E5D3 /* CAPSceneDelegateProxy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CAPSceneDelegateProxy.swift; sourceTree = ""; }; - 957BD93E2E78A4A20056874C /* SystemBars.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SystemBars.swift; sourceTree = ""; }; - A327E6B228DB8B2800CA8B0A /* HttpRequestHandler.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HttpRequestHandler.swift; sourceTree = ""; }; - A327E6B428DB8B2900CA8B0A /* CapacitorHttp.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CapacitorHttp.swift; sourceTree = ""; }; - A327E6B528DB8B2900CA8B0A /* CapacitorUrlRequest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CapacitorUrlRequest.swift; sourceTree = ""; }; - A38C3D7628484E76004B3680 /* CapacitorCookies.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CapacitorCookies.swift; sourceTree = ""; }; - A38C3D7A2848BE6F004B3680 /* CapacitorCookieManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CapacitorCookieManager.swift; sourceTree = ""; }; - A71289E527F380A500DADDF3 /* Router.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Router.swift; sourceTree = ""; }; - A71289EA27F380FD00DADDF3 /* RouterTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RouterTests.swift; sourceTree = ""; }; - A7187FD12BD1CB7D00093C45 /* CAPPluginMethod.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CAPPluginMethod.swift; sourceTree = ""; }; - A76739782B98E09700795F7B /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; path = PrivacyInfo.xcprivacy; sourceTree = ""; }; - A771ADED2C8B845000AF234D /* DateCodableTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DateCodableTests.swift; sourceTree = ""; }; - A771ADF02C8B909100AF234D /* URLCodableTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = URLCodableTests.swift; sourceTree = ""; }; - A7BE62CB2B486A5400165ACB /* KeyValueStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeyValueStore.swift; sourceTree = ""; }; - A7D474D42C8BA8E8005620A8 /* DataCodableTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DataCodableTests.swift; sourceTree = ""; }; - A7D474D72C8BA8FD005620A8 /* NonconformingFloatCodableTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NonconformingFloatCodableTests.swift; sourceTree = ""; }; - A7D8B3512B238A840003FAD6 /* JSValueEncoder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JSValueEncoder.swift; sourceTree = ""; }; - A7D8B3562B23B2110003FAD6 /* CodableTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CodableTests.swift; sourceTree = ""; }; - A7D8B3602B263B8D0003FAD6 /* CodableTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = CodableTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; - A7D8B3622B263B8D0003FAD6 /* NestedCodableTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NestedCodableTests.swift; sourceTree = ""; }; - A7D8B36D2B2692300003FAD6 /* SuperCodableTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SuperCodableTests.swift; sourceTree = ""; }; - A7D9312E2B23710300FF59A2 /* JSValueDecoder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JSValueDecoder.swift; sourceTree = ""; }; - A7DB03AB29B001E300888AE9 /* CAPBridgedPlugin+getMethod.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "CAPBridgedPlugin+getMethod.swift"; sourceTree = ""; }; - A7F7EDCC291EC75C0015B73B /* CAPPlugin+LoadInstance.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "CAPPlugin+LoadInstance.swift"; sourceTree = ""; }; - A7F7EDD4292BE8520015B73B /* CAPInstancePlugin.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CAPInstancePlugin.swift; sourceTree = ""; }; -/* End PBXFileReference section */ - -/* Begin PBXFrameworksBuildPhase section */ - 50503EDB1FC08594003606DC /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - 501CBAA71FC0A723009B0D4D /* WebKit.framework in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 50503EE51FC08595003606DC /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - 50503EE91FC08595003606DC /* Capacitor.framework in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 6296A778253A2E49005A202A /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; - A7D8B35D2B263B8D0003FAD6 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - A7D8B3642B263B8D0003FAD6 /* Capacitor.framework in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXFrameworksBuildPhase section */ - -/* Begin PBXGroup section */ - 501CBAA51FC0A723009B0D4D /* Frameworks */ = { - isa = PBXGroup; - children = ( - 501CBAA61FC0A723009B0D4D /* WebKit.framework */, - ); - name = Frameworks; - sourceTree = ""; - }; - 50503ED51FC08594003606DC = { - isa = PBXGroup; - children = ( - 62959AE12524DA7700A3D7F1 /* Capacitor */, - 50503EEC1FC08595003606DC /* CapacitorTests */, - 6296A77C253A2E49005A202A /* TestsHostApp */, - A7D8B3612B263B8D0003FAD6 /* CodableTests */, - 50503EE01FC08594003606DC /* Products */, - 501CBAA51FC0A723009B0D4D /* Frameworks */, - ); - sourceTree = ""; - }; - 50503EE01FC08594003606DC /* Products */ = { - isa = PBXGroup; - children = ( - 50503EDF1FC08594003606DC /* Capacitor.framework */, - 50503EE81FC08595003606DC /* CapacitorTests.xctest */, - 6296A77B253A2E49005A202A /* TestsHostApp.app */, - A7D8B3602B263B8D0003FAD6 /* CodableTests.xctest */, - ); - name = Products; - sourceTree = ""; - }; - 50503EEC1FC08595003606DC /* CapacitorTests */ = { - isa = PBXGroup; - children = ( - 50503EED1FC08595003606DC /* CapacitorTests.swift */, - 621ECCC2254204B700D3D615 /* BridgedTypesTests.swift */, - 62FABD2225AE60BA007B3814 /* BridgedTypesTests.m */, - 62A91C3325535F5700861508 /* ConfigurationTests.swift */, - 62FABD2A25AE6182007B3814 /* BridgedTypesHelper.swift */, - 621ECCC7254204BE00D3D615 /* JSONSerializationWrapper.h */, - 621ECCC6254204BE00D3D615 /* JSONSerializationWrapper.m */, - 6263685F25F6EC0100576C1C /* PluginCallAccessorTests.m */, - 621ECCCD254204C400D3D615 /* CapacitorTests-Bridging-Header.h */, - 62E79C712638B23300414164 /* JSExportTests.swift */, - 62959BBD2526510200A3D7F1 /* Info.plist */, - A71289EA27F380FD00DADDF3 /* RouterTests.swift */, - ); - path = CapacitorTests; - sourceTree = ""; - }; - 62959AE12524DA7700A3D7F1 /* Capacitor */ = { - isa = PBXGroup; - children = ( - 9527076F2FD9DD260079E5D3 /* CAPSceneDelegateProxy.swift */, - A7D9312C2B2370EF00FF59A2 /* Codable */, - 0F8F33B127DA980A003F49D6 /* PluginConfig.swift */, - A76739782B98E09700795F7B /* PrivacyInfo.xcprivacy */, - 62959B0F2524DA7700A3D7F1 /* Capacitor.h */, - 62959B132524DA7700A3D7F1 /* CAPPlugin.h */, - 62959B012524DA7700A3D7F1 /* CAPPlugin.m */, - A7F7EDCC291EC75C0015B73B /* CAPPlugin+LoadInstance.swift */, - 62959AE52524DA7700A3D7F1 /* CAPBridgedPlugin.h */, - A7DB03AB29B001E300888AE9 /* CAPBridgedPlugin+getMethod.swift */, - 62959B092524DA7700A3D7F1 /* CAPPluginMethod.h */, - 62959AE82524DA7700A3D7F1 /* CAPPluginMethod.m */, - A7187FD12BD1CB7D00093C45 /* CAPPluginMethod.swift */, - 62959AE22524DA7700A3D7F1 /* CAPPluginCall.h */, - 62959B062524DA7700A3D7F1 /* CAPPluginCall.m */, - 62959AE62524DA7700A3D7F1 /* CAPPluginCall.swift */, - A7F7EDD4292BE8520015B73B /* CAPInstancePlugin.swift */, - 62ADC0C925CB678000E914DE /* PluginCallResult.swift */, - 621ECCBB2542046400D3D615 /* JSTypes.swift */, - 621ECCB62542045900D3D615 /* CAPBridgedJSTypes.h */, - 621ECCB42542045900D3D615 /* CAPBridgedJSTypes.m */, - 623D68F9254C5037002D01D1 /* KeyPath.swift */, - 62959AFF2524DA7700A3D7F1 /* JS.swift */, - 62959AE32524DA7700A3D7F1 /* JSExport.swift */, - 621ECCD4254205BD00D3D615 /* CAPBridgeProtocol.swift */, - 621ECCD9254205C400D3D615 /* CapacitorBridge.swift */, - 62959B042524DA7700A3D7F1 /* CAPBridgeViewController.swift */, - 621ECCE2254206A600D3D615 /* CAPApplicationDelegateProxy.swift */, - 62959B0A2524DA7700A3D7F1 /* CAPBridgeDelegate.swift */, - 62E207AD2588234500A78983 /* WebViewDelegationHandler.swift */, - 625AF1EC258963C700869675 /* WebViewAssetHandler.swift */, - 62959AEA2524DA7700A3D7F1 /* Plugins */, - 623D6907254C6FDF002D01D1 /* CAPInstanceDescriptor.h */, - 623D6908254C6FDF002D01D1 /* CAPInstanceDescriptor.m */, - 623D6913254C7030002D01D1 /* CAPInstanceDescriptor.swift */, - 623D691B254C7462002D01D1 /* CAPInstanceConfiguration.h */, - 623D691C254C7462002D01D1 /* CAPInstanceConfiguration.m */, - 6214934625509C3F006C36F9 /* CAPInstanceConfiguration.swift */, - 62959B082524DA7700A3D7F1 /* CAPLog.swift */, - 62959B102524DA7700A3D7F1 /* DocLinks.swift */, - 62959B152524DA7700A3D7F1 /* CAPNotifications.swift */, - 62959B072524DA7700A3D7F1 /* CapacitorExtension.swift */, - 62959B112524DA7700A3D7F1 /* Data+Capacitor.swift */, - 62FABD1925AE5C01007B3814 /* Array+Capacitor.swift */, - 62D43AEF2581817500673C24 /* WKWebView+Capacitor.swift */, - 62D43B642582A13D00673C24 /* WKWebView+Capacitor.m */, - 62959AE92524DA7700A3D7F1 /* UIColor.swift */, - 62959AFE2524DA7700A3D7F1 /* UIStatusBarManager+CAPHandleTapAction.m */, - 62959B122524DA7700A3D7F1 /* Info.plist */, - 62959B8225253A9500A3D7F1 /* Capacitor.modulemap */, - 373A69C0255C9360000A6F44 /* NotificationHandlerProtocol.swift */, - 373A69F1255C95D0000A6F44 /* NotificationRouter.swift */, - 62E79C562638AF7500414164 /* assets */, - A71289E527F380A500DADDF3 /* Router.swift */, - A7BE62CB2B486A5400165ACB /* KeyValueStore.swift */, - 0F83E884285A332D006C43CB /* AppUUID.swift */, - ); - path = Capacitor; - sourceTree = ""; - }; - 62959AEA2524DA7700A3D7F1 /* Plugins */ = { - isa = PBXGroup; - children = ( - 957BD93E2E78A4A20056874C /* SystemBars.swift */, - A327E6B428DB8B2900CA8B0A /* CapacitorHttp.swift */, - A327E6B528DB8B2900CA8B0A /* CapacitorUrlRequest.swift */, - A327E6B228DB8B2800CA8B0A /* HttpRequestHandler.swift */, - 62959AEF2524DA7700A3D7F1 /* Console.swift */, - 62959AF32524DA7700A3D7F1 /* WebView.swift */, - A38C3D7628484E76004B3680 /* CapacitorCookies.swift */, - A38C3D7A2848BE6F004B3680 /* CapacitorCookieManager.swift */, - ); - path = Plugins; - sourceTree = ""; - }; - 6296A77C253A2E49005A202A /* TestsHostApp */ = { - isa = PBXGroup; - children = ( - 6296A77D253A2E49005A202A /* AppDelegate.swift */, - 6296A7A1253A2E49005A202A /* SceneDelegate.swift */, - 6296A781253A2E49005A202A /* ViewController.swift */, - 62E0735125535E6500BAAADB /* configurations */, - 6296A783253A2E49005A202A /* Main.storyboard */, - 6296A786253A2E49005A202A /* Assets.xcassets */, - 6296A788253A2E49005A202A /* LaunchScreen.storyboard */, - 6296A78B253A2E49005A202A /* Info.plist */, - ); - path = TestsHostApp; - sourceTree = ""; - }; - 62E0735125535E6500BAAADB /* configurations */ = { - isa = PBXGroup; - children = ( - 62E0735225535E6500BAAADB /* server.json */, - 62E0735325535E6500BAAADB /* bad.json */, - 62E0735425535E6500BAAADB /* flat.json */, - 626D2D902613B4BB0046CE81 /* hidinglogs.json */, - 62E0735525535E6500BAAADB /* hierarchy.json */, - 62A91C392553710300861508 /* nonjson.json */, - ); - path = configurations; - sourceTree = ""; - }; - 62E79C562638AF7500414164 /* assets */ = { - isa = PBXGroup; - children = ( - 62E79C572638AF7500414164 /* native-bridge.js */, - ); - path = assets; - sourceTree = ""; - }; - A7D8B3612B263B8D0003FAD6 /* CodableTests */ = { - isa = PBXGroup; - children = ( - A7D8B3622B263B8D0003FAD6 /* NestedCodableTests.swift */, - A7D8B3562B23B2110003FAD6 /* CodableTests.swift */, - A7D8B36D2B2692300003FAD6 /* SuperCodableTests.swift */, - A771ADED2C8B845000AF234D /* DateCodableTests.swift */, - A771ADF02C8B909100AF234D /* URLCodableTests.swift */, - A7D474D42C8BA8E8005620A8 /* DataCodableTests.swift */, - A7D474D72C8BA8FD005620A8 /* NonconformingFloatCodableTests.swift */, - ); - path = CodableTests; - sourceTree = ""; - }; - A7D9312C2B2370EF00FF59A2 /* Codable */ = { - isa = PBXGroup; - children = ( - A7D9312E2B23710300FF59A2 /* JSValueDecoder.swift */, - A7D8B3512B238A840003FAD6 /* JSValueEncoder.swift */, - ); - path = Codable; - sourceTree = ""; - }; -/* End PBXGroup section */ - -/* Begin PBXHeadersBuildPhase section */ - 50503EDC1FC08594003606DC /* Headers */ = { - isa = PBXHeadersBuildPhase; - buildActionMask = 2147483647; - files = ( - 62959B412524DA7800A3D7F1 /* Capacitor.h in Headers */, - 62959B452524DA7800A3D7F1 /* CAPPlugin.h in Headers */, - 62959B162524DA7800A3D7F1 /* CAPPluginCall.h in Headers */, - 62959B3B2524DA7800A3D7F1 /* CAPPluginMethod.h in Headers */, - 623D691D254C7462002D01D1 /* CAPInstanceConfiguration.h in Headers */, - 623D6909254C6FDF002D01D1 /* CAPInstanceDescriptor.h in Headers */, - 62959B192524DA7800A3D7F1 /* CAPBridgedPlugin.h in Headers */, - 621ECCB82542045900D3D615 /* CAPBridgedJSTypes.h in Headers */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXHeadersBuildPhase section */ - -/* Begin PBXNativeTarget section */ - 50503EDE1FC08594003606DC /* Capacitor */ = { - isa = PBXNativeTarget; - buildConfigurationList = 50503EF31FC08595003606DC /* Build configuration list for PBXNativeTarget "Capacitor" */; - buildPhases = ( - 50503EDA1FC08594003606DC /* Sources */, - 50503EDB1FC08594003606DC /* Frameworks */, - 50503EDC1FC08594003606DC /* Headers */, - 50503EDD1FC08594003606DC /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = Capacitor; - productName = Avocado; - productReference = 50503EDF1FC08594003606DC /* Capacitor.framework */; - productType = "com.apple.product-type.framework"; - }; - 50503EE71FC08595003606DC /* CapacitorTests */ = { - isa = PBXNativeTarget; - buildConfigurationList = 50503EF61FC08595003606DC /* Build configuration list for PBXNativeTarget "CapacitorTests" */; - buildPhases = ( - 50503EE41FC08595003606DC /* Sources */, - 50503EE51FC08595003606DC /* Frameworks */, - 50503EE61FC08595003606DC /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - 50503EEB1FC08595003606DC /* PBXTargetDependency */, - 6296A797253A2EAE005A202A /* PBXTargetDependency */, - ); - name = CapacitorTests; - productName = AvocadoTests; - productReference = 50503EE81FC08595003606DC /* CapacitorTests.xctest */; - productType = "com.apple.product-type.bundle.unit-test"; - }; - 6296A77A253A2E49005A202A /* TestsHostApp */ = { - isa = PBXNativeTarget; - buildConfigurationList = 6296A78F253A2E49005A202A /* Build configuration list for PBXNativeTarget "TestsHostApp" */; - buildPhases = ( - 6296A777253A2E49005A202A /* Sources */, - 6296A778253A2E49005A202A /* Frameworks */, - 6296A779253A2E49005A202A /* Resources */, - 622BB9C32541FE1900A5DBCA /* CopyFiles */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = TestsHostApp; - productName = TestsHostApp; - productReference = 6296A77B253A2E49005A202A /* TestsHostApp.app */; - productType = "com.apple.product-type.application"; - }; - A7D8B35F2B263B8D0003FAD6 /* CodableTests */ = { - isa = PBXNativeTarget; - buildConfigurationList = A7D8B3672B263B8D0003FAD6 /* Build configuration list for PBXNativeTarget "CodableTests" */; - buildPhases = ( - A7D8B35C2B263B8D0003FAD6 /* Sources */, - A7D8B35D2B263B8D0003FAD6 /* Frameworks */, - A7D8B35E2B263B8D0003FAD6 /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - A7D8B3662B263B8D0003FAD6 /* PBXTargetDependency */, - ); - name = CodableTests; - productName = CodableTests; - productReference = A7D8B3602B263B8D0003FAD6 /* CodableTests.xctest */; - productType = "com.apple.product-type.bundle.unit-test"; - }; -/* End PBXNativeTarget section */ - -/* Begin PBXProject section */ - 50503ED61FC08594003606DC /* Project object */ = { - isa = PBXProject; - attributes = { - LastSwiftUpdateCheck = 1500; - LastUpgradeCheck = 1240; - ORGANIZATIONNAME = "Drifty Co."; - TargetAttributes = { - 50503EDE1FC08594003606DC = { - CreatedOnToolsVersion = 9.0; - LastSwiftMigration = 0940; - ProvisioningStyle = Automatic; - }; - 50503EE71FC08595003606DC = { - CreatedOnToolsVersion = 9.0; - LastSwiftMigration = 1200; - ProvisioningStyle = Automatic; - TestTargetID = 6296A77A253A2E49005A202A; - }; - 6296A77A253A2E49005A202A = { - CreatedOnToolsVersion = 12.0; - ProvisioningStyle = Automatic; - }; - A7D8B35F2B263B8D0003FAD6 = { - CreatedOnToolsVersion = 15.0.1; - ProvisioningStyle = Automatic; - }; - }; - }; - buildConfigurationList = 50503ED91FC08594003606DC /* Build configuration list for PBXProject "Capacitor" */; - compatibilityVersion = "Xcode 8.0"; - developmentRegion = en; - hasScannedForEncodings = 0; - knownRegions = ( - en, - Base, - ); - mainGroup = 50503ED51FC08594003606DC; - productRefGroup = 50503EE01FC08594003606DC /* Products */; - projectDirPath = ""; - projectRoot = ""; - targets = ( - 50503EDE1FC08594003606DC /* Capacitor */, - 50503EE71FC08595003606DC /* CapacitorTests */, - 6296A77A253A2E49005A202A /* TestsHostApp */, - A7D8B35F2B263B8D0003FAD6 /* CodableTests */, - ); - }; -/* End PBXProject section */ - -/* Begin PBXResourcesBuildPhase section */ - 50503EDD1FC08594003606DC /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - A76739792B98E09700795F7B /* PrivacyInfo.xcprivacy in Resources */, - 62E79CD7263A178B00414164 /* native-bridge.js in Resources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 50503EE61FC08595003606DC /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 6296A779253A2E49005A202A /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 6296A78A253A2E49005A202A /* LaunchScreen.storyboard in Resources */, - 6296A787253A2E49005A202A /* Assets.xcassets in Resources */, - 6296A785253A2E49005A202A /* Main.storyboard in Resources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - A7D8B35E2B263B8D0003FAD6 /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXResourcesBuildPhase section */ - -/* Begin PBXSourcesBuildPhase section */ - 50503EDA1FC08594003606DC /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - A38C3D7728484E76004B3680 /* CapacitorCookies.swift in Sources */, - A71289E627F380A500DADDF3 /* Router.swift in Sources */, - A327E6B828DB8B2900CA8B0A /* CapacitorUrlRequest.swift in Sources */, - A7D9312F2B23710300FF59A2 /* JSValueDecoder.swift in Sources */, - 62959B362524DA7800A3D7F1 /* CAPBridgeViewController.swift in Sources */, - 621ECCB72542045900D3D615 /* CAPBridgedJSTypes.m in Sources */, - 621ECCD6254205BD00D3D615 /* CAPBridgeProtocol.swift in Sources */, - 62D43AF02581817500673C24 /* WKWebView+Capacitor.swift in Sources */, - 62959B432524DA7800A3D7F1 /* Data+Capacitor.swift in Sources */, - 62E207AE2588234500A78983 /* WebViewDelegationHandler.swift in Sources */, - A7187FD22BD1CB7D00093C45 /* CAPPluginMethod.swift in Sources */, - 621ECCBC2542046400D3D615 /* JSTypes.swift in Sources */, - 621ECCDA254205C400D3D615 /* CapacitorBridge.swift in Sources */, - 62959B382524DA7800A3D7F1 /* CAPPluginCall.m in Sources */, - 623D690A254C6FDF002D01D1 /* CAPInstanceDescriptor.m in Sources */, - A7D8B3522B238A840003FAD6 /* JSValueEncoder.swift in Sources */, - A7F7EDD5292BE8520015B73B /* CAPInstancePlugin.swift in Sources */, - A38C3D7B2848BE6F004B3680 /* CapacitorCookieManager.swift in Sources */, - 952707712FD9DD2D0079E5D3 /* CAPSceneDelegateProxy.swift in Sources */, - 62959B1D2524DA7800A3D7F1 /* UIColor.swift in Sources */, - 62959B332524DA7800A3D7F1 /* CAPPlugin.m in Sources */, - 62959B1C2524DA7800A3D7F1 /* CAPPluginMethod.m in Sources */, - 62ADC0CA25CB678000E914DE /* PluginCallResult.swift in Sources */, - 62959B472524DA7800A3D7F1 /* CAPNotifications.swift in Sources */, - 62D43B652582A13D00673C24 /* WKWebView+Capacitor.m in Sources */, - 62959B312524DA7800A3D7F1 /* JS.swift in Sources */, - 373A69F2255C95D0000A6F44 /* NotificationRouter.swift in Sources */, - 62959B1A2524DA7800A3D7F1 /* CAPPluginCall.swift in Sources */, - 62959B302524DA7800A3D7F1 /* UIStatusBarManager+CAPHandleTapAction.m in Sources */, - 62959B392524DA7800A3D7F1 /* CapacitorExtension.swift in Sources */, - A327E6B628DB8B2900CA8B0A /* HttpRequestHandler.swift in Sources */, - 957BD9402E78A4A50056874C /* SystemBars.swift in Sources */, - 62959B422524DA7800A3D7F1 /* DocLinks.swift in Sources */, - 62FABD1A25AE5C01007B3814 /* Array+Capacitor.swift in Sources */, - A7BE62CC2B486A5400165ACB /* KeyValueStore.swift in Sources */, - 62959B172524DA7800A3D7F1 /* JSExport.swift in Sources */, - 373A69C1255C9360000A6F44 /* NotificationHandlerProtocol.swift in Sources */, - 0F83E885285A332E006C43CB /* AppUUID.swift in Sources */, - 625AF1ED258963C700869675 /* WebViewAssetHandler.swift in Sources */, - A327E6B728DB8B2900CA8B0A /* CapacitorHttp.swift in Sources */, - 0F8F33B327DA980A003F49D6 /* PluginConfig.swift in Sources */, - 62959B3C2524DA7800A3D7F1 /* CAPBridgeDelegate.swift in Sources */, - 623D691E254C7462002D01D1 /* CAPInstanceConfiguration.m in Sources */, - 623D68FA254C5037002D01D1 /* KeyPath.swift in Sources */, - 62959B222524DA7800A3D7F1 /* Console.swift in Sources */, - 62959B3A2524DA7800A3D7F1 /* CAPLog.swift in Sources */, - A7DB03AC29B001E300888AE9 /* CAPBridgedPlugin+getMethod.swift in Sources */, - 6214934725509C3F006C36F9 /* CAPInstanceConfiguration.swift in Sources */, - 623D6914254C7030002D01D1 /* CAPInstanceDescriptor.swift in Sources */, - 621ECCE3254206A600D3D615 /* CAPApplicationDelegateProxy.swift in Sources */, - A7F7EDCD291EC75C0015B73B /* CAPPlugin+LoadInstance.swift in Sources */, - 62959B262524DA7800A3D7F1 /* WebView.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 50503EE41FC08595003606DC /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 62E79C722638B23300414164 /* JSExportTests.swift in Sources */, - 50503EEE1FC08595003606DC /* CapacitorTests.swift in Sources */, - 62FABD2B25AE6182007B3814 /* BridgedTypesHelper.swift in Sources */, - 621ECCC8254204BE00D3D615 /* JSONSerializationWrapper.m in Sources */, - 62A91C3425535F5700861508 /* ConfigurationTests.swift in Sources */, - 62FABD2325AE60BA007B3814 /* BridgedTypesTests.m in Sources */, - 621ECCC3254204B700D3D615 /* BridgedTypesTests.swift in Sources */, - A71289EB27F380FD00DADDF3 /* RouterTests.swift in Sources */, - 6263686025F6EC0100576C1C /* PluginCallAccessorTests.m in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 6296A777253A2E49005A202A /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 6296A782253A2E49005A202A /* ViewController.swift in Sources */, - 6296A77E253A2E49005A202A /* AppDelegate.swift in Sources */, - 6296A7A0253A2E49005A202A /* SceneDelegate.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - A7D8B35C2B263B8D0003FAD6 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - A771ADEE2C8B845000AF234D /* DateCodableTests.swift in Sources */, - A7D8B3632B263B8D0003FAD6 /* NestedCodableTests.swift in Sources */, - A7D474D52C8BA8E8005620A8 /* DataCodableTests.swift in Sources */, - A7D8B36A2B263B990003FAD6 /* CodableTests.swift in Sources */, - A7D8B36E2B2692300003FAD6 /* SuperCodableTests.swift in Sources */, - A7D474D82C8BA8FD005620A8 /* NonconformingFloatCodableTests.swift in Sources */, - A771ADF12C8B909100AF234D /* URLCodableTests.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXSourcesBuildPhase section */ - -/* Begin PBXTargetDependency section */ - 50503EEB1FC08595003606DC /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 50503EDE1FC08594003606DC /* Capacitor */; - targetProxy = 50503EEA1FC08595003606DC /* PBXContainerItemProxy */; - }; - 6296A797253A2EAE005A202A /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 6296A77A253A2E49005A202A /* TestsHostApp */; - targetProxy = 6296A796253A2EAE005A202A /* PBXContainerItemProxy */; - }; - A7D8B3662B263B8D0003FAD6 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 50503EDE1FC08594003606DC /* Capacitor */; - targetProxy = A7D8B3652B263B8D0003FAD6 /* PBXContainerItemProxy */; - }; -/* End PBXTargetDependency section */ - -/* Begin PBXVariantGroup section */ - 6296A783253A2E49005A202A /* Main.storyboard */ = { - isa = PBXVariantGroup; - children = ( - 6296A784253A2E49005A202A /* Base */, - ); - name = Main.storyboard; - sourceTree = ""; - }; - 6296A788253A2E49005A202A /* LaunchScreen.storyboard */ = { - isa = PBXVariantGroup; - children = ( - 6296A789253A2E49005A202A /* Base */, - ); - name = LaunchScreen.storyboard; - sourceTree = ""; - }; -/* End PBXVariantGroup section */ - -/* Begin XCBuildConfiguration section */ - 50503EF11FC08595003606DC /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - BUILD_LIBRARY_FOR_DISTRIBUTION = YES; - CLANG_ANALYZER_NONNULL = YES; - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - CODE_SIGN_IDENTITY = "iPhone Developer"; - COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 1; - DEBUG_INFORMATION_FORMAT = dwarf; - ENABLE_STRICT_OBJC_MSGSEND = YES; - ENABLE_TESTABILITY = YES; - GCC_C_LANGUAGE_STANDARD = gnu11; - GCC_DYNAMIC_NO_PIC = NO; - GCC_NO_COMMON_BLOCKS = YES; - GCC_OPTIMIZATION_LEVEL = 0; - GCC_PREPROCESSOR_DEFINITIONS = ( - "DEBUG=1", - "$(inherited)", - ); - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 16.0; - MTL_ENABLE_DEBUG_INFO = YES; - ONLY_ACTIVE_ARCH = YES; - SDKROOT = iphoneos; - SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; - SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 5.0; - VERSIONING_SYSTEM = "apple-generic"; - VERSION_INFO_PREFIX = ""; - }; - name = Debug; - }; - 50503EF21FC08595003606DC /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - BUILD_LIBRARY_FOR_DISTRIBUTION = YES; - CLANG_ANALYZER_NONNULL = YES; - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - CODE_SIGN_IDENTITY = "iPhone Developer"; - COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 1; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - ENABLE_NS_ASSERTIONS = NO; - ENABLE_STRICT_OBJC_MSGSEND = YES; - GCC_C_LANGUAGE_STANDARD = gnu11; - GCC_NO_COMMON_BLOCKS = YES; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 16.0; - MTL_ENABLE_DEBUG_INFO = NO; - SDKROOT = iphoneos; - SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; - SWIFT_VERSION = 5.0; - VALIDATE_PRODUCT = YES; - VERSIONING_SYSTEM = "apple-generic"; - VERSION_INFO_PREFIX = ""; - }; - name = Release; - }; - 50503EF41FC08595003606DC /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - CODE_SIGN_IDENTITY = ""; - CODE_SIGN_STYLE = Automatic; - DEFINES_MODULE = YES; - DEVELOPMENT_TEAM = ""; - DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 1; - DYLIB_INSTALL_NAME_BASE = "@rpath"; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)", - ); - INFOPLIST_FILE = Capacitor/Info.plist; - INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 16.0; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; - MODULEMAP_FILE = Capacitor/Capacitor.modulemap; - PRODUCT_BUNDLE_IDENTIFIER = com.capacitorjs.ios.Capacitor; - PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; - SKIP_INSTALL = YES; - SUPPORTS_MACCATALYST = YES; - SWIFT_OBJC_BRIDGING_HEADER = ""; - SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; - }; - name = Debug; - }; - 50503EF51FC08595003606DC /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - CODE_SIGN_IDENTITY = ""; - CODE_SIGN_STYLE = Automatic; - DEFINES_MODULE = YES; - DEVELOPMENT_TEAM = ""; - DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 1; - DYLIB_INSTALL_NAME_BASE = "@rpath"; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)", - ); - INFOPLIST_FILE = Capacitor/Info.plist; - INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 16.0; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; - MODULEMAP_FILE = Capacitor/Capacitor.modulemap; - PRODUCT_BUNDLE_IDENTIFIER = com.capacitorjs.ios.Capacitor; - PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; - SKIP_INSTALL = YES; - SUPPORTS_MACCATALYST = YES; - SWIFT_OBJC_BRIDGING_HEADER = ""; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; - }; - name = Release; - }; - 50503EF71FC08595003606DC /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; - BUILD_LIBRARY_FOR_DISTRIBUTION = NO; - CLANG_ENABLE_MODULES = YES; - CODE_SIGN_STYLE = Automatic; - DEVELOPMENT_TEAM = ""; - INFOPLIST_FILE = CapacitorTests/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = com.capacitorjs.ios.CapacitorTests; - PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_OBJC_BRIDGING_HEADER = "CapacitorTests/CapacitorTests-Bridging-Header.h"; - SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; - TEST_HOST = "$(BUILT_PRODUCTS_DIR)/TestsHostApp.app/TestsHostApp"; - }; - name = Debug; - }; - 50503EF81FC08595003606DC /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; - BUILD_LIBRARY_FOR_DISTRIBUTION = NO; - CLANG_ENABLE_MODULES = YES; - CODE_SIGN_STYLE = Automatic; - DEVELOPMENT_TEAM = ""; - INFOPLIST_FILE = CapacitorTests/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = com.capacitorjs.ios.CapacitorTests; - PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_OBJC_BRIDGING_HEADER = "CapacitorTests/CapacitorTests-Bridging-Header.h"; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; - TEST_HOST = "$(BUILT_PRODUCTS_DIR)/TestsHostApp.app/TestsHostApp"; - }; - name = Release; - }; - 6296A78C253A2E49005A202A /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; - CLANG_ENABLE_OBJC_WEAK = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; - CODE_SIGN_STYLE = Automatic; - DEVELOPMENT_TEAM = ""; - INFOPLIST_FILE = TestsHostApp/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 16.0; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; - MTL_FAST_MATH = YES; - PRODUCT_BUNDLE_IDENTIFIER = com.capacitorjs.ios.TestsHostApp; - PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; - }; - name = Debug; - }; - 6296A78D253A2E49005A202A /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; - CLANG_ENABLE_OBJC_WEAK = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; - CODE_SIGN_STYLE = Automatic; - DEVELOPMENT_TEAM = ""; - INFOPLIST_FILE = TestsHostApp/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 16.0; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - MTL_FAST_MATH = YES; - PRODUCT_BUNDLE_IDENTIFIER = com.capacitorjs.ios.TestsHostApp; - PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; - }; - name = Release; - }; - A7D8B3682B263B8D0003FAD6 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; - CLANG_ENABLE_OBJC_WEAK = YES; - CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; - CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; - DEVELOPMENT_TEAM = ""; - ENABLE_USER_SCRIPT_SANDBOXING = YES; - GCC_C_LANGUAGE_STANDARD = gnu17; - GENERATE_INFOPLIST_FILE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 16.0; - LOCALIZATION_PREFERS_STRING_CATALOGS = YES; - MARKETING_VERSION = 1.0; - MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; - MTL_FAST_MATH = YES; - PRODUCT_BUNDLE_IDENTIFIER = com.capacitorjs.ios.CodableTests; - PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)"; - SWIFT_EMIT_LOC_STRINGS = NO; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; - }; - name = Debug; - }; - A7D8B3692B263B8D0003FAD6 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; - CLANG_ENABLE_OBJC_WEAK = YES; - CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; - CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; - DEVELOPMENT_TEAM = ""; - ENABLE_USER_SCRIPT_SANDBOXING = YES; - GCC_C_LANGUAGE_STANDARD = gnu17; - GENERATE_INFOPLIST_FILE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 16.0; - LOCALIZATION_PREFERS_STRING_CATALOGS = YES; - MARKETING_VERSION = 1.0; - MTL_FAST_MATH = YES; - PRODUCT_BUNDLE_IDENTIFIER = com.capacitorjs.ios.CodableTests; - PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_EMIT_LOC_STRINGS = NO; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; - }; - name = Release; - }; -/* End XCBuildConfiguration section */ - -/* Begin XCConfigurationList section */ - 50503ED91FC08594003606DC /* Build configuration list for PBXProject "Capacitor" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 50503EF11FC08595003606DC /* Debug */, - 50503EF21FC08595003606DC /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 50503EF31FC08595003606DC /* Build configuration list for PBXNativeTarget "Capacitor" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 50503EF41FC08595003606DC /* Debug */, - 50503EF51FC08595003606DC /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 50503EF61FC08595003606DC /* Build configuration list for PBXNativeTarget "CapacitorTests" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 50503EF71FC08595003606DC /* Debug */, - 50503EF81FC08595003606DC /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 6296A78F253A2E49005A202A /* Build configuration list for PBXNativeTarget "TestsHostApp" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 6296A78C253A2E49005A202A /* Debug */, - 6296A78D253A2E49005A202A /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - A7D8B3672B263B8D0003FAD6 /* Build configuration list for PBXNativeTarget "CodableTests" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - A7D8B3682B263B8D0003FAD6 /* Debug */, - A7D8B3692B263B8D0003FAD6 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; -/* End XCConfigurationList section */ - }; - rootObject = 50503ED61FC08594003606DC /* Project object */; -} diff --git a/ios/Capacitor/Capacitor.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/ios/Capacitor/Capacitor.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist deleted file mode 100644 index 18d981003d..0000000000 --- a/ios/Capacitor/Capacitor.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +++ /dev/null @@ -1,8 +0,0 @@ - - - - - IDEDidComputeMac32BitWarning - - - diff --git a/ios/Capacitor/Capacitor.xcodeproj/xcshareddata/xcschemes/Capacitor.xcscheme b/ios/Capacitor/Capacitor.xcodeproj/xcshareddata/xcschemes/Capacitor.xcscheme deleted file mode 100644 index ed774e08e0..0000000000 --- a/ios/Capacitor/Capacitor.xcodeproj/xcshareddata/xcschemes/Capacitor.xcscheme +++ /dev/null @@ -1,87 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/ios/Capacitor/Capacitor.xcworkspace/contents.xcworkspacedata b/ios/Capacitor/Capacitor.xcworkspace/contents.xcworkspacedata deleted file mode 100644 index 37b6585fc3..0000000000 --- a/ios/Capacitor/Capacitor.xcworkspace/contents.xcworkspacedata +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - diff --git a/ios/Capacitor/Capacitor.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/ios/Capacitor/Capacitor.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist deleted file mode 100644 index 18d981003d..0000000000 --- a/ios/Capacitor/Capacitor.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +++ /dev/null @@ -1,8 +0,0 @@ - - - - - IDEDidComputeMac32BitWarning - - - diff --git a/ios/Capacitor/Capacitor/CAPBridgedJSTypes.h b/ios/Capacitor/Capacitor/CAPBridgedJSTypes.h deleted file mode 100644 index 67f8a9501d..0000000000 --- a/ios/Capacitor/Capacitor/CAPBridgedJSTypes.h +++ /dev/null @@ -1,19 +0,0 @@ -// Convenience methods for bridging to/from JavaScript types. Deliberately hidden from -// Swift by omission (to avoid collisions with Swift protocols), use -// `#import ` if working in Objective-C. - -#import -#import - -@protocol BridgedJSValueContainerImplementation -@required -- (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 - -@interface CAPPluginCall (BridgedJSProtocol) -@end diff --git a/ios/Capacitor/Capacitor/CAPBridgedJSTypes.m b/ios/Capacitor/Capacitor/CAPBridgedJSTypes.m deleted file mode 100644 index c8ec07da7f..0000000000 --- a/ios/Capacitor/Capacitor/CAPBridgedJSTypes.m +++ /dev/null @@ -1,51 +0,0 @@ -#import -#import "CAPBridgedJSTypes.h" - -@implementation CAPPluginCall (BridgedJSProtocol) -- (NSString * _Nullable)getString:(NSString * _Nonnull)key defaultValue:(NSString * _Nullable)defaultValue { - id value = [[self dictionaryRepresentation] objectForKey:key]; - if (value != nil && [value isKindOfClass:[NSString class]]) { - return value; - } - return defaultValue; -} - -- (NSDate * _Nullable)getDate:(NSString * _Nonnull)key defaultValue:(NSDate * _Nullable)defaultValue { - id value = [[self dictionaryRepresentation] objectForKey:key]; - if (value != nil && [value isKindOfClass:[NSDate class]]) { - return value; - } - else if (value != nil && [value isKindOfClass:[NSString class]]) { - return [[[self class] jsDateFormatter] dateFromString:value]; - } - return defaultValue; -} - -- (NSDictionary * _Nullable)getObject:(NSString * _Nonnull)key defaultValue:(NSDictionary * _Nullable)defaultValue { - id value = [[self dictionaryRepresentation] objectForKey:key]; - if (value != nil && [value isKindOfClass:[NSDictionary class]]) { - return value; - } - 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]]) { - return value; - } - return defaultValue; -} - -- (BOOL)getBool:(NSString * _Nonnull)key defaultValue:(BOOL)defaultValue { - return [[self getNumber:key defaultValue:[NSNumber numberWithBool:defaultValue]] boolValue]; -} -@end diff --git a/ios/Capacitor/Capacitor/CAPBridgedPlugin.h b/ios/Capacitor/Capacitor/CAPBridgedPlugin.h deleted file mode 100644 index a6f6324de1..0000000000 --- a/ios/Capacitor/Capacitor/CAPBridgedPlugin.h +++ /dev/null @@ -1,41 +0,0 @@ -#import "CAPPluginMethod.h" - -#if defined(__cplusplus) -#define CAP_EXTERN extern "C" __attribute__((visibility("default"))) -#else -#define CAP_EXTERN extern __attribute__((visibility("default"))) -#endif - -#define CAPPluginReturnNone @"none" -#define CAPPluginReturnCallback @"callback" -#define CAPPluginReturnPromise @"promise" - -@class CAPPluginCall; -@class CAPPlugin; - -@protocol CAPBridgedPlugin -@property (nonnull, readonly) NSString *identifier; -@property (nonnull, readonly) NSString *jsName; -@property (nonnull, readonly) NSArray *pluginMethods; -@end - -#define CAP_PLUGIN_CONFIG(plugin_id, js_name) \ -- (NSString *)identifier { return @#plugin_id; } \ -- (NSString *)jsName { return @js_name; } -#define CAP_PLUGIN_METHOD(method_name, method_return_type) \ -[methods addObject:[[CAPPluginMethod alloc] initWithName:@#method_name returnType:method_return_type]] - -#define CAP_PLUGIN(objc_name, js_name, methods_body) \ -@interface objc_name : NSObject \ -@end \ -@interface objc_name (CAPPluginCategory) \ -@end \ -@implementation objc_name (CAPPluginCategory) \ -- (NSArray *)pluginMethods { \ - NSMutableArray *methods = [NSMutableArray new]; \ - methods_body \ - return methods; \ -} \ -CAP_PLUGIN_CONFIG(objc_name, js_name) \ -@end - diff --git a/ios/Capacitor/Capacitor/CAPInstanceConfiguration.h b/ios/Capacitor/Capacitor/CAPInstanceConfiguration.h deleted file mode 100644 index 171dbb4634..0000000000 --- a/ios/Capacitor/Capacitor/CAPInstanceConfiguration.h +++ /dev/null @@ -1,38 +0,0 @@ -#ifndef CAPInstanceConfiguration_h -#define CAPInstanceConfiguration_h - -@import UIKit; - -@class CAPInstanceDescriptor; - -NS_SWIFT_NAME(InstanceConfiguration) -@interface CAPInstanceConfiguration: NSObject -@property (nonatomic, readonly, nullable) NSString *appendedUserAgentString; -@property (nonatomic, readonly, nullable) NSString *overridenUserAgentString; -@property (nonatomic, readonly, nullable) UIColor *backgroundColor; -@property (nonatomic, readonly, nonnull) NSArray *allowedNavigationHostnames; -@property (nonatomic, readonly, nonnull) NSURL *localURL; -@property (nonatomic, readonly, nonnull) NSURL *serverURL; -@property (nonatomic, readonly, nullable) NSString *errorPath; -@property (nonatomic, readonly, nonnull) NSDictionary *pluginConfigurations; -@property (nonatomic, readonly) BOOL loggingEnabled; -@property (nonatomic, readonly) BOOL scrollingEnabled; -@property (nonatomic, readonly) BOOL zoomingEnabled; -@property (nonatomic, readonly) BOOL allowLinkPreviews; -@property (nonatomic, readonly) BOOL handleApplicationNotifications; -@property (nonatomic, readonly) BOOL isWebDebuggable; -@property (nonatomic, readonly) BOOL hasInitialFocus; -@property (nonatomic, readonly) BOOL cordovaDeployDisabled; -@property (nonatomic, readonly) UIScrollViewContentInsetAdjustmentBehavior contentInsetAdjustmentBehavior; -@property (nonatomic, readonly, nonnull) NSURL *appLocation; -@property (nonatomic, readonly, nullable) NSString *appStartPath; -@property (nonatomic, readonly) BOOL limitsNavigationsToAppBoundDomains; -@property (nonatomic, readonly, nullable) NSString *preferredContentMode; - -@property (nonatomic, readonly, nonnull) NSDictionary *legacyConfig DEPRECATED_MSG_ATTRIBUTE("Use direct properties instead"); - -- (instancetype _Nonnull)initWithDescriptor:(CAPInstanceDescriptor* _Nonnull)descriptor isDebug:(BOOL)debug NS_SWIFT_NAME(init(with:isDebug:)); -- (instancetype _Nonnull)updatingAppLocation:(NSURL* _Nonnull)location NS_SWIFT_NAME(updatingAppLocation(_:)); -@end - -#endif /* CAPInstanceConfiguration_h */ diff --git a/ios/Capacitor/Capacitor/CAPInstanceConfiguration.m b/ios/Capacitor/Capacitor/CAPInstanceConfiguration.m deleted file mode 100644 index d6b7785e34..0000000000 --- a/ios/Capacitor/Capacitor/CAPInstanceConfiguration.m +++ /dev/null @@ -1,93 +0,0 @@ -#import "CAPInstanceConfiguration.h" -#import - -@interface CAPInstanceConfiguration (Internal) -- (instancetype)initWithConfiguration:(CAPInstanceConfiguration*)configuration andLocation:(NSURL*)location; -@end - - -@implementation CAPInstanceConfiguration - -- (instancetype)initWithDescriptor:(CAPInstanceDescriptor *)descriptor isDebug:(BOOL)debug { - if (self = [super init]) { - // first, give the descriptor a chance to make itself internally consistent - [descriptor normalize]; - // now copy the simple properties - _appendedUserAgentString = descriptor.appendedUserAgentString; - _overridenUserAgentString = descriptor.overridenUserAgentString; - _backgroundColor = descriptor.backgroundColor; - _allowedNavigationHostnames = descriptor.allowedNavigationHostnames; - switch (descriptor.loggingBehavior) { - case CAPInstanceLoggingBehaviorProduction: - _loggingEnabled = true; - break; - case CAPInstanceLoggingBehaviorDebug: - _loggingEnabled = debug; - break; - default: - _loggingEnabled = false; - break; - } - _scrollingEnabled = descriptor.scrollingEnabled; - _zoomingEnabled = descriptor.zoomingEnabled; - _allowLinkPreviews = descriptor.allowLinkPreviews; - _handleApplicationNotifications = descriptor.handleApplicationNotifications; - _contentInsetAdjustmentBehavior = descriptor.contentInsetAdjustmentBehavior; - _appLocation = descriptor.appLocation; - _appStartPath = descriptor.appStartPath; - _limitsNavigationsToAppBoundDomains = descriptor.limitsNavigationsToAppBoundDomains; - _preferredContentMode = descriptor.preferredContentMode; - _pluginConfigurations = descriptor.pluginConfigurations; - _isWebDebuggable = descriptor.isWebDebuggable; - _hasInitialFocus = descriptor.hasInitialFocus; - _legacyConfig = descriptor.legacyConfig; - // construct the necessary URLs - _localURL = [[NSURL alloc] initWithString:[NSString stringWithFormat:@"%@://%@", descriptor.urlScheme, descriptor.urlHostname]]; - if (descriptor.serverURL != nil) { - _serverURL = [[NSURL alloc] initWithString:(descriptor.serverURL)]; - } - else { - _serverURL = _localURL; - } - _errorPath = descriptor.errorPath; - // extract the one value we care about from the cordova configuration - _cordovaDeployDisabled = [descriptor cordovaDeployDisabled]; - } - return self; -} - -- (instancetype)initWithConfiguration:(CAPInstanceConfiguration*)configuration andLocation:(NSURL*)location { - if (self = [super init]) { - _appendedUserAgentString = [[configuration appendedUserAgentString] copy]; - _overridenUserAgentString = [[configuration overridenUserAgentString] copy]; - _backgroundColor = configuration.backgroundColor; - _allowedNavigationHostnames = [[configuration allowedNavigationHostnames] copy]; - _localURL = [[configuration localURL] copy]; - _serverURL = [[configuration serverURL] copy]; - _errorPath = [[configuration errorPath] copy]; - _pluginConfigurations = [[configuration pluginConfigurations] copy]; - _loggingEnabled = configuration.loggingEnabled; - _scrollingEnabled = configuration.scrollingEnabled; - _zoomingEnabled = configuration.zoomingEnabled; - _allowLinkPreviews = configuration.allowLinkPreviews; - _handleApplicationNotifications = configuration.handleApplicationNotifications; - _isWebDebuggable = configuration.isWebDebuggable; - _hasInitialFocus = configuration.hasInitialFocus; - _cordovaDeployDisabled = configuration.cordovaDeployDisabled; - _contentInsetAdjustmentBehavior = configuration.contentInsetAdjustmentBehavior; - // we don't care about internal usage of deprecated APIs and the framework should build cleanly -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wdeprecated-declarations" - _legacyConfig = [[configuration legacyConfig] copy]; -#pragma clang diagnostic pop - _appStartPath = configuration.appStartPath; - _appLocation = [location copy]; - } - return self; -} - -- (instancetype)updatingAppLocation:(NSURL*)location { - return [[CAPInstanceConfiguration alloc] initWithConfiguration:self andLocation:location]; -} - -@end diff --git a/ios/Capacitor/Capacitor/CAPInstanceDescriptor.h b/ios/Capacitor/Capacitor/CAPInstanceDescriptor.h deleted file mode 100644 index 3ca447e6f8..0000000000 --- a/ios/Capacitor/Capacitor/CAPInstanceDescriptor.h +++ /dev/null @@ -1,167 +0,0 @@ -#ifndef CAPInstanceDescriptor_h -#define CAPInstanceDescriptor_h - -@import UIKit; - - -typedef NS_ENUM(NSInteger, CAPInstanceType) { - CAPInstanceTypeFixed NS_SWIFT_NAME(fixed), - CAPInstanceTypeVariable NS_SWIFT_NAME(variable) -} NS_SWIFT_NAME(InstanceType); - -typedef NS_OPTIONS(NSUInteger, CAPInstanceWarning) { - CAPInstanceWarningMissingAppDir NS_SWIFT_NAME(missingAppDir) = 1 << 0, - CAPInstanceWarningMissingFile NS_SWIFT_NAME(missingFile) = 1 << 1, - CAPInstanceWarningInvalidFile NS_SWIFT_NAME(invalidFile) = 1 << 2, - CAPInstanceWarningMissingCordovaFile NS_SWIFT_NAME(missingCordovaFile) = 1 << 3, - CAPInstanceWarningInvalidCordovaFile NS_SWIFT_NAME(invalidCordovaFile) = 1 << 4 -} NS_SWIFT_NAME(InstanceWarning); - -typedef NS_OPTIONS(NSUInteger, CAPInstanceLoggingBehavior) { - CAPInstanceLoggingBehaviorNone NS_SWIFT_NAME(none) = 1 << 0, - CAPInstanceLoggingBehaviorDebug NS_SWIFT_NAME(debug) = 1 << 1, - CAPInstanceLoggingBehaviorProduction NS_SWIFT_NAME(production) = 1 << 2, -} NS_SWIFT_NAME(InstanceLoggingBehavior); - -extern NSString * _Nonnull const CAPInstanceDescriptorDefaultScheme NS_SWIFT_UNAVAILABLE("Use InstanceDescriptorDefaults"); -extern NSString * _Nonnull const CAPInstanceDescriptorDefaultHostname NS_SWIFT_UNAVAILABLE("Use InstanceDescriptorDefaults"); - -NS_SWIFT_NAME(InstanceDescriptor) -@interface CAPInstanceDescriptor : NSObject -/** - @brief A value to append to the @c User-Agent string. Ignored if @c overridenUserAgentString is set. - @discussion Set by @c appendUserAgent in the configuration file. - */ -@property (nonatomic, copy, nullable) NSString *appendedUserAgentString; -/** - @brief A value that will completely replace the @c User-Agent string. Overrides @c appendedUserAgentString. - @discussion Set by @c overrideUserAgent in the configuration file. - */ -@property (nonatomic, copy, nullable) NSString *overridenUserAgentString; -/** - @brief The background color to set on the web view where content is not visible. - @discussion Set by @c backgroundColor in the configuration file. - */ -@property (nonatomic, retain, nullable) UIColor *backgroundColor; -/** - @brief Hostnames to which the web view is allowed to navigate without opening an external browser. - @discussion Set by @c allowNavigation in the configuration file. - */ -@property (nonatomic, copy, nonnull) NSArray *allowedNavigationHostnames; -/** - @brief The scheme that will be used for the server URL. - @discussion Defaults to @c capacitor. Set by @c server.iosScheme in the configuration file. - */ -@property (nonatomic, copy, nullable) NSString *urlScheme; -/** - @brief The path to a local html page to display in case of errors. - @discussion Defaults to nil. - */ -@property (nonatomic, copy, nullable) NSString *errorPath; -/** - @brief The hostname that will be used for the server URL. - @discussion Defaults to @c localhost. Set by @c server.hostname in the configuration file. - */ -@property (nonatomic, copy, nullable) NSString *urlHostname; -/** - @brief The fully formed URL that will be used as the server URL. - @discussion Defaults to nil, in which case the server URL will be constructed from @c urlScheme and @c urlHostname. If set, it will override the other properties. Set by @c server.url in the configuration file. - */ -@property (nonatomic, copy, nullable) NSString *serverURL; -/** - @brief The JSON dictionary that contains the plugin-specific configuration information. - @discussion Set by @c plugins in the configuration file. - */ -@property (nonatomic, retain, nonnull) NSDictionary *pluginConfigurations; -/** - @brief The build configurations under which logging should be enabled. - @discussion Defaults to @c debug. Set by @c loggingBehavior in the configuration file. - */ -@property (nonatomic, assign) CAPInstanceLoggingBehavior loggingBehavior; -/** - @brief Whether or not the web view can scroll. - @discussion Set by @c ios.scrollEnabled in the configuration file. Corresponds to @c isScrollEnabled on WKWebView. - */ -@property (nonatomic, assign) BOOL scrollingEnabled; -/** - @brief Whether or not the web view can zoom. - @discussion Set by @c zoomEnabled in the configuration file. - */ -@property (nonatomic, assign) BOOL zoomingEnabled; -/** - @brief Whether or not the web view will preview links. - @discussion Set by @c ios.allowsLinkPreview in the configuration file. Corresponds to @c allowsLinkPreview on WKWebView. - */ -@property (nonatomic, assign) BOOL allowLinkPreviews; -/** - @brief Whether or not the Capacitor runtime will set itself as the @c UNUserNotificationCenter delegate. - @discussion Defaults to @c true. Required to be @c true for notification plugins to work correctly. Set to @c false if your application will handle notifications independently. - */ -@property (nonatomic, assign) BOOL handleApplicationNotifications; -/** - @brief Enables web debugging by setting isInspectable of @c WKWebView to @c true on iOS 16.4 and greater - @discussion Defaults to true in debug mode and false in production - */ -@property (nonatomic, assign) BOOL isWebDebuggable; -/** - @brief Whether or not the webview will have focus. - @discussion Defaults to @c true. Set by @c ios.initialFocus in the configuration file. - */ -@property (nonatomic, assign) BOOL hasInitialFocus; - -/** - @brief How the web view will inset its content - @discussion Set by @c ios.contentInset in the configuration file. Corresponds to @c contentInsetAdjustmentBehavior on WKWebView. - */ -@property (nonatomic, assign) UIScrollViewContentInsetAdjustmentBehavior contentInsetAdjustmentBehavior; -/** - @brief The base file URL from which Capacitor will load resources - @discussion Defaults to @c public/ located at the root of the application bundle. - */ -@property (nonatomic, copy, nonnull) NSURL *appLocation; -/** - @brief The path (relative to @c appLocation) which Capacitor will use for the inital URL at launch. - @discussion Defaults to nil, in which case Capacitor will attempt to load @c index.html. - */ -@property (nonatomic, copy, nullable) NSString *appStartPath; -/** - @brief Whether or not the Capacitor WebView will limit the navigation to @c WKAppBoundDomains listed in the Info.plist. - @discussion Defaults to @c false. Set by @c ios.limitsNavigationsToAppBoundDomains in the configuration file. Required to be @c true for plugins to work if the app includes @c WKAppBoundDomains in the Info.plist. - */ -@property (nonatomic, assign) BOOL limitsNavigationsToAppBoundDomains; -/** - @brief The content mode for the web view to use when it loads and renders web content. - @discussion Defaults to @c recommended. Set by @c ios.preferredContentMode in the configuration file. - */ -@property (nonatomic, copy, nullable) NSString *preferredContentMode; -/** - @brief The parser used to load the cofiguration for Cordova plugins. - */ -@property (nonatomic, copy, nonnull) NSObject *cordovaConfiguration; -/** - @brief Warnings generated during initialization. - */ -@property (nonatomic, assign) CAPInstanceWarning warnings; -/** - @brief The type of instance. - */ -@property (nonatomic, readonly) CAPInstanceType instanceType; -/** - @brief The JSON dictionary representing the contents of the configuration file. - @warning Deprecated. Do not use. - */ -@property (nonatomic, retain, nonnull) NSDictionary *legacyConfig; -/** - @brief Initialize the descriptor with the default environment. This assumes that the application was built with the help of the Capacitor CLI and that that the web app is located inside the application bundle at @c public/. - */ -- (instancetype _Nonnull)initAsDefault NS_SWIFT_NAME(init()); -/** - @brief Initialize the descriptor for use in other contexts. The app location is the one required parameter. - @param appURL The location of the folder containing the web app. - @param configURL The location of the Capacitor configuration file. - @param cordovaURL The location of the Cordova configuration file. - */ -- (instancetype _Nonnull)initAtLocation:(NSURL* _Nonnull)appURL configuration:(NSURL* _Nullable)configURL cordovaConfiguration:(NSURL* _Nullable)cordovaURL NS_SWIFT_NAME(init(at:configuration:cordovaConfiguration:)); -@end - -#endif /* CAPInstanceDescriptor_h */ diff --git a/ios/Capacitor/Capacitor/CAPInstanceDescriptor.m b/ios/Capacitor/Capacitor/CAPInstanceDescriptor.m deleted file mode 100644 index acdbc08caf..0000000000 --- a/ios/Capacitor/Capacitor/CAPInstanceDescriptor.m +++ /dev/null @@ -1,55 +0,0 @@ -#import "CAPInstanceDescriptor.h" -#import - -// Swift extensions marked as @objc and internal are available to the Obj-C runtime but are not available at compile time. -// so we need this declaration to avoid compiler complaints -@interface CAPInstanceDescriptor (InternalSwiftExtension) -- (void)_parseConfigurationAt:(NSURL *)configURL cordovaConfiguration:(NSURL *)cordovaURL; -@end - -NSString* const CAPInstanceDescriptorDefaultScheme = @"capacitor"; -NSString* const CAPInstanceDescriptorDefaultHostname = @"localhost"; - -@implementation CAPInstanceDescriptor -- (instancetype)initAsDefault { - if (self = [super init]) { - _instanceType = CAPInstanceTypeFixed; - [self _setDefaultsWithAppLocation:[[NSBundle mainBundle] URLForResource:@"public" withExtension:nil]]; - [self _parseConfigurationAt:[[NSBundle mainBundle] URLForResource:@"capacitor.config" withExtension:@"json"] cordovaConfiguration:[[NSBundle mainBundle] URLForResource:@"config" withExtension:@"xml"]]; - } - return self; -} - -- (instancetype)initAtLocation:(NSURL*)appURL configuration:(NSURL*)configURL cordovaConfiguration:(NSURL*)cordovaURL { - if (self = [super init]) { - _instanceType = CAPInstanceTypeVariable; - [self _setDefaultsWithAppLocation:appURL]; - [self _parseConfigurationAt:configURL cordovaConfiguration:cordovaURL]; - } - return self; -} - -- (void)_setDefaultsWithAppLocation:(NSURL*)location { - _allowedNavigationHostnames = @[]; - _urlScheme = CAPInstanceDescriptorDefaultScheme; - _urlHostname = CAPInstanceDescriptorDefaultHostname; - _pluginConfigurations = @{}; - _legacyConfig = @{}; - _loggingBehavior = CAPInstanceLoggingBehaviorDebug; - _scrollingEnabled = YES; - _zoomingEnabled = NO; - _allowLinkPreviews = YES; - _handleApplicationNotifications = YES; - _isWebDebuggable = NO; - _hasInitialFocus = YES; - _contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever; - _appLocation = location; - _limitsNavigationsToAppBoundDomains = FALSE; - _warnings = 0; - if (location == nil) { - _warnings |= CAPInstanceWarningMissingAppDir; - // location is nil so assume it was supposed to be the default - _appLocation = [[[NSBundle mainBundle] resourceURL] URLByAppendingPathComponent:@"public"]; - } -} -@end diff --git a/ios/Capacitor/Capacitor/CAPPlugin.h b/ios/Capacitor/Capacitor/CAPPlugin.h deleted file mode 100644 index f22d9be2a0..0000000000 --- a/ios/Capacitor/Capacitor/CAPPlugin.h +++ /dev/null @@ -1,59 +0,0 @@ -#import -#import - -@protocol CAPBridgeProtocol; -@class CAPPluginCall; - -@class PluginConfig; - -@interface CAPPlugin : NSObject - -@property (nonatomic, weak, nullable) WKWebView *webView; -@property (nonatomic, weak, nullable) id bridge; -@property (nonatomic, strong, nonnull) NSString *pluginId; -@property (nonatomic, strong, nonnull) NSString *pluginName; -@property (nonatomic, strong, nullable) NSMutableDictionary*> *eventListeners; -@property (nonatomic, strong, nullable) NSMutableDictionary *> *retainedEventArguments; -@property (nonatomic, assign) BOOL shouldStringifyDatesInCalls; - -- (instancetype _Nonnull) initWithBridge:(id _Nonnull) bridge pluginId:(NSString* _Nonnull) pluginId pluginName:(NSString* _Nonnull) pluginName DEPRECATED_MSG_ATTRIBUTE("This initializer is deprecated and is not suggested for use. Any data set through this init method will be overridden when it is loaded on the bridge."); -- (void)addEventListener:(NSString* _Nonnull)eventName listener:(CAPPluginCall* _Nonnull)listener; -- (void)removeEventListener:(NSString* _Nonnull)eventName listener:(CAPPluginCall* _Nonnull)listener; -- (void)notifyListeners:(NSString* _Nonnull)eventName data:(NSDictionary* _Nullable)data; -- (void)notifyListeners:(NSString* _Nonnull)eventName data:(NSDictionary* _Nullable)data retainUntilConsumed:(BOOL)retain; -- (NSArray* _Nullable)getListeners:(NSString* _Nonnull)eventName; -- (BOOL)hasListeners:(NSString* _Nonnull)eventName; -- (void)addListener:(CAPPluginCall* _Nonnull)call; -- (void)removeListener:(CAPPluginCall* _Nonnull)call; -- (void)removeAllListeners:(CAPPluginCall* _Nonnull)call; -/** - * Default implementation of the capacitor 3.0 permission pattern - */ -- (void)checkPermissions:(CAPPluginCall* _Nonnull)call; -- (void)requestPermissions:(CAPPluginCall* _Nonnull)call; -/** - * Give the plugins a chance to take control when a URL is about to be loaded in the WebView. - * Returning true causes the WebView to abort loading the URL. - * Returning false causes the WebView to continue loading the URL. - * Returning nil will defer to the default Capacitor policy - */ -- (NSNumber* _Nullable)shouldOverrideLoad:(WKNavigationAction* _Nonnull)navigationAction; -/** - * Allows plugins to hook into and respond to the WebView's URL authentication challenge. - * Returning false will defer to the default response of [.rejectProtectionSpace](https://developer.apple.com/documentation/Foundation/URLSession/AuthChallengeDisposition/rejectProtectionSpace). - */ -- (BOOL)handleWKWebViewURLAuthenticationChallenge:(NSURLAuthenticationChallenge* _Nonnull)challenge completionHandler:(void (^_Nonnull)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential * _Nullable credential))completionHandler; - -// Called after init if the plugin wants to do -// some loading so the plugin author doesn't -// need to override init() --(void)load; --(NSString* _Nonnull)getId; --(BOOL)getBool:(CAPPluginCall* _Nonnull) call field:(NSString* _Nonnull)field defaultValue:(BOOL)defaultValue DEPRECATED_MSG_ATTRIBUTE("Use accessors on CAPPluginCall instead. See CAPBridgedJSTypes.h for Obj-C implementations."); --(NSString* _Nullable)getString:(CAPPluginCall* _Nonnull)call field:(NSString* _Nonnull)field defaultValue:(NSString* _Nonnull)defaultValue DEPRECATED_MSG_ATTRIBUTE("Use accessors on CAPPluginCall instead. See CAPBridgedJSTypes.h for Obj-C implementations."); --(PluginConfig* _Nonnull)getConfig; --(void)setCenteredPopover:(UIViewController* _Nonnull) vc; --(void)setCenteredPopover:(UIViewController* _Nonnull) vc size:(CGSize) size; --(BOOL)supportsPopover DEPRECATED_MSG_ATTRIBUTE("All iOS 13+ devices support popover"); - -@end diff --git a/ios/Capacitor/Capacitor/CAPPlugin.m b/ios/Capacitor/Capacitor/CAPPlugin.m deleted file mode 100644 index 92bf24e7dd..0000000000 --- a/ios/Capacitor/Capacitor/CAPPlugin.m +++ /dev/null @@ -1,176 +0,0 @@ -#import "CAPPlugin.h" -#import "CAPBridgedJSTypes.h" -#import -#import - -@implementation CAPPlugin - --(instancetype) initWithBridge:(id)bridge pluginId:(NSString *)pluginId pluginName:(NSString *)pluginName { - self.bridge = bridge; - self.webView = bridge.webView; - self.pluginId = pluginId; - self.pluginName = pluginName; - self.eventListeners = [[NSMutableDictionary alloc] init]; - self.retainedEventArguments = [[NSMutableDictionary alloc] init]; - self.shouldStringifyDatesInCalls = true; - return self; -} - --(NSString *) getId { - return self.pluginName; -} - -- (BOOL)getBool:(CAPPluginCall *)call field:(NSString *)field defaultValue:(BOOL)defaultValue { - NSNumber* value = [call getNumber:field defaultValue:[NSNumber numberWithBool:defaultValue]]; - return [value boolValue]; -} - -- (NSString *) getString:(CAPPluginCall *)call field:(NSString *)field defaultValue:(NSString *)defaultValue { - return [call getString:field defaultValue:defaultValue]; -} - --(PluginConfig*)getConfig { - return [self.bridge.config getPluginConfig:self.pluginName]; -} - --(void)load {} - -- (void)addEventListener:(NSString *)eventName listener:(CAPPluginCall *)listener { - NSMutableArray *listenersForEvent = [self.eventListeners objectForKey:eventName]; - if(listenersForEvent == nil || [listenersForEvent count] == 0) { - listenersForEvent = [[NSMutableArray alloc] initWithObjects:listener, nil]; - [self.eventListeners setValue:listenersForEvent forKey:eventName]; - - [self sendRetainedArgumentsForEvent:eventName]; - } else { - [listenersForEvent addObject:listener]; - } -} - -- (void)sendRetainedArgumentsForEvent:(NSString *)eventName { - // copy retained args and null source to prevent potential race conditions - NSMutableArray *retained = [self.retainedEventArguments objectForKey:eventName]; - if (retained == nil) { - return; - } - - [self.retainedEventArguments removeObjectForKey:eventName]; - - for(id data in retained) { - [self notifyListeners:eventName data:data]; - } -} - -- (void)removeEventListener:(NSString *)eventName listener:(CAPPluginCall *)listener { - NSMutableArray *listenersForEvent = [self.eventListeners objectForKey:eventName]; - if(!listenersForEvent) { return; } - NSUInteger listenerIndex = [listenersForEvent indexOfObject:listener]; - if(listenerIndex == NSNotFound) { - return; - } - [listenersForEvent removeObjectAtIndex:listenerIndex]; -} - -- (void)notifyListeners:(NSString *)eventName data:(NSDictionary *)data { - [self notifyListeners:eventName data:data retainUntilConsumed:NO]; -} - -- (void)notifyListeners:(NSString *)eventName data:(NSDictionary *)data retainUntilConsumed:(BOOL)retain { - NSArray *listenersForEvent = [self.eventListeners objectForKey:eventName]; - if(listenersForEvent == nil || [listenersForEvent count] == 0) { - if (retain == YES) { - - if ([self.retainedEventArguments objectForKey:eventName] == nil) { - [self.retainedEventArguments setObject:[[NSMutableArray alloc] init] forKey:eventName]; - } - - [[self.retainedEventArguments objectForKey:eventName] addObject:data]; - } - return; - } - - for (int i=0; i < listenersForEvent.count; i++) { - CAPPluginCall *call = listenersForEvent[i]; - if (call != nil) { - CAPPluginCallResult *result = [[CAPPluginCallResult alloc] init:data]; - call.successHandler(result, call); - } - } -} - -- (void)addListener:(CAPPluginCall *)call { - NSString *eventName = [call.options objectForKey:@"eventName"]; - [call setKeepAlive:TRUE]; - [self addEventListener:eventName listener:call]; -} - -- (void)removeListener:(CAPPluginCall *)call { - NSString *eventName = [call.options objectForKey:@"eventName"]; - NSString *callbackId = [call.options objectForKey:@"callbackId"]; - CAPPluginCall *storedCall = [self.bridge savedCallWithID:callbackId]; - [self removeEventListener:eventName listener:storedCall]; - [self.bridge releaseCallWithID:callbackId]; -} - -- (void)removeAllListeners:(CAPPluginCall *)call { - [self.eventListeners removeAllObjects]; - [call resolve]; -} - -- (NSArray*)getListeners:(NSString *)eventName { - NSArray* listeners = [self.eventListeners objectForKey:eventName]; - return listeners; -} - -- (BOOL)hasListeners:(NSString *)eventName { - NSArray* listeners = [self.eventListeners objectForKey:eventName]; - - if (listeners == nil) { - return false; - } - return [listeners count] > 0; -} - -- (void)checkPermissions:(CAPPluginCall *)call { - [call resolve]; -} - -- (void)requestPermissions:(CAPPluginCall *)call { - [call resolve]; -} - -/** - * Configure popover sourceRect, sourceView and permittedArrowDirections to show it centered - */ --(void)setCenteredPopover:(UIViewController *) vc { - if (self.bridge.viewController != nil) { - vc.popoverPresentationController.sourceRect = CGRectMake(self.bridge.viewController.view.center.x, self.bridge.viewController.view.center.y, 0, 0); - vc.popoverPresentationController.sourceView = self.bridge.viewController.view; - vc.popoverPresentationController.permittedArrowDirections = 0; - } -} - --(void)setCenteredPopover:(UIViewController* _Nonnull) vc size:(CGSize) size { - if (self.bridge.viewController != nil) { - vc.popoverPresentationController.sourceRect = CGRectMake(self.bridge.viewController.view.center.x, self.bridge.viewController.view.center.y, 0, 0); - vc.preferredContentSize = size; - vc.popoverPresentationController.sourceView = self.bridge.viewController.view; - vc.popoverPresentationController.permittedArrowDirections = 0; - } -} - --(BOOL)supportsPopover { - return YES; -} - -- (NSNumber*)shouldOverrideLoad:(WKNavigationAction*)navigationAction { - return nil; -} - -- (BOOL)handleWKWebViewURLAuthenticationChallenge:(NSURLAuthenticationChallenge* _Nonnull)challenge completionHandler:(void (^_Nonnull)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential * _Nullable credential))completionHandler { - return NO; -} - - -@end - diff --git a/ios/Capacitor/Capacitor/CAPPluginCall.h b/ios/Capacitor/Capacitor/CAPPluginCall.h deleted file mode 100644 index 129dba7ff2..0000000000 --- a/ios/Capacitor/Capacitor/CAPPluginCall.h +++ /dev/null @@ -1,25 +0,0 @@ -#import - -@class CAPPluginCall; -@class CAPPluginCallResult; -@class CAPPluginCallError; - -typedef void(^CAPPluginCallSuccessHandler)(CAPPluginCallResult *result, CAPPluginCall* call); -typedef void(^CAPPluginCallErrorHandler)(CAPPluginCallError *error); - -@interface CAPPluginCall : NSObject - -@property (nonatomic, assign) BOOL isSaved DEPRECATED_MSG_ATTRIBUTE("Use 'keepAlive' instead."); -@property (nonatomic, assign) BOOL keepAlive; -@property (nonatomic, strong) NSString *callbackId; -@property (nonatomic, strong) NSString *methodName; -@property (nonatomic, strong) NSDictionary *options; -@property (nonatomic, copy) CAPPluginCallSuccessHandler successHandler; -@property (nonatomic, copy) CAPPluginCallErrorHandler errorHandler; - -- (instancetype)initWithCallbackId:(NSString *)callbackId options:(NSDictionary *)options success:(CAPPluginCallSuccessHandler)success error:(CAPPluginCallErrorHandler)error DEPRECATED_MSG_ATTRIBUTE("Specify the method name as well."); - -- (instancetype)initWithCallbackId:(NSString *)callbackId methodName:(NSString *)methodName options:(NSDictionary *)options success:(CAPPluginCallSuccessHandler)success error:(CAPPluginCallErrorHandler)error; - -- (void)save DEPRECATED_MSG_ATTRIBUTE("Use the 'keepAlive' property instead."); -@end diff --git a/ios/Capacitor/Capacitor/CAPPluginCall.m b/ios/Capacitor/Capacitor/CAPPluginCall.m deleted file mode 100644 index fc99de3835..0000000000 --- a/ios/Capacitor/Capacitor/CAPPluginCall.m +++ /dev/null @@ -1,36 +0,0 @@ -#import -#import "CAPPluginCall.h" - -@implementation CAPPluginCall - -- (instancetype)initWithCallbackId:(NSString *)callbackId options:(NSDictionary *)options success:(CAPPluginCallSuccessHandler) success error:(CAPPluginCallErrorHandler) error __deprecated { - self.callbackId = callbackId; - self.methodName = @""; - self.options = options; - self.successHandler = success; - self.errorHandler = error; - return self; -} - -- (instancetype)initWithCallbackId:(NSString *)callbackId methodName:(NSString *)methodName options:(NSDictionary *)options success:(CAPPluginCallSuccessHandler) success error:(CAPPluginCallErrorHandler) error { - self.callbackId = callbackId; - self.methodName = methodName; - self.options = options; - self.successHandler = success; - self.errorHandler = error; - return self; -} - -- (BOOL)isSaved { - return self.keepAlive; -} - -- (void)setIsSaved:(BOOL)saved { - self.keepAlive = saved; -} - -- (void)save { - self.keepAlive = true; -} - -@end diff --git a/ios/Capacitor/Capacitor/CAPPluginCall.swift b/ios/Capacitor/Capacitor/CAPPluginCall.swift deleted file mode 100644 index 24d16a9e40..0000000000 --- a/ios/Capacitor/Capacitor/CAPPluginCall.swift +++ /dev/null @@ -1,84 +0,0 @@ -import Foundation - -/** - * Swift niceties for CAPPluginCall - */ - -extension CAPPluginCall: JSValueContainer { - public var jsObjectRepresentation: JSObject { - return options as? JSObject ?? [:] - } -} - -@objc extension CAPPluginCall: BridgedJSValueContainer { - public var dictionaryRepresentation: NSDictionary { - return options as NSDictionary - } - - public static var jsDateFormatter: ISO8601DateFormatter = { - return ISO8601DateFormatter() - }() -} - -@objc public extension CAPPluginCall { - func resolve() { - successHandler(CAPPluginCallResult(nil), self) - } - - func resolve(_ data: PluginCallResultData = [:]) { - successHandler(CAPPluginCallResult(data), self) - } - - func reject(_ message: String, _ code: String? = nil, _ error: Error? = nil, _ data: PluginCallResultData? = nil) { - errorHandler(CAPPluginCallError(message: message, code: code, error: error, data: data)) - } - - func unimplemented() { - unimplemented("not implemented") - } - - func unimplemented(_ message: String) { - errorHandler(CAPPluginCallError(message: message, code: "UNIMPLEMENTED", error: nil, data: [:])) - } - - func unavailable() { - unavailable("not available") - } - - func unavailable(_ message: String) { - errorHandler(CAPPluginCallError(message: message, code: "UNAVAILABLE", error: nil, data: [:])) - } -} - -// MARK: Codable Support -public extension CAPPluginCall { - /// Encodes the given value to a ``JSObject`` and resolves the call. If an error is thrown during encoding, ``reject(_:_:_:_:)`` is called. - /// - Parameters: - /// - data: The value to encode - /// - encoder: The encoder to use. Defaults to `JSValueEncoder()` - /// - messageForRejectionFromError: A closure that takes the error thrown from ``JSValueEncoder/encodeJSObject(_:)`` - /// and returns a string to be provided to ``reject(_:_:_:_:)``. Defaults to a function that returns "Failed encoding response". - func resolve( - with data: T, - encoder: JSValueEncoder = JSValueEncoder(), - messageForRejectionFromError: (Error) -> String = { _ in "Failed encoding response" } - ) { - do { - let encoded = try encoder.encodeJSObject(data) - resolve(encoded) - } catch { - let message = messageForRejectionFromError(error) - reject(message, nil, error) - } - } - - /// Decodes the options to the given type. - /// - Parameters: - /// - type: The type to decode to. - /// - decoder: The decoder to use. Defaults to `JSValueDecoder()`. - /// - Throws: If the options cannot be decoded. - /// - Returns: The decoded value. - func decode(_ type: T.Type, decoder: JSValueDecoder = JSValueDecoder()) throws -> T { - try decoder.decode(type, from: options as? JSObject ?? [:]) - } -} diff --git a/ios/Capacitor/Capacitor/CAPPluginMethod.h b/ios/Capacitor/Capacitor/CAPPluginMethod.h deleted file mode 100644 index 8c075383b3..0000000000 --- a/ios/Capacitor/Capacitor/CAPPluginMethod.h +++ /dev/null @@ -1,36 +0,0 @@ -#import "CAPPluginCall.h" -#import "CAPPlugin.h" - -typedef enum { - CAPPluginMethodArgumentNotNullable, - CAPPluginMethodArgumentNullable -} CAPPluginMethodArgumentNullability; - -typedef NSString CAPPluginReturnType; - -/** - * Represents a single argument to a plugin method. - */ -@interface CAPPluginMethodArgument : NSObject - -@property (nonatomic, copy) NSString *name; -@property (nonatomic, assign) CAPPluginMethodArgumentNullability nullability; - -- (instancetype)initWithName:(NSString *)name nullability:(CAPPluginMethodArgumentNullability)nullability type:(NSString *)type; - -@end - -/** - * Represents a method that a plugin supports, with the ability - * to compute selectors and invoke the method. - */ -@interface CAPPluginMethod : NSObject - -@property (nonatomic, assign) SEL selector; -@property (nonatomic, strong) NSString *name; // Raw method name -@property (nonatomic, strong) CAPPluginReturnType *returnType; // Return type of method (i.e. callback/promise/sync) - -- (instancetype)initWithName:(NSString *)name returnType:(CAPPluginReturnType *)returnType; -- (instancetype)initWithSelector:(SEL)selector returnType:(CAPPluginReturnType *)returnType; - -@end diff --git a/ios/Capacitor/Capacitor/CAPPluginMethod.m b/ios/Capacitor/Capacitor/CAPPluginMethod.m deleted file mode 100644 index d765540e92..0000000000 --- a/ios/Capacitor/Capacitor/CAPPluginMethod.m +++ /dev/null @@ -1,44 +0,0 @@ -#import -#import "CAPPluginMethod.h" - -typedef void(^CAPCallback)(id _arg, NSInteger index); - -@implementation CAPPluginMethodArgument - -- (instancetype)initWithName:(NSString *)name nullability:(CAPPluginMethodArgumentNullability)nullability type:(NSString *)type { - self.name = name; - self.nullability = nullability; - return self; -} - -@end - -@implementation CAPPluginMethod { - // NSInvocation's retainArguments doesn't work with our arguments - // so we have to retain args manually - NSMutableArray *_manualRetainArgs; - // Retain invocation instance - NSInvocation *_invocation; - NSMutableArray *_methodArgumentCallbacks; - CAPPluginCall *_call; - SEL _selector; -} - --(instancetype)initWithName:(NSString *)name returnType:(CAPPluginReturnType *)returnType { - self.name = name; - self.selector = NSSelectorFromString([name stringByAppendingString:@":"]); - self.returnType = returnType; - return self; -} - --(instancetype)initWithSelector:(SEL) selector returnType:(CAPPluginReturnType *)returnType { - // need to drop the : from the selector string - NSString* rawSelString = NSStringFromSelector(selector); - self.name = [rawSelString substringToIndex:[rawSelString length] - 1]; - self.selector = selector; - self.returnType = returnType; - return self; -} - -@end - diff --git a/ios/Capacitor/Capacitor/CAPPluginMethod.swift b/ios/Capacitor/Capacitor/CAPPluginMethod.swift deleted file mode 100644 index 0df641ad33..0000000000 --- a/ios/Capacitor/Capacitor/CAPPluginMethod.swift +++ /dev/null @@ -1,17 +0,0 @@ -// -// CAPPluginMethod.swift -// Capacitor -// -// Created by Steven Sherry on 4/18/24. -// Copyright © 2024 Drifty Co. All rights reserved. -// - -extension CAPPluginMethod { - public enum ReturnType: String { - case promise, callback, none - } - - public convenience init(_ selector: Selector, returnType: ReturnType = .promise) { - self.init(selector: selector, returnType: returnType.rawValue) - } -} diff --git a/ios/Capacitor/Capacitor/CAPSceneDelegateProxy.swift b/ios/Capacitor/Capacitor/CAPSceneDelegateProxy.swift deleted file mode 100644 index b55d8a9366..0000000000 --- a/ios/Capacitor/Capacitor/CAPSceneDelegateProxy.swift +++ /dev/null @@ -1,85 +0,0 @@ -// -// CAPSceneDelegateProxy.swift -// Capacitor -// -// Created by Joseph Orlando Pender on 6/10/26. -// Copyright © 2026 Drifty Co. All rights reserved. -// - -import Foundation - -@objc(CAPSceneDelegateProxy) -public class SceneDelegateProxy: NSObject, UISceneDelegate { - public static let shared = SceneDelegateProxy() - - public private(set) var lastURL: URL? - - public func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) { - NotificationCenter.default.post(name: .capacitorSceneWillConnect, object: scene) - - // Plugins haven't loaded yet on a cold start, so notifications posted here are - // missed. Deliver them on the first capacitorViewDidAppear, once plugins are - // registered. - var token: NSObjectProtocol? - token = NotificationCenter.default.addObserver(forName: .capacitorViewDidAppear, object: nil, queue: .main) { _ in - if let token { - NotificationCenter.default.removeObserver(token) - } - if !connectionOptions.urlContexts.isEmpty { - self.scene(scene, openURLContexts: connectionOptions.urlContexts) - } - for userActivity in connectionOptions.userActivities { - self.scene(scene, continue: userActivity) - } - } - } - - public func scene(_ scene: UIScene, openURLContexts URLContexts: Set) { - for context in URLContexts { - lastURL = context.url - ApplicationDelegateProxy.shared.lastURL = context.url - let options = Self.openURLOptions(from: context.options) - - // Capacitor 8 backwards compat - NotificationCenter.default.post(name: .capacitorOpenURL, object: [ - "url": context.url, - "options": options - ]) - - NotificationCenter.default.post(name: .capacitorSceneOpenURL, object: scene, userInfo: [ - "url": context.url, - "options": options - ]) - } - } - - public func scene(_ scene: UIScene, continue userActivity: NSUserActivity) { - guard userActivity.activityType == NSUserActivityTypeBrowsingWeb, - let url = userActivity.webpageURL else { - return - } - lastURL = url - ApplicationDelegateProxy.shared.lastURL = url - - // Capacitor 8 backwards compat - NotificationCenter.default.post(name: .capacitorOpenUniversalLink, object: [ - "url": url - ]) - - NotificationCenter.default.post(name: .capacitorSceneOpenUniversalLink, object: scene, userInfo: [ - "url": url - ]) - } - - private static func openURLOptions(from sceneOptions: UIScene.OpenURLOptions) -> [UIApplication.OpenURLOptionsKey: Any] { - var options: [UIApplication.OpenURLOptionsKey: Any] = [:] - if let sourceApplication = sceneOptions.sourceApplication { - options[.sourceApplication] = sourceApplication - } - if let annotation = sceneOptions.annotation { - options[.annotation] = annotation - } - options[.openInPlace] = sceneOptions.openInPlace - return options - } -} diff --git a/ios/Capacitor/Capacitor/Capacitor.h b/ios/Capacitor/Capacitor/Capacitor.h deleted file mode 100644 index 7170982981..0000000000 --- a/ios/Capacitor/Capacitor/Capacitor.h +++ /dev/null @@ -1,15 +0,0 @@ -#import - -//! Project version number for bridge. -FOUNDATION_EXPORT double CapacitorVersionNumber; - -//! Project version string for bridge. -FOUNDATION_EXPORT const unsigned char CapacitorVersionString[]; - -#import -#import -#import -#import -#import -#import - diff --git a/ios/Capacitor/Capacitor/Capacitor.modulemap b/ios/Capacitor/Capacitor/Capacitor.modulemap deleted file mode 100644 index b39eb8e8d1..0000000000 --- a/ios/Capacitor/Capacitor/Capacitor.modulemap +++ /dev/null @@ -1,8 +0,0 @@ -framework module Capacitor { - umbrella header "Capacitor.h" - exclude header "CAPBridgedJSTypes.h" - exclude header "CAPBridgeViewController+CDVScreenOrientationDelegate.h" - - export * - module * { export * } -} diff --git a/ios/Capacitor/Capacitor/Info.plist b/ios/Capacitor/Capacitor/Info.plist deleted file mode 100644 index 1007fd9dd7..0000000000 --- a/ios/Capacitor/Capacitor/Info.plist +++ /dev/null @@ -1,24 +0,0 @@ - - - - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - FMWK - CFBundleShortVersionString - 1.0 - CFBundleVersion - $(CURRENT_PROJECT_VERSION) - NSPrincipalClass - - - diff --git a/ios/Capacitor/Capacitor/UIStatusBarManager+CAPHandleTapAction.m b/ios/Capacitor/Capacitor/UIStatusBarManager+CAPHandleTapAction.m deleted file mode 100644 index 44272a33ba..0000000000 --- a/ios/Capacitor/Capacitor/UIStatusBarManager+CAPHandleTapAction.m +++ /dev/null @@ -1,37 +0,0 @@ -#import -#import -#import - -@implementation UIStatusBarManager (CAPHandleTapAction) - -+ (void)load { - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ - Class class = [self class]; - SEL originalSelector = NSSelectorFromString(@"handleTapAction:"); - SEL swizzledSelector = @selector(nofity_handleTapAction:); - - Method originalMethod = class_getInstanceMethod(class, originalSelector); - Method swizzledMethod = class_getInstanceMethod(class, swizzledSelector); - - BOOL didAddMethod = class_addMethod(class, - originalSelector, - method_getImplementation(swizzledMethod), - method_getTypeEncoding(swizzledMethod)); - if (didAddMethod) { - class_replaceMethod(class, - swizzledSelector, - method_getImplementation(originalMethod), - method_getTypeEncoding(originalMethod)); - } else { - method_exchangeImplementations(originalMethod, swizzledMethod); - } - }); -} - --(void)nofity_handleTapAction:(id)arg1 { - [[NSNotificationCenter defaultCenter] postNotification:[NSNotification notificationWithName:NSNotification.capacitorStatusBarTapped object:nil]]; - [self nofity_handleTapAction:arg1]; -} - -@end diff --git a/ios/Capacitor/Capacitor/WKWebView+Capacitor.m b/ios/Capacitor/Capacitor/WKWebView+Capacitor.m deleted file mode 100644 index b861f0637d..0000000000 --- a/ios/Capacitor/Capacitor/WKWebView+Capacitor.m +++ /dev/null @@ -1,15 +0,0 @@ -#import -#import - -// Swift extensions marked as @objc and internal are available to the runtime but won't be found at compile time -// so we need this declaration to avoid compiler complaints. -@interface WKWebView (InternalSwiftExtension) -+ (void)_swizzleKeyboardMethods; -@end - -// +load is the safest place to swizzle methods but that won't work from a swift extension so we need this wrapper. -@implementation WKWebView (CapacitorAutoFocus) -+ (void)load { - [self _swizzleKeyboardMethods]; -} -@end diff --git a/ios/Capacitor/CapacitorTests/BridgedTypesHelper.swift b/ios/Capacitor/CapacitorTests/BridgedTypesHelper.swift deleted file mode 100644 index 9df3f786a8..0000000000 --- a/ios/Capacitor/CapacitorTests/BridgedTypesHelper.swift +++ /dev/null @@ -1,31 +0,0 @@ -import Foundation -@testable import Capacitor - -enum BridgeTypeError: Error { - case badCast -} - -@objc class BridgedTypesHelper: NSObject { - @objc static let shared = BridgedTypesHelper() - - var untypedArray: [Any] { - return [] - } - - @objc func validTransformationOf(array: [Any]) -> [Any] { - let result = JSTypes.coerceArrayToJSArray(array)!.capacitor.replacingNullValues() - return result.capacitor.replacingOptionalValues() as [Any] - } - - @objc func invalidTransformationOf(array: [Any]) -> [Any] { - let result = JSTypes.coerceArrayToJSArray(array)!.capacitor.replacingNullValues() - return result as [Any] - } - - @objc func testCast(of array: [Any], atIndex index: Int) throws -> Any { - if let castArray = array as? [JSValue] { - return castArray[index] as Any - } - throw BridgeTypeError.badCast - } -} diff --git a/ios/Capacitor/CapacitorTests/BridgedTypesTests.m b/ios/Capacitor/CapacitorTests/BridgedTypesTests.m deleted file mode 100644 index 9d11f66c4c..0000000000 --- a/ios/Capacitor/CapacitorTests/BridgedTypesTests.m +++ /dev/null @@ -1,46 +0,0 @@ -#import -#import -#import "CapacitorTests-Swift.h" - -// interface for this class -@interface BridgedTypesTestsObjc : XCTestCase -@end - -@implementation BridgedTypesTestsObjc - -- (void)setUp { - // Put setup code here. This method is called before the invocation of each test method in the class. -} - -- (void)tearDown { - // Put teardown code here. This method is called after the invocation of each test method in the class. -} - -- (void)testNullHandling { - NSArray* source = @[@"test", [NSNull null], @3]; - NSArray* result = [[BridgedTypesHelper shared] validTransformationOfArray:source]; - NSError *error = nil; - // test that the replaced null value exists - id value = [result objectAtIndex:1]; - XCTAssertNotNil(value); - XCTAssertTrue([value isKindOfClass:[NSNull class]]); - // test that the null value casts to non-optional - value = [[BridgedTypesHelper shared] testCastOf:result atIndex:1 error:&error]; - XCTAssertNotNil(value); - XCTAssertNil(error); -} - -- (void)testOptionalHandling { - NSArray* source = @[@"test", [NSNull null], @3]; - NSArray* result = [[BridgedTypesHelper shared] invalidTransformationOfArray:source]; - NSError *error = nil; - // test that the removed null value, now optional, is automatically transformed back into a NSNull - id value = [result objectAtIndex:1]; - XCTAssertNotNil(value); - XCTAssertTrue([value isKindOfClass:[NSNull class]]); - // test that the optional value fails to cast to non-optional - value = [[BridgedTypesHelper shared] testCastOf:result atIndex:1 error:&error]; - XCTAssertNil(value); - XCTAssertNotNil(error); -} -@end diff --git a/ios/Capacitor/CapacitorTests/BridgedTypesTests.swift b/ios/Capacitor/CapacitorTests/BridgedTypesTests.swift deleted file mode 100644 index f88b4e320e..0000000000 --- a/ios/Capacitor/CapacitorTests/BridgedTypesTests.swift +++ /dev/null @@ -1,202 +0,0 @@ -import XCTest - -@testable import Capacitor - -class TestContainer: NSObject, JSValueContainer { - var coercedDictionary: [AnyHashable: Any] = [:] - - public static var jsDateFormatter: ISO8601DateFormatter = { - return ISO8601DateFormatter() - }() - - public var jsObjectRepresentation: JSObject { - return coercedDictionary as? JSObject ?? [:] - } -} - -class BridgedTypesTests: XCTestCase { - static var unserializedDictionary: [AnyHashable: Any] = [:] - static var deserializedDictionary: [AnyHashable: Any] = [:] - - var unserializedDictionary: [AnyHashable: Any] = [:] - var deserializedDictionary: [AnyHashable: Any] = [:] - var testContainer = TestContainer() - - override class func setUp() { - let formatter = ISO8601DateFormatter() - // an ISO 8601 string does not necessarily include subsecond precision, so we can't just capture the current date - // or else we won't be able to compare the objects since they could differ by milliseconds or nanoseonds. so instead - // we use a fixed timestamp at a whole hour. - let date = NSDate(timeIntervalSinceReferenceDate: 632854800) - let subDictionary: [AnyHashable: Any] = ["testIntArray": [0, 1, 2], "testStringArray": ["1", "2", "3"], "testDictionary":["foo":"bar"]] - var dictionary: [AnyHashable: Any] = ["testInt": 1 as Int, "testFloat": Float.pi, "testBool": true as Bool, "testString": "Some string value", "testChild": subDictionary, "testDateString": formatter.string(from: date as Date)] - let serializer = JSONSerializationWrapper(dictionary: dictionary)! - var unwrappedResult = serializer.unwrappedResult()! - // date objects are not handled by the JSON serializer, so we have to insert these after the roundtrip - unwrappedResult["testDateObject"] = date - dictionary["testDateObject"] = date - unserializedDictionary = dictionary - deserializedDictionary = unwrappedResult - } - - override func setUpWithError() throws { - // Put setup code here. This method is called before the invocation of each test method in the class. - unserializedDictionary = BridgedTypesTests.unserializedDictionary - deserializedDictionary = BridgedTypesTests.deserializedDictionary - testContainer.coercedDictionary = JSTypes.coerceDictionaryToJSObject(deserializedDictionary)! - } - - override func tearDownWithError() throws { - // Put teardown code here. This method is called after the invocation of each test method in the class. - } - - func testTranslation() throws { - XCTAssertTrue(unserializedDictionary.count > 0) - XCTAssertTrue(deserializedDictionary.count > 0) - XCTAssertTrue(testContainer.coercedDictionary.count > 0) - } - - func testCastingFailure() throws { - var castResult = deserializedDictionary as? JSObject - XCTAssertNil(castResult) - - castResult = unserializedDictionary as? JSObject - XCTAssertNil(castResult) - } - - func testCoercionSuccess() throws { - let coercedResult = JSTypes.coerceDictionaryToJSObject(deserializedDictionary) - XCTAssertNotNil(coercedResult) - } - - func testRoundtripEquality() throws { - let coercedResult = JSTypes.coerceDictionaryToJSObject(deserializedDictionary)! - let foo: NSDictionary = coercedResult as NSDictionary - let bar: NSDictionary = unserializedDictionary as NSDictionary - - XCTAssertEqual(foo, bar) - } - - func testTypeEquavalency() throws { - let coercedResult = JSTypes.coerceDictionaryToJSObject(deserializedDictionary)! - let coercedFloat = coercedResult["testFloat"] as? Float - let sourceFloat = unserializedDictionary["testFloat"] as? Float - let resultFloat = deserializedDictionary["testFloat"] as? Float - - XCTAssertNotNil(coercedFloat) - XCTAssertNotNil(sourceFloat) - XCTAssertNotNil(resultFloat) - - XCTAssertEqual(coercedFloat, sourceFloat) - XCTAssertEqual(sourceFloat, resultFloat) - XCTAssertEqual(coercedFloat, Float.pi) - } - - func testNumberWrapping() throws { - // the original number is a swift primitive float - let sourceFloat = unserializedDictionary["testFloat"]! - XCTAssertTrue(type(of: sourceFloat) == Float.self) - - // but after serialization/deserilization, it will be wrapped as an NSNumber - let wrappedFloat = deserializedDictionary["testFloat"]! - let underlyingType: AnyObject.Type = NSClassFromString("__NSCFNumber")! - XCTAssertTrue(type(of: wrappedFloat) == underlyingType.self) - - // coercion will keep the NSNumber type since there's no way to recover it - let coercedResult = JSTypes.coerceDictionaryToJSObject(deserializedDictionary)! - let coercedFloat = coercedResult["testFloat"]! - XCTAssertTrue(type(of: coercedFloat) == underlyingType.self) - - // but the cast accessor should restore it - let castFloat = testContainer.getFloat("testFloat")! - XCTAssertTrue(type(of: castFloat) == Float.self) - XCTAssertEqual(sourceFloat as! Float, castFloat) - } - - func testDateObject() throws { - let coercedResult = JSTypes.coerceDictionaryToJSObject(deserializedDictionary)! - let date = coercedResult["testDateObject"] as! Date - XCTAssertNotNil(date) - XCTAssertTrue(type(of: date) == Date.self) - } - - func testDateParsing() throws { - let coercedResult = JSTypes.coerceDictionaryToJSObject(deserializedDictionary)! - let formatter = ISO8601DateFormatter() - let parsedDate = formatter.date(from: coercedResult["testDateString"] as! String)! - let dateObject = coercedResult["testDateObject"] as! Date - XCTAssertNotNil(parsedDate) - XCTAssertNotNil(dateObject) - XCTAssertTrue(dateObject.compare(parsedDate) == .orderedSame) - } - - func testDateExtensions() throws { - let parsedDate = testContainer.getDate("testDateString")! - let dateObject = testContainer.getDate("testDateObject")! - XCTAssertNotNil(parsedDate) - XCTAssertNotNil(dateObject) - XCTAssertTrue(dateObject.compare(parsedDate) == .orderedSame) - } - - func testDateCoercion() throws { - let stringifiedDictionary = JSTypes.coerceDictionaryToJSObject(deserializedDictionary, formattingDatesAsStrings: true)! - let unstringifiedDictionary = JSTypes.coerceDictionaryToJSObject(deserializedDictionary, formattingDatesAsStrings: false)! - let stringifiedValue = stringifiedDictionary["testDateObject"]! - let unstringifiedValue = unstringifiedDictionary["testDateObject"]! - XCTAssertTrue(type(of: stringifiedValue) == String.self) - XCTAssertTrue(type(of: unstringifiedValue) == Date.self) - XCTAssertEqual(stringifiedValue as! String, stringifiedDictionary["testDateString"] as! String) - } - - func testDateResultWrapping() throws { - let result = try PluginCallResult.dictionary(["date": unserializedDictionary["testDateObject"]!]).jsonRepresentation() - XCTAssertEqual(result, "{\"date\":\"\(unserializedDictionary["testDateString"] as! String)\"}") - } - - func testResultMerging() throws { - let result = try PluginCallResult.dictionary(["number": 1]).jsonRepresentation(includingFields: ["string":"foo"]) - // ordering of the pairs should be non-deterministic - if result != "{\"string\":\"foo\",\"number\":1}" && result != "{\"number\":1,\"string\":\"foo\"}" { - XCTAssert(false) - } - } - - func testNullWrapping() throws { - let dictionary: [AnyHashable: Any] = ["testInt": 1 as Int, "testNull": NSNull()] - let coercedDictionary = JSTypes.coerceDictionaryToJSObject(dictionary)! - XCTAssertNotNil(coercedDictionary) - XCTAssertEqual(coercedDictionary.count, 2) - XCTAssertTrue(coercedDictionary["testNull"]! is NSNull) - } - - func testNullTransformation() throws { - let array: [Any] = [1, NSNull(), "test string"] - let coercedArray = JSTypes.coerceArrayToJSArray(array)! - XCTAssertNotNil(coercedArray) - XCTAssertEqual(coercedArray.count, 3) - XCTAssertTrue(type(of: coercedArray[1]) == NSNull.self) - let filteredArray = coercedArray.capacitor.replacingNullValues() - XCTAssertEqual(filteredArray.count, 3) - XCTAssertNil(filteredArray[1]) - let restoredArray = filteredArray.capacitor.replacingOptionalValues() - XCTAssertEqual(restoredArray.count, 3) - XCTAssertNotNil(restoredArray[1]) - XCTAssertTrue(restoredArray[0] is NSNumber) - XCTAssertTrue(restoredArray[1] is NSNull) - XCTAssertTrue(restoredArray[2] is String) - } - - func testSparseArrayCastSuccess() throws { - let array: [Any] = ["test string 1", "test string 2", NSNull()] - let sparseArray = JSTypes.coerceArrayToJSArray(array)?.capacitor.replacingNullValues() as? [String?] - XCTAssertNotNil(sparseArray) - XCTAssertEqual(sparseArray!.count, 3) - XCTAssertNil(sparseArray![2]) - } - - func testSparseArrayCastFailure() throws { - let array: [Any] = ["test string 1", 1, NSNull()] - let sparseArray = JSTypes.coerceArrayToJSArray(array)?.capacitor.replacingNullValues() as? [String?] - XCTAssertNil(sparseArray) - } -} diff --git a/ios/Capacitor/CapacitorTests/CapacitorTests-Bridging-Header.h b/ios/Capacitor/CapacitorTests/CapacitorTests-Bridging-Header.h deleted file mode 100644 index b0f308df84..0000000000 --- a/ios/Capacitor/CapacitorTests/CapacitorTests-Bridging-Header.h +++ /dev/null @@ -1,5 +0,0 @@ -// -// Use this file to import your target's public headers that you would like to expose to Swift. -// - -#import "JSONSerializationWrapper.h" diff --git a/ios/Capacitor/CapacitorTests/CapacitorTests.swift b/ios/Capacitor/CapacitorTests/CapacitorTests.swift deleted file mode 100644 index 45427ea3a7..0000000000 --- a/ios/Capacitor/CapacitorTests/CapacitorTests.swift +++ /dev/null @@ -1,38 +0,0 @@ -import XCTest -@testable import Capacitor - -class MockBridgeViewController: CAPBridgeViewController { -} - -class MockAssetHandler: WebViewAssetHandler { -} - -class MockDelegationHandler: WebViewDelegationHandler { -} - -class MockBridge: CapacitorBridge { - override public func registerPlugins() { - Swift.print("REGISTER PLUGINS") - } -} - -class CapacitorTests: XCTestCase { - var bridge: MockBridge? - - override func setUp() { - super.setUp() - // Put setup code here. This method is called before the invocation of each test method in the class. - let descriptor = InstanceDescriptor.init() - bridge = MockBridge( - with: InstanceConfiguration(with: descriptor, isDebug: true), - delegate: MockBridgeViewController(), - assetHandler: MockAssetHandler(router: CapacitorRouter()), - delegationHandler: MockDelegationHandler() - ) - } - - override func tearDown() { - // Put teardown code here. This method is called after the invocation of each test method in the class. - super.tearDown() - } -} diff --git a/ios/Capacitor/CapacitorTests/ConfigurationTests.swift b/ios/Capacitor/CapacitorTests/ConfigurationTests.swift deleted file mode 100644 index ca67ec0c6d..0000000000 --- a/ios/Capacitor/CapacitorTests/ConfigurationTests.swift +++ /dev/null @@ -1,198 +0,0 @@ -import XCTest - -@testable import Capacitor - -class ConfigurationTests: XCTestCase { - enum ConfigFile: String, CaseIterable { - case flat = "flat" - case nested = "hierarchy" - case server = "server" - case invalid = "bad" - case deprecated = "hidinglogs" - case nonparsable = "nonjson" - } - static var files: [ConfigFile: URL] = [:] - - override class func setUp() { - for file in ConfigFile.allCases { - if let url = Bundle.main.url(forResource: file.rawValue, withExtension: "json", subdirectory: "configurations") { - files[file] = url - } - } - } - - override func setUpWithError() throws { - XCTAssert(ConfigurationTests.files.count == ConfigFile.allCases.count, "Not all configuration files were located") - } - - override func tearDownWithError() throws { - // Put teardown code here. This method is called after the invocation of each test method in the class. - } - - func testDefaultErrors() throws { - let descriptor = InstanceDescriptor.init() - XCTAssertTrue(descriptor.warnings.contains(.missingAppDir)) - XCTAssertTrue(descriptor.warnings.contains(.missingFile)) - } - - func testMissingAppDetection() throws { - var url = Bundle.main.resourceURL! - url.appendPathComponent("app", isDirectory: true) - let descriptor = InstanceDescriptor.init(at: url, configuration: nil, cordovaConfiguration: nil) - XCTAssertTrue(descriptor.warnings.contains(.missingAppDir), "A missing app directory was ignored") - } - - func testFailedParsing() throws { - let url = Bundle.main.url(forResource: "configurations", withExtension: "")! - let descriptor = InstanceDescriptor.init(at: url, configuration: ConfigurationTests.files[.nonparsable], cordovaConfiguration: nil) - XCTAssertTrue(descriptor.warnings.contains(.invalidFile)) - } - - func testDefaults() throws { - let url = Bundle.main.url(forResource: "configurations", withExtension: "")! - let descriptor = InstanceDescriptor.init(at: url, configuration: nil, cordovaConfiguration: nil) - XCTAssertNil(descriptor.backgroundColor) - XCTAssertEqual(descriptor.urlScheme, "capacitor") - XCTAssertEqual(descriptor.urlHostname, "localhost") - XCTAssertNil(descriptor.serverURL) - XCTAssertTrue(descriptor.scrollingEnabled) - XCTAssertEqual(descriptor.loggingBehavior, .debug) - XCTAssertTrue(descriptor.allowLinkPreviews) - XCTAssertEqual(descriptor.contentInsetAdjustmentBehavior, .never) - } - - func testDeprecatedParsing() throws { - let url = Bundle.main.url(forResource: "configurations", withExtension: "")! - let descriptor = InstanceDescriptor.init(at: url, configuration: ConfigurationTests.files[.deprecated], cordovaConfiguration: nil) - #warning("Is this supposed to fail?") - XCTExpectFailure { - XCTAssertEqual(descriptor.loggingBehavior, .none) - } - } - - func testDeprecatedOverrideParsing() throws { - let url = Bundle.main.url(forResource: "configurations", withExtension: "")! - let descriptor = InstanceDescriptor.init(at: url, configuration: ConfigurationTests.files[.server], cordovaConfiguration: nil) - XCTAssertEqual(descriptor.loggingBehavior, .production) - } - - func testTopLevelParsing() throws { - let url = Bundle.main.url(forResource: "configurations", withExtension: "")! - let descriptor = InstanceDescriptor.init(at: url, configuration: ConfigurationTests.files[.flat], cordovaConfiguration: nil) - XCTAssertEqual(descriptor.backgroundColor, UIColor(red: 1, green: 1, blue: 1, alpha: 1)) - XCTAssertEqual(descriptor.overridenUserAgentString, "level 1 override") - XCTAssertEqual(descriptor.appendedUserAgentString, "level 1 append") - XCTAssertEqual(descriptor.loggingBehavior, .debug) - } - - func testNestedParsing() throws { - let url = Bundle.main.url(forResource: "configurations", withExtension: "")! - let descriptor = InstanceDescriptor.init(at: url, configuration: ConfigurationTests.files[.nested], cordovaConfiguration: nil) - XCTAssertEqual(descriptor.backgroundColor, UIColor(red: 0, green: 0, blue: 0, alpha: 1)) - XCTAssertEqual(descriptor.overridenUserAgentString, "level 2 override") - XCTAssertEqual(descriptor.appendedUserAgentString, "level 2 append") - XCTAssertEqual(descriptor.loggingBehavior, .none) - XCTAssertFalse(descriptor.scrollingEnabled) - XCTAssertEqual(descriptor.contentInsetAdjustmentBehavior, .scrollableAxes) - } - - func testServerParsing() throws { - let url = Bundle.main.url(forResource: "configurations", withExtension: "")! - let descriptor = InstanceDescriptor.init(at: url, configuration: ConfigurationTests.files[.server], cordovaConfiguration: nil) - XCTAssertEqual(descriptor.urlScheme, "override") - XCTAssertEqual(descriptor.urlHostname, "myhost") - XCTAssertEqual(descriptor.serverURL, "http://192.168.100.1:2057") - } - - func testBadDataParsing() throws { - let url = Bundle.main.url(forResource: "configurations", withExtension: "")! - let descriptor = InstanceDescriptor.init(at: url, configuration: ConfigurationTests.files[.invalid], cordovaConfiguration: nil) - XCTAssertNil(descriptor.backgroundColor) - XCTAssertEqual(descriptor.loggingBehavior, .debug) - XCTAssertEqual(descriptor.contentInsetAdjustmentBehavior, .never) - } - - func testBadDataTransformation() throws { - let url = Bundle.main.url(forResource: "configurations", withExtension: "")! - let descriptor = InstanceDescriptor.init(at: url, configuration: ConfigurationTests.files[.invalid], cordovaConfiguration: nil) - let configuration = InstanceConfiguration(with: descriptor, isDebug: true) - #warning("Address this. These tests haven't been run during CI since maybe ever?") - XCTExpectFailure { - XCTAssertEqual(configuration.serverURL, URL(string: "capacitor://myhost"), "Invalid server.url and invalid ioScheme were not ignored") - } - } - - func testServerTransformation() throws { - let url = Bundle.main.url(forResource: "configurations", withExtension: "")! - let descriptor = InstanceDescriptor.init(at: url, configuration: ConfigurationTests.files[.server], cordovaConfiguration: nil) - let configuration = InstanceConfiguration(with: descriptor, isDebug: true) - XCTAssertEqual(configuration.serverURL, URL(string: "http://192.168.100.1:2057")) - XCTAssertEqual(configuration.localURL, URL(string: "override://myhost")) - } - - func testPluginConfig() throws { - let url = Bundle.main.url(forResource: "configurations", withExtension: "")! - let descriptor = InstanceDescriptor.init(at: url, configuration: ConfigurationTests.files[.flat], cordovaConfiguration: nil) - let configuration = InstanceConfiguration(with: descriptor, isDebug: true) - let value = configuration.getPluginConfig("SplashScreen").getInt("launchShowDuration", 0) - XCTAssertEqual(value, 1) - } - - func testLegacyConfig() throws { - let url = Bundle.main.url(forResource: "configurations", withExtension: "")! - // a top-level legacy key is exposed through the direct property accessor - let flatDescriptor = InstanceDescriptor.init(at: url, configuration: ConfigurationTests.files[.flat], cordovaConfiguration: nil) - let flatConfiguration = InstanceConfiguration(with: flatDescriptor, isDebug: true) - XCTAssertEqual(flatConfiguration.overridenUserAgentString, "level 1 override") - // a platform-specific legacy key overrides the top-level one - let nestedDescriptor = InstanceDescriptor.init(at: url, configuration: ConfigurationTests.files[.nested], cordovaConfiguration: nil) - let nestedConfiguration = InstanceConfiguration(with: nestedDescriptor, isDebug: true) - XCTAssertEqual(nestedConfiguration.overridenUserAgentString, "level 2 override") - } - - func testNavigationRules() throws { - let url = Bundle.main.url(forResource: "configurations", withExtension: "")! - let descriptor = InstanceDescriptor.init(at: url, configuration: ConfigurationTests.files[.server], cordovaConfiguration: nil) - let configuration = InstanceConfiguration(with: descriptor, isDebug: true) - XCTAssertTrue(configuration.shouldAllowNavigation(to: "ionic.io")) - XCTAssertTrue(configuration.shouldAllowNavigation(to: "ionic.io".uppercased())) - XCTAssertTrue(configuration.shouldAllowNavigation(to: "test.capacitorjs.com")) - XCTAssertTrue(configuration.shouldAllowNavigation(to: "192.168.0.1")) - XCTAssertTrue(configuration.shouldAllowNavigation(to: "subdomain.test.ionicframework.com")) - XCTAssertTrue(configuration.shouldAllowNavigation(to: "wildcard1.wildcard2.example.com")) - XCTAssertFalse(configuration.shouldAllowNavigation(to: "wildcard1.example.com")) - XCTAssertFalse(configuration.shouldAllowNavigation(to: "google.com")) - XCTAssertFalse(configuration.shouldAllowNavigation(to: "192.168.0.2")) - XCTAssertFalse(configuration.shouldAllowNavigation(to: "ionicframework.com")) - } - - func testNoLoggingTransformation() throws { - let url = Bundle.main.url(forResource: "configurations", withExtension: "")! - let descriptor = InstanceDescriptor.init(at: url, configuration: nil, cordovaConfiguration: nil) - descriptor.loggingBehavior = .none - var configuration = InstanceConfiguration(with: descriptor, isDebug: false) - XCTAssertFalse(configuration.loggingEnabled) - configuration = InstanceConfiguration(with: descriptor, isDebug: true) - XCTAssertFalse(configuration.loggingEnabled) - } - - func testDebugLoggingTransformation() throws { - let url = Bundle.main.url(forResource: "configurations", withExtension: "")! - let descriptor = InstanceDescriptor.init(at: url, configuration: nil, cordovaConfiguration: nil) - descriptor.loggingBehavior = .debug - var configuration = InstanceConfiguration(with: descriptor, isDebug: false) - XCTAssertFalse(configuration.loggingEnabled) - configuration = InstanceConfiguration(with: descriptor, isDebug: true) - XCTAssertTrue(configuration.loggingEnabled) - } - - func testProductionLoggingTransformation() throws { - let url = Bundle.main.url(forResource: "configurations", withExtension: "")! - let descriptor = InstanceDescriptor.init(at: url, configuration: nil, cordovaConfiguration: nil) - descriptor.loggingBehavior = .production - var configuration = InstanceConfiguration(with: descriptor, isDebug: false) - XCTAssertTrue(configuration.loggingEnabled) - configuration = InstanceConfiguration(with: descriptor, isDebug: true) - XCTAssertTrue(configuration.loggingEnabled) - } -} diff --git a/ios/Capacitor/CapacitorTests/Info.plist b/ios/Capacitor/CapacitorTests/Info.plist deleted file mode 100644 index 6c40a6cd0c..0000000000 --- a/ios/Capacitor/CapacitorTests/Info.plist +++ /dev/null @@ -1,22 +0,0 @@ - - - - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - BNDL - CFBundleShortVersionString - 1.0 - CFBundleVersion - 1 - - diff --git a/ios/Capacitor/CapacitorTests/JSExportTests.swift b/ios/Capacitor/CapacitorTests/JSExportTests.swift deleted file mode 100644 index 0cd57593b5..0000000000 --- a/ios/Capacitor/CapacitorTests/JSExportTests.swift +++ /dev/null @@ -1,24 +0,0 @@ -import XCTest - -@testable import Capacitor - -class JSExportTests: XCTestCase { - - override func setUpWithError() throws { - // Put setup code here. This method is called before the invocation of each test method in the class. - } - - override func tearDownWithError() throws { - // Put teardown code here. This method is called after the invocation of each test method in the class. - } - - func testBridgeBundle() throws { - let contentController = WKUserContentController() - do { - try Capacitor.JSExport.exportBridgeJS(userContentController: contentController) - } - catch { - XCTFail() - } - } -} diff --git a/ios/Capacitor/CapacitorTests/JSONSerializationWrapper.h b/ios/Capacitor/CapacitorTests/JSONSerializationWrapper.h deleted file mode 100644 index 96ca66281b..0000000000 --- a/ios/Capacitor/CapacitorTests/JSONSerializationWrapper.h +++ /dev/null @@ -1,9 +0,0 @@ -#import - -@interface JSONSerializationWrapper : NSObject -@property (nonatomic, copy) NSDictionary* _Nonnull dictionary; - -- (instancetype _Nullable)initWithDictionary:(NSDictionary* _Nonnull)options; -- (NSDictionary * _Nullable)unwrappedResult; - -@end diff --git a/ios/Capacitor/CapacitorTests/JSONSerializationWrapper.m b/ios/Capacitor/CapacitorTests/JSONSerializationWrapper.m deleted file mode 100644 index 6316c9c88b..0000000000 --- a/ios/Capacitor/CapacitorTests/JSONSerializationWrapper.m +++ /dev/null @@ -1,24 +0,0 @@ - -#import "JSONSerializationWrapper.h" - -@implementation JSONSerializationWrapper - -- (instancetype)initWithDictionary:(NSDictionary *)dictionary { - self = [super init]; - if (self != nil) { - _dictionary = dictionary; - } - return self; -} - -- (NSDictionary *)unwrappedResult { - NSError* error = nil; - NSData* serializedData = [NSJSONSerialization dataWithJSONObject:[self dictionary] options:NSJSONWritingPrettyPrinted error:&error]; - if (serializedData != nil) { - NSDictionary* result = [NSJSONSerialization JSONObjectWithData:serializedData options:0 error:&error]; - return result; - } - return nil; -} - -@end diff --git a/ios/Capacitor/CapacitorTests/PluginCallAccessorTests.m b/ios/Capacitor/CapacitorTests/PluginCallAccessorTests.m deleted file mode 100644 index 4d665aeec1..0000000000 --- a/ios/Capacitor/CapacitorTests/PluginCallAccessorTests.m +++ /dev/null @@ -1,98 +0,0 @@ -#import -#import -#import -#import "CapacitorTests-Swift.h" - -// interface for this class -@interface PluginCallAccessorTests : XCTestCase -@property (strong, nonatomic) CAPPluginCall* call; -@end - -@implementation PluginCallAccessorTests - -- (void)setUp { - [super setUp]; - NSDate* date = [[NSDate alloc] initWithTimeIntervalSinceReferenceDate:632854800]; - NSISO8601DateFormatter *formatter = [[NSISO8601DateFormatter alloc] init]; - NSDictionary* options = @{@"testString":@"foo", - @"testDict": @{@"testSubkey":@"sub value"}, - @"testFloat": @3.14159, - @"testDateObject": date, - @"testDateString": [formatter stringFromDate:date], - @"testBoolTrue": @TRUE, - @"testBoolFalse": @FALSE}; - [self setCall:[[CAPPluginCall alloc] initWithCallbackId:@"test" methodName:@"test" options:options success:NULL error:NULL]]; -} - -- (void)testStringAccessor { - NSString* value = [[self call] getString:@"testString" defaultValue:NULL]; - XCTAssertEqual(value, @"foo"); - - value = [[self call] getString:@"badString" defaultValue:NULL]; - XCTAssertNil(value); - - value = [[self call] getString:@"badString" defaultValue:@"default"]; - XCTAssertEqual(value, @"default"); -} - -- (void)testDateObjectAccessor { - NSDate* value = [[self call] getDate:@"testDateObject" defaultValue:NULL]; - XCTAssertEqual([value timeIntervalSinceReferenceDate], 632854800); - - value = [[self call] getDate:@"badString" defaultValue:NULL]; - XCTAssertNil(value); - - NSDate *defaultDate = [NSDate date]; - value = [[self call] getDate:@"badString" defaultValue:defaultDate]; - XCTAssertEqual(value, defaultDate); -} - -- (void)testDateStringAccessor { - NSDate* objectValue = [[self call] getDate:@"testDateObject" defaultValue:NULL]; - NSDate* stringValue = [[self call] getDate:@"testDateString" defaultValue:NULL]; - XCTAssertNotNil(objectValue); - XCTAssertNotNil(stringValue); - XCTAssertEqual(objectValue, stringValue); -} - -- (void)testObjectAccessor { - NSDictionary* value = [[self call] getObject:@"testDict" defaultValue:NULL]; - XCTAssertEqual([value objectForKey:@"testSubkey"], @"sub value"); - - value = [[self call] getObject:@"badString" defaultValue:NULL]; - XCTAssertNil(value); - - value = [[self call] getObject:@"badString" defaultValue:@{@"defaultKey":@"default"}]; - XCTAssertEqual([value objectForKey:@"defaultKey"], @"default"); -} - -- (void)testNumberAccessor { - NSNumber* value = [[self call] getNumber:@"testFloat" defaultValue:NULL]; - XCTAssertNotNil(value); - XCTAssertTrue([value isEqualToNumber:@3.14159]); - - value = [[self call] getNumber:@"badString" defaultValue:NULL]; - XCTAssertNil(value); - - value = [[self call] getNumber:@"badString" defaultValue:@100]; - XCTAssertEqual([value intValue], 100); - - value = [[self call] getNumber:@"testBoolTrue" defaultValue:NULL]; - XCTAssertNotNil(value); - XCTAssertEqual([value boolValue], TRUE); -} - -- (void)testBoolAccessor { - BOOL value = [[self call] getBool:@"testBoolTrue" defaultValue:false]; - XCTAssertTrue(value); - - value = [[self call] getBool:@"testBoolFalse" defaultValue:true]; - XCTAssertFalse(value); - - value = [[self call] getBool:@"badString" defaultValue:true]; - XCTAssertTrue(value); - - value = [[self call] getBool:@"badString" defaultValue:false]; - XCTAssertFalse(value); -} -@end diff --git a/ios/Capacitor/CapacitorTests/RouterTests.swift b/ios/Capacitor/CapacitorTests/RouterTests.swift deleted file mode 100644 index 181551ee72..0000000000 --- a/ios/Capacitor/CapacitorTests/RouterTests.swift +++ /dev/null @@ -1,39 +0,0 @@ -// -// RouterTests.swift -// CapacitorTests -// -// Created by Steven Sherry on 3/29/22. -// Copyright © 2022 Drifty Co. All rights reserved. -// - -import XCTest -@testable import Capacitor - -class RouterTests: XCTestCase { - - func testRouterReturnsIndexWhenProvidedEmptyPath() { - checkRouter(path: "", expected: "/index.html") - } - - func testRouterReturnsIndexWhenProviedPathWithoutExtension() { - checkRouter(path: "/a/valid/path/no/ext", expected: "/index.html") - } - - func testRouterReturnsPathWhenProvidedValidPath() { - checkRouter(path: "/a/valid/path.ext", expected: "/a/valid/path.ext") - } - - func testRouterReturnsPathWhenProvidedValidPathWithExtensionAndSpaces() { - checkRouter(path: "/a/valid/file path.ext", expected: "/a/valid/file path.ext") - } - - func checkRouter(path: String, expected: String) { - XCTContext.runActivity(named: "router creates route path correctly") { _ in - var router = CapacitorRouter() - XCTAssertEqual(router.route(for: path), expected) - router.basePath = "/A/Route" - XCTAssertEqual(router.route(for: path), "/A/Route" + expected) - } - } - -} diff --git a/ios/Capacitor/CodableTests/CodableTests.swift b/ios/Capacitor/CodableTests/CodableTests.swift deleted file mode 100644 index bfdbe57162..0000000000 --- a/ios/Capacitor/CodableTests/CodableTests.swift +++ /dev/null @@ -1,194 +0,0 @@ -// -// JSValueDecoderTest.swift -// CapacitorTests -// -// Created by Steven Sherry on 12/8/23. -// Copyright © 2023 Drifty Co. All rights reserved. -// - -import XCTest -import Capacitor - -private struct Pet: Codable, Equatable { - var name: String - var breed: String - var isVaccinated: Bool -} - -private struct Person: Codable, Equatable { - var name: String - var age: UInt - var pet: Pet? - var family: [Person]? -} - -private let rawPet: JSObject = [ - "name": "Penny", - "breed": "Chihuahua", - "isVaccinated": true -] - -private let rawPeople: JSArray = [ - [ "name": "Anakin", - "age": 41 as NSNumber - ], - [ "name": "Leia", - "age": 20 as NSNumber - ] -] - -private let rawPerson: JSObject = [ - "name": "Luke", - "age": 20 as NSNumber, - "pet": rawPet, - "family": rawPeople -] - -private let person = Person( - name: "Luke", - age: 20, - pet: .init( - name: "Penny", - breed: "Chihuahua", - isVaccinated: true - ), - family: [ - Person(name: "Anakin", age: 41), - Person(name: "Leia", age: 20) - ] -) - -final class JSValueDecoderTest: XCTestCase { - func testDecode_when_provided_a_valid_keyed_container_for_the_target_type__decoding_is_successful() throws { - let decoder = JSValueDecoder() - let decodedPerson = try decoder.decode(Person.self, from: rawPerson) - XCTAssertEqual(decodedPerson, person) - } - - func testDecode__when_provided_a_valid_unkeyed_container_for_the_target_type__decoding_is_successful() throws { - let decoder = JSValueDecoder() - let decodedPeople = try decoder.decode([Person].self, from: rawPeople) - XCTAssertEqual(person.family, decodedPeople) - } - - func testDecode__when_provided_a_single_value_for_the_target_type__decoding_is_successful() throws { - let decoder = JSValueDecoder() - let decodedNumber = try decoder.decode(UInt.self, from: 100 as NSNumber) - XCTAssertEqual(100, decodedNumber) - } - - func testDecode__when_provided_an_invalid_keyed_container_for_the_target_type__decoding_fails() throws { - let decoder = JSValueDecoder() - var invalidRawPerson = rawPerson - invalidRawPerson["name"] = nil - XCTAssertThrowsError(try decoder.decode(Person.self, from: invalidRawPerson)) - } - - func testDecode__when_provided_an_invalid_unkeyed_container_for_the_target_type__decoding_fails() throws { - let decoder = JSValueDecoder() - var invalidRawPeople = try XCTUnwrap(rawPeople as? [JSObject]) - invalidRawPeople[0]["name"] = nil - XCTAssertThrowsError(try decoder.decode([Person].self, from: invalidRawPeople)) - } - - func testDecode__when_provided_an_invalid_single_value_type_for_the_input_value__decoding_fails() throws { - let decoder = JSValueDecoder() - XCTAssertThrowsError(try decoder.decode(UInt.self, from: -1 as NSNumber)) - } - - func testDecode__when_provided_a_valid_nested_array__decoding_is_successful() throws { - let decoder = JSValueDecoder() - let nestedPeople: JSArray = [rawPeople, rawPeople] - let decodedPeople = try decoder.decode([[Person]].self, from: nestedPeople) - XCTAssertEqual([person.family, person.family], decodedPeople) - } - - func testDecode_when_attempting_to_decode_a_class__decoding_fails() throws { - class Pet: Decodable { - var name: String - var breed: String - var isVaccinated: String - init(name: String, breed: String, isVaccinated: String) { - self.name = name - self.breed = breed - self.isVaccinated = isVaccinated - } - } - - let decoder = JSValueDecoder() - XCTAssertThrowsError(try decoder.decode(Pet.self, from: rawPet)) - } - - func testDecode__when_nsnull_explicitly_present_in_container__it_correctly_decodes_to_nil() throws { - let decoder = JSValueDecoder() - var rawPerson = rawPerson - rawPerson["pet"] = NSNull() - - let decodedPerson = try decoder.decode(Person.self, from: rawPerson) - XCTAssertNil(decodedPerson.pet) - } -} - -final class JSValueEncoderTest: XCTestCase { - func testEncode__when_provided_with_an_instance_of_nonclass_codable_instance__encoding_succeeds() throws { - let encoder = JSValueEncoder() - let encodedValue = try encoder.encode(person) - let encodedObject = try XCTUnwrap(encodedValue as? JSObject) - - let name = try XCTUnwrap(encodedObject["name"] as? String) - XCTAssertEqual(person.name, name) - let age = try XCTUnwrap(encodedObject["age"] as? NSNumber) - XCTAssertEqual(person.age as NSNumber, age) - - let pet = try XCTUnwrap(encodedObject["pet"] as? JSObject) - let petName = try XCTUnwrap(pet["name"] as? String) - XCTAssertEqual(person.pet?.name, petName) - let petBreed = try XCTUnwrap(pet["breed"] as? String) - XCTAssertEqual(person.pet?.breed, petBreed) - let petIsVaccinated = try XCTUnwrap(pet["isVaccinated"] as? Bool) - XCTAssertEqual(person.pet?.isVaccinated, petIsVaccinated) - - let family = try XCTUnwrap(encodedObject["family"] as? [JSObject]) - XCTAssertEqual(person.family?.count, family.count) - let aniName = try XCTUnwrap(family[0]["name"] as? String) - XCTAssertEqual(person.family?[0].name, aniName) - let aniAge = try XCTUnwrap(family[0]["age"] as? NSNumber) - XCTAssertEqual(person.family?[0].age as? NSNumber, aniAge) - - let leiaName = try XCTUnwrap(family[1]["name"] as? String) - XCTAssertEqual(person.family?[1].name, leiaName) - let leiaAge = try XCTUnwrap(family[1]["age"] as? NSNumber) - XCTAssertEqual(person.family?[1].age as? NSNumber, leiaAge) - } - - func testEncode__when_provided_an_instance_of_a_nested_unkeyed_container__encoding_succedds() throws { - let encoder = JSValueEncoder() - let encodedValue = try encoder.encode([person.family, person.family]) - let encodedArray = try XCTUnwrap(encodedValue as? [[JSObject]]) - XCTAssertEqual(encodedArray.count, 2) - XCTAssertEqual(encodedArray[0].count, 2) - XCTAssertEqual(encodedArray[1].count, 2) - - let family = try XCTUnwrap(person.family) - - XCTAssertEqual(family[0].name, encodedArray[0][0]["name"] as? String) - XCTAssertEqual(family[0].name, encodedArray[1][0]["name"] as? String) - XCTAssertEqual(family[0].age as NSNumber, encodedArray[0][0]["age"] as? NSNumber) - XCTAssertEqual(family[0].age as NSNumber, encodedArray[1][0]["age"] as? NSNumber) - XCTAssertEqual(family[1].name, encodedArray[0][1]["name"] as? String) - XCTAssertEqual(family[1].name, encodedArray[1][1]["name"] as? String) - XCTAssertEqual(family[1].age as NSNumber, encodedArray[0][1]["age"] as? NSNumber) - XCTAssertEqual(family[1].age as NSNumber, encodedArray[1][1]["age"] as? NSNumber) - } - - func testEncode__when_nil_is_present_in_value__and_optional_encoding_is_set_to_explicit_nulls__it_is_encoded_as_nsnull() throws { - struct Test: Encodable { - var name: String? - } - - let explicitEncoder = JSValueEncoder(optionalEncodingStrategy: .explicitNulls) - let encoded = try XCTUnwrap(try explicitEncoder.encode(Test()) as? JSObject) - XCTAssertTrue(encoded["name"] is NSNull) - XCTAssertNotNil(encoded["name"]) - } -} diff --git a/ios/Capacitor/CodableTests/DataCodableTests.swift b/ios/Capacitor/CodableTests/DataCodableTests.swift deleted file mode 100644 index 112b2bc155..0000000000 --- a/ios/Capacitor/CodableTests/DataCodableTests.swift +++ /dev/null @@ -1,155 +0,0 @@ -// -// DataCodableTests.swift -// CodableTests -// -// Created by Steven Sherry on 9/6/24. -// Copyright © 2024 Drifty Co. All rights reserved. -// - -import XCTest -import Capacitor - -private struct Foo: Codable, Equatable { - var data: Data -} - -private let jsonString = #"{ "key": "value" }"# -private let jsonData = jsonString.data(using: .utf8)! -private let jsonByteArray: [NSNumber] = [123, 32, 34, 107, 101, 121, 34, 58, 32, 34, 118, 97, 108, 117, 101, 34, 32, 125] -private let jsonBase64 = "eyAia2V5IjogInZhbHVlIiB9" - -class JSValueDecoderDataTests: XCTestCase { - func testDecode_data__default_root() throws { - let decoder = JSValueDecoder() - let result = try decoder.decode(Data.self, from: jsonByteArray) - XCTAssertEqual(result, jsonData) - } - - func testDecode_data__default_array() throws { - let decoder = JSValueDecoder() - let result = try decoder.decode([Data].self, from: [jsonByteArray, jsonByteArray]) - XCTAssertEqual(result, [jsonData, jsonData]) - } - - func testDecode_data__default_struct() throws { - let decoder = JSValueDecoder() - let result = try decoder.decode(Foo.self, from: ["data": jsonByteArray]) - XCTAssertEqual(result, .init(data: jsonData)) - } - - func testDecode_data__base64_root() throws { - let decoder = JSValueDecoder(dataDecodingStrategy: .base64) - let result = try decoder.decode(Data.self, from: jsonBase64) - XCTAssertEqual(result, jsonData) - } - - func testDecode_data__base64_array() throws { - let decoder = JSValueDecoder(dataDecodingStrategy: .base64) - let result = try decoder.decode([Data].self, from: [jsonBase64, jsonBase64]) - XCTAssertEqual(result, [jsonData, jsonData]) - } - - func testDecode_data__base64_struct() throws { - let decoder = JSValueDecoder(dataDecodingStrategy: .base64) - let result = try decoder.decode(Foo.self, from: ["data": jsonBase64]) - XCTAssertEqual(result, .init(data: jsonData)) - } - - let customStrategy = JSValueDecoder.DataDecodingStrategy.custom { decoder in - var container = try decoder.unkeyedContainer() - var byteArray: [UInt8] = [] - while !container.isAtEnd { - byteArray.append(try container.decode(UInt8.self)) - } - return Data(byteArray) - } - - func testDecode_data__custom_root() throws { - let decoder = JSValueDecoder(dataDecodingStrategy: customStrategy) - let result = try decoder.decode(Data.self, from: jsonByteArray) - XCTAssertEqual(result, jsonData) - } - - func testDecode_data__custom_array() throws { - let decoder = JSValueDecoder(dataDecodingStrategy: customStrategy) - let result = try decoder.decode([Data].self, from: [jsonByteArray, jsonByteArray]) - XCTAssertEqual(result, [jsonData, jsonData]) - } - - func testDecode_data__custom_struct() throws { - let decoder = JSValueDecoder(dataDecodingStrategy: customStrategy) - let result = try decoder.decode(Foo.self, from: ["data": jsonByteArray]) - XCTAssertEqual(result, .init(data: jsonData)) - } -} - -class JSValueEncoderDataTests: XCTestCase { - func testEncode_data__default_root() throws { - let encoder = JSValueEncoder() - let rawResult = try encoder.encode(jsonData) - let result = try XCTUnwrap(rawResult as? [NSNumber]) - XCTAssertEqual(result, jsonByteArray) - } - - func testEncode_data__default_array() throws { - let encoder = JSValueEncoder() - let rawResult = try encoder.encode([jsonData, jsonData]) - let result = try XCTUnwrap(rawResult as? [[NSNumber]]) - XCTAssertEqual(result, [jsonByteArray, jsonByteArray]) - } - - func testEncode_data__default_struct() throws { - let encoder = JSValueEncoder() - let rawResult = try encoder.encode(Foo(data: jsonData)) - let result = try XCTUnwrap(rawResult as? [String: [NSNumber]]) - XCTAssertEqual(result, ["data": jsonByteArray]) - } - - func testEncode_data__base64_root() throws { - let encoder = JSValueEncoder(dataEncodingStrategy: .base64) - let rawResult = try encoder.encode(jsonData) - let result = try XCTUnwrap(rawResult as? String) - XCTAssertEqual(result, jsonBase64) - } - - func testEncode_data__base64_array() throws { - let encoder = JSValueEncoder(dataEncodingStrategy: .base64) - let rawResult = try encoder.encode([jsonData, jsonData]) - let result = try XCTUnwrap(rawResult as? [String]) - XCTAssertEqual(result, [jsonBase64, jsonBase64]) - } - - func testEncode_data__base64_struct() throws { - let encoder = JSValueEncoder(dataEncodingStrategy: .base64) - let rawResult = try encoder.encode(Foo(data: jsonData)) - let result = try XCTUnwrap(rawResult as? [String: String]) - XCTAssertEqual(result, ["data": jsonBase64]) - } - - let customStrategy = JSValueEncoder.DataEncodingStrategy.custom { data, encoder in - let byteArray = data.map { $0 } - var unkeyedContainer = encoder.unkeyedContainer() - try unkeyedContainer.encode(contentsOf: byteArray) - } - - func testEncode_data__custom_root() throws { - let encoder = JSValueEncoder(dataEncodingStrategy: customStrategy) - let rawResult = try encoder.encode(jsonData) - let result = try XCTUnwrap(rawResult as? [NSNumber]) - XCTAssertEqual(result, jsonByteArray) - } - - func testEncode_data__custom_array() throws { - let encoder = JSValueEncoder(dataEncodingStrategy: customStrategy) - let rawResult = try encoder.encode([jsonData, jsonData]) - let result = try XCTUnwrap(rawResult as? [[NSNumber]]) - XCTAssertEqual(result, [jsonByteArray, jsonByteArray]) - } - - func testEncode_data__custom_struct() throws { - let encoder = JSValueEncoder(dataEncodingStrategy: customStrategy) - let rawResult = try encoder.encode(Foo(data: jsonData)) - let result = try XCTUnwrap(rawResult as? [String: [NSNumber]]) - XCTAssertEqual(result, ["data": jsonByteArray]) - } -} diff --git a/ios/Capacitor/CodableTests/URLCodableTests.swift b/ios/Capacitor/CodableTests/URLCodableTests.swift deleted file mode 100644 index 33a739a31e..0000000000 --- a/ios/Capacitor/CodableTests/URLCodableTests.swift +++ /dev/null @@ -1,62 +0,0 @@ -// -// URLCodableTests.swift -// CodableTests -// -// Created by Steven Sherry on 9/6/24. -// Copyright © 2024 Drifty Co. All rights reserved. -// - -import XCTest -import Capacitor - -private let urlString = "https://capacitorjs.com" -private let url = URL(string: urlString)! - -private struct Website: Codable, Equatable { - var url: URL -} - -class JSValueDecoderURLTests: XCTestCase { - let decoder = JSValueDecoder() - - func testDecode_url__root() throws { - let result = try decoder.decode(URL.self, from: urlString) - XCTAssertEqual(result, url) - } - - func testDecode_url__array() throws { - let result = try decoder.decode([URL].self, from: [urlString, urlString]) - XCTAssertEqual(result, [url, url]) - } - - func testDecode_url__struct() throws { - let result = try decoder.decode(Website.self, from: ["url": urlString]) - XCTAssertEqual(result, .init(url: url)) - } - - func testDecode_url__fails_when_invalid_url_string_is_provided() { - XCTAssertThrowsError(try decoder.decode(URL.self, from: "🐞://🐞.com/🐞")) - } -} - -class JSValueEncoderURLTests: XCTestCase { - let encoder = JSValueEncoder() - - func testEncode_url__root() throws { - let rawResult = try encoder.encode(url) - let result = try XCTUnwrap(rawResult as? String) - XCTAssertEqual(result, urlString) - } - - func testEncode_url__array() throws { - let rawResult = try encoder.encode([url, url]) - let result = try XCTUnwrap(rawResult as? [String]) - XCTAssertEqual(result, [urlString, urlString]) - } - - func testEncode_url__struct() throws { - let rawResult = try encoder.encode(Website(url: url)) - let result = try XCTUnwrap(rawResult as? [String: String]) - XCTAssertEqual(result, ["url": urlString]) - } -} diff --git a/ios/Capacitor/TestsHostApp/AppDelegate.swift b/ios/Capacitor/TestsHostApp/AppDelegate.swift deleted file mode 100644 index 9107e3c451..0000000000 --- a/ios/Capacitor/TestsHostApp/AppDelegate.swift +++ /dev/null @@ -1,18 +0,0 @@ -import UIKit - -@main -class AppDelegate: UIResponder, UIApplicationDelegate { - func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { - // Override point for customization after application launch. - return true - } - - func application(_ application: UIApplication, - configurationForConnecting connectingSceneSession: UISceneSession, - options: UIScene.ConnectionOptions) -> UISceneConfiguration { - let config = UISceneConfiguration(name: "Default Configuration", - sessionRole: connectingSceneSession.role) - config.delegateClass = SceneDelegate.self - return config - } -} diff --git a/ios/Capacitor/TestsHostApp/Assets.xcassets/AccentColor.colorset/Contents.json b/ios/Capacitor/TestsHostApp/Assets.xcassets/AccentColor.colorset/Contents.json deleted file mode 100644 index eb87897008..0000000000 --- a/ios/Capacitor/TestsHostApp/Assets.xcassets/AccentColor.colorset/Contents.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "colors" : [ - { - "idiom" : "universal" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/ios/Capacitor/TestsHostApp/Assets.xcassets/AppIcon.appiconset/Contents.json b/ios/Capacitor/TestsHostApp/Assets.xcassets/AppIcon.appiconset/Contents.json deleted file mode 100644 index 9221b9bb1a..0000000000 --- a/ios/Capacitor/TestsHostApp/Assets.xcassets/AppIcon.appiconset/Contents.json +++ /dev/null @@ -1,98 +0,0 @@ -{ - "images" : [ - { - "idiom" : "iphone", - "scale" : "2x", - "size" : "20x20" - }, - { - "idiom" : "iphone", - "scale" : "3x", - "size" : "20x20" - }, - { - "idiom" : "iphone", - "scale" : "2x", - "size" : "29x29" - }, - { - "idiom" : "iphone", - "scale" : "3x", - "size" : "29x29" - }, - { - "idiom" : "iphone", - "scale" : "2x", - "size" : "40x40" - }, - { - "idiom" : "iphone", - "scale" : "3x", - "size" : "40x40" - }, - { - "idiom" : "iphone", - "scale" : "2x", - "size" : "60x60" - }, - { - "idiom" : "iphone", - "scale" : "3x", - "size" : "60x60" - }, - { - "idiom" : "ipad", - "scale" : "1x", - "size" : "20x20" - }, - { - "idiom" : "ipad", - "scale" : "2x", - "size" : "20x20" - }, - { - "idiom" : "ipad", - "scale" : "1x", - "size" : "29x29" - }, - { - "idiom" : "ipad", - "scale" : "2x", - "size" : "29x29" - }, - { - "idiom" : "ipad", - "scale" : "1x", - "size" : "40x40" - }, - { - "idiom" : "ipad", - "scale" : "2x", - "size" : "40x40" - }, - { - "idiom" : "ipad", - "scale" : "1x", - "size" : "76x76" - }, - { - "idiom" : "ipad", - "scale" : "2x", - "size" : "76x76" - }, - { - "idiom" : "ipad", - "scale" : "2x", - "size" : "83.5x83.5" - }, - { - "idiom" : "ios-marketing", - "scale" : "1x", - "size" : "1024x1024" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/ios/Capacitor/TestsHostApp/Assets.xcassets/Contents.json b/ios/Capacitor/TestsHostApp/Assets.xcassets/Contents.json deleted file mode 100644 index 73c00596a7..0000000000 --- a/ios/Capacitor/TestsHostApp/Assets.xcassets/Contents.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/ios/Capacitor/TestsHostApp/Base.lproj/LaunchScreen.storyboard b/ios/Capacitor/TestsHostApp/Base.lproj/LaunchScreen.storyboard deleted file mode 100644 index 865e9329f3..0000000000 --- a/ios/Capacitor/TestsHostApp/Base.lproj/LaunchScreen.storyboard +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/ios/Capacitor/TestsHostApp/Base.lproj/Main.storyboard b/ios/Capacitor/TestsHostApp/Base.lproj/Main.storyboard deleted file mode 100644 index 25a763858e..0000000000 --- a/ios/Capacitor/TestsHostApp/Base.lproj/Main.storyboard +++ /dev/null @@ -1,24 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/ios/Capacitor/TestsHostApp/Info.plist b/ios/Capacitor/TestsHostApp/Info.plist deleted file mode 100644 index 5b531f7b27..0000000000 --- a/ios/Capacitor/TestsHostApp/Info.plist +++ /dev/null @@ -1,66 +0,0 @@ - - - - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - $(PRODUCT_BUNDLE_PACKAGE_TYPE) - CFBundleShortVersionString - 1.0 - CFBundleVersion - 1 - LSRequiresIPhoneOS - - UIApplicationSceneManifest - - UIApplicationSupportsMultipleScenes - - UISceneConfigurations - - UIWindowSceneSessionRoleApplication - - - UISceneConfigurationName - Default Configuration - UISceneDelegateClassName - $(PRODUCT_MODULE_NAME).SceneDelegate - UISceneStoryboardFile - Main - - - - - UIApplicationSupportsIndirectInputEvents - - UILaunchStoryboardName - LaunchScreen - UIMainStoryboardFile - Main - UIRequiredDeviceCapabilities - - armv7 - - UISupportedInterfaceOrientations - - UIInterfaceOrientationPortrait - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - - UISupportedInterfaceOrientations~ipad - - UIInterfaceOrientationPortrait - UIInterfaceOrientationPortraitUpsideDown - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - - - diff --git a/ios/Capacitor/TestsHostApp/SceneDelegate.swift b/ios/Capacitor/TestsHostApp/SceneDelegate.swift deleted file mode 100644 index e0be6e9cfe..0000000000 --- a/ios/Capacitor/TestsHostApp/SceneDelegate.swift +++ /dev/null @@ -1,5 +0,0 @@ -import UIKit - -class SceneDelegate: UIResponder, UIWindowSceneDelegate { - var window: UIWindow? -} diff --git a/ios/Capacitor/TestsHostApp/ViewController.swift b/ios/Capacitor/TestsHostApp/ViewController.swift deleted file mode 100644 index ae980e1ea3..0000000000 --- a/ios/Capacitor/TestsHostApp/ViewController.swift +++ /dev/null @@ -1,9 +0,0 @@ -import UIKit - -class ViewController: UIViewController { - - override func viewDidLoad() { - super.viewDidLoad() - // Do any additional setup after loading the view. - } -} diff --git a/ios/CapacitorCordova.podspec b/ios/CapacitorCordova.podspec index 98f6bc3474..e5d7cf82a4 100644 --- a/ios/CapacitorCordova.podspec +++ b/ios/CapacitorCordova.podspec @@ -16,11 +16,12 @@ Pod::Spec.new do |s| s.authors = { 'Ionic Team' => 'hi@ionicframework.com' } s.source = { git: 'https://github.com/ionic-team/capacitor', tag: s.version.to_s } s.platform = :ios, 16.0 - s.source_files = "#{prefix}CapacitorCordova/CapacitorCordova/**/*.{h,m,swift}" - s.public_header_files = "#{prefix}CapacitorCordova/CapacitorCordova/Classes/Public/*.h", - "#{prefix}CapacitorCordova/CapacitorCordova/CapacitorCordova.h" - s.module_map = "#{prefix}CapacitorCordova/CapacitorCordova/CapacitorCordova.modulemap" - s.resource_bundles = { 'CapacitorCordova' => ["#{prefix}CapacitorCordova/CapacitorCordova/PrivacyInfo.xcprivacy"] } + s.source_files = "#{prefix}Sources/Cordova/**/*.{h,m}", + "#{prefix}Sources/CapacitorCordova/**/*.swift" + s.public_header_files = "#{prefix}Sources/Cordova/include/*.h", + "#{prefix}Sources/Cordova/CapacitorCordova.h" + s.module_map = "#{prefix}Sources/Cordova/CapacitorCordova.modulemap" + s.resource_bundles = { 'CapacitorCordova' => ["#{prefix}Sources/Cordova/PrivacyInfo.xcprivacy"] } s.requires_arc = true s.dependency 'Capacitor', s.version.to_s s.framework = 'WebKit' diff --git a/ios/CapacitorCordova/CapacitorCordova.xcodeproj/project.pbxproj b/ios/CapacitorCordova/CapacitorCordova.xcodeproj/project.pbxproj deleted file mode 100644 index 59d25512a5..0000000000 --- a/ios/CapacitorCordova/CapacitorCordova.xcodeproj/project.pbxproj +++ /dev/null @@ -1,499 +0,0 @@ -// !$*UTF8*$! -{ - archiveVersion = 1; - classes = { - }; - objectVersion = 48; - objects = { - -/* Begin PBXBuildFile section */ - 0B61A7E52B114AA00035F2DB /* CDVWebViewProcessPoolFactory.m in Sources */ = {isa = PBXBuildFile; fileRef = 0B61A7E32B114A9F0035F2DB /* CDVWebViewProcessPoolFactory.m */; }; - 0B61A7E62B114AA00035F2DB /* CDVWebViewProcessPoolFactory.h in Headers */ = {isa = PBXBuildFile; fileRef = 0B61A7E42B114AA00035F2DB /* CDVWebViewProcessPoolFactory.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 1DBF5C182E9E908A00FAC24F /* CDVAvailabilityDeprecated.h in Headers */ = {isa = PBXBuildFile; fileRef = 1DBF5C172E9E908A00FAC24F /* CDVAvailabilityDeprecated.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 2F4F657C2091F1FD00EAA994 /* NSDictionary+CordovaPreferences.m in Sources */ = {isa = PBXBuildFile; fileRef = 2F4F657A2091F1FD00EAA994 /* NSDictionary+CordovaPreferences.m */; }; - 2F4F657D2091F1FD00EAA994 /* NSDictionary+CordovaPreferences.h in Headers */ = {isa = PBXBuildFile; fileRef = 2F4F657B2091F1FD00EAA994 /* NSDictionary+CordovaPreferences.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 2F5C86E11FE94845004B09C7 /* CapacitorCordova.h in Headers */ = {isa = PBXBuildFile; fileRef = 2F5C86DF1FE94845004B09C7 /* CapacitorCordova.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 2F5C871D1FE98418004B09C7 /* CDVPluginResult.m in Sources */ = {isa = PBXBuildFile; fileRef = 2F5C87121FE98417004B09C7 /* CDVPluginResult.m */; }; - 2F5C871E1FE98418004B09C7 /* CDV.h in Headers */ = {isa = PBXBuildFile; fileRef = 2F5C87131FE98417004B09C7 /* CDV.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 2F5C871F1FE98418004B09C7 /* CDVCommandDelegateImpl.m in Sources */ = {isa = PBXBuildFile; fileRef = 2F5C87141FE98417004B09C7 /* CDVCommandDelegateImpl.m */; }; - 2F5C87201FE98418004B09C7 /* CDVInvokedUrlCommand.m in Sources */ = {isa = PBXBuildFile; fileRef = 2F5C87151FE98417004B09C7 /* CDVInvokedUrlCommand.m */; }; - 2F5C87211FE98418004B09C7 /* CDVPlugin.m in Sources */ = {isa = PBXBuildFile; fileRef = 2F5C87161FE98417004B09C7 /* CDVPlugin.m */; }; - 2F5C87221FE98418004B09C7 /* CDVCommandDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = 2F5C87171FE98417004B09C7 /* CDVCommandDelegate.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 2F5C87231FE98418004B09C7 /* CDVCommandDelegateImpl.h in Headers */ = {isa = PBXBuildFile; fileRef = 2F5C87181FE98417004B09C7 /* CDVCommandDelegateImpl.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 2F5C87241FE98418004B09C7 /* CDVInvokedUrlCommand.h in Headers */ = {isa = PBXBuildFile; fileRef = 2F5C87191FE98418004B09C7 /* CDVInvokedUrlCommand.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 2F5C87251FE98418004B09C7 /* CDVAvailability.h in Headers */ = {isa = PBXBuildFile; fileRef = 2F5C871A1FE98418004B09C7 /* CDVAvailability.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 2F5C87261FE98418004B09C7 /* CDVPluginResult.h in Headers */ = {isa = PBXBuildFile; fileRef = 2F5C871B1FE98418004B09C7 /* CDVPluginResult.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 2F5C87271FE98418004B09C7 /* CDVPlugin.h in Headers */ = {isa = PBXBuildFile; fileRef = 2F5C871C1FE98418004B09C7 /* CDVPlugin.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 2F856BFF203DEB320047344A /* CDVViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = 2F856BFD203DEB320047344A /* CDVViewController.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 2F856C00203DEB320047344A /* CDVViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 2F856BFE203DEB320047344A /* CDVViewController.m */; }; - 2F8AC283217F3A20008C2C33 /* CDVURLProtocol.m in Sources */ = {isa = PBXBuildFile; fileRef = 2F8AC281217F3A20008C2C33 /* CDVURLProtocol.m */; }; - 2F8AC284217F3A20008C2C33 /* CDVURLProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = 2F8AC282217F3A20008C2C33 /* CDVURLProtocol.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 2F92AB5224D9ABA000954A4A /* CDVPlugin+Resources.m in Sources */ = {isa = PBXBuildFile; fileRef = 2F92AB5024D9ABA000954A4A /* CDVPlugin+Resources.m */; }; - 2F92AB5324D9ABA000954A4A /* CDVPlugin+Resources.h in Headers */ = {isa = PBXBuildFile; fileRef = 2F92AB5124D9ABA000954A4A /* CDVPlugin+Resources.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 2FAD9772203C77B9000D30F8 /* CDVConfigParser.h in Headers */ = {isa = PBXBuildFile; fileRef = 2FAD9770203C77B8000D30F8 /* CDVConfigParser.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 2FAD9773203C77B9000D30F8 /* CDVConfigParser.m in Sources */ = {isa = PBXBuildFile; fileRef = 2FAD9771203C77B9000D30F8 /* CDVConfigParser.m */; }; - 2FE19E2A20473160002A4E89 /* AppDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = 2FE19E2820473160002A4E89 /* AppDelegate.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 2FE19E2B20473160002A4E89 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 2FE19E2920473160002A4E89 /* AppDelegate.m */; }; - 62959B66252524CD00A3D7F1 /* CDVScreenOrientationDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = 62959B65252524CD00A3D7F1 /* CDVScreenOrientationDelegate.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 62959B6A252524D700A3D7F1 /* CDVPluginManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 62959B68252524D700A3D7F1 /* CDVPluginManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 62959B6B252524D700A3D7F1 /* CDVPluginManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 62959B69252524D700A3D7F1 /* CDVPluginManager.m */; }; - A76739742B98CC7800795F7B /* PrivacyInfo.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = A76739732B98CC7800795F7B /* PrivacyInfo.xcprivacy */; }; - D4DA0E9B2FFD28C60031AA74 /* Plugin.swift in Sources */ = {isa = PBXBuildFile; fileRef = D4DA0E9A2FFD28C60031AA74 /* Plugin.swift */; }; - D4DA0ED52FFD573E0031AA74 /* Capacitor.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D4DA0ED42FFD573E0031AA74 /* Capacitor.framework */; }; - D4DA0ED62FFD573E0031AA74 /* Capacitor.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = D4DA0ED42FFD573E0031AA74 /* Capacitor.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; -/* End PBXBuildFile section */ - -/* Begin PBXCopyFilesBuildPhase section */ - D4DA0ED72FFD573E0031AA74 /* Embed Frameworks */ = { - isa = PBXCopyFilesBuildPhase; - buildActionMask = 2147483647; - dstPath = ""; - dstSubfolderSpec = 10; - files = ( - D4DA0ED62FFD573E0031AA74 /* Capacitor.framework in Embed Frameworks */, - ); - name = "Embed Frameworks"; - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXCopyFilesBuildPhase section */ - -/* Begin PBXFileReference section */ - 0B61A7E32B114A9F0035F2DB /* CDVWebViewProcessPoolFactory.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CDVWebViewProcessPoolFactory.m; sourceTree = ""; }; - 0B61A7E42B114AA00035F2DB /* CDVWebViewProcessPoolFactory.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CDVWebViewProcessPoolFactory.h; sourceTree = ""; }; - 1DBF5C172E9E908A00FAC24F /* CDVAvailabilityDeprecated.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CDVAvailabilityDeprecated.h; sourceTree = ""; }; - 2F4F657A2091F1FD00EAA994 /* NSDictionary+CordovaPreferences.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSDictionary+CordovaPreferences.m"; sourceTree = ""; }; - 2F4F657B2091F1FD00EAA994 /* NSDictionary+CordovaPreferences.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSDictionary+CordovaPreferences.h"; sourceTree = ""; }; - 2F5C86DC1FE94845004B09C7 /* Cordova.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Cordova.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 2F5C86DF1FE94845004B09C7 /* CapacitorCordova.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CapacitorCordova.h; sourceTree = ""; }; - 2F5C86E01FE94845004B09C7 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 2F5C87121FE98417004B09C7 /* CDVPluginResult.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CDVPluginResult.m; sourceTree = ""; }; - 2F5C87131FE98417004B09C7 /* CDV.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CDV.h; sourceTree = ""; }; - 2F5C87141FE98417004B09C7 /* CDVCommandDelegateImpl.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CDVCommandDelegateImpl.m; sourceTree = ""; }; - 2F5C87151FE98417004B09C7 /* CDVInvokedUrlCommand.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CDVInvokedUrlCommand.m; sourceTree = ""; }; - 2F5C87161FE98417004B09C7 /* CDVPlugin.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CDVPlugin.m; sourceTree = ""; }; - 2F5C87171FE98417004B09C7 /* CDVCommandDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CDVCommandDelegate.h; sourceTree = ""; }; - 2F5C87181FE98417004B09C7 /* CDVCommandDelegateImpl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CDVCommandDelegateImpl.h; sourceTree = ""; }; - 2F5C87191FE98418004B09C7 /* CDVInvokedUrlCommand.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CDVInvokedUrlCommand.h; sourceTree = ""; }; - 2F5C871A1FE98418004B09C7 /* CDVAvailability.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CDVAvailability.h; sourceTree = ""; }; - 2F5C871B1FE98418004B09C7 /* CDVPluginResult.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CDVPluginResult.h; sourceTree = ""; }; - 2F5C871C1FE98418004B09C7 /* CDVPlugin.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CDVPlugin.h; sourceTree = ""; }; - 2F856BFD203DEB320047344A /* CDVViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CDVViewController.h; sourceTree = ""; }; - 2F856BFE203DEB320047344A /* CDVViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CDVViewController.m; sourceTree = ""; }; - 2F8AC281217F3A20008C2C33 /* CDVURLProtocol.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CDVURLProtocol.m; sourceTree = ""; }; - 2F8AC282217F3A20008C2C33 /* CDVURLProtocol.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CDVURLProtocol.h; sourceTree = ""; }; - 2F92AB5024D9ABA000954A4A /* CDVPlugin+Resources.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "CDVPlugin+Resources.m"; sourceTree = ""; }; - 2F92AB5124D9ABA000954A4A /* CDVPlugin+Resources.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "CDVPlugin+Resources.h"; sourceTree = ""; }; - 2FAD9770203C77B8000D30F8 /* CDVConfigParser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CDVConfigParser.h; sourceTree = ""; }; - 2FAD9771203C77B9000D30F8 /* CDVConfigParser.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CDVConfigParser.m; sourceTree = ""; }; - 2FE19E2820473160002A4E89 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; - 2FE19E2920473160002A4E89 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; - 62959B5F252522CB00A3D7F1 /* CapacitorCordova.modulemap */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = "sourcecode.module-map"; path = CapacitorCordova.modulemap; sourceTree = ""; }; - 62959B65252524CD00A3D7F1 /* CDVScreenOrientationDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CDVScreenOrientationDelegate.h; sourceTree = ""; }; - 62959B68252524D700A3D7F1 /* CDVPluginManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CDVPluginManager.h; sourceTree = ""; }; - 62959B69252524D700A3D7F1 /* CDVPluginManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CDVPluginManager.m; sourceTree = ""; }; - A76739732B98CC7800795F7B /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; lastKnownFileType = text.xml; path = PrivacyInfo.xcprivacy; sourceTree = ""; }; - D4DA0E962FFD28680031AA74 /* Capacitor.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = Capacitor.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - D4DA0E9A2FFD28C60031AA74 /* Plugin.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Plugin.swift; sourceTree = ""; }; - D4DA0ED42FFD573E0031AA74 /* Capacitor.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = Capacitor.framework; sourceTree = BUILT_PRODUCTS_DIR; }; -/* End PBXFileReference section */ - -/* Begin PBXFrameworksBuildPhase section */ - 2F5C86D81FE94845004B09C7 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - D4DA0ED52FFD573E0031AA74 /* Capacitor.framework in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXFrameworksBuildPhase section */ - -/* Begin PBXGroup section */ - 2F5C86D21FE94845004B09C7 = { - isa = PBXGroup; - children = ( - 2F5C86DE1FE94845004B09C7 /* CapacitorCordova */, - D4DA0E952FFD28680031AA74 /* Frameworks */, - 2F5C86DD1FE94845004B09C7 /* Products */, - ); - sourceTree = ""; - }; - 2F5C86DD1FE94845004B09C7 /* Products */ = { - isa = PBXGroup; - children = ( - 2F5C86DC1FE94845004B09C7 /* Cordova.framework */, - ); - name = Products; - sourceTree = ""; - }; - 2F5C86DE1FE94845004B09C7 /* CapacitorCordova */ = { - isa = PBXGroup; - children = ( - 2F5C86E71FE94859004B09C7 /* Classes */, - 2F5C86DF1FE94845004B09C7 /* CapacitorCordova.h */, - 62959B5F252522CB00A3D7F1 /* CapacitorCordova.modulemap */, - 2F5C86E01FE94845004B09C7 /* Info.plist */, - A76739732B98CC7800795F7B /* PrivacyInfo.xcprivacy */, - ); - path = CapacitorCordova; - sourceTree = ""; - }; - 2F5C86E71FE94859004B09C7 /* Classes */ = { - isa = PBXGroup; - children = ( - 2F5C86E81FE94861004B09C7 /* Public */, - ); - path = Classes; - sourceTree = ""; - }; - 2F5C86E81FE94861004B09C7 /* Public */ = { - isa = PBXGroup; - children = ( - D4DA0E9A2FFD28C60031AA74 /* Plugin.swift */, - 2FE19E2820473160002A4E89 /* AppDelegate.h */, - 2FE19E2920473160002A4E89 /* AppDelegate.m */, - 2F5C87131FE98417004B09C7 /* CDV.h */, - 2F5C871A1FE98418004B09C7 /* CDVAvailability.h */, - 1DBF5C172E9E908A00FAC24F /* CDVAvailabilityDeprecated.h */, - 2F5C87171FE98417004B09C7 /* CDVCommandDelegate.h */, - 2F5C87141FE98417004B09C7 /* CDVCommandDelegateImpl.m */, - 2F5C87181FE98417004B09C7 /* CDVCommandDelegateImpl.h */, - 2FAD9770203C77B8000D30F8 /* CDVConfigParser.h */, - 2FAD9771203C77B9000D30F8 /* CDVConfigParser.m */, - 2F5C87191FE98418004B09C7 /* CDVInvokedUrlCommand.h */, - 2F5C87151FE98417004B09C7 /* CDVInvokedUrlCommand.m */, - 2F92AB5124D9ABA000954A4A /* CDVPlugin+Resources.h */, - 2F92AB5024D9ABA000954A4A /* CDVPlugin+Resources.m */, - 2F5C871C1FE98418004B09C7 /* CDVPlugin.h */, - 2F5C87161FE98417004B09C7 /* CDVPlugin.m */, - 62959B68252524D700A3D7F1 /* CDVPluginManager.h */, - 62959B69252524D700A3D7F1 /* CDVPluginManager.m */, - 2F5C871B1FE98418004B09C7 /* CDVPluginResult.h */, - 2F5C87121FE98417004B09C7 /* CDVPluginResult.m */, - 62959B65252524CD00A3D7F1 /* CDVScreenOrientationDelegate.h */, - 2F8AC282217F3A20008C2C33 /* CDVURLProtocol.h */, - 2F8AC281217F3A20008C2C33 /* CDVURLProtocol.m */, - 2F4F657B2091F1FD00EAA994 /* NSDictionary+CordovaPreferences.h */, - 2F4F657A2091F1FD00EAA994 /* NSDictionary+CordovaPreferences.m */, - 2F856BFD203DEB320047344A /* CDVViewController.h */, - 2F856BFE203DEB320047344A /* CDVViewController.m */, - 0B61A7E42B114AA00035F2DB /* CDVWebViewProcessPoolFactory.h */, - 0B61A7E32B114A9F0035F2DB /* CDVWebViewProcessPoolFactory.m */, - ); - path = Public; - sourceTree = ""; - }; - D4DA0E952FFD28680031AA74 /* Frameworks */ = { - isa = PBXGroup; - children = ( - D4DA0ED42FFD573E0031AA74 /* Capacitor.framework */, - D4DA0E962FFD28680031AA74 /* Capacitor.framework */, - ); - name = Frameworks; - sourceTree = ""; - }; -/* End PBXGroup section */ - -/* Begin PBXHeadersBuildPhase section */ - 2F5C86D91FE94845004B09C7 /* Headers */ = { - isa = PBXHeadersBuildPhase; - buildActionMask = 2147483647; - files = ( - 2FE19E2A20473160002A4E89 /* AppDelegate.h in Headers */, - 2F5C871E1FE98418004B09C7 /* CDV.h in Headers */, - 2F5C87231FE98418004B09C7 /* CDVCommandDelegateImpl.h in Headers */, - 2F5C87251FE98418004B09C7 /* CDVAvailability.h in Headers */, - 2F5C87271FE98418004B09C7 /* CDVPlugin.h in Headers */, - 2F5C87261FE98418004B09C7 /* CDVPluginResult.h in Headers */, - 2F5C87221FE98418004B09C7 /* CDVCommandDelegate.h in Headers */, - 2F5C87241FE98418004B09C7 /* CDVInvokedUrlCommand.h in Headers */, - 2FAD9772203C77B9000D30F8 /* CDVConfigParser.h in Headers */, - 2F856BFF203DEB320047344A /* CDVViewController.h in Headers */, - 2F4F657D2091F1FD00EAA994 /* NSDictionary+CordovaPreferences.h in Headers */, - 2F8AC284217F3A20008C2C33 /* CDVURLProtocol.h in Headers */, - 2F92AB5324D9ABA000954A4A /* CDVPlugin+Resources.h in Headers */, - 62959B66252524CD00A3D7F1 /* CDVScreenOrientationDelegate.h in Headers */, - 0B61A7E62B114AA00035F2DB /* CDVWebViewProcessPoolFactory.h in Headers */, - 62959B6A252524D700A3D7F1 /* CDVPluginManager.h in Headers */, - 1DBF5C182E9E908A00FAC24F /* CDVAvailabilityDeprecated.h in Headers */, - 2F5C86E11FE94845004B09C7 /* CapacitorCordova.h in Headers */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXHeadersBuildPhase section */ - -/* Begin PBXNativeTarget section */ - 2F5C86DB1FE94845004B09C7 /* Cordova */ = { - isa = PBXNativeTarget; - buildConfigurationList = 2F5C86E41FE94845004B09C7 /* Build configuration list for PBXNativeTarget "Cordova" */; - buildPhases = ( - 2F5C86D71FE94845004B09C7 /* Sources */, - 2F5C86D81FE94845004B09C7 /* Frameworks */, - 2F5C86D91FE94845004B09C7 /* Headers */, - 2F5C86DA1FE94845004B09C7 /* Resources */, - D4DA0ED72FFD573E0031AA74 /* Embed Frameworks */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = Cordova; - productName = AvocadoCordova; - productReference = 2F5C86DC1FE94845004B09C7 /* Cordova.framework */; - productType = "com.apple.product-type.framework"; - }; -/* End PBXNativeTarget section */ - -/* Begin PBXProject section */ - 2F5C86D31FE94845004B09C7 /* Project object */ = { - isa = PBXProject; - attributes = { - LastUpgradeCheck = 1220; - ORGANIZATIONNAME = jcesarmobile; - TargetAttributes = { - 2F5C86DB1FE94845004B09C7 = { - CreatedOnToolsVersion = 9.2; - LastSwiftMigration = 2650; - ProvisioningStyle = Automatic; - }; - }; - }; - buildConfigurationList = 2F5C86D61FE94845004B09C7 /* Build configuration list for PBXProject "CapacitorCordova" */; - compatibilityVersion = "Xcode 8.0"; - developmentRegion = en; - hasScannedForEncodings = 0; - knownRegions = ( - en, - Base, - ); - mainGroup = 2F5C86D21FE94845004B09C7; - productRefGroup = 2F5C86DD1FE94845004B09C7 /* Products */; - projectDirPath = ""; - projectRoot = ""; - targets = ( - 2F5C86DB1FE94845004B09C7 /* Cordova */, - ); - }; -/* End PBXProject section */ - -/* Begin PBXResourcesBuildPhase section */ - 2F5C86DA1FE94845004B09C7 /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - A76739742B98CC7800795F7B /* PrivacyInfo.xcprivacy in Resources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXResourcesBuildPhase section */ - -/* Begin PBXSourcesBuildPhase section */ - 2F5C86D71FE94845004B09C7 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 62959B6B252524D700A3D7F1 /* CDVPluginManager.m in Sources */, - 2F5C871F1FE98418004B09C7 /* CDVCommandDelegateImpl.m in Sources */, - 2F5C871D1FE98418004B09C7 /* CDVPluginResult.m in Sources */, - 2F4F657C2091F1FD00EAA994 /* NSDictionary+CordovaPreferences.m in Sources */, - 0B61A7E52B114AA00035F2DB /* CDVWebViewProcessPoolFactory.m in Sources */, - 2F5C87211FE98418004B09C7 /* CDVPlugin.m in Sources */, - 2F92AB5224D9ABA000954A4A /* CDVPlugin+Resources.m in Sources */, - 2FAD9773203C77B9000D30F8 /* CDVConfigParser.m in Sources */, - 2F856C00203DEB320047344A /* CDVViewController.m in Sources */, - 2F5C87201FE98418004B09C7 /* CDVInvokedUrlCommand.m in Sources */, - D4DA0E9B2FFD28C60031AA74 /* Plugin.swift in Sources */, - 2FE19E2B20473160002A4E89 /* AppDelegate.m in Sources */, - 2F8AC283217F3A20008C2C33 /* CDVURLProtocol.m in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXSourcesBuildPhase section */ - -/* Begin XCBuildConfiguration section */ - 2F5C86E21FE94845004B09C7 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_NONNULL = YES; - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - CODE_SIGN_IDENTITY = "iPhone Developer"; - COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 1; - DEBUG_INFORMATION_FORMAT = dwarf; - ENABLE_STRICT_OBJC_MSGSEND = YES; - ENABLE_TESTABILITY = YES; - GCC_C_LANGUAGE_STANDARD = gnu11; - GCC_DYNAMIC_NO_PIC = NO; - GCC_NO_COMMON_BLOCKS = YES; - GCC_OPTIMIZATION_LEVEL = 0; - GCC_PREPROCESSOR_DEFINITIONS = ( - "DEBUG=1", - "$(inherited)", - ); - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 16.0; - MTL_ENABLE_DEBUG_INFO = YES; - ONLY_ACTIVE_ARCH = YES; - SDKROOT = iphoneos; - VERSIONING_SYSTEM = "apple-generic"; - VERSION_INFO_PREFIX = ""; - }; - name = Debug; - }; - 2F5C86E31FE94845004B09C7 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_NONNULL = YES; - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - CODE_SIGN_IDENTITY = "iPhone Developer"; - COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 1; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - ENABLE_NS_ASSERTIONS = NO; - ENABLE_STRICT_OBJC_MSGSEND = YES; - GCC_C_LANGUAGE_STANDARD = gnu11; - GCC_NO_COMMON_BLOCKS = YES; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 16.0; - MTL_ENABLE_DEBUG_INFO = NO; - SDKROOT = iphoneos; - VALIDATE_PRODUCT = YES; - VERSIONING_SYSTEM = "apple-generic"; - VERSION_INFO_PREFIX = ""; - }; - name = Release; - }; - 2F5C86E51FE94845004B09C7 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - CLANG_ENABLE_MODULES = YES; - CODE_SIGN_IDENTITY = ""; - CODE_SIGN_STYLE = Automatic; - DEFINES_MODULE = YES; - DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 1; - DYLIB_INSTALL_NAME_BASE = "@rpath"; - INFOPLIST_FILE = CapacitorCordova/Info.plist; - INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; - MODULEMAP_FILE = CapacitorCordova/CapacitorCordova.modulemap; - PRODUCT_BUNDLE_IDENTIFIER = com.getcapacitor.ios.CapacitorCordova; - PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; - SKIP_INSTALL = YES; - SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; - }; - name = Debug; - }; - 2F5C86E61FE94845004B09C7 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - CLANG_ENABLE_MODULES = YES; - CODE_SIGN_IDENTITY = ""; - CODE_SIGN_STYLE = Automatic; - DEFINES_MODULE = YES; - DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 1; - DYLIB_INSTALL_NAME_BASE = "@rpath"; - INFOPLIST_FILE = CapacitorCordova/Info.plist; - INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; - MODULEMAP_FILE = CapacitorCordova/CapacitorCordova.modulemap; - PRODUCT_BUNDLE_IDENTIFIER = com.getcapacitor.ios.CapacitorCordova; - PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; - SKIP_INSTALL = YES; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; - }; - name = Release; - }; -/* End XCBuildConfiguration section */ - -/* Begin XCConfigurationList section */ - 2F5C86D61FE94845004B09C7 /* Build configuration list for PBXProject "CapacitorCordova" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 2F5C86E21FE94845004B09C7 /* Debug */, - 2F5C86E31FE94845004B09C7 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 2F5C86E41FE94845004B09C7 /* Build configuration list for PBXNativeTarget "Cordova" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 2F5C86E51FE94845004B09C7 /* Debug */, - 2F5C86E61FE94845004B09C7 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; -/* End XCConfigurationList section */ - }; - rootObject = 2F5C86D31FE94845004B09C7 /* Project object */; -} diff --git a/ios/CapacitorCordova/CapacitorCordova.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/ios/CapacitorCordova/CapacitorCordova.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist deleted file mode 100644 index 18d981003d..0000000000 --- a/ios/CapacitorCordova/CapacitorCordova.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +++ /dev/null @@ -1,8 +0,0 @@ - - - - - IDEDidComputeMac32BitWarning - - - diff --git a/ios/CapacitorCordova/CapacitorCordova/Info.plist b/ios/CapacitorCordova/CapacitorCordova/Info.plist deleted file mode 100644 index 1483c473b4..0000000000 --- a/ios/CapacitorCordova/CapacitorCordova/Info.plist +++ /dev/null @@ -1,26 +0,0 @@ - - - - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleDisplayName - Cordova - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - FMWK - CFBundleShortVersionString - 1.0 - CFBundleVersion - $(CURRENT_PROJECT_VERSION) - NSPrincipalClass - - - diff --git a/ios/Capacitor/Capacitor/AppUUID.swift b/ios/Sources/Capacitor/AppUUID.swift similarity index 100% rename from ios/Capacitor/Capacitor/AppUUID.swift rename to ios/Sources/Capacitor/AppUUID.swift diff --git a/ios/Capacitor/Capacitor/Array+Capacitor.swift b/ios/Sources/Capacitor/Array+Capacitor.swift similarity index 97% rename from ios/Capacitor/Capacitor/Array+Capacitor.swift rename to ios/Sources/Capacitor/Array+Capacitor.swift index e9d7a6f810..7c9e4db595 100644 --- a/ios/Capacitor/Capacitor/Array+Capacitor.swift +++ b/ios/Sources/Capacitor/Array+Capacitor.swift @@ -1,3 +1,5 @@ +import Foundation + // convenience wrappers to transform Arrays between NSNull and Optional values, for interoperability with Obj-C extension Array: CapacitorExtension {} extension CapacitorExtensionTypeWrapper where T == [JSValue] { diff --git a/ios/Sources/Capacitor/BridgedJSValueContainerImplementation.swift b/ios/Sources/Capacitor/BridgedJSValueContainerImplementation.swift new file mode 100644 index 0000000000..12deade7e3 --- /dev/null +++ b/ios/Sources/Capacitor/BridgedJSValueContainerImplementation.swift @@ -0,0 +1,54 @@ +// +// BridgedJSValueContainerImplementation.swift +// Capacitor +// +// Copyright © 2024 Drifty Co. All rights reserved. +// + +import Foundation + +/// Protocol for accessing JavaScript values with type safety. +/// Provides convenience accessors for extracting and converting JavaScript types. +@objc public protocol BridgedJSValueContainerImplementation: NSObjectProtocol { + /// Extract a string value from the container + /// - Parameters: + /// - key: The key to retrieve + /// - defaultValue: Value to return if key is missing or not a string + /// - Returns: The string value or defaultValue + @objc func getString(_ key: String, defaultValue: String?) -> String? + + /// Extract a date value from the container, with ISO8601 string parsing + /// - Parameters: + /// - key: The key to retrieve + /// - defaultValue: Value to return if key is missing or not a date + /// - Returns: The date value or defaultValue + @objc func getDate(_ key: String, defaultValue: Date?) -> Date? + + /// Extract a dictionary (object) value from the container + /// - Parameters: + /// - key: The key to retrieve + /// - defaultValue: Value to return if key is missing or not a dictionary + /// - Returns: The dictionary value or defaultValue + @objc func getObject(_ key: String, defaultValue: [String: Any]?) -> [String: Any]? + + /// Extract an array value from the container + /// - Parameters: + /// - key: The key to retrieve + /// - defaultValue: Value to return if key is missing or not an array + /// - Returns: The array value or defaultValue + @objc func getArray(_ key: String, defaultValue: [Any]?) -> [Any]? + + /// Extract a number value from the container + /// - Parameters: + /// - key: The key to retrieve + /// - defaultValue: Value to return if key is missing or not a number + /// - Returns: The number value or defaultValue + @objc func getNumber(_ key: String, defaultValue: NSNumber?) -> NSNumber? + + /// Extract a boolean value from the container + /// - Parameters: + /// - key: The key to retrieve + /// - defaultValue: Value to return if key is missing or not a number + /// - Returns: The boolean value or defaultValue + @objc func getBool(_ key: String, defaultValue: Bool) -> Bool +} diff --git a/ios/Capacitor/Capacitor/CAPApplicationDelegateProxy.swift b/ios/Sources/Capacitor/CAPApplicationDelegateProxy.swift similarity index 98% rename from ios/Capacitor/Capacitor/CAPApplicationDelegateProxy.swift rename to ios/Sources/Capacitor/CAPApplicationDelegateProxy.swift index 37ec2e023d..2a563aed54 100644 --- a/ios/Capacitor/Capacitor/CAPApplicationDelegateProxy.swift +++ b/ios/Sources/Capacitor/CAPApplicationDelegateProxy.swift @@ -1,4 +1,5 @@ import Foundation +import UIKit @objc(CAPApplicationDelegateProxy) public class ApplicationDelegateProxy: NSObject, UIApplicationDelegate { diff --git a/ios/Capacitor/Capacitor/CAPBridgeDelegate.swift b/ios/Sources/Capacitor/CAPBridgeDelegate.swift similarity index 92% rename from ios/Capacitor/Capacitor/CAPBridgeDelegate.swift rename to ios/Sources/Capacitor/CAPBridgeDelegate.swift index 845ac18fd2..c0524148c1 100644 --- a/ios/Capacitor/Capacitor/CAPBridgeDelegate.swift +++ b/ios/Sources/Capacitor/CAPBridgeDelegate.swift @@ -1,4 +1,5 @@ import Foundation +import WebKit public protocol CAPBridgeDelegate: AnyObject { var bridgedWebView: WKWebView? { get } diff --git a/ios/Capacitor/Capacitor/CAPBridgeProtocol.swift b/ios/Sources/Capacitor/CAPBridgeProtocol.swift similarity index 100% rename from ios/Capacitor/Capacitor/CAPBridgeProtocol.swift rename to ios/Sources/Capacitor/CAPBridgeProtocol.swift diff --git a/ios/Capacitor/Capacitor/CAPBridgeViewController.swift b/ios/Sources/Capacitor/CAPBridgeViewController.swift similarity index 98% rename from ios/Capacitor/Capacitor/CAPBridgeViewController.swift rename to ios/Sources/Capacitor/CAPBridgeViewController.swift index 33f17be66c..2c4503d9f4 100644 --- a/ios/Capacitor/Capacitor/CAPBridgeViewController.swift +++ b/ios/Sources/Capacitor/CAPBridgeViewController.swift @@ -27,6 +27,12 @@ import WebKit }() override public final func loadView() { + // Set up status bar tap handling + UIStatusBarManager.ensureSwizzling() + + // Set up keyboard interaction handling + WKWebView.ensureKeyboardSwizzling() + // load the configuration and set the logging flag let configDescriptor = instanceDescriptor() let configuration = InstanceConfiguration(with: configDescriptor, isDebug: CapacitorBridge.isDevEnvironment) diff --git a/ios/Capacitor/Capacitor/CAPBridgedPlugin+getMethod.swift b/ios/Sources/Capacitor/CAPBridgedPlugin+getMethod.swift similarity index 100% rename from ios/Capacitor/Capacitor/CAPBridgedPlugin+getMethod.swift rename to ios/Sources/Capacitor/CAPBridgedPlugin+getMethod.swift diff --git a/ios/Sources/Capacitor/CAPBridgedPlugin.swift b/ios/Sources/Capacitor/CAPBridgedPlugin.swift new file mode 100644 index 0000000000..b8c59d2f44 --- /dev/null +++ b/ios/Sources/Capacitor/CAPBridgedPlugin.swift @@ -0,0 +1,21 @@ +// +// CAPBridgedPlugin.swift +// Capacitor +// +// Copyright © 2024 Drifty Co. All rights reserved. +// + +import Foundation + +/// Protocol for plugins that are bridged to JavaScript. +/// Plugins conforming to this protocol expose their structure and methods for registration with Capacitor. +@objc public protocol CAPBridgedPlugin: NSObjectProtocol { + /// Unique identifier for the plugin within the bridge (typically the package name or plugin id) + @objc var identifier: String { get } + + /// Name exposed to JavaScript (the plugin's JavaScript class name) + @objc var jsName: String { get } + + /// Array of plugin methods available to JavaScript + @objc var pluginMethods: [CAPPluginMethod] { get } +} diff --git a/ios/Capacitor/Capacitor/CAPInstanceConfiguration.swift b/ios/Sources/Capacitor/CAPInstanceConfiguration.swift similarity index 87% rename from ios/Capacitor/Capacitor/CAPInstanceConfiguration.swift rename to ios/Sources/Capacitor/CAPInstanceConfiguration.swift index 7b1aff6316..82a117b440 100644 --- a/ios/Capacitor/Capacitor/CAPInstanceConfiguration.swift +++ b/ios/Sources/Capacitor/CAPInstanceConfiguration.swift @@ -1,5 +1,14 @@ +// +// CAPInstanceConfiguration.swift +// Capacitor +// +// Copyright © 2024 Drifty Co. All rights reserved. +// + import Foundation +// MARK: - Computed Properties + extension InstanceConfiguration { @objc public var appStartFileURL: URL { if let path = appStartPath { @@ -19,17 +28,24 @@ extension InstanceConfiguration { guard let errorPath = errorPath else { return nil } - return localURL.appendingPathComponent(errorPath) } +} + +// MARK: - Plugin Configuration +extension InstanceConfiguration { @objc public func getPluginConfig(_ pluginId: String) -> PluginConfig { if let cfg = (pluginConfigurations as? JSObject)?[keyPath: KeyPath("\(pluginId)")] as? JSObject { return PluginConfig(config: cfg) } return PluginConfig(config: JSObject()) } +} + +// MARK: - Navigation +extension InstanceConfiguration { @objc public func shouldAllowNavigation(to host: String) -> Bool { for hostname in allowedNavigationHostnames { if doesHost(host, match: hostname) { @@ -39,25 +55,19 @@ extension InstanceConfiguration { return false } - // MARK: - Private - private func doesHost(_ host: String, match pattern: String) -> Bool { - // bail early in the simple case if pattern == "*" { return true } - // break apart the pieces var hostComponents = host.lowercased().split(separator: ".") var patternComponents = pattern.lowercased().split(separator: ".") guard hostComponents.count == patternComponents.count else { return false } - // remove any wildcard segments for wildcard in patternComponents.enumerated().reversed().filter({ $0.element == "*" }) { hostComponents.remove(at: wildcard.offset) patternComponents.remove(at: wildcard.offset) } - // match with what's left return hostComponents == patternComponents } } diff --git a/ios/Capacitor/Capacitor/CAPInstanceDescriptor.swift b/ios/Sources/Capacitor/CAPInstanceDescriptor.swift similarity index 88% rename from ios/Capacitor/Capacitor/CAPInstanceDescriptor.swift rename to ios/Sources/Capacitor/CAPInstanceDescriptor.swift index 495de0634d..3bee942ea4 100644 --- a/ios/Capacitor/Capacitor/CAPInstanceDescriptor.swift +++ b/ios/Sources/Capacitor/CAPInstanceDescriptor.swift @@ -1,4 +1,35 @@ +// +// CAPInstanceDescriptor.swift +// Capacitor +// +// Copyright © 2024 Drifty Co. All rights reserved. +// + import Foundation +import UIKit +import WebKit + +@objc public enum InstanceType: Int { + case fixed = 0 + case variable = 1 +} + +public struct InstanceWarning: OptionSet, Sendable { + public let rawValue: UInt + public init(rawValue: UInt) { self.rawValue = rawValue } + + public static let missingAppDir = InstanceWarning(rawValue: 1 << 0) + public static let missingFile = InstanceWarning(rawValue: 1 << 1) + public static let invalidFile = InstanceWarning(rawValue: 1 << 2) + public static let missingCordovaFile = InstanceWarning(rawValue: 1 << 3) + public static let invalidCordovaFile = InstanceWarning(rawValue: 1 << 4) +} + +@objc public enum InstanceLoggingBehavior: UInt { + case none = 1 + case debug = 2 + case production = 4 +} public enum InstanceDescriptorDefaults { public static let scheme = "capacitor" @@ -149,18 +180,14 @@ extension InstanceDescriptor { @objc public func normalize() { // first, make sure the scheme is valid var schemeValid = false - if let scheme = urlScheme, WKWebView.handlesURLScheme(scheme) == false, - scheme.range(of: "^[a-z][a-z0-9.+-]*$", options: [.regularExpression, .caseInsensitive], range: nil, locale: nil) != nil { + if WKWebView.handlesURLScheme(urlScheme) == false, + urlScheme.range(of: "^[a-z][a-z0-9.+-]*$", options: [.regularExpression, .caseInsensitive], range: nil, locale: nil) != nil { schemeValid = true } if !schemeValid { // reset to the default urlScheme = InstanceDescriptorDefaults.scheme } - // make sure we have a hostname - if urlHostname == nil { - urlHostname = InstanceDescriptorDefaults.hostname - } // now validate the server.url var urlValid = false if let server = serverURL, URL(string: server) != nil { diff --git a/ios/Capacitor/Capacitor/CAPInstancePlugin.swift b/ios/Sources/Capacitor/CAPInstancePlugin.swift similarity index 93% rename from ios/Capacitor/Capacitor/CAPInstancePlugin.swift rename to ios/Sources/Capacitor/CAPInstancePlugin.swift index 0a73e434f1..5cc76f74f3 100644 --- a/ios/Capacitor/Capacitor/CAPInstancePlugin.swift +++ b/ios/Sources/Capacitor/CAPInstancePlugin.swift @@ -6,5 +6,7 @@ // Copyright © 2022 Drifty Co. All rights reserved. // +import Foundation + /// A CAPPlugin subclass meant to be explicitly initialized by the caller and not the bridge. @objc open class CAPInstancePlugin: CAPPlugin {} diff --git a/ios/Capacitor/Capacitor/CAPLog.swift b/ios/Sources/Capacitor/CAPLog.swift similarity index 100% rename from ios/Capacitor/Capacitor/CAPLog.swift rename to ios/Sources/Capacitor/CAPLog.swift diff --git a/ios/Capacitor/Capacitor/CAPNotifications.swift b/ios/Sources/Capacitor/CAPNotifications.swift similarity index 99% rename from ios/Capacitor/Capacitor/CAPNotifications.swift rename to ios/Sources/Capacitor/CAPNotifications.swift index 19272e63b9..4a9c8f38f1 100644 --- a/ios/Capacitor/Capacitor/CAPNotifications.swift +++ b/ios/Sources/Capacitor/CAPNotifications.swift @@ -1,3 +1,5 @@ +import UserNotifications + /** Notificaton types for NotificationCenter and NSNotificationCenter diff --git a/ios/Capacitor/Capacitor/CAPPlugin+LoadInstance.swift b/ios/Sources/Capacitor/CAPPlugin+LoadInstance.swift similarity index 100% rename from ios/Capacitor/Capacitor/CAPPlugin+LoadInstance.swift rename to ios/Sources/Capacitor/CAPPlugin+LoadInstance.swift diff --git a/ios/Sources/Capacitor/CAPPlugin.swift b/ios/Sources/Capacitor/CAPPlugin.swift new file mode 100644 index 0000000000..6d5d12752d --- /dev/null +++ b/ios/Sources/Capacitor/CAPPlugin.swift @@ -0,0 +1,208 @@ +import Foundation +import WebKit +import UIKit + +@objc open class CAPPlugin: NSObject { + @objc public weak var webView: WKWebView? + @objc public weak var bridge: CAPBridgeProtocol? + @objc public var pluginId: String = "" + @objc public var pluginName: String = "" + @objc public var eventListeners: NSMutableDictionary = [:] + @objc public var retainedEventArguments: NSMutableDictionary = [:] + @objc public var shouldStringifyDatesInCalls = true + + @objc public init(bridge: CAPBridgeProtocol, pluginId: String, pluginName: String) { + super.init() + self.bridge = bridge + self.webView = bridge.webView + self.pluginId = pluginId + self.pluginName = pluginName + self.eventListeners = NSMutableDictionary() + self.retainedEventArguments = NSMutableDictionary() + self.shouldStringifyDatesInCalls = true + } + + @objc override public required init() { + super.init() + self.bridge = nil + self.webView = nil + self.pluginId = "" + self.pluginName = "" + self.eventListeners = NSMutableDictionary() + self.retainedEventArguments = NSMutableDictionary() + self.shouldStringifyDatesInCalls = true + } + + @objc public func getId() -> String { + return pluginName + } + + @objc public func getBool(_ call: CAPPluginCall, field: String, defaultValue: Bool) -> Bool { + let value = call.getNumber(field, defaultValue: NSNumber(value: defaultValue)) + return value?.boolValue ?? defaultValue + } + + @objc public func getString(_ call: CAPPluginCall, field: String, defaultValue: String) -> String { + return call.getString(field, defaultValue: defaultValue) ?? defaultValue + } + + @objc public func getConfig() -> PluginConfig { + guard let bridge = bridge else { return PluginConfig(config: [:]) } + return bridge.config.getPluginConfig(pluginName) + } + + @objc open func load() { + } + + @objc public func addEventListener(_ eventName: String, listener: CAPPluginCall) { + var listenersForEvent = eventListeners.object(forKey: eventName) as? NSMutableArray + + if listenersForEvent == nil || listenersForEvent?.count == 0 { + listenersForEvent = NSMutableArray(object: listener) + eventListeners.setValue(listenersForEvent, forKey: eventName) + sendRetainedArguments(forEvent: eventName) + } else { + listenersForEvent?.add(listener) + } + } + + @objc public func removeEventListener(_ eventName: String, listener: CAPPluginCall) { + guard let listenersForEvent = eventListeners.object(forKey: eventName) as? NSMutableArray else { + return + } + + let listenerIndex = listenersForEvent.index(of: listener) + guard listenerIndex != NSNotFound else { + return + } + + listenersForEvent.removeObject(at: listenerIndex) + } + + @objc public func notifyListeners(_ eventName: String, data: [String: Any]?) { + notifyListeners(eventName, data: data, retainUntilConsumed: false) + } + + @objc public func notifyListeners(_ eventName: String, data: [String: Any]?, retainUntilConsumed: Bool) { + guard let listenersForEvent = eventListeners.object(forKey: eventName) as? [CAPPluginCall] else { + if retainUntilConsumed { + if retainedEventArguments.object(forKey: eventName) == nil { + retainedEventArguments.setValue(NSMutableArray(), forKey: eventName) + } + (retainedEventArguments.object(forKey: eventName) as? NSMutableArray)?.add(data ?? [:]) + } + return + } + + for call in listenersForEvent { + let result = CAPPluginCallResult(data ?? [:]) + call.successHandler(result, call) + } + } + + @objc public func addListener(_ call: CAPPluginCall) { + guard let eventName = call.options["eventName"] as? String else { + return + } + call.keepAlive = true + addEventListener(eventName, listener: call) + } + + @objc public func removeListener(_ call: CAPPluginCall) { + guard let eventName = call.options["eventName"] as? String, + let callbackId = call.options["callbackId"] as? String else { + return + } + + guard let storedCall = bridge?.savedCall(withID: callbackId) else { + return + } + + removeEventListener(eventName, listener: storedCall) + bridge?.releaseCall(withID: callbackId) + } + + @objc public func removeAllListeners(_ call: CAPPluginCall) { + eventListeners.removeAllObjects() + call.resolve() + } + + @objc public func getListeners(_ eventName: String) -> [CAPPluginCall]? { + return eventListeners.object(forKey: eventName) as? [CAPPluginCall] + } + + @objc public func hasListeners(_ eventName: String) -> Bool { + guard let listeners = eventListeners.object(forKey: eventName) as? NSArray else { + return false + } + return listeners.count > 0 + } + + @objc public func checkPermissions(_ call: CAPPluginCall) { + call.resolve() + } + + @objc public func requestPermissions(_ call: CAPPluginCall) { + call.resolve() + } + + @objc public func setCenteredPopover(_ vc: UIViewController) { + guard let viewController = bridge?.viewController else { + return + } + + let popover = vc.popoverPresentationController + popover?.sourceRect = CGRect( + x: viewController.view.center.x, + y: viewController.view.center.y, + width: 0, + height: 0 + ) + popover?.sourceView = viewController.view + popover?.permittedArrowDirections = [] + } + + @objc public func setCenteredPopover(_ vc: UIViewController, size: CGSize) { + guard let viewController = bridge?.viewController else { + return + } + + vc.preferredContentSize = size + let popover = vc.popoverPresentationController + popover?.sourceRect = CGRect( + x: viewController.view.center.x, + y: viewController.view.center.y, + width: 0, + height: 0 + ) + popover?.sourceView = viewController.view + popover?.permittedArrowDirections = [] + } + + @objc public func supportsPopover() -> Bool { + return true + } + + @objc public func shouldOverrideLoad(_ navigationAction: WKNavigationAction) -> NSNumber? { + return nil + } + + @objc public func handleWKWebViewURLAuthenticationChallenge( + _ challenge: URLAuthenticationChallenge, + completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void + ) -> Bool { + return false + } + + private func sendRetainedArguments(forEvent eventName: String) { + guard let retained = retainedEventArguments.object(forKey: eventName) as? NSMutableArray else { + return + } + + retainedEventArguments.removeObject(forKey: eventName) + + for data in retained { + notifyListeners(eventName, data: data as? [String: Any]) + } + } +} diff --git a/ios/Sources/Capacitor/CAPPluginCall.swift b/ios/Sources/Capacitor/CAPPluginCall.swift new file mode 100644 index 0000000000..fa7fe53b8d --- /dev/null +++ b/ios/Sources/Capacitor/CAPPluginCall.swift @@ -0,0 +1,186 @@ +import Foundation + +public typealias CAPPluginCallSuccessHandler = (CAPPluginCallResult, CAPPluginCall) -> Void +public typealias CAPPluginCallErrorHandler = (CAPPluginCallError) -> Void + +@objc open class CAPPluginCall: NSObject { + // MARK: - Properties + + @objc public var callbackId: String + @objc public var methodName: String + @objc public var options: [String: Any] + @objc public var successHandler: CAPPluginCallSuccessHandler + @objc public var errorHandler: CAPPluginCallErrorHandler + @objc public var keepAlive: Bool = false + + // MARK: - Initialization + + @objc public init( + callbackId: String, + methodName: String, + options: [String: Any], + success: @escaping CAPPluginCallSuccessHandler, + error: @escaping CAPPluginCallErrorHandler + ) { + self.callbackId = callbackId + self.methodName = methodName + self.options = options + self.successHandler = success + self.errorHandler = error + super.init() + } + + @objc public convenience init( + callbackId: String, + options: [String: Any], + success: @escaping CAPPluginCallSuccessHandler, + error: @escaping CAPPluginCallErrorHandler + ) { + self.init( + callbackId: callbackId, + methodName: "", + options: options, + success: success, + error: error + ) + } + + // MARK: - Accessors + + public func getString(_ key: String) -> String? { + options[key] as? String + } + + @objc public func getString(_ key: String, defaultValue: String? = nil) -> String? { + getString(key) ?? defaultValue + } + + @objc public func getNumber(_ key: String, defaultValue: NSNumber? = nil) -> NSNumber? { + if let number = options[key] as? NSNumber { + return number + } + if let int = options[key] as? Int { + return NSNumber(value: int) + } + if let double = options[key] as? Double { + return NSNumber(value: double) + } + return defaultValue + } + + @objc public func getBool(_ key: String, defaultValue: Bool) -> Bool { + guard let number = getNumber(key) else { return defaultValue } + return number.boolValue + } + + @objc public func getObject(_ key: String) -> [String: Any]? { + options[key] as? [String: Any] + } + + @objc public func getArray(_ key: String) -> [Any]? { + options[key] as? [Any] + } + + public func getDate(_ key: String) -> Date? { + guard let value = options[key] else { + return nil + } + + if let date = value as? Date { + return date + } + + if let dateString = value as? String { + return Self.jsDateFormatter.date(from: dateString) + } + + return nil + } + + @objc public func getDate(_ key: String, defaultValue: Date? = nil) -> Date? { + getDate(key) ?? defaultValue + } + + // MARK: - Deprecated + + @objc public var isSaved: Bool { + get { keepAlive } + set { keepAlive = newValue } + } + + @objc public func save() { + keepAlive = true + } +} + +// MARK: - JSValue Representation + +extension CAPPluginCall: JSValueContainer { + public var jsObjectRepresentation: JSObject { + options as? JSObject ?? [:] + } +} + +@objc extension CAPPluginCall: BridgedJSValueContainer { + public var dictionaryRepresentation: NSDictionary { + options as NSDictionary + } + + public static var jsDateFormatter: ISO8601DateFormatter { + ISO8601DateFormatter() + } +} + +// MARK: - Result Handling + +@objc public extension CAPPluginCall { + func resolve() { + successHandler(CAPPluginCallResult(nil), self) + } + + func resolve(_ data: PluginCallResultData = [:]) { + successHandler(CAPPluginCallResult(data), self) + } + + func reject(_ message: String, _ code: String? = nil, _ error: Error? = nil, _ data: PluginCallResultData? = nil) { + errorHandler(CAPPluginCallError(message: message, code: code, error: error, data: data)) + } + + func unimplemented() { + unimplemented("not implemented") + } + + func unimplemented(_ message: String) { + errorHandler(CAPPluginCallError(message: message, code: "UNIMPLEMENTED", error: nil, data: [:])) + } + + func unavailable() { + unavailable("not available") + } + + func unavailable(_ message: String) { + errorHandler(CAPPluginCallError(message: message, code: "UNAVAILABLE", error: nil, data: [:])) + } +} + +// MARK: - Codable Support + +public extension CAPPluginCall { + func resolve( + with data: T, + encoder: JSValueEncoder = JSValueEncoder(), + messageForRejectionFromError: (Error) -> String = { _ in "Failed encoding response" } + ) { + do { + let encoded = try encoder.encodeJSObject(data) + resolve(encoded) + } catch { + let message = messageForRejectionFromError(error) + reject(message, nil, error) + } + } + + func decode(_ type: T.Type, decoder: JSValueDecoder = JSValueDecoder()) throws -> T { + try decoder.decode(type, from: options as? JSObject ?? [:]) + } +} diff --git a/ios/Sources/Capacitor/CAPPluginMethod.swift b/ios/Sources/Capacitor/CAPPluginMethod.swift new file mode 100644 index 0000000000..2cf78243f5 --- /dev/null +++ b/ios/Sources/Capacitor/CAPPluginMethod.swift @@ -0,0 +1,66 @@ +// +// CAPPluginMethod.swift +// Capacitor +// +// Created by Steven Sherry on 4/18/24. +// Copyright © 2024 Drifty Co. All rights reserved. +// + +import Foundation + +public typealias CAPPluginReturnType = String + +public let CAPPluginReturnNone: CAPPluginReturnType = "none" +public let CAPPluginReturnCallback: CAPPluginReturnType = "callback" +public let CAPPluginReturnPromise: CAPPluginReturnType = "promise" + +@objc public enum CAPPluginMethodArgumentNullability: Int { + case notNullable = 0 + case nullable = 1 +} + +@objc open class CAPPluginMethodArgument: NSObject { + @objc public var name: String + @objc public var nullability: CAPPluginMethodArgumentNullability + @objc public var type: String + + @objc public init(name: String, nullability: CAPPluginMethodArgumentNullability, type: String) { + self.name = name + self.nullability = nullability + self.type = type + super.init() + } +} + +@objc open class CAPPluginMethod: NSObject { + @objc public var selector: Selector + @objc public var name: String + @objc public var returnType: CAPPluginReturnType + + @objc public init(name: String, returnType: CAPPluginReturnType) { + self.name = name + self.selector = Selector(name + ":") + self.returnType = returnType + super.init() + } + + @objc public init(selector: Selector, returnType: CAPPluginReturnType) { + let selectorString = NSStringFromSelector(selector) + self.name = String(selectorString.dropLast()) + self.selector = selector + self.returnType = returnType + super.init() + } +} + +// MARK: - Convenience Helpers + +extension CAPPluginMethod { + public enum ReturnType: String { + case promise, callback, none + } + + public convenience init(_ selector: Selector, returnType: ReturnType = .promise) { + self.init(selector: selector, returnType: returnType.rawValue) + } +} diff --git a/ios/Sources/Capacitor/CAPSceneDelegateProxy.swift b/ios/Sources/Capacitor/CAPSceneDelegateProxy.swift new file mode 100644 index 0000000000..f03fb5c887 --- /dev/null +++ b/ios/Sources/Capacitor/CAPSceneDelegateProxy.swift @@ -0,0 +1,205 @@ +// +// CAPSceneDelegateProxy.swift +// Capacitor +// +// Created by Joseph Orlando Pender on 6/10/26. +// Copyright © 2026 Drifty Co. All rights reserved. +// + +import Foundation +import UIKit + +@objc(CAPSceneDelegateProxy) +public class SceneDelegateProxy: NSObject, UISceneDelegate { + public static let shared = SceneDelegateProxy() + + public private(set) var lastURL: URL? + + public func scene( + _ scene: UIScene, willConnectTo session: UISceneSession, + options connectionOptions: UIScene.ConnectionOptions + ) { + NotificationCenter.default.post(name: .capacitorSceneWillConnect, object: scene) + + // Plugins haven't loaded yet on a cold start, so notifications posted here are + // missed. Deliver them on the first capacitorViewDidAppear, once plugins are + // registered. + var token: NSObjectProtocol? + token = NotificationCenter.default.addObserver(forName: .capacitorViewDidAppear, object: nil, queue: .main) { _ in + if let token { + NotificationCenter.default.removeObserver(token) + } + if !connectionOptions.urlContexts.isEmpty { + self.scene(scene, openURLContexts: connectionOptions.urlContexts) + } + for userActivity in connectionOptions.userActivities { + self.scene(scene, continue: userActivity) + } + } + } + + public func scene(_ scene: UIScene, openURLContexts URLContexts: Set) { + for context in URLContexts { + lastURL = context.url + ApplicationDelegateProxy.shared.lastURL = context.url + let options = Self.openURLOptions(from: context.options) + + // Capacitor 8 backwards compat + NotificationCenter.default.post( + name: .capacitorOpenURL, + object: [ + "url": context.url, + "options": options + ]) + + NotificationCenter.default.post( + name: .capacitorSceneOpenURL, object: scene, + userInfo: [ + "url": context.url, + "options": options + ]) + } + } + + public func scene(_ scene: UIScene, continue userActivity: NSUserActivity) { + guard userActivity.activityType == NSUserActivityTypeBrowsingWeb, + let url = userActivity.webpageURL + else { + return + } + lastURL = url + ApplicationDelegateProxy.shared.lastURL = url + + // Capacitor 8 backwards compat + NotificationCenter.default.post( + name: .capacitorOpenUniversalLink, + object: [ + "url": url + ]) + + NotificationCenter.default.post( + name: .capacitorSceneOpenUniversalLink, object: scene, + userInfo: [ + "url": url + ]) + } + + /// Routes a URL into Capacitor's open-URL handlers from a SwiftUI App-struct app. + /// + /// This is the recommended integration point for apps whose root is a `SwiftUI.App` + /// and which therefore do not declare an explicit `UISceneDelegate` subclass. + /// Call it from the `.onOpenURL` modifier inside the scene body: + /// + /// ```swift + /// WindowGroup { + /// CapacitorView() + /// .onOpenURL { url in + /// SceneDelegateProxy.shared.handle(openURL: url) + /// } + /// } + /// ``` + /// + /// Posts the same notifications as the `scene(_:openURLContexts:)` protocol path — + /// both `.capacitorOpenURL` (Capacitor 8 back-compat payload) and + /// `.capacitorSceneOpenURL` (scene-aware, with the resolved scene as the notification + /// object and the URL in `userInfo`). + /// + /// - Parameters: + /// - openURL: The URL to route. + /// - scene: The scene that received the URL. SwiftUI's `.onOpenURL` does not + /// surface a scene reference, so this defaults to `nil`; when `nil`, the active + /// foreground `UIWindowScene` is resolved from + /// `UIApplication.shared.connectedScenes`. For single-scene apps (the Phase 1 + /// default) this is unambiguous; multi-scene URL routing is Phase 2. + public func handle(openURL: URL, scene: UIScene? = nil) { + let targetScene = scene ?? Self.activeForegroundScene() + lastURL = openURL + let options: [UIApplication.OpenURLOptionsKey: Any] = [:] + + // Capacitor 8 backwards compat + NotificationCenter.default.post( + name: .capacitorOpenURL, + object: [ + "url": openURL, + "options": options + ]) + + NotificationCenter.default.post( + name: .capacitorSceneOpenURL, object: targetScene, + userInfo: [ + "url": openURL, + "options": options + ]) + } + + /// Routes a browsing-web `NSUserActivity` into Capacitor's universal-link handlers + /// from a SwiftUI App-struct app. + /// + /// This is the recommended integration point for SwiftUI App-struct apps. Call it + /// from the `.onContinueUserActivity` modifier inside the scene body: + /// + /// ```swift + /// WindowGroup { + /// CapacitorView() + /// .onContinueUserActivity(NSUserActivityTypeBrowsingWeb) { activity in + /// SceneDelegateProxy.shared.handle(userActivity: activity) + /// } + /// } + /// ``` + /// + /// Only activities with `activityType == NSUserActivityTypeBrowsingWeb` and a + /// non-nil `webpageURL` produce notifications; other activity types are silently + /// ignored, matching the `scene(_:continue:)` protocol path. When a notification is + /// produced, both `.capacitorOpenUniversalLink` (Capacitor 8 back-compat payload) + /// and `.capacitorSceneOpenUniversalLink` (scene-aware) are posted. + /// + /// - Parameters: + /// - userActivity: The activity to inspect. + /// - scene: The scene that received the activity. SwiftUI does not surface a + /// scene reference here either, so this defaults to `nil`; when `nil`, the + /// active foreground `UIWindowScene` is resolved from + /// `UIApplication.shared.connectedScenes`. + public func handle(userActivity: NSUserActivity, scene: UIScene? = nil) { + guard userActivity.activityType == NSUserActivityTypeBrowsingWeb, + let url = userActivity.webpageURL + else { + return + } + let targetScene = scene ?? Self.activeForegroundScene() + lastURL = url + + // Capacitor 8 backwards compat + NotificationCenter.default.post( + name: .capacitorOpenUniversalLink, + object: [ + "url": url + ]) + + NotificationCenter.default.post( + name: .capacitorSceneOpenUniversalLink, object: targetScene, + userInfo: [ + "url": url + ]) + } + + private static func activeForegroundScene() -> UIWindowScene? { + let scenes = UIApplication.shared.connectedScenes + if let active = scenes.first(where: { $0.activationState == .foregroundActive }) + as? UIWindowScene { + return active + } + return scenes.first(where: { $0.activationState == .foregroundInactive }) as? UIWindowScene + } + + private static func openURLOptions(from sceneOptions: UIScene.OpenURLOptions) -> [UIApplication.OpenURLOptionsKey: Any] { + var options: [UIApplication.OpenURLOptionsKey: Any] = [:] + if let sourceApplication = sceneOptions.sourceApplication { + options[.sourceApplication] = sourceApplication + } + if let annotation = sceneOptions.annotation { + options[.annotation] = annotation + } + options[.openInPlace] = sceneOptions.openInPlace + return options + } +} diff --git a/ios/Capacitor/Capacitor/CapacitorBridge.swift b/ios/Sources/Capacitor/CapacitorBridge.swift similarity index 98% rename from ios/Capacitor/Capacitor/CapacitorBridge.swift rename to ios/Sources/Capacitor/CapacitorBridge.swift index 7a29ffb542..2e45a74229 100644 --- a/ios/Capacitor/Capacitor/CapacitorBridge.swift +++ b/ios/Sources/Capacitor/CapacitorBridge.swift @@ -256,7 +256,7 @@ open class CapacitorBridge: NSObject, CAPBridgeProtocol { do { if let pluginJSON = Bundle.main.url(forResource: "capacitor.config", withExtension: "json") { let pluginData = try Data(contentsOf: pluginJSON) - var registrationList = try JSONDecoder().decode(RegistrationList.self, from: pluginData) + let registrationList = try JSONDecoder().decode(RegistrationList.self, from: pluginData) for plugin in registrationList.packageClassList { if let pluginClass = NSClassFromString(plugin), pluginClass is CAPPlugin.Type { @@ -451,11 +451,9 @@ open class CapacitorBridge: NSObject, CAPBridgeProtocol { } }) - if let pluginCall = pluginCall { - plugin.perform(selector, with: pluginCall) - if pluginCall.keepAlive { - self?.saveCall(pluginCall) - } + plugin.perform(selector, with: pluginCall) + if pluginCall.keepAlive { + self?.saveCall(pluginCall) } // let timeElapsed = CFAbsoluteTimeGetCurrent() - startTime diff --git a/ios/Capacitor/Capacitor/CapacitorExtension.swift b/ios/Sources/Capacitor/CapacitorExtension.swift similarity index 100% rename from ios/Capacitor/Capacitor/CapacitorExtension.swift rename to ios/Sources/Capacitor/CapacitorExtension.swift diff --git a/ios/Capacitor/Capacitor/Codable/JSValueDecoder.swift b/ios/Sources/Capacitor/Codable/JSValueDecoder.swift similarity index 100% rename from ios/Capacitor/Capacitor/Codable/JSValueDecoder.swift rename to ios/Sources/Capacitor/Codable/JSValueDecoder.swift diff --git a/ios/Capacitor/Capacitor/Codable/JSValueEncoder.swift b/ios/Sources/Capacitor/Codable/JSValueEncoder.swift similarity index 100% rename from ios/Capacitor/Capacitor/Codable/JSValueEncoder.swift rename to ios/Sources/Capacitor/Codable/JSValueEncoder.swift diff --git a/ios/Capacitor/Capacitor/Data+Capacitor.swift b/ios/Sources/Capacitor/Data+Capacitor.swift similarity index 97% rename from ios/Capacitor/Capacitor/Data+Capacitor.swift rename to ios/Sources/Capacitor/Data+Capacitor.swift index 1105c581ad..d58c073d52 100644 --- a/ios/Capacitor/Capacitor/Data+Capacitor.swift +++ b/ios/Sources/Capacitor/Data+Capacitor.swift @@ -1,3 +1,5 @@ +import Foundation + extension Data: CapacitorExtension {} public extension CapacitorExtensionTypeWrapper where T == Data { diff --git a/ios/Capacitor/Capacitor/DocLinks.swift b/ios/Sources/Capacitor/DocLinks.swift similarity index 100% rename from ios/Capacitor/Capacitor/DocLinks.swift rename to ios/Sources/Capacitor/DocLinks.swift diff --git a/ios/Sources/Capacitor/InstanceConfiguration.swift b/ios/Sources/Capacitor/InstanceConfiguration.swift new file mode 100644 index 0000000000..e54de9e864 --- /dev/null +++ b/ios/Sources/Capacitor/InstanceConfiguration.swift @@ -0,0 +1,115 @@ +// +// InstanceConfiguration.swift +// Capacitor +// +// Copyright © 2024 Drifty Co. All rights reserved. +// + +import Foundation +import UIKit + +@objc(CAPInstanceConfiguration) +open class InstanceConfiguration: NSObject { + // MARK: - Properties + + @objc public let appendedUserAgentString: String? + @objc public let overridenUserAgentString: String? + @objc public let backgroundColor: UIColor? + @objc public let allowedNavigationHostnames: [String] + @objc public let localURL: URL + @objc public let serverURL: URL + @objc public let errorPath: String? + @objc public let pluginConfigurations: [String: Any] + @objc public let loggingEnabled: Bool + @objc public let scrollingEnabled: Bool + @objc public let zoomingEnabled: Bool + @objc public let allowLinkPreviews: Bool + @objc public let handleApplicationNotifications: Bool + @objc public let isWebDebuggable: Bool + @objc public let hasInitialFocus: Bool + @objc public let cordovaDeployDisabled: Bool + @objc public let contentInsetAdjustmentBehavior: UIScrollView.ContentInsetAdjustmentBehavior + @objc public let appLocation: URL + @objc public let appStartPath: String? + @objc public let limitsNavigationsToAppBoundDomains: Bool + @objc public let preferredContentMode: String? + @objc public let legacyConfig: [String: Any] + + // MARK: - Initialization + + @objc public init(with descriptor: InstanceDescriptor, isDebug: Bool) { + descriptor.normalize() + + self.appendedUserAgentString = descriptor.appendedUserAgentString + self.overridenUserAgentString = descriptor.overridenUserAgentString + self.backgroundColor = descriptor.backgroundColor + self.allowedNavigationHostnames = descriptor.allowedNavigationHostnames + self.scrollingEnabled = descriptor.scrollingEnabled + self.zoomingEnabled = descriptor.zoomingEnabled + self.allowLinkPreviews = descriptor.allowLinkPreviews + self.handleApplicationNotifications = descriptor.handleApplicationNotifications + self.contentInsetAdjustmentBehavior = descriptor.contentInsetAdjustmentBehavior + self.appLocation = descriptor.appLocation + self.appStartPath = descriptor.appStartPath + self.limitsNavigationsToAppBoundDomains = descriptor.limitsNavigationsToAppBoundDomains + self.preferredContentMode = descriptor.preferredContentMode + self.pluginConfigurations = descriptor.pluginConfigurations + self.isWebDebuggable = descriptor.isWebDebuggable + self.hasInitialFocus = descriptor.hasInitialFocus + self.legacyConfig = descriptor.legacyConfig + self.errorPath = descriptor.errorPath + self.cordovaDeployDisabled = descriptor.cordovaDeployDisabled + + switch descriptor.loggingBehavior { + case .production: + self.loggingEnabled = true + case .debug: + self.loggingEnabled = isDebug + case .none: + self.loggingEnabled = false + @unknown default: + self.loggingEnabled = false + } + + self.localURL = URL(string: "\(descriptor.urlScheme)://\(descriptor.urlHostname)")! + + if let serverURLString = descriptor.serverURL { + self.serverURL = URL(string: serverURLString) ?? self.localURL + } else { + self.serverURL = self.localURL + } + + super.init() + } + + @objc public init(with configuration: InstanceConfiguration, andLocation location: URL) { + self.appendedUserAgentString = configuration.appendedUserAgentString + self.overridenUserAgentString = configuration.overridenUserAgentString + self.backgroundColor = configuration.backgroundColor + self.allowedNavigationHostnames = configuration.allowedNavigationHostnames + self.localURL = configuration.localURL + self.serverURL = configuration.serverURL + self.errorPath = configuration.errorPath + self.pluginConfigurations = configuration.pluginConfigurations + self.loggingEnabled = configuration.loggingEnabled + self.scrollingEnabled = configuration.scrollingEnabled + self.zoomingEnabled = configuration.zoomingEnabled + self.allowLinkPreviews = configuration.allowLinkPreviews + self.handleApplicationNotifications = configuration.handleApplicationNotifications + self.isWebDebuggable = configuration.isWebDebuggable + self.hasInitialFocus = configuration.hasInitialFocus + self.cordovaDeployDisabled = configuration.cordovaDeployDisabled + self.contentInsetAdjustmentBehavior = configuration.contentInsetAdjustmentBehavior + self.legacyConfig = configuration.legacyConfig + self.appStartPath = configuration.appStartPath + self.appLocation = location + self.limitsNavigationsToAppBoundDomains = configuration.limitsNavigationsToAppBoundDomains + self.preferredContentMode = configuration.preferredContentMode + + super.init() + } + + @objc public func updatingAppLocation(_ location: URL) -> InstanceConfiguration { + InstanceConfiguration(with: self, andLocation: location) + } +} diff --git a/ios/Sources/Capacitor/InstanceDescriptor.swift b/ios/Sources/Capacitor/InstanceDescriptor.swift new file mode 100644 index 0000000000..225d31b228 --- /dev/null +++ b/ios/Sources/Capacitor/InstanceDescriptor.swift @@ -0,0 +1,95 @@ +// +// InstanceDescriptor.swift +// Capacitor +// +// Copyright © 2024 Drifty Co. All rights reserved. +// + +import Foundation +import UIKit +import WebKit + +@objc(CAPInstanceDescriptor) +open class InstanceDescriptor: NSObject { + // MARK: - Properties + + @objc public var appendedUserAgentString: String? + @objc public var overridenUserAgentString: String? + @objc public var backgroundColor: UIColor? + @objc public var allowedNavigationHostnames: [String] = [] + @objc public var urlScheme: String = InstanceDescriptorDefaults.scheme + @objc public var urlHostname: String = InstanceDescriptorDefaults.hostname + @objc public var serverURL: String? + @objc public var errorPath: String? + @objc public var pluginConfigurations: [String: Any] = [:] + @objc public var loggingBehavior: InstanceLoggingBehavior = .debug + @objc public var scrollingEnabled: Bool = true + @objc public var zoomingEnabled: Bool = false + @objc public var allowLinkPreviews: Bool = true + @objc public var handleApplicationNotifications: Bool = true + @objc public var isWebDebuggable: Bool = false + @objc public var hasInitialFocus: Bool = true + @objc public var contentInsetAdjustmentBehavior: UIScrollView.ContentInsetAdjustmentBehavior = .never + @objc public var appLocation: URL + @objc public var appStartPath: String? + @objc public var limitsNavigationsToAppBoundDomains: Bool = false + @objc public var preferredContentMode: String? + @objc public var cordovaConfiguration: NSObject + public var warnings: InstanceWarning = [] + public let instanceType: InstanceType + @objc public var legacyConfig: [String: Any] = [:] + + // MARK: - Initialization + + @objc override public init() { + self.instanceType = .fixed + let publicURL = Bundle.main.url(forResource: "public", withExtension: nil) + self.appLocation = publicURL ?? Bundle.main.resourceURL ?? URL(fileURLWithPath: "/") + self.cordovaConfiguration = NSObject() + + super.init() + + setDefaults(withAppLocation: publicURL) + _parseConfiguration( + at: Bundle.main.url(forResource: "capacitor.config", withExtension: "json"), + cordovaConfiguration: Bundle.main.url(forResource: "config", withExtension: "xml") + ) + } + + @objc public init(at appURL: URL, configuration configURL: URL?, cordovaConfiguration cordovaURL: URL?) { + self.instanceType = .variable + self.appLocation = appURL + self.cordovaConfiguration = NSObject() + + super.init() + + setDefaults(withAppLocation: appURL) + _parseConfiguration(at: configURL, cordovaConfiguration: cordovaURL) + } + + // MARK: - Private + + private func setDefaults(withAppLocation location: URL?) { + allowedNavigationHostnames = [] + urlScheme = InstanceDescriptorDefaults.scheme + urlHostname = InstanceDescriptorDefaults.hostname + pluginConfigurations = [:] + legacyConfig = [:] + loggingBehavior = .debug + scrollingEnabled = true + zoomingEnabled = false + allowLinkPreviews = true + handleApplicationNotifications = true + isWebDebuggable = false + hasInitialFocus = true + contentInsetAdjustmentBehavior = .never + limitsNavigationsToAppBoundDomains = false + + if let location = location { + appLocation = location + } else { + warnings.insert(.missingAppDir) + appLocation = Bundle.main.resourceURL?.appendingPathComponent("public") ?? URL(fileURLWithPath: "/") + } + } +} diff --git a/ios/Capacitor/Capacitor/JS.swift b/ios/Sources/Capacitor/JS.swift similarity index 100% rename from ios/Capacitor/Capacitor/JS.swift rename to ios/Sources/Capacitor/JS.swift diff --git a/ios/Capacitor/Capacitor/JSExport.swift b/ios/Sources/Capacitor/JSExport.swift similarity index 93% rename from ios/Capacitor/Capacitor/JSExport.swift rename to ios/Sources/Capacitor/JSExport.swift index c51da733df..0a4b352b1f 100644 --- a/ios/Capacitor/Capacitor/JSExport.swift +++ b/ios/Sources/Capacitor/JSExport.swift @@ -1,3 +1,5 @@ +import WebKit + internal struct PluginHeaderMethod: Codable { let name: String let rtype: String? @@ -22,8 +24,12 @@ internal class JSExport { } static func exportBridgeJS(userContentController: WKUserContentController) throws { - let capBundle = Bundle(for: Self.self) - guard let jsUrl = capBundle.url(forResource: "native-bridge", withExtension: "js") else { + #if SWIFT_PACKAGE + let jsUrl = Bundle.module.url(forResource: "native-bridge", withExtension: "js", subdirectory: "assets") + #else + let jsUrl = Bundle(for: Self.self).url(forResource: "native-bridge", withExtension: "js") + #endif + guard let jsUrl else { CAPLog.print("ERROR: Required native-bridge.js file in Capacitor not found. Bridge will not function!") throw CapacitorBridgeError.errorExportingCoreJS } @@ -107,7 +113,7 @@ internal class JSExport { } private static func createPluginHeaderMethod(method: CAPPluginMethod) -> PluginHeaderMethod { - var rtype = method.returnType + var rtype: String? = method.returnType if rtype == "none" { rtype = nil } @@ -115,8 +121,8 @@ internal class JSExport { } private static func generateMethod(pluginClassName: String, method: CAPPluginMethod) -> String { - let methodName = method.name! - let returnType = method.returnType! + let methodName = method.name + let returnType = method.returnType var paramList = [String]() // add the catch-all @@ -138,7 +144,7 @@ internal class JSExport { var lines = [String]() // Create the function declaration - lines.append("t['\(method.name!)'] = function(\(paramString)) {") + lines.append("t['\(methodName)'] = function(\(paramString)) {") // Create the call to Capacitor ... if returnType == CAPPluginReturnNone { diff --git a/ios/Capacitor/Capacitor/JSTypes.swift b/ios/Sources/Capacitor/JSTypes.swift similarity index 100% rename from ios/Capacitor/Capacitor/JSTypes.swift rename to ios/Sources/Capacitor/JSTypes.swift diff --git a/ios/Capacitor/Capacitor/KeyPath.swift b/ios/Sources/Capacitor/KeyPath.swift similarity index 100% rename from ios/Capacitor/Capacitor/KeyPath.swift rename to ios/Sources/Capacitor/KeyPath.swift diff --git a/ios/Capacitor/Capacitor/KeyValueStore.swift b/ios/Sources/Capacitor/KeyValueStore.swift similarity index 100% rename from ios/Capacitor/Capacitor/KeyValueStore.swift rename to ios/Sources/Capacitor/KeyValueStore.swift diff --git a/ios/Capacitor/Capacitor/NotificationHandlerProtocol.swift b/ios/Sources/Capacitor/NotificationHandlerProtocol.swift similarity index 90% rename from ios/Capacitor/Capacitor/NotificationHandlerProtocol.swift rename to ios/Sources/Capacitor/NotificationHandlerProtocol.swift index 2b559bd811..3274da0260 100644 --- a/ios/Capacitor/Capacitor/NotificationHandlerProtocol.swift +++ b/ios/Sources/Capacitor/NotificationHandlerProtocol.swift @@ -1,4 +1,5 @@ import Foundation +import UserNotifications @objc(CAPNotificationHandlerProtocol) public protocol NotificationHandlerProtocol { func willPresent(notification: UNNotification) -> UNNotificationPresentationOptions diff --git a/ios/Capacitor/Capacitor/NotificationRouter.swift b/ios/Sources/Capacitor/NotificationRouter.swift similarity index 99% rename from ios/Capacitor/Capacitor/NotificationRouter.swift rename to ios/Sources/Capacitor/NotificationRouter.swift index 99fcbb2550..7a29babee3 100644 --- a/ios/Capacitor/Capacitor/NotificationRouter.swift +++ b/ios/Sources/Capacitor/NotificationRouter.swift @@ -1,4 +1,5 @@ import Foundation +import UserNotifications @objc(CAPNotificationRouter) public class NotificationRouter: NSObject, UNUserNotificationCenterDelegate { var handleApplicationNotifications: Bool { diff --git a/ios/Capacitor/Capacitor/PluginCallResult.swift b/ios/Sources/Capacitor/PluginCallResult.swift similarity index 100% rename from ios/Capacitor/Capacitor/PluginCallResult.swift rename to ios/Sources/Capacitor/PluginCallResult.swift diff --git a/ios/Capacitor/Capacitor/PluginConfig.swift b/ios/Sources/Capacitor/PluginConfig.swift similarity index 100% rename from ios/Capacitor/Capacitor/PluginConfig.swift rename to ios/Sources/Capacitor/PluginConfig.swift diff --git a/ios/Capacitor/Capacitor/Plugins/CapacitorCookieManager.swift b/ios/Sources/Capacitor/Plugins/CapacitorCookieManager.swift similarity index 99% rename from ios/Capacitor/Capacitor/Plugins/CapacitorCookieManager.swift rename to ios/Sources/Capacitor/Plugins/CapacitorCookieManager.swift index 782c245b0b..2f4025d7dc 100644 --- a/ios/Capacitor/Capacitor/Plugins/CapacitorCookieManager.swift +++ b/ios/Sources/Capacitor/Plugins/CapacitorCookieManager.swift @@ -1,4 +1,5 @@ import Foundation +import WebKit public class CapacitorWKCookieObserver: NSObject, WKHTTPCookieStoreObserver { // Sync WKWebView Cookies to HTTPCookieStorage diff --git a/ios/Capacitor/Capacitor/Plugins/CapacitorCookies.swift b/ios/Sources/Capacitor/Plugins/CapacitorCookies.swift similarity index 100% rename from ios/Capacitor/Capacitor/Plugins/CapacitorCookies.swift rename to ios/Sources/Capacitor/Plugins/CapacitorCookies.swift diff --git a/ios/Capacitor/Capacitor/Plugins/CapacitorHttp.swift b/ios/Sources/Capacitor/Plugins/CapacitorHttp.swift similarity index 100% rename from ios/Capacitor/Capacitor/Plugins/CapacitorHttp.swift rename to ios/Sources/Capacitor/Plugins/CapacitorHttp.swift diff --git a/ios/Capacitor/Capacitor/Plugins/CapacitorUrlRequest.swift b/ios/Sources/Capacitor/Plugins/CapacitorUrlRequest.swift similarity index 100% rename from ios/Capacitor/Capacitor/Plugins/CapacitorUrlRequest.swift rename to ios/Sources/Capacitor/Plugins/CapacitorUrlRequest.swift diff --git a/ios/Capacitor/Capacitor/Plugins/Console.swift b/ios/Sources/Capacitor/Plugins/Console.swift similarity index 100% rename from ios/Capacitor/Capacitor/Plugins/Console.swift rename to ios/Sources/Capacitor/Plugins/Console.swift diff --git a/ios/Capacitor/Capacitor/Plugins/HttpRequestHandler.swift b/ios/Sources/Capacitor/Plugins/HttpRequestHandler.swift similarity index 100% rename from ios/Capacitor/Capacitor/Plugins/HttpRequestHandler.swift rename to ios/Sources/Capacitor/Plugins/HttpRequestHandler.swift diff --git a/ios/Capacitor/Capacitor/Plugins/SystemBars.swift b/ios/Sources/Capacitor/Plugins/SystemBars.swift similarity index 94% rename from ios/Capacitor/Capacitor/Plugins/SystemBars.swift rename to ios/Sources/Capacitor/Plugins/SystemBars.swift index 2c7d6753cc..98c5f2f532 100644 --- a/ios/Capacitor/Capacitor/Plugins/SystemBars.swift +++ b/ios/Sources/Capacitor/Plugins/SystemBars.swift @@ -1,4 +1,5 @@ import Foundation +import UIKit @objc(CAPSystemBarsPlugin) public class CAPSystemBarsPlugin: CAPPlugin, CAPBridgedPlugin { @@ -20,13 +21,14 @@ public class CAPSystemBarsPlugin: CAPPlugin, CAPBridgedPlugin { } @objc override public func load() { - let hidden = getConfig().getBoolean("hidden", false) + let config = getConfig() + let hidden = config.getBoolean("hidden", false) - if let style = getConfig().getString("style", "DEFAULT") { + if let style = config.getString("style", "DEFAULT") { setStyle(style: style) } - if let animation = getConfig().getString("animation") { + if let animation = config.getString("animation") { setAnimation(animation: animation) } diff --git a/ios/Capacitor/Capacitor/Plugins/WebView.swift b/ios/Sources/Capacitor/Plugins/WebView.swift similarity index 100% rename from ios/Capacitor/Capacitor/Plugins/WebView.swift rename to ios/Sources/Capacitor/Plugins/WebView.swift diff --git a/ios/Capacitor/Capacitor/PrivacyInfo.xcprivacy b/ios/Sources/Capacitor/PrivacyInfo.xcprivacy similarity index 100% rename from ios/Capacitor/Capacitor/PrivacyInfo.xcprivacy rename to ios/Sources/Capacitor/PrivacyInfo.xcprivacy diff --git a/ios/Capacitor/Capacitor/Router.swift b/ios/Sources/Capacitor/Router.swift similarity index 100% rename from ios/Capacitor/Capacitor/Router.swift rename to ios/Sources/Capacitor/Router.swift diff --git a/ios/Capacitor/Capacitor/UIColor.swift b/ios/Sources/Capacitor/UIColor.swift similarity index 99% rename from ios/Capacitor/Capacitor/UIColor.swift rename to ios/Sources/Capacitor/UIColor.swift index b33bd3d4a6..ebfc6e6f91 100644 --- a/ios/Capacitor/Capacitor/UIColor.swift +++ b/ios/Sources/Capacitor/UIColor.swift @@ -1,3 +1,5 @@ +import UIKit + extension UIColor: CapacitorExtension {} public extension CapacitorExtensionTypeWrapper where T: UIColor { // disable linting for the short variable names, since that's the point of the method diff --git a/ios/Sources/Capacitor/UIStatusBarManager+CAPHandleTapAction.swift b/ios/Sources/Capacitor/UIStatusBarManager+CAPHandleTapAction.swift new file mode 100644 index 0000000000..663bbd9054 --- /dev/null +++ b/ios/Sources/Capacitor/UIStatusBarManager+CAPHandleTapAction.swift @@ -0,0 +1,53 @@ +// +// UIStatusBarManager+CAPHandleTapAction.swift +// Capacitor +// +// Copyright © 2024 Drifty Co. All rights reserved. +// + +import Foundation +import UIKit +import ObjectiveC + +extension UIStatusBarManager { + private static let swizzle: Void = { + let classRef = UIStatusBarManager.self + let originalSelector = Selector(("handleTapAction:")) + let swizzledSelector = #selector(UIStatusBarManager.nofity_handleTapAction(_:)) + + guard let originalMethod = class_getInstanceMethod(classRef, originalSelector), + let swizzledMethod = class_getInstanceMethod(classRef, swizzledSelector) else { + return + } + + let didAddMethod = class_addMethod( + classRef, + originalSelector, + method_getImplementation(swizzledMethod), + method_getTypeEncoding(swizzledMethod) + ) + + if didAddMethod { + class_replaceMethod( + classRef, + swizzledSelector, + method_getImplementation(originalMethod), + method_getTypeEncoding(originalMethod) + ) + } else { + method_exchangeImplementations(originalMethod, swizzledMethod) + } + }() + + static func ensureSwizzling() { + _ = swizzle + } + + @objc func nofity_handleTapAction(_ arg: Any) { + NotificationCenter.default.post( + name: Notification.Name(rawValue: "CapacitorStatusBarTappedNotification"), + object: nil + ) + nofity_handleTapAction(arg) + } +} diff --git a/ios/Capacitor/Capacitor/WKWebView+Capacitor.swift b/ios/Sources/Capacitor/WKWebView+Capacitor.swift similarity index 90% rename from ios/Capacitor/Capacitor/WKWebView+Capacitor.swift rename to ios/Sources/Capacitor/WKWebView+Capacitor.swift index 6bde0d3b36..a9037a6117 100644 --- a/ios/Capacitor/Capacitor/WKWebView+Capacitor.swift +++ b/ios/Sources/Capacitor/WKWebView+Capacitor.swift @@ -17,9 +17,18 @@ public extension CapacitorExtensionTypeWrapper where T == WKWebView { } } -private var associatedKeyboardFlagHandle: UInt8 = 0 +nonisolated(unsafe) private var associatedKeyboardFlagHandle: UInt8 = 0 internal extension WKWebView { + // Automatically initialize keyboard swizzling at class load time + private static let keyboardSwizzleInitializer: Void = { + _swizzleKeyboardMethods() + }() + + static func ensureKeyboardSwizzling() { + _ = keyboardSwizzleInitializer + } + // Our lazy property can't be represented in Obj-C so we need this simple wrapper. // swiftlint:disable identifier_name @objc static func _swizzleKeyboardMethods() { diff --git a/ios/Capacitor/Capacitor/WebViewAssetHandler.swift b/ios/Sources/Capacitor/WebViewAssetHandler.swift similarity index 99% rename from ios/Capacitor/Capacitor/WebViewAssetHandler.swift rename to ios/Sources/Capacitor/WebViewAssetHandler.swift index acc8effb74..d9488ea3c5 100644 --- a/ios/Capacitor/Capacitor/WebViewAssetHandler.swift +++ b/ios/Sources/Capacitor/WebViewAssetHandler.swift @@ -1,4 +1,5 @@ import Foundation +import WebKit import UniformTypeIdentifiers @objc(CAPWebViewAssetHandler) diff --git a/ios/Capacitor/Capacitor/WebViewDelegationHandler.swift b/ios/Sources/Capacitor/WebViewDelegationHandler.swift similarity index 100% rename from ios/Capacitor/Capacitor/WebViewDelegationHandler.swift rename to ios/Sources/Capacitor/WebViewDelegationHandler.swift diff --git a/ios/Capacitor/Capacitor/assets/native-bridge.js b/ios/Sources/Capacitor/assets/native-bridge.js similarity index 100% rename from ios/Capacitor/Capacitor/assets/native-bridge.js rename to ios/Sources/Capacitor/assets/native-bridge.js diff --git a/ios/CapacitorCordova/CapacitorCordova/Classes/Public/Plugin.swift b/ios/Sources/CapacitorCordova/Plugin.swift similarity index 99% rename from ios/CapacitorCordova/CapacitorCordova/Classes/Public/Plugin.swift rename to ios/Sources/CapacitorCordova/Plugin.swift index d58c4ca33f..40e9657e8b 100644 --- a/ios/CapacitorCordova/CapacitorCordova/Classes/Public/Plugin.swift +++ b/ios/Sources/CapacitorCordova/Plugin.swift @@ -1,4 +1,5 @@ import Capacitor +import Cordova @objc(CordovaPlugin) public class CordovaPlugin: CAPPlugin, CAPBridgedPlugin { diff --git a/ios/CapacitorCordova/CapacitorCordova/Classes/Public/AppDelegate.m b/ios/Sources/Cordova/AppDelegate.m similarity index 100% rename from ios/CapacitorCordova/CapacitorCordova/Classes/Public/AppDelegate.m rename to ios/Sources/Cordova/AppDelegate.m diff --git a/ios/CapacitorCordova/CapacitorCordova/Classes/Public/CDVCommandDelegateImpl.m b/ios/Sources/Cordova/CDVCommandDelegateImpl.m similarity index 100% rename from ios/CapacitorCordova/CapacitorCordova/Classes/Public/CDVCommandDelegateImpl.m rename to ios/Sources/Cordova/CDVCommandDelegateImpl.m diff --git a/ios/CapacitorCordova/CapacitorCordova/Classes/Public/CDVConfigParser.m b/ios/Sources/Cordova/CDVConfigParser.m similarity index 100% rename from ios/CapacitorCordova/CapacitorCordova/Classes/Public/CDVConfigParser.m rename to ios/Sources/Cordova/CDVConfigParser.m diff --git a/ios/CapacitorCordova/CapacitorCordova/Classes/Public/CDVInvokedUrlCommand.m b/ios/Sources/Cordova/CDVInvokedUrlCommand.m similarity index 100% rename from ios/CapacitorCordova/CapacitorCordova/Classes/Public/CDVInvokedUrlCommand.m rename to ios/Sources/Cordova/CDVInvokedUrlCommand.m diff --git a/ios/CapacitorCordova/CapacitorCordova/Classes/Public/CDVPlugin+Resources.m b/ios/Sources/Cordova/CDVPlugin+Resources.m similarity index 100% rename from ios/CapacitorCordova/CapacitorCordova/Classes/Public/CDVPlugin+Resources.m rename to ios/Sources/Cordova/CDVPlugin+Resources.m diff --git a/ios/CapacitorCordova/CapacitorCordova/Classes/Public/CDVPlugin.m b/ios/Sources/Cordova/CDVPlugin.m similarity index 100% rename from ios/CapacitorCordova/CapacitorCordova/Classes/Public/CDVPlugin.m rename to ios/Sources/Cordova/CDVPlugin.m diff --git a/ios/CapacitorCordova/CapacitorCordova/Classes/Public/CDVPluginManager.m b/ios/Sources/Cordova/CDVPluginManager.m similarity index 100% rename from ios/CapacitorCordova/CapacitorCordova/Classes/Public/CDVPluginManager.m rename to ios/Sources/Cordova/CDVPluginManager.m diff --git a/ios/CapacitorCordova/CapacitorCordova/Classes/Public/CDVPluginResult.m b/ios/Sources/Cordova/CDVPluginResult.m similarity index 100% rename from ios/CapacitorCordova/CapacitorCordova/Classes/Public/CDVPluginResult.m rename to ios/Sources/Cordova/CDVPluginResult.m diff --git a/ios/CapacitorCordova/CapacitorCordova/Classes/Public/CDVURLProtocol.m b/ios/Sources/Cordova/CDVURLProtocol.m similarity index 100% rename from ios/CapacitorCordova/CapacitorCordova/Classes/Public/CDVURLProtocol.m rename to ios/Sources/Cordova/CDVURLProtocol.m diff --git a/ios/CapacitorCordova/CapacitorCordova/Classes/Public/CDVViewController.m b/ios/Sources/Cordova/CDVViewController.m similarity index 100% rename from ios/CapacitorCordova/CapacitorCordova/Classes/Public/CDVViewController.m rename to ios/Sources/Cordova/CDVViewController.m diff --git a/ios/CapacitorCordova/CapacitorCordova/Classes/Public/CDVWebViewProcessPoolFactory.m b/ios/Sources/Cordova/CDVWebViewProcessPoolFactory.m similarity index 96% rename from ios/CapacitorCordova/CapacitorCordova/Classes/Public/CDVWebViewProcessPoolFactory.m rename to ios/Sources/Cordova/CDVWebViewProcessPoolFactory.m index f232836d07..febda12a9b 100644 --- a/ios/CapacitorCordova/CapacitorCordova/Classes/Public/CDVWebViewProcessPoolFactory.m +++ b/ios/Sources/Cordova/CDVWebViewProcessPoolFactory.m @@ -19,7 +19,7 @@ Licensed to the Apache Software Foundation (ASF) under one @import Foundation; @import WebKit; -#import +#import "CDVWebViewProcessPoolFactory.h" #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wdeprecated-declarations" diff --git a/ios/CapacitorCordova/CapacitorCordova/CapacitorCordova.h b/ios/Sources/Cordova/CapacitorCordova.h similarity index 100% rename from ios/CapacitorCordova/CapacitorCordova/CapacitorCordova.h rename to ios/Sources/Cordova/CapacitorCordova.h diff --git a/ios/CapacitorCordova/CapacitorCordova/CapacitorCordova.modulemap b/ios/Sources/Cordova/CapacitorCordova.modulemap similarity index 100% rename from ios/CapacitorCordova/CapacitorCordova/CapacitorCordova.modulemap rename to ios/Sources/Cordova/CapacitorCordova.modulemap diff --git a/ios/CapacitorCordova/CapacitorCordova/Classes/Public/NSDictionary+CordovaPreferences.m b/ios/Sources/Cordova/NSDictionary+CordovaPreferences.m similarity index 100% rename from ios/CapacitorCordova/CapacitorCordova/Classes/Public/NSDictionary+CordovaPreferences.m rename to ios/Sources/Cordova/NSDictionary+CordovaPreferences.m diff --git a/ios/CapacitorCordova/CapacitorCordova/PrivacyInfo.xcprivacy b/ios/Sources/Cordova/PrivacyInfo.xcprivacy similarity index 100% rename from ios/CapacitorCordova/CapacitorCordova/PrivacyInfo.xcprivacy rename to ios/Sources/Cordova/PrivacyInfo.xcprivacy diff --git a/ios/CapacitorCordova/CapacitorCordova/Classes/Public/AppDelegate.h b/ios/Sources/Cordova/include/AppDelegate.h similarity index 100% rename from ios/CapacitorCordova/CapacitorCordova/Classes/Public/AppDelegate.h rename to ios/Sources/Cordova/include/AppDelegate.h diff --git a/ios/CapacitorCordova/CapacitorCordova/Classes/Public/CDV.h b/ios/Sources/Cordova/include/CDV.h similarity index 100% rename from ios/CapacitorCordova/CapacitorCordova/Classes/Public/CDV.h rename to ios/Sources/Cordova/include/CDV.h diff --git a/ios/CapacitorCordova/CapacitorCordova/Classes/Public/CDVAvailability.h b/ios/Sources/Cordova/include/CDVAvailability.h similarity index 100% rename from ios/CapacitorCordova/CapacitorCordova/Classes/Public/CDVAvailability.h rename to ios/Sources/Cordova/include/CDVAvailability.h diff --git a/ios/CapacitorCordova/CapacitorCordova/Classes/Public/CDVAvailabilityDeprecated.h b/ios/Sources/Cordova/include/CDVAvailabilityDeprecated.h similarity index 100% rename from ios/CapacitorCordova/CapacitorCordova/Classes/Public/CDVAvailabilityDeprecated.h rename to ios/Sources/Cordova/include/CDVAvailabilityDeprecated.h diff --git a/ios/CapacitorCordova/CapacitorCordova/Classes/Public/CDVCommandDelegate.h b/ios/Sources/Cordova/include/CDVCommandDelegate.h similarity index 100% rename from ios/CapacitorCordova/CapacitorCordova/Classes/Public/CDVCommandDelegate.h rename to ios/Sources/Cordova/include/CDVCommandDelegate.h diff --git a/ios/CapacitorCordova/CapacitorCordova/Classes/Public/CDVCommandDelegateImpl.h b/ios/Sources/Cordova/include/CDVCommandDelegateImpl.h similarity index 100% rename from ios/CapacitorCordova/CapacitorCordova/Classes/Public/CDVCommandDelegateImpl.h rename to ios/Sources/Cordova/include/CDVCommandDelegateImpl.h diff --git a/ios/CapacitorCordova/CapacitorCordova/Classes/Public/CDVConfigParser.h b/ios/Sources/Cordova/include/CDVConfigParser.h similarity index 100% rename from ios/CapacitorCordova/CapacitorCordova/Classes/Public/CDVConfigParser.h rename to ios/Sources/Cordova/include/CDVConfigParser.h diff --git a/ios/CapacitorCordova/CapacitorCordova/Classes/Public/CDVInvokedUrlCommand.h b/ios/Sources/Cordova/include/CDVInvokedUrlCommand.h similarity index 100% rename from ios/CapacitorCordova/CapacitorCordova/Classes/Public/CDVInvokedUrlCommand.h rename to ios/Sources/Cordova/include/CDVInvokedUrlCommand.h diff --git a/ios/CapacitorCordova/CapacitorCordova/Classes/Public/CDVPlugin+Resources.h b/ios/Sources/Cordova/include/CDVPlugin+Resources.h similarity index 100% rename from ios/CapacitorCordova/CapacitorCordova/Classes/Public/CDVPlugin+Resources.h rename to ios/Sources/Cordova/include/CDVPlugin+Resources.h diff --git a/ios/CapacitorCordova/CapacitorCordova/Classes/Public/CDVPlugin.h b/ios/Sources/Cordova/include/CDVPlugin.h similarity index 100% rename from ios/CapacitorCordova/CapacitorCordova/Classes/Public/CDVPlugin.h rename to ios/Sources/Cordova/include/CDVPlugin.h diff --git a/ios/CapacitorCordova/CapacitorCordova/Classes/Public/CDVPluginManager.h b/ios/Sources/Cordova/include/CDVPluginManager.h similarity index 100% rename from ios/CapacitorCordova/CapacitorCordova/Classes/Public/CDVPluginManager.h rename to ios/Sources/Cordova/include/CDVPluginManager.h diff --git a/ios/CapacitorCordova/CapacitorCordova/Classes/Public/CDVPluginResult.h b/ios/Sources/Cordova/include/CDVPluginResult.h similarity index 100% rename from ios/CapacitorCordova/CapacitorCordova/Classes/Public/CDVPluginResult.h rename to ios/Sources/Cordova/include/CDVPluginResult.h diff --git a/ios/CapacitorCordova/CapacitorCordova/Classes/Public/CDVScreenOrientationDelegate.h b/ios/Sources/Cordova/include/CDVScreenOrientationDelegate.h similarity index 100% rename from ios/CapacitorCordova/CapacitorCordova/Classes/Public/CDVScreenOrientationDelegate.h rename to ios/Sources/Cordova/include/CDVScreenOrientationDelegate.h diff --git a/ios/CapacitorCordova/CapacitorCordova/Classes/Public/CDVURLProtocol.h b/ios/Sources/Cordova/include/CDVURLProtocol.h similarity index 100% rename from ios/CapacitorCordova/CapacitorCordova/Classes/Public/CDVURLProtocol.h rename to ios/Sources/Cordova/include/CDVURLProtocol.h diff --git a/ios/CapacitorCordova/CapacitorCordova/Classes/Public/CDVViewController.h b/ios/Sources/Cordova/include/CDVViewController.h similarity index 100% rename from ios/CapacitorCordova/CapacitorCordova/Classes/Public/CDVViewController.h rename to ios/Sources/Cordova/include/CDVViewController.h diff --git a/ios/CapacitorCordova/CapacitorCordova/Classes/Public/CDVWebViewProcessPoolFactory.h b/ios/Sources/Cordova/include/CDVWebViewProcessPoolFactory.h similarity index 96% rename from ios/CapacitorCordova/CapacitorCordova/Classes/Public/CDVWebViewProcessPoolFactory.h rename to ios/Sources/Cordova/include/CDVWebViewProcessPoolFactory.h index ba0b913599..982684c205 100644 --- a/ios/CapacitorCordova/CapacitorCordova/Classes/Public/CDVWebViewProcessPoolFactory.h +++ b/ios/Sources/Cordova/include/CDVWebViewProcessPoolFactory.h @@ -18,7 +18,7 @@ */ #import -#import +#import "CDVAvailabilityDeprecated.h" /** @Metadata { diff --git a/ios/CapacitorCordova/CapacitorCordova/Classes/Public/NSDictionary+CordovaPreferences.h b/ios/Sources/Cordova/include/NSDictionary+CordovaPreferences.h similarity index 100% rename from ios/CapacitorCordova/CapacitorCordova/Classes/Public/NSDictionary+CordovaPreferences.h rename to ios/Sources/Cordova/include/NSDictionary+CordovaPreferences.h diff --git a/ios/Tests/CapacitorTests/BridgedTypesCoercionTests.swift b/ios/Tests/CapacitorTests/BridgedTypesCoercionTests.swift new file mode 100644 index 0000000000..e149fcb4b8 --- /dev/null +++ b/ios/Tests/CapacitorTests/BridgedTypesCoercionTests.swift @@ -0,0 +1,56 @@ +import Foundation +import Testing +@testable import Capacitor + +private enum BridgedTypesCoercionError: Error { + case badCast +} + +private enum BridgedTypesCoercionHelper { + static func validTransformation(of array: [Any]) -> [Any] { + let result = JSTypes.coerceArrayToJSArray(array)!.capacitor.replacingNullValues() + return result.capacitor.replacingOptionalValues() as [Any] + } + + static func invalidTransformation(of array: [Any]) -> [Any] { + let result = JSTypes.coerceArrayToJSArray(array)!.capacitor.replacingNullValues() + return result as [Any] + } + + static func testCast(of array: [Any], atIndex index: Int) throws -> Any { + if let castArray = array as? [JSValue] { + return castArray[index] as Any + } + throw BridgedTypesCoercionError.badCast + } +} + +struct BridgedTypesCoercionTests { + @Test func nullHandling() throws { + let source: [Any] = ["test", NSNull(), 3] + let result = BridgedTypesCoercionHelper.validTransformation(of: source) + + // the replaced null value exists + let value = result[1] + #expect(value is NSNull) + + // the null value casts to non-optional + let castValue = try BridgedTypesCoercionHelper.testCast(of: result, atIndex: 1) + #expect(castValue is NSNull) + } + + @Test func optionalHandling() throws { + let source: [Any] = ["test", NSNull(), 3] + let result = BridgedTypesCoercionHelper.invalidTransformation(of: source) + + // bridging the optional-holding array to NSArray (as happens when passing values across + // the JS bridge) coerces the removed null value's `nil` back into an NSNull + let value = (result as NSArray).object(at: 1) + #expect(value is NSNull) + + // the optional value fails to cast to non-optional + #expect(throws: BridgedTypesCoercionError.badCast) { + try BridgedTypesCoercionHelper.testCast(of: result, atIndex: 1) + } + } +} diff --git a/ios/Tests/CapacitorTests/BridgedTypesTests.swift b/ios/Tests/CapacitorTests/BridgedTypesTests.swift new file mode 100644 index 0000000000..96afab539c --- /dev/null +++ b/ios/Tests/CapacitorTests/BridgedTypesTests.swift @@ -0,0 +1,218 @@ +import Foundation +import Testing +@testable import Capacitor + +private class TestContainer: NSObject, JSValueContainer { + var coercedDictionary: [AnyHashable: Any] = [:] + + static var jsDateFormatter: ISO8601DateFormatter = { + return ISO8601DateFormatter() + }() + + var jsObjectRepresentation: JSObject { + return coercedDictionary as? JSObject ?? [:] + } +} + +struct BridgedTypesTests { + private static let fixture = BridgedTypesFixture() + + private struct BridgedTypesFixture { + let unserializedDictionary: [AnyHashable: Any] + let deserializedDictionary: [AnyHashable: Any] + + init() { + let formatter = ISO8601DateFormatter() + let date = NSDate(timeIntervalSinceReferenceDate: 632854800) + let subDictionary: [AnyHashable: Any] = [ + "testIntArray": [0, 1, 2], + "testStringArray": ["1", "2", "3"], + "testDictionary": ["foo": "bar"] + ] + var dictionary: [AnyHashable: Any] = [ + "testInt": 1 as Int, + "testFloat": Float.pi, + "testBool": true as Bool, + "testString": "Some string value", + "testChild": subDictionary, + "testDateString": formatter.string(from: date as Date) + ] + let serializer = JSONSerializationWrapper(dictionary: dictionary)! + var unwrappedResult = serializer.unwrappedResult()! + unwrappedResult["testDateObject"] = date + dictionary["testDateObject"] = date + self.unserializedDictionary = dictionary + self.deserializedDictionary = unwrappedResult + } + } + + @Test func testTranslation() throws { + let unserializedDictionary = Self.fixture.unserializedDictionary + let deserializedDictionary = Self.fixture.deserializedDictionary + let testContainer = TestContainer() + testContainer.coercedDictionary = JSTypes.coerceDictionaryToJSObject(deserializedDictionary)! + + #expect(unserializedDictionary.count > 0) + #expect(deserializedDictionary.count > 0) + #expect(testContainer.coercedDictionary.count > 0) + } + + @Test func testCastingFailure() throws { + let deserializedDictionary = Self.fixture.deserializedDictionary + let unserializedDictionary = Self.fixture.unserializedDictionary + + var castResult = deserializedDictionary as? JSObject + #expect(castResult == nil) + + castResult = unserializedDictionary as? JSObject + #expect(castResult == nil) + } + + @Test func testCoercionSuccess() throws { + let deserializedDictionary = Self.fixture.deserializedDictionary + let coercedResult = JSTypes.coerceDictionaryToJSObject(deserializedDictionary) + #expect(coercedResult != nil) + } + + @Test func testRoundtripEquality() throws { + let deserializedDictionary = Self.fixture.deserializedDictionary + let unserializedDictionary = Self.fixture.unserializedDictionary + let coercedResult = JSTypes.coerceDictionaryToJSObject(deserializedDictionary)! + let foo: NSDictionary = coercedResult as NSDictionary + let bar: NSDictionary = unserializedDictionary as NSDictionary + + #expect(foo == bar) + } + + @Test func testTypeEquivalency() throws { + let deserializedDictionary = Self.fixture.deserializedDictionary + let unserializedDictionary = Self.fixture.unserializedDictionary + let coercedResult = JSTypes.coerceDictionaryToJSObject(deserializedDictionary)! + let coercedFloat = coercedResult["testFloat"] as? Float + let sourceFloat = unserializedDictionary["testFloat"] as? Float + let resultFloat = deserializedDictionary["testFloat"] as? Float + + #expect(coercedFloat != nil) + #expect(sourceFloat != nil) + #expect(resultFloat != nil) + + #expect(coercedFloat == sourceFloat) + #expect(sourceFloat == resultFloat) + #expect(coercedFloat == Float.pi) + } + + @Test func testNumberWrapping() throws { + let deserializedDictionary = Self.fixture.deserializedDictionary + let unserializedDictionary = Self.fixture.unserializedDictionary + let testContainer = TestContainer() + testContainer.coercedDictionary = JSTypes.coerceDictionaryToJSObject(deserializedDictionary)! + + let sourceFloat = unserializedDictionary["testFloat"]! + #expect(type(of: sourceFloat) == Float.self) + + let wrappedFloat = deserializedDictionary["testFloat"]! + let underlyingType: AnyObject.Type = NSClassFromString("__NSCFNumber")! + #expect(type(of: wrappedFloat) == underlyingType.self) + + let coercedResult = JSTypes.coerceDictionaryToJSObject(deserializedDictionary)! + let coercedFloat = coercedResult["testFloat"]! + #expect(type(of: coercedFloat) == underlyingType.self) + + let castFloat = testContainer.getFloat("testFloat")! + #expect(type(of: castFloat) == Float.self) + #expect((sourceFloat as! Float) == castFloat) + } + + @Test func testDateObject() throws { + let deserializedDictionary = Self.fixture.deserializedDictionary + let coercedResult = JSTypes.coerceDictionaryToJSObject(deserializedDictionary)! + let date = coercedResult["testDateObject"] as! Date + #expect(date != nil) + #expect(type(of: date) == Date.self) + } + + @Test func testDateParsing() throws { + let deserializedDictionary = Self.fixture.deserializedDictionary + let coercedResult = JSTypes.coerceDictionaryToJSObject(deserializedDictionary)! + let formatter = ISO8601DateFormatter() + let parsedDate = formatter.date(from: coercedResult["testDateString"] as! String)! + let dateObject = coercedResult["testDateObject"] as! Date + #expect(parsedDate != nil) + #expect(dateObject != nil) + #expect(dateObject.compare(parsedDate) == .orderedSame) + } + + @Test func testDateExtensions() throws { + let deserializedDictionary = Self.fixture.deserializedDictionary + let testContainer = TestContainer() + testContainer.coercedDictionary = JSTypes.coerceDictionaryToJSObject(deserializedDictionary)! + + let parsedDate = testContainer.getDate("testDateString")! + let dateObject = testContainer.getDate("testDateObject")! + #expect(parsedDate != nil) + #expect(dateObject != nil) + #expect(dateObject.compare(parsedDate) == .orderedSame) + } + + @Test func testDateCoercion() throws { + let deserializedDictionary = Self.fixture.deserializedDictionary + let stringifiedDictionary = JSTypes.coerceDictionaryToJSObject(deserializedDictionary, formattingDatesAsStrings: true)! + let unstringifiedDictionary = JSTypes.coerceDictionaryToJSObject(deserializedDictionary, formattingDatesAsStrings: false)! + let stringifiedValue = stringifiedDictionary["testDateObject"]! + let unstringifiedValue = unstringifiedDictionary["testDateObject"]! + #expect(type(of: stringifiedValue) == String.self) + #expect(type(of: unstringifiedValue) == Date.self) + #expect((stringifiedValue as! String) == (stringifiedDictionary["testDateString"] as! String)) + } + + @Test func testDateResultWrapping() throws { + let unserializedDictionary = Self.fixture.unserializedDictionary + let result = try PluginCallResult.dictionary(["date": unserializedDictionary["testDateObject"]!]).jsonRepresentation() + #expect(result == "{\"date\":\"\(unserializedDictionary["testDateString"] as! String)\"}") + } + + @Test func testResultMerging() throws { + let result = try PluginCallResult.dictionary(["number": 1]).jsonRepresentation(includingFields: ["string": "foo"]) + let isValid = result == "{\"string\":\"foo\",\"number\":1}" || result == "{\"number\":1,\"string\":\"foo\"}" + #expect(isValid) + } + + @Test func testNullWrapping() throws { + let dictionary: [AnyHashable: Any] = ["testInt": 1 as Int, "testNull": NSNull()] + let coercedDictionary = JSTypes.coerceDictionaryToJSObject(dictionary)! + #expect(coercedDictionary != nil) + #expect(coercedDictionary.count == 2) + #expect(coercedDictionary["testNull"]! is NSNull) + } + + @Test func testNullTransformation() throws { + let array: [Any] = [1, NSNull(), "test string"] + let coercedArray = JSTypes.coerceArrayToJSArray(array)! + #expect(coercedArray != nil) + #expect(coercedArray.count == 3) + #expect(type(of: coercedArray[1]) == NSNull.self) + let filteredArray = coercedArray.capacitor.replacingNullValues() + #expect(filteredArray.count == 3) + #expect(filteredArray[1] == nil) + let restoredArray = filteredArray.capacitor.replacingOptionalValues() + #expect(restoredArray.count == 3) + #expect(restoredArray[1] != nil) + #expect(restoredArray[0] is NSNumber) + #expect(restoredArray[1] is NSNull) + #expect(restoredArray[2] is String) + } + + @Test func testSparseArrayCastSuccess() throws { + let array: [Any] = ["test string 1", "test string 2", NSNull()] + let sparseArray = JSTypes.coerceArrayToJSArray(array)?.capacitor.replacingNullValues() as? [String?] + #expect(sparseArray != nil) + #expect(sparseArray!.count == 3) + #expect(sparseArray![2] == nil) + } + + @Test func testSparseArrayCastFailure() throws { + let array: [Any] = ["test string 1", 1, NSNull()] + let sparseArray = JSTypes.coerceArrayToJSArray(array)?.capacitor.replacingNullValues() as? [String?] + #expect(sparseArray == nil) + } +} diff --git a/ios/Tests/CapacitorTests/CodableTests.swift b/ios/Tests/CapacitorTests/CodableTests.swift new file mode 100644 index 0000000000..972ef394f2 --- /dev/null +++ b/ios/Tests/CapacitorTests/CodableTests.swift @@ -0,0 +1,195 @@ +import Foundation +import Testing +import Capacitor + +private struct Pet: Codable, Equatable { + var name: String + var breed: String + var isVaccinated: Bool +} + +private struct Person: Codable, Equatable { + var name: String + var age: UInt + var pet: Pet? + var family: [Person]? +} + +private let rawPet: JSObject = [ + "name": "Penny", + "breed": "Chihuahua", + "isVaccinated": true +] + +private let rawPeople: JSArray = [ + [ "name": "Anakin", + "age": 41 as NSNumber + ], + [ "name": "Leia", + "age": 20 as NSNumber + ] +] + +private let rawPerson: JSObject = [ + "name": "Luke", + "age": 20 as NSNumber, + "pet": rawPet, + "family": rawPeople +] + +private let person = Person( + name: "Luke", + age: 20, + pet: .init( + name: "Penny", + breed: "Chihuahua", + isVaccinated: true + ), + family: [ + Person(name: "Anakin", age: 41), + Person(name: "Leia", age: 20) + ] +) + +struct JSValueDecoderTests { + @Test func decodingValidKeyedContainerSucceeds() throws { + let decoder = JSValueDecoder() + let decodedPerson = try decoder.decode(Person.self, from: rawPerson) + #expect(decodedPerson == person) + } + + @Test func decodingValidUnkeyedContainerSucceeds() throws { + let decoder = JSValueDecoder() + let decodedPeople = try decoder.decode([Person].self, from: rawPeople) + #expect(person.family == decodedPeople) + } + + @Test func decodingSingleValueSucceeds() throws { + let decoder = JSValueDecoder() + let decodedNumber = try decoder.decode(UInt.self, from: 100 as NSNumber) + #expect(decodedNumber == 100) + } + + @Test func decodingInvalidKeyedContainerFails() throws { + let decoder = JSValueDecoder() + var invalidRawPerson = rawPerson + invalidRawPerson["name"] = nil + #expect(throws: DecodingError.self) { + try decoder.decode(Person.self, from: invalidRawPerson) + } + } + + @Test func decodingInvalidUnkeyedContainerFails() throws { + let decoder = JSValueDecoder() + var invalidRawPeople = try #require(rawPeople as? [JSObject]) + invalidRawPeople[0]["name"] = nil + #expect(throws: DecodingError.self) { + try decoder.decode([Person].self, from: invalidRawPeople) + } + } + + @Test func decodingInvalidSingleValueTypeFails() throws { + let decoder = JSValueDecoder() + #expect(throws: DecodingError.self) { + try decoder.decode(UInt.self, from: -1 as NSNumber) + } + } + + @Test func decodingValidNestedArraySucceeds() throws { + let decoder = JSValueDecoder() + let nestedPeople: JSArray = [rawPeople, rawPeople] + let decodedPeople = try decoder.decode([[Person]].self, from: nestedPeople) + #expect([person.family, person.family] == decodedPeople) + } + + @Test func decodingClassFails() throws { + class Pet: Decodable { + var name: String + var breed: String + var isVaccinated: String + init(name: String, breed: String, isVaccinated: String) { + self.name = name + self.breed = breed + self.isVaccinated = isVaccinated + } + } + + let decoder = JSValueDecoder() + #expect(throws: DecodingError.self) { + try decoder.decode(Pet.self, from: rawPet) + } + } + + @Test func decodingNSNullToNilSucceeds() throws { + let decoder = JSValueDecoder() + var rawPersonWithNull = rawPerson + rawPersonWithNull["pet"] = NSNull() + + let decodedPerson = try decoder.decode(Person.self, from: rawPersonWithNull) + #expect(decodedPerson.pet == nil) + } +} + +struct JSValueEncoderTests { + @Test func encodingNonclassCodableSucceeds() throws { + let encoder = JSValueEncoder() + let encodedValue = try encoder.encode(person) + let encodedObject = try #require(encodedValue as? JSObject) + + let name = try #require(encodedObject["name"] as? String) + #expect(person.name == name) + let age = try #require(encodedObject["age"] as? NSNumber) + #expect(person.age as NSNumber == age) + + let pet = try #require(encodedObject["pet"] as? JSObject) + let petName = try #require(pet["name"] as? String) + #expect(person.pet?.name == petName) + let petBreed = try #require(pet["breed"] as? String) + #expect(person.pet?.breed == petBreed) + let petIsVaccinated = try #require(pet["isVaccinated"] as? Bool) + #expect(person.pet?.isVaccinated == petIsVaccinated) + + let family = try #require(encodedObject["family"] as? [JSObject]) + #expect(person.family?.count == family.count) + let aniName = try #require(family[0]["name"] as? String) + #expect(person.family?[0].name == aniName) + let aniAge = try #require(family[0]["age"] as? NSNumber) + #expect(person.family?[0].age as? NSNumber == aniAge) + + let leiaName = try #require(family[1]["name"] as? String) + #expect(person.family?[1].name == leiaName) + let leiaAge = try #require(family[1]["age"] as? NSNumber) + #expect(person.family?[1].age as? NSNumber == leiaAge) + } + + @Test func encodingNestedUnkeyedContainerSucceeds() throws { + let encoder = JSValueEncoder() + let encodedValue = try encoder.encode([person.family, person.family]) + let encodedArray = try #require(encodedValue as? [[JSObject]]) + #expect(encodedArray.count == 2) + #expect(encodedArray[0].count == 2) + #expect(encodedArray[1].count == 2) + + let family = try #require(person.family) + + #expect(family[0].name == encodedArray[0][0]["name"] as? String) + #expect(family[0].name == encodedArray[1][0]["name"] as? String) + #expect(family[0].age as NSNumber == encodedArray[0][0]["age"] as? NSNumber) + #expect(family[0].age as NSNumber == encodedArray[1][0]["age"] as? NSNumber) + #expect(family[1].name == encodedArray[0][1]["name"] as? String) + #expect(family[1].name == encodedArray[1][1]["name"] as? String) + #expect(family[1].age as NSNumber == encodedArray[0][1]["age"] as? NSNumber) + #expect(family[1].age as NSNumber == encodedArray[1][1]["age"] as? NSNumber) + } + + @Test func encodingNilWithExplicitNullsSucceeds() throws { + struct Test: Encodable { + var name: String? + } + + let explicitEncoder = JSValueEncoder(optionalEncodingStrategy: .explicitNulls) + let encoded = try #require(try explicitEncoder.encode(Test()) as? JSObject) + #expect(encoded["name"] is NSNull) + #expect(encoded["name"] != nil) + } +} diff --git a/ios/Tests/CapacitorTests/ConfigurationTests.swift b/ios/Tests/CapacitorTests/ConfigurationTests.swift new file mode 100644 index 0000000000..6e9055beb7 --- /dev/null +++ b/ios/Tests/CapacitorTests/ConfigurationTests.swift @@ -0,0 +1,192 @@ +import Foundation +import Testing +import UIKit +@testable import Capacitor + +struct ConfigurationTests { + enum ConfigFile: String, CaseIterable { + case flat = "flat" + case nested = "hierarchy" + case server = "server" + case invalid = "bad" + case deprecated = "hidinglogs" + case nonparsable = "nonjson" + } + + private static let configFiles = loadConfigFiles() + + private static func loadConfigFiles() -> [ConfigFile: URL] { + var files: [ConfigFile: URL] = [:] + for file in ConfigFile.allCases { + if let url = Bundle.module.url(forResource: file.rawValue, withExtension: "json", subdirectory: "configurations") { + files[file] = url + } + } + return files + } + + private func getConfigURL() -> URL { + Bundle.module.resourceURL?.appendingPathComponent("configurations") ?? + Bundle.module.resourceURL ?? Bundle.main.resourceURL ?? URL(fileURLWithPath: "/") + } + + @Test func defaultErrors() throws { + let descriptor = InstanceDescriptor.init() + #expect(descriptor.warnings.contains(.missingAppDir)) + #expect(descriptor.warnings.contains(.missingFile)) + } + + @Test func missingAppDetection() throws { + var url = getConfigURL() + url.appendPathComponent("app", isDirectory: true) + let descriptor = InstanceDescriptor.init(at: url, configuration: nil, cordovaConfiguration: nil) + #expect(descriptor.warnings.contains(.missingAppDir)) + } + + @Test func failedParsing() throws { + let url = getConfigURL() + let descriptor = InstanceDescriptor.init(at: url, configuration: Self.configFiles[.nonparsable], cordovaConfiguration: nil) + #expect(descriptor.warnings.contains(.invalidFile)) + } + + @Test func defaults() throws { + let url = getConfigURL() + let descriptor = InstanceDescriptor.init(at: url, configuration: nil, cordovaConfiguration: nil) + #expect(descriptor.backgroundColor == nil) + #expect(descriptor.urlScheme == "capacitor") + #expect(descriptor.urlHostname == "localhost") + #expect(descriptor.serverURL == nil) + #expect(descriptor.scrollingEnabled == true) + #expect(descriptor.loggingBehavior == .debug) + #expect(descriptor.allowLinkPreviews == true) + #expect(descriptor.contentInsetAdjustmentBehavior == .never) + } + + @Test func deprecatedParsing() throws { + let url = getConfigURL() + let descriptor = InstanceDescriptor.init(at: url, configuration: Self.configFiles[.deprecated], cordovaConfiguration: nil) + #expect(descriptor.loggingBehavior != .none) + } + + @Test func deprecatedOverrideParsing() throws { + let url = getConfigURL() + let descriptor = InstanceDescriptor.init(at: url, configuration: Self.configFiles[.server], cordovaConfiguration: nil) + #expect(descriptor.loggingBehavior == .production) + } + + @Test func topLevelParsing() throws { + let url = getConfigURL() + let descriptor = InstanceDescriptor.init(at: url, configuration: Self.configFiles[.flat], cordovaConfiguration: nil) + #expect(descriptor.backgroundColor == UIColor(red: 1, green: 1, blue: 1, alpha: 1)) + #expect(descriptor.overridenUserAgentString == "level 1 override") + #expect(descriptor.appendedUserAgentString == "level 1 append") + #expect(descriptor.loggingBehavior == .debug) + } + + @Test func nestedParsing() throws { + let url = getConfigURL() + let descriptor = InstanceDescriptor.init(at: url, configuration: Self.configFiles[.nested], cordovaConfiguration: nil) + #expect(descriptor.backgroundColor == UIColor(red: 0, green: 0, blue: 0, alpha: 1)) + #expect(descriptor.overridenUserAgentString == "level 2 override") + #expect(descriptor.appendedUserAgentString == "level 2 append") + #expect(descriptor.loggingBehavior == .none) + #expect(descriptor.scrollingEnabled == false) + #expect(descriptor.contentInsetAdjustmentBehavior == .scrollableAxes) + } + + @Test func serverParsing() throws { + let url = getConfigURL() + let descriptor = InstanceDescriptor.init(at: url, configuration: Self.configFiles[.server], cordovaConfiguration: nil) + #expect(descriptor.urlScheme == "override") + #expect(descriptor.urlHostname == "myhost") + #expect(descriptor.serverURL == "http://192.168.100.1:2057") + } + + @Test func badDataParsing() throws { + let url = getConfigURL() + let descriptor = InstanceDescriptor.init(at: url, configuration: Self.configFiles[.invalid], cordovaConfiguration: nil) + #expect(descriptor.backgroundColor == nil) + #expect(descriptor.loggingBehavior == .debug) + #expect(descriptor.contentInsetAdjustmentBehavior == .never) + } + + @Test func badDataTransformation() throws { + let url = getConfigURL() + let descriptor = InstanceDescriptor.init(at: url, configuration: Self.configFiles[.invalid], cordovaConfiguration: nil) + let configuration = InstanceConfiguration(with: descriptor, isDebug: true) + #expect(configuration.serverURL != URL(string: "capacitor://myhost")) + } + + @Test func serverTransformation() throws { + let url = getConfigURL() + let descriptor = InstanceDescriptor.init(at: url, configuration: Self.configFiles[.server], cordovaConfiguration: nil) + let configuration = InstanceConfiguration(with: descriptor, isDebug: true) + #expect(configuration.serverURL == URL(string: "http://192.168.100.1:2057")) + #expect(configuration.localURL == URL(string: "override://myhost")) + } + + @Test func pluginConfig() throws { + let url = getConfigURL() + let descriptor = InstanceDescriptor.init(at: url, configuration: Self.configFiles[.flat], cordovaConfiguration: nil) + let configuration = InstanceConfiguration(with: descriptor, isDebug: true) + let value = configuration.getPluginConfig("SplashScreen").getInt("launchShowDuration", 0) + #expect(value == 1) + } + + @Test func legacyConfig() throws { + let url = getConfigURL() + let flatDescriptor = InstanceDescriptor.init(at: url, configuration: Self.configFiles[.flat], cordovaConfiguration: nil) + let flatConfiguration = InstanceConfiguration(with: flatDescriptor, isDebug: true) + #expect(flatConfiguration.overridenUserAgentString == "level 1 override") + + let nestedDescriptor = InstanceDescriptor.init(at: url, configuration: Self.configFiles[.nested], cordovaConfiguration: nil) + let nestedConfiguration = InstanceConfiguration(with: nestedDescriptor, isDebug: true) + #expect(nestedConfiguration.overridenUserAgentString == "level 2 override") + } + + @Test func navigationRules() throws { + let url = getConfigURL() + let descriptor = InstanceDescriptor.init(at: url, configuration: Self.configFiles[.server], cordovaConfiguration: nil) + let configuration = InstanceConfiguration(with: descriptor, isDebug: true) + #expect(configuration.shouldAllowNavigation(to: "ionic.io") == true) + #expect(configuration.shouldAllowNavigation(to: "ionic.io".uppercased()) == true) + #expect(configuration.shouldAllowNavigation(to: "test.capacitorjs.com") == true) + #expect(configuration.shouldAllowNavigation(to: "192.168.0.1") == true) + #expect(configuration.shouldAllowNavigation(to: "subdomain.test.ionicframework.com") == true) + #expect(configuration.shouldAllowNavigation(to: "wildcard1.wildcard2.example.com") == true) + #expect(configuration.shouldAllowNavigation(to: "wildcard1.example.com") == false) + #expect(configuration.shouldAllowNavigation(to: "google.com") == false) + #expect(configuration.shouldAllowNavigation(to: "192.168.0.2") == false) + #expect(configuration.shouldAllowNavigation(to: "ionicframework.com") == false) + } + + @Test func noLoggingTransformation() throws { + let url = getConfigURL() + let descriptor = InstanceDescriptor.init(at: url, configuration: nil, cordovaConfiguration: nil) + descriptor.loggingBehavior = .none + var configuration = InstanceConfiguration(with: descriptor, isDebug: false) + #expect(configuration.loggingEnabled == false) + configuration = InstanceConfiguration(with: descriptor, isDebug: true) + #expect(configuration.loggingEnabled == false) + } + + @Test func debugLoggingTransformation() throws { + let url = getConfigURL() + let descriptor = InstanceDescriptor.init(at: url, configuration: nil, cordovaConfiguration: nil) + descriptor.loggingBehavior = .debug + var configuration = InstanceConfiguration(with: descriptor, isDebug: false) + #expect(configuration.loggingEnabled == false) + configuration = InstanceConfiguration(with: descriptor, isDebug: true) + #expect(configuration.loggingEnabled == true) + } + + @Test func productionLoggingTransformation() throws { + let url = getConfigURL() + let descriptor = InstanceDescriptor.init(at: url, configuration: nil, cordovaConfiguration: nil) + descriptor.loggingBehavior = .production + var configuration = InstanceConfiguration(with: descriptor, isDebug: false) + #expect(configuration.loggingEnabled == true) + configuration = InstanceConfiguration(with: descriptor, isDebug: true) + #expect(configuration.loggingEnabled == true) + } +} diff --git a/ios/Tests/CapacitorTests/DataCodableTests.swift b/ios/Tests/CapacitorTests/DataCodableTests.swift new file mode 100644 index 0000000000..01645a9c33 --- /dev/null +++ b/ios/Tests/CapacitorTests/DataCodableTests.swift @@ -0,0 +1,148 @@ +import Foundation +import Testing +import Capacitor + +private struct Foo: Codable, Equatable { + var data: Data +} + +private let jsonString = #"{ "key": "value" }"# +private let jsonData = jsonString.data(using: .utf8)! +private let jsonByteArray: [NSNumber] = [123, 32, 34, 107, 101, 121, 34, 58, 32, 34, 118, 97, 108, 117, 101, 34, 32, 125] +private let jsonBase64 = "eyAia2V5IjogInZhbHVlIiB9" + +private let customDecodingStrategy = JSValueDecoder.DataDecodingStrategy.custom { decoder in + var container = try decoder.unkeyedContainer() + var byteArray: [UInt8] = [] + while !container.isAtEnd { + byteArray.append(try container.decode(UInt8.self)) + } + return Data(byteArray) +} + +private let customEncodingStrategy = JSValueEncoder.DataEncodingStrategy.custom { data, encoder in + let byteArray = data.map { $0 } + var unkeyedContainer = encoder.unkeyedContainer() + try unkeyedContainer.encode(contentsOf: byteArray) +} + +struct JSValueDecoderDataTests { + @Test func decodingDataDefaultRoot() throws { + let decoder = JSValueDecoder() + let result = try decoder.decode(Data.self, from: jsonByteArray) + #expect(result == jsonData) + } + + @Test func decodingDataDefaultArray() throws { + let decoder = JSValueDecoder() + let result = try decoder.decode([Data].self, from: [jsonByteArray, jsonByteArray]) + #expect(result == [jsonData, jsonData]) + } + + @Test func decodingDataDefaultStruct() throws { + let decoder = JSValueDecoder() + let result = try decoder.decode(Foo.self, from: ["data": jsonByteArray]) + #expect(result == .init(data: jsonData)) + } + + @Test func decodingDataBase64Root() throws { + let decoder = JSValueDecoder(dataDecodingStrategy: .base64) + let result = try decoder.decode(Data.self, from: jsonBase64) + #expect(result == jsonData) + } + + @Test func decodingDataBase64Array() throws { + let decoder = JSValueDecoder(dataDecodingStrategy: .base64) + let result = try decoder.decode([Data].self, from: [jsonBase64, jsonBase64]) + #expect(result == [jsonData, jsonData]) + } + + @Test func decodingDataBase64Struct() throws { + let decoder = JSValueDecoder(dataDecodingStrategy: .base64) + let result = try decoder.decode(Foo.self, from: ["data": jsonBase64]) + #expect(result == .init(data: jsonData)) + } + + @Test func decodingDataCustomRoot() throws { + let decoder = JSValueDecoder(dataDecodingStrategy: customDecodingStrategy) + let result = try decoder.decode(Data.self, from: jsonByteArray) + #expect(result == jsonData) + } + + @Test func decodingDataCustomArray() throws { + let decoder = JSValueDecoder(dataDecodingStrategy: customDecodingStrategy) + let result = try decoder.decode([Data].self, from: [jsonByteArray, jsonByteArray]) + #expect(result == [jsonData, jsonData]) + } + + @Test func decodingDataCustomStruct() throws { + let decoder = JSValueDecoder(dataDecodingStrategy: customDecodingStrategy) + let result = try decoder.decode(Foo.self, from: ["data": jsonByteArray]) + #expect(result == .init(data: jsonData)) + } +} + +struct JSValueEncoderDataTests { + @Test func encodingDataDefaultRoot() throws { + let encoder = JSValueEncoder() + let rawResult = try encoder.encode(jsonData) + let result = try #require(rawResult as? [NSNumber]) + #expect(result == jsonByteArray) + } + + @Test func encodingDataDefaultArray() throws { + let encoder = JSValueEncoder() + let rawResult = try encoder.encode([jsonData, jsonData]) + let result = try #require(rawResult as? [[NSNumber]]) + #expect(result == [jsonByteArray, jsonByteArray]) + } + + @Test func encodingDataDefaultStruct() throws { + let encoder = JSValueEncoder() + let rawResult = try encoder.encode(Foo(data: jsonData)) + let result = try #require(rawResult as? [String: [NSNumber]]) + #expect(result == ["data": jsonByteArray]) + } + + @Test func encodingDataBase64Root() throws { + let encoder = JSValueEncoder(dataEncodingStrategy: .base64) + let rawResult = try encoder.encode(jsonData) + let result = try #require(rawResult as? String) + #expect(result == jsonBase64) + } + + @Test func encodingDataBase64Array() throws { + let encoder = JSValueEncoder(dataEncodingStrategy: .base64) + let rawResult = try encoder.encode([jsonData, jsonData]) + let result = try #require(rawResult as? [String]) + #expect(result == [jsonBase64, jsonBase64]) + } + + @Test func encodingDataBase64Struct() throws { + let encoder = JSValueEncoder(dataEncodingStrategy: .base64) + let rawResult = try encoder.encode(Foo(data: jsonData)) + let result = try #require(rawResult as? [String: String]) + #expect(result == ["data": jsonBase64]) + } + + @Test func encodingDataCustomRoot() throws { + let encoder = JSValueEncoder(dataEncodingStrategy: customEncodingStrategy) + let rawResult = try encoder.encode(jsonData) + let result = try #require(rawResult as? [NSNumber]) + #expect(result == jsonByteArray) + } + + @Test func encodingDataCustomArray() throws { + let encoder = JSValueEncoder(dataEncodingStrategy: customEncodingStrategy) + let rawResult = try encoder.encode([jsonData, jsonData]) + let result = try #require(rawResult as? [[NSNumber]]) + #expect(result == [jsonByteArray, jsonByteArray]) + } + + @Test func encodingDataCustomStruct() throws { + let encoder = JSValueEncoder(dataEncodingStrategy: customEncodingStrategy) + let rawResult = try encoder.encode(Foo(data: jsonData)) + let result = try #require(rawResult as? [String: [NSNumber]]) + #expect(result == ["data": jsonByteArray]) + } +} diff --git a/ios/Capacitor/CodableTests/DateCodableTests.swift b/ios/Tests/CapacitorTests/DateCodableTests.swift similarity index 62% rename from ios/Capacitor/CodableTests/DateCodableTests.swift rename to ios/Tests/CapacitorTests/DateCodableTests.swift index 656832acff..5578059765 100644 --- a/ios/Capacitor/CodableTests/DateCodableTests.swift +++ b/ios/Tests/CapacitorTests/DateCodableTests.swift @@ -1,15 +1,7 @@ -// -// DateCodableTests.swift -// CodableTests -// -// Created by Steven Sherry on 9/6/24. -// Copyright © 2024 Drifty Co. All rights reserved. -// - -import XCTest +import Foundation +import Testing import Capacitor -// Fixture data that all refers to the same Date and Time private let timeIntervalSinceReferenceDate: TimeInterval = 747268580 private let referenceDate = Date(timeIntervalSinceReferenceDate: timeIntervalSinceReferenceDate) private let secondsSince1970 = 1725575780 as Double @@ -24,45 +16,45 @@ private let formatter: DateFormatter = { formatter.locale = .init(identifier: "en_US") return formatter }() -private let formatted = "Sep 5, 2024 at 5:36:20 PM CDT" +private let formatted = "Sep 5, 2024 at 5:36:20\u{202F}PM CDT" private struct Foo: Codable, Equatable { var date: Date } -final class JSValueDecoderDateTests: XCTestCase { - func testDecode_date__default() throws { +struct JSValueDecoderDateTests { + @Test func decodingDateDefault() throws { let reference = timeIntervalSinceReferenceDate let decoder = JSValueDecoder() let result = try decoder.decode(Date.self, from: reference) - XCTAssertEqual(result, referenceDate) + #expect(result == referenceDate) } - func testDecode_date__secondsSince1970() throws { + @Test func decodingDateSecondsSince1970() throws { let decoder = JSValueDecoder(dateDecodingStrategy: .secondsSince1970) let result = try decoder.decode(Date.self, from: secondsSince1970) - XCTAssertEqual(result, referenceDate) + #expect(result == referenceDate) } - func testDecode_date__millisecondsSince1970() throws { + @Test func decodingDateMillisecondsSince1970() throws { let decoder = JSValueDecoder(dateDecodingStrategy: .millisecondsSince1970) let result = try decoder.decode(Date.self, from: millisecondsSince1970) - XCTAssertEqual(result, referenceDate) + #expect(result == referenceDate) } - func testDecode_date__iso8601() throws { + @Test func decodingDateISO8601() throws { let decoder = JSValueDecoder(dateDecodingStrategy: .iso8601) let result = try decoder.decode(Date.self, from: iso8601) - XCTAssertEqual(result, referenceDate) + #expect(result == referenceDate) } - func testDecode_date__formatted() throws { + @Test func decodingDateFormatted() throws { let decoder = JSValueDecoder(dateDecodingStrategy: .formatted(formatter)) let result = try decoder.decode(Date.self, from: formatted) - XCTAssertEqual(result, referenceDate) + #expect(result == referenceDate) } - func testDecode_date__custom() throws { + @Test func decodingDateCustom() throws { let strategy = JSValueDecoder.DateDecodingStrategy.custom { decoder in let container = try decoder.singleValueContainer() let referenceDateString = try container.decode(String.self) @@ -75,61 +67,61 @@ final class JSValueDecoderDateTests: XCTestCase { let referenceString = "\(timeIntervalSinceReferenceDate)" let decoder = JSValueDecoder(dateDecodingStrategy: strategy) let result = try decoder.decode(Date.self, from: referenceString) - XCTAssertEqual(result, referenceDate) + #expect(result == referenceDate) } - func testDecode_date__array() throws { + @Test func decodingDateArray() throws { let dateArray = [iso8601, iso8601] let decoder = JSValueDecoder(dateDecodingStrategy: .iso8601) let result = try decoder.decode([Date].self, from: dateArray) - XCTAssertEqual(result, [referenceDate, referenceDate]) + #expect(result == [referenceDate, referenceDate]) } - func testDecode_date__struct() throws { + @Test func decodingDateStruct() throws { let value = ["date": iso8601] as JSObject let decoder = JSValueDecoder(dateDecodingStrategy: .iso8601) let result = try decoder.decode(Foo.self, from: value) - XCTAssertEqual(result, Foo(date: referenceDate)) + #expect(result == Foo(date: referenceDate)) } } -final class JSValueEncoderDateTests: XCTestCase { - func testEncode_date__default() throws { +struct JSValueEncoderDateTests { + @Test func encodingDateDefault() throws { let encoder = JSValueEncoder() let rawResult = try encoder.encode(referenceDate) - let result = try XCTUnwrap(rawResult as? Double) - XCTAssertEqual(result, timeIntervalSinceReferenceDate) + let result = try #require(rawResult as? Double) + #expect(result == timeIntervalSinceReferenceDate) } - func testEncode_date__secondsSince1970() throws { + @Test func encodingDateSecondsSince1970() throws { let encoder = JSValueEncoder(dateEncodingStrategy: .secondsSince1970) let rawResult = try encoder.encode(referenceDate) - let result = try XCTUnwrap(rawResult as? Double) - XCTAssertEqual(result, secondsSince1970) + let result = try #require(rawResult as? Double) + #expect(result == secondsSince1970) } - func testEncode_date__millisecondsSince1970() throws { + @Test func encodingDateMillisecondsSince1970() throws { let encoder = JSValueEncoder(dateEncodingStrategy: .millisecondsSince1970) let rawResult = try encoder.encode(referenceDate) - let result = try XCTUnwrap(rawResult as? Double) - XCTAssertEqual(result, millisecondsSince1970) + let result = try #require(rawResult as? Double) + #expect(result == millisecondsSince1970) } - func testEncode_date__iso8601() throws { + @Test func encodingDateISO8601() throws { let encoder = JSValueEncoder(dateEncodingStrategy: .iso8601) let rawResult = try encoder.encode(referenceDate) - let result = try XCTUnwrap(rawResult as? String) - XCTAssertEqual(result, iso8601) + let result = try #require(rawResult as? String) + #expect(result == iso8601) } - func testEncode_date__formatted() throws { + @Test func encodingDateFormatted() throws { let encoder = JSValueEncoder(dateEncodingStrategy: .formatted(formatter)) let rawResult = try encoder.encode(referenceDate) - let result = try XCTUnwrap(rawResult as? String) - XCTAssertEqual(result, formatted) + let result = try #require(rawResult as? String) + #expect(result == formatted) } - func testEncode_date__custom() throws { + @Test func encodingDateCustom() throws { let strategy = JSValueEncoder.DateEncodingStrategy.custom { date, encoder in var container = encoder.singleValueContainer() try container.encode("\(date.timeIntervalSinceReferenceDate)") @@ -137,22 +129,22 @@ final class JSValueEncoderDateTests: XCTestCase { let encoder = JSValueEncoder(dateEncodingStrategy: strategy) let rawResult = try encoder.encode(referenceDate) - let result = try XCTUnwrap(rawResult as? String) - XCTAssertEqual(result, "\(timeIntervalSinceReferenceDate)") + let result = try #require(rawResult as? String) + #expect(result == "\(timeIntervalSinceReferenceDate)") } - func testEncode_date__array() throws { + @Test func encodingDateArray() throws { let encoder = JSValueEncoder(dateEncodingStrategy: .iso8601) let array = [referenceDate, referenceDate] let rawResult = try encoder.encode(array) - let result = try XCTUnwrap(rawResult as? [String]) - XCTAssertEqual(result, [iso8601, iso8601]) + let result = try #require(rawResult as? [String]) + #expect(result == [iso8601, iso8601]) } - func testEncode_date__struct() throws { + @Test func encodingDateStruct() throws { let encoder = JSValueEncoder(dateEncodingStrategy: .iso8601) let rawResult = try encoder.encode(Foo(date: referenceDate)) - let result = try XCTUnwrap(rawResult as? [String: String]) - XCTAssertEqual(result, ["date": iso8601]) + let result = try #require(rawResult as? [String: String]) + #expect(result == ["date": iso8601]) } } diff --git a/ios/Tests/CapacitorTests/JSExportTests.swift b/ios/Tests/CapacitorTests/JSExportTests.swift new file mode 100644 index 0000000000..7a9c800324 --- /dev/null +++ b/ios/Tests/CapacitorTests/JSExportTests.swift @@ -0,0 +1,10 @@ +import Testing +import WebKit +@testable import Capacitor + +struct JSExportTests { + @Test @MainActor func bridgeBundleExports() throws { + let contentController = WKUserContentController() + try Capacitor.JSExport.exportBridgeJS(userContentController: contentController) + } +} diff --git a/ios/Tests/CapacitorTests/JSONSerializationWrapper.swift b/ios/Tests/CapacitorTests/JSONSerializationWrapper.swift new file mode 100644 index 0000000000..898382c7ff --- /dev/null +++ b/ios/Tests/CapacitorTests/JSONSerializationWrapper.swift @@ -0,0 +1,16 @@ +import Foundation + +final class JSONSerializationWrapper { + let dictionary: [AnyHashable: Any] + + init?(dictionary: [AnyHashable: Any]) { + self.dictionary = dictionary + } + + func unwrappedResult() -> [AnyHashable: Any]? { + guard let serializedData = try? JSONSerialization.data(withJSONObject: dictionary, options: [.prettyPrinted]) else { + return nil + } + return try? JSONSerialization.jsonObject(with: serializedData, options: []) as? [AnyHashable: Any] + } +} diff --git a/ios/Capacitor/CodableTests/NestedCodableTests.swift b/ios/Tests/CapacitorTests/NestedCodableTests.swift similarity index 64% rename from ios/Capacitor/CodableTests/NestedCodableTests.swift rename to ios/Tests/CapacitorTests/NestedCodableTests.swift index 32ac2f68e0..89ef5ad351 100644 --- a/ios/Capacitor/CodableTests/NestedCodableTests.swift +++ b/ios/Tests/CapacitorTests/NestedCodableTests.swift @@ -1,15 +1,8 @@ -// -// CodableTests.swift -// CodableTests -// -// Created by Steven Sherry on 12/10/23. -// Copyright © 2023 Drifty Co. All rights reserved. -// - -import XCTest +import Foundation +import Testing import Capacitor -final class NestedCodableTests: XCTestCase { +struct NestedCodableTests { private let nestedData: JSObject = [ "id": 1, "user": [ @@ -30,34 +23,32 @@ final class NestedCodableTests: XCTestCase { reviewCount: 4 ) - func testDecode__when_decoding_a_decodable_value_with_a_custom_implementation_with_nested_values__it_successfully_decodes() throws { + @Test func decodingNestedValueWithCustomImplementation() throws { let decoder = JSValueDecoder() let decoded = try decoder.decode(Flattened.self, from: nestedData) - XCTAssertEqual(decoded, flatData) + #expect(decoded == flatData) } - func testEncode__when_encoding_an_encodable_value_with_a_custom_implementation_with_nested_values__it_successfully_encodes() throws { + @Test func encodingNestedValueWithCustomImplementation() throws { let encoder = JSValueEncoder() - let encoded = try XCTUnwrap(try encoder.encode(flatData) as? JSObject) - - print(encoded) - let encodedId = try XCTUnwrap(encoded["id"] as? NSNumber) - let encodedUser = try XCTUnwrap(encoded["user"] as? JSObject) - let encodedUserName = try XCTUnwrap(encodedUser["userName"] as? String) - let encodedRealInfo = try XCTUnwrap(encodedUser["realInfo"] as? JSObject) - let encodedFullName = try XCTUnwrap(encodedRealInfo["fullName"] as? String) - let encodedReviewCount = try XCTUnwrap(encoded["reviewCount"] as? JSArray) - let encodedCountEntry = try XCTUnwrap(encodedReviewCount[0] as? JSObject) - let encodedCount = try XCTUnwrap(encodedCountEntry["count"] as? NSNumber) - - XCTAssertEqual(encodedId, flatData.id as NSNumber) - XCTAssertEqual(encodedUserName, flatData.userName) - XCTAssertEqual(encodedFullName, flatData.fullName) - XCTAssertEqual(encodedCount, flatData.reviewCount as NSNumber) + let encoded = try #require(try encoder.encode(flatData) as? JSObject) + + let encodedId = try #require(encoded["id"] as? NSNumber) + let encodedUser = try #require(encoded["user"] as? JSObject) + let encodedUserName = try #require(encodedUser["userName"] as? String) + let encodedRealInfo = try #require(encodedUser["realInfo"] as? JSObject) + let encodedFullName = try #require(encodedRealInfo["fullName"] as? String) + let encodedReviewCount = try #require(encoded["reviewCount"] as? JSArray) + let encodedCountEntry = try #require(encodedReviewCount[0] as? JSObject) + let encodedCount = try #require(encodedCountEntry["count"] as? NSNumber) + + #expect(encodedId == flatData.id as NSNumber) + #expect(encodedUserName == flatData.userName) + #expect(encodedFullName == flatData.fullName) + #expect(encodedCount == flatData.reviewCount as NSNumber) } } -// Example taken from https://stackoverflow.com/questions/44549310/how-to-decode-a-nested-json-struct-with-swift-decodable-protocol private struct Flattened: Equatable { let id: Int let userName: String @@ -83,7 +74,6 @@ extension Flattened: Decodable { } init(from decoder: Decoder) throws { - // id let container = try decoder.container(keyedBy: RootKeys.self) id = try container.decode(Int.self, forKey: .id) let userContainer = try container.nestedContainer(keyedBy: UserKeys.self, forKey: .user) diff --git a/ios/Capacitor/CodableTests/NonconformingFloatCodableTests.swift b/ios/Tests/CapacitorTests/NonconformingFloatCodableTests.swift similarity index 50% rename from ios/Capacitor/CodableTests/NonconformingFloatCodableTests.swift rename to ios/Tests/CapacitorTests/NonconformingFloatCodableTests.swift index 9cfdb36156..69112d16a8 100644 --- a/ios/Capacitor/CodableTests/NonconformingFloatCodableTests.swift +++ b/ios/Tests/CapacitorTests/NonconformingFloatCodableTests.swift @@ -1,42 +1,34 @@ -// -// NonconformingFloatCodableTests.swift -// CodableTests -// -// Created by Steven Sherry on 9/6/24. -// Copyright © 2024 Drifty Co. All rights reserved. -// - -import XCTest +import Testing import Capacitor private struct Foo: Codable, Equatable { var number: Double } -class JSValueEncoderNonConformingFloatTests: XCTestCase { - func testEncode_float__default_root() throws { +struct JSValueEncoderNonConformingFloatTests { + @Test func encodingFloatDefaultRoot() throws { let encoder = JSValueEncoder() let rawResult = try encoder.encode(Double.infinity) - let result = try XCTUnwrap(rawResult as? Double) - XCTAssertEqual(result, .infinity) + let result = try #require(rawResult as? Double) + #expect(result == .infinity) } - func testEncode_float__default_array() throws { + @Test func encodingFloatDefaultArray() throws { let encoder = JSValueEncoder() let rawResult = try encoder.encode([Double.infinity, -.infinity, .nan]) - let result = try XCTUnwrap(rawResult as? [Double]) - XCTAssertEqual(result[0...1], [.infinity, -.infinity]) - XCTAssertTrue(result[2].isNaN) + let result = try #require(rawResult as? [Double]) + #expect(result[0...1] == [.infinity, -.infinity]) + #expect(result[2].isNaN) } - func testEncode_float__default_struct() throws { + @Test func encodingFloatDefaultStruct() throws { let encoder = JSValueEncoder() let rawResult = try encoder.encode(Foo.init(number: .infinity)) - let result = try XCTUnwrap(rawResult as? [String: Double]) - XCTAssertEqual(result, ["number": .infinity]) + let result = try #require(rawResult as? [String: Double]) + #expect(result == ["number": .infinity]) } - func testEncode_float__convertToString_root() throws { + @Test func encodingFloatConvertToStringRoot() throws { let encoder = JSValueEncoder( nonConformingFloatEncodingStategy: .convertToString( positiveInfinity: "pos", @@ -46,19 +38,19 @@ class JSValueEncoderNonConformingFloatTests: XCTestCase { ) var rawResult = try encoder.encode(Double.infinity) - var result = try XCTUnwrap(rawResult as? String) - XCTAssertEqual(result, "pos") + var result = try #require(rawResult as? String) + #expect(result == "pos") rawResult = try encoder.encode(-Double.infinity) - result = try XCTUnwrap(rawResult as? String) - XCTAssertEqual(result, "neg") + result = try #require(rawResult as? String) + #expect(result == "neg") rawResult = try encoder.encode(Double.nan) - result = try XCTUnwrap(rawResult as? String) - XCTAssertEqual(result, "nan") + result = try #require(rawResult as? String) + #expect(result == "nan") } - func testEncode_float__convertToString_array() throws { + @Test func encodingFloatConvertToStringArray() throws { let encoder = JSValueEncoder( nonConformingFloatEncodingStategy: .convertToString( positiveInfinity: "pos", @@ -68,11 +60,11 @@ class JSValueEncoderNonConformingFloatTests: XCTestCase { ) let rawResult = try encoder.encode([Double.infinity, -.infinity, .nan]) - let result = try XCTUnwrap(rawResult as? [String]) - XCTAssertEqual(result, ["pos", "neg", "nan"]) + let result = try #require(rawResult as? [String]) + #expect(result == ["pos", "neg", "nan"]) } - func testEncode_float__convertToString_struct() throws { + @Test func encodingFloatConvertToStringStruct() throws { let encoder = JSValueEncoder( nonConformingFloatEncodingStategy: .convertToString( positiveInfinity: "pos", @@ -82,92 +74,104 @@ class JSValueEncoderNonConformingFloatTests: XCTestCase { ) var rawResult = try encoder.encode(Foo(number: .infinity)) - var result = try XCTUnwrap(rawResult as? [String: String]) - XCTAssertEqual(result, ["number": "pos"]) + var result = try #require(rawResult as? [String: String]) + #expect(result == ["number": "pos"]) rawResult = try encoder.encode(Foo(number: -.infinity)) - result = try XCTUnwrap(rawResult as? [String: String]) - XCTAssertEqual(result, ["number": "neg"]) + result = try #require(rawResult as? [String: String]) + #expect(result == ["number": "neg"]) rawResult = try encoder.encode(Foo(number: .nan)) - result = try XCTUnwrap(rawResult as? [String: String]) - XCTAssertEqual(result, ["number": "nan"]) + result = try #require(rawResult as? [String: String]) + #expect(result == ["number": "nan"]) } - func testEncode_float__throw_root() throws { + @Test func encodingFloatThrowRoot() throws { let encoder = JSValueEncoder(nonConformingFloatEncodingStategy: .throw) - XCTAssertThrowsError(try encoder.encode(Double.infinity)) + #expect(throws: EncodingError.self) { + try encoder.encode(Double.infinity) + } } - func testEncode_float__throw_array() throws { + @Test func encodingFloatThrowArray() throws { let encoder = JSValueEncoder(nonConformingFloatEncodingStategy: .throw) - XCTAssertThrowsError(try encoder.encode([Double.infinity, -.infinity, .nan])) + #expect(throws: EncodingError.self) { + try encoder.encode([Double.infinity, -.infinity, .nan]) + } } - func testEncode_float__throw_struct() throws { + @Test func encodingFloatThrowStruct() throws { let encoder = JSValueEncoder(nonConformingFloatEncodingStategy: .throw) - XCTAssertThrowsError(try encoder.encode(Foo(number: .infinity))) + #expect(throws: EncodingError.self) { + try encoder.encode(Foo(number: .infinity)) + } } } -class JSValueDecoderNonConformingFloatTests: XCTestCase { - func testDecode_float__default_root() throws { +struct JSValueDecoderNonConformingFloatTests { + @Test func decodingFloatDefaultRoot() throws { let decoder = JSValueDecoder() let result = try decoder.decode(Double.self, from: Double.infinity) - XCTAssertEqual(result, .infinity) + #expect(result == .infinity) } - func testDecode_float__default_array() throws { + @Test func decodingFloatDefaultArray() throws { let decoder = JSValueDecoder() let result = try decoder.decode([Double].self, from: [Double.infinity, Double.infinity]) - XCTAssertEqual(result, [.infinity, .infinity]) + #expect(result == [.infinity, .infinity]) } - func testDecode_float__default_struct() throws { + @Test func decodingFloatDefaultStruct() throws { let decoder = JSValueDecoder() let result = try decoder.decode(Foo.self, from: ["number": Double.infinity]) - XCTAssertEqual(result, .init(number: .infinity)) + #expect(result == .init(number: .infinity)) } - func testDecode_float__throw_root() throws { + @Test func decodingFloatThrowRoot() throws { let decoder = JSValueDecoder(nonConformingFloatDecodingStrategy: .throw) - XCTAssertThrowsError(try decoder.decode(Double.self, from: Double.infinity)) + #expect(throws: DecodingError.self) { + try decoder.decode(Double.self, from: Double.infinity) + } } - func testDecode_float__throw_array() throws { + @Test func decodingFloatThrowArray() throws { let decoder = JSValueDecoder(nonConformingFloatDecodingStrategy: .throw) - XCTAssertThrowsError(try decoder.decode([Double].self, from: [Double.infinity, Double.infinity])) + #expect(throws: DecodingError.self) { + try decoder.decode([Double].self, from: [Double.infinity, Double.infinity]) + } } - func testDecode_float__throw_struct() throws { + @Test func decodingFloatThrowStruct() throws { let decoder = JSValueDecoder(nonConformingFloatDecodingStrategy: .throw) - XCTAssertThrowsError(try decoder.decode(Foo.self, from: ["number": Double.infinity])) + #expect(throws: DecodingError.self) { + try decoder.decode(Foo.self, from: ["number": Double.infinity]) + } } - func testDecode_float__convertFromString_root() throws { + @Test func decodingFloatConvertFromStringRoot() throws { let decoder = JSValueDecoder(nonConformingFloatDecodingStrategy: .convertFromString(positiveInfinity: "pos", negativeInfinity: "neg", nan: "nan")) var result = try decoder.decode(Double.self, from: "pos") - XCTAssertEqual(result, .infinity) + #expect(result == .infinity) result = try decoder.decode(Double.self, from: "neg") - XCTAssertEqual(result, -.infinity) + #expect(result == -.infinity) result = try decoder.decode(Double.self, from: "nan") - XCTAssertTrue(result.isNaN) + #expect(result.isNaN) } - func testDecode_float__convertFromString_array() throws { + @Test func decodingFloatConvertFromStringArray() throws { let decoder = JSValueDecoder(nonConformingFloatDecodingStrategy: .convertFromString(positiveInfinity: "pos", negativeInfinity: "neg", nan: "nan")) let result = try decoder.decode([Double].self, from: ["pos", "neg", "nan"]) - XCTAssertEqual(result[0...1], [.infinity, -.infinity]) - XCTAssertTrue(result[2].isNaN) + #expect(result[0...1] == [.infinity, -.infinity]) + #expect(result[2].isNaN) } - func testDecode_float__convertFromString_struct() throws { + @Test func decodingFloatConvertFromStringStruct() throws { let decoder = JSValueDecoder(nonConformingFloatDecodingStrategy: .convertFromString(positiveInfinity: "pos", negativeInfinity: "neg", nan: "nan")) var result = try decoder.decode(Foo.self, from: ["number": "pos"]) - XCTAssertEqual(result, .init(number: .infinity)) + #expect(result == .init(number: .infinity)) result = try decoder.decode(Foo.self, from: ["number": "neg"]) - XCTAssertEqual(result, .init(number: -.infinity)) + #expect(result == .init(number: -.infinity)) result = try decoder.decode(Foo.self, from: ["number": "nan"]) - XCTAssertTrue(result.number.isNaN) + #expect(result.number.isNaN) } } diff --git a/ios/Tests/CapacitorTests/PluginCallAccessorTests.swift b/ios/Tests/CapacitorTests/PluginCallAccessorTests.swift new file mode 100644 index 0000000000..f89a221b86 --- /dev/null +++ b/ios/Tests/CapacitorTests/PluginCallAccessorTests.swift @@ -0,0 +1,76 @@ +import Foundation +import Testing +@testable import Capacitor + +struct PluginCallAccessorTests { + private static let referenceDate = Date(timeIntervalSinceReferenceDate: 632854800) + + private static func makeCall() -> CAPPluginCall { + let formatter = ISO8601DateFormatter() + let options: [String: Any] = [ + "testString": "foo", + "testDict": ["testSubkey": "sub value"], + "testFloat": 3.14159, + "testDateObject": referenceDate, + "testDateString": formatter.string(from: referenceDate), + "testBoolTrue": true, + "testBoolFalse": false + ] + return CAPPluginCall(callbackId: "test", methodName: "test", options: options, success: { _, _ in }, error: { _ in }) + } + + @Test func stringAccessor() { + let call = Self.makeCall() + #expect(call.getString("testString") == "foo") + #expect(call.getString("badString") == nil) + #expect(call.getString("badString", defaultValue: "default") == "default") + } + + @Test func dateObjectAccessor() { + let call = Self.makeCall() + #expect(call.getDate("testDateObject")?.timeIntervalSinceReferenceDate == 632854800) + #expect(call.getDate("badString") == nil) + + let defaultDate = Date() + #expect(call.getDate("badString", defaultValue: defaultDate) == defaultDate) + } + + @Test func dateStringAccessor() { + let call = Self.makeCall() + let objectValue = call.getDate("testDateObject") + let stringValue = call.getDate("testDateString") + #expect(objectValue != nil) + #expect(stringValue != nil) + #expect(objectValue == stringValue) + } + + @Test func objectAccessor() { + let call = Self.makeCall() + let value = call.getObject("testDict") + #expect(value?["testSubkey"] as? String == "sub value") + #expect(call.getObject("badString") == nil) + } + + @Test func numberAccessor() { + let call = Self.makeCall() + var value = call.getNumber("testFloat") + #expect(value == NSNumber(value: 3.14159)) + + value = call.getNumber("badString") + #expect(value == nil) + + value = call.getNumber("badString", defaultValue: 100) + #expect(value?.intValue == 100) + + value = call.getNumber("testBoolTrue") + #expect(value?.boolValue == true) + } + + @Test func boolAccessor() { + let call = Self.makeCall() + #expect(call.getBool("testBoolTrue", defaultValue: false) == true) + #expect(call.getBool("testBoolFalse", defaultValue: true) == false) + #expect(call.getBool("badString", defaultValue: true) == true) + #expect(call.getBool("badString", defaultValue: false) == false) + } +} diff --git a/ios/Capacitor/TestsHostApp/configurations/bad.json b/ios/Tests/CapacitorTests/Resources/configurations/bad.json similarity index 100% rename from ios/Capacitor/TestsHostApp/configurations/bad.json rename to ios/Tests/CapacitorTests/Resources/configurations/bad.json diff --git a/ios/Capacitor/TestsHostApp/configurations/flat.json b/ios/Tests/CapacitorTests/Resources/configurations/flat.json similarity index 100% rename from ios/Capacitor/TestsHostApp/configurations/flat.json rename to ios/Tests/CapacitorTests/Resources/configurations/flat.json diff --git a/ios/Capacitor/TestsHostApp/configurations/hidinglogs.json b/ios/Tests/CapacitorTests/Resources/configurations/hidinglogs.json similarity index 100% rename from ios/Capacitor/TestsHostApp/configurations/hidinglogs.json rename to ios/Tests/CapacitorTests/Resources/configurations/hidinglogs.json diff --git a/ios/Capacitor/TestsHostApp/configurations/hierarchy.json b/ios/Tests/CapacitorTests/Resources/configurations/hierarchy.json similarity index 100% rename from ios/Capacitor/TestsHostApp/configurations/hierarchy.json rename to ios/Tests/CapacitorTests/Resources/configurations/hierarchy.json diff --git a/ios/Capacitor/TestsHostApp/configurations/nonjson.json b/ios/Tests/CapacitorTests/Resources/configurations/nonjson.json similarity index 100% rename from ios/Capacitor/TestsHostApp/configurations/nonjson.json rename to ios/Tests/CapacitorTests/Resources/configurations/nonjson.json diff --git a/ios/Capacitor/TestsHostApp/configurations/server.json b/ios/Tests/CapacitorTests/Resources/configurations/server.json similarity index 100% rename from ios/Capacitor/TestsHostApp/configurations/server.json rename to ios/Tests/CapacitorTests/Resources/configurations/server.json diff --git a/ios/Tests/CapacitorTests/RouterTests.swift b/ios/Tests/CapacitorTests/RouterTests.swift new file mode 100644 index 0000000000..2a33861a17 --- /dev/null +++ b/ios/Tests/CapacitorTests/RouterTests.swift @@ -0,0 +1,27 @@ +import Testing +@testable import Capacitor + +struct RouterTests { + @Test func routerReturnsIndexWhenProvidedEmptyPath() { + checkRouter(path: "", expected: "/index.html") + } + + @Test func routerReturnsIndexWhenProvidedPathWithoutExtension() { + checkRouter(path: "/a/valid/path/no/ext", expected: "/index.html") + } + + @Test func routerReturnsPathWhenProvidedValidPath() { + checkRouter(path: "/a/valid/path.ext", expected: "/a/valid/path.ext") + } + + @Test func routerReturnsPathWhenProvidedValidPathWithExtensionAndSpaces() { + checkRouter(path: "/a/valid/file path.ext", expected: "/a/valid/file path.ext") + } + + private func checkRouter(path: String, expected: String) { + var router = CapacitorRouter() + #expect(router.route(for: path) == expected) + router.basePath = "/A/Route" + #expect(router.route(for: path) == "/A/Route" + expected) + } +} diff --git a/ios/Capacitor/CodableTests/SuperCodableTests.swift b/ios/Tests/CapacitorTests/SuperCodableTests.swift similarity index 60% rename from ios/Capacitor/CodableTests/SuperCodableTests.swift rename to ios/Tests/CapacitorTests/SuperCodableTests.swift index 7a7035809d..99f4fe1d33 100644 --- a/ios/Capacitor/CodableTests/SuperCodableTests.swift +++ b/ios/Tests/CapacitorTests/SuperCodableTests.swift @@ -1,61 +1,54 @@ -// -// SuperCodableTests.swift -// CodableTests -// -// Created by Steven Sherry on 12/10/23. -// Copyright © 2023 Drifty Co. All rights reserved. -// - -import XCTest +import Foundation +import Testing import Capacitor -final class SuperCodableTests: XCTestCase { - // MARK: Keyed Super Encoding/Decoding - func testEncode__when_given_a_value_that_encodes_to_a_keyed_superEncoder_without_specifying_a_key__it_encodes_the_super_container_with_the_string_key_super() throws { +struct SuperCodableTests { + @Test func encodingKeyedSuperEncoderWithoutKeyUsesDefaultKey() throws { let sut = JSValueEncoder() let value = KeyedSubSuper(bool: true) let encoded = try sut.encodeJSObject(value) - let bool = try XCTUnwrap(encoded["bool"] as? Bool) - XCTAssertTrue(bool) - let superObject = try XCTUnwrap(encoded["super"] as? JSObject) - let number = try XCTUnwrap(superObject["number"] as? NSNumber) - XCTAssertEqual(0, number) - let string = try XCTUnwrap(superObject["string"] as? String) - XCTAssertEqual("empty", string) + let bool = try #require(encoded["bool"] as? Bool) + #expect(bool == true) + let superObject = try #require(encoded["super"] as? JSObject) + let number = try #require(superObject["number"] as? NSNumber) + #expect(number == 0) + let string = try #require(superObject["string"] as? String) + #expect(string == "empty") } - func testEncode__when_given_a_value_that_encodes_to_a_keyed_superEncoder_with_a_specific_key__it_encodes_the_super_container_with_the_provided_key() throws { + + @Test func encodingKeyedSuperEncoderWithSpecificKey() throws { let sut = JSValueEncoder() let value = KeyedSubSuperKeyed(bool: false) value.number = 5 value.string = "encoding" let encoded = try sut.encodeJSObject(value) - let bool = try XCTUnwrap(encoded["bool"] as? Bool) - XCTAssertFalse(bool) - let superObject = try XCTUnwrap(encoded["info"] as? JSObject) - let number = try XCTUnwrap(superObject["number"] as? NSNumber) - XCTAssertEqual(5, number) - let string = try XCTUnwrap(superObject["string"] as? String) - XCTAssertEqual("encoding", string) + let bool = try #require(encoded["bool"] as? Bool) + #expect(bool == false) + let superObject = try #require(encoded["info"] as? JSObject) + let number = try #require(superObject["number"] as? NSNumber) + #expect(number == 5) + let string = try #require(superObject["string"] as? String) + #expect(string == "encoding") } - func testEncode__when_given_a_value_that_encodes_its_superclass_without_a_superEncoder__it_encodes_the_entire_structure_flattened() throws { + @Test func encodingSuperclassWithoutSuperEncoderFlattenStructure() throws { let sut = JSValueEncoder() let value = KeyedSubSuperFlat(bool: true) value.number = 10 value.string = "flattened" let encoded = try sut.encodeJSObject(value) - let bool = try XCTUnwrap(encoded["bool"] as? Bool) - XCTAssertTrue(bool) - let number = try XCTUnwrap(encoded["number"] as? NSNumber) - XCTAssertEqual(10, number) - let string = try XCTUnwrap(encoded["string"] as? String) - XCTAssertEqual("flattened", string) + let bool = try #require(encoded["bool"] as? Bool) + #expect(bool == true) + let number = try #require(encoded["number"] as? NSNumber) + #expect(number == 10) + let string = try #require(encoded["string"] as? String) + #expect(string == "flattened") } - func testDecode__when_given_a_value_that_decodes_its_superclass_without_specifying_a_key__it_will_attempt_to_decode_the_super_container_from_the_super_key() throws { + @Test func decodingSuperclassWithoutKeyUsesSuperKey() throws { let sut = JSValueDecoder() let value: JSObject = [ "super": [ @@ -66,12 +59,12 @@ final class SuperCodableTests: XCTestCase { ] let decoded = try sut.decode(KeyedSubSuper.self, from: value) - XCTAssertTrue(decoded.bool) - XCTAssertEqual(decoded.number, 5) - XCTAssertEqual(decoded.string, "super decoding") + #expect(decoded.bool == true) + #expect(decoded.number == 5) + #expect(decoded.string == "super decoding") } - func testDecode__when_given_a_value_that_decodes_its_superclass_with_a_specific_key__it_will_attempt_to_decode_the_super_container_from_the_specified_key() throws { + @Test func decodingSuperclassWithSpecificKey() throws { let sut = JSValueDecoder() let value: JSObject = [ "info": [ @@ -82,12 +75,12 @@ final class SuperCodableTests: XCTestCase { ] let decoded = try sut.decode(KeyedSubSuperKeyed.self, from: value) - XCTAssertFalse(decoded.bool) - XCTAssertEqual(decoded.number, 9) - XCTAssertEqual(decoded.string, "info decoding") + #expect(decoded.bool == false) + #expect(decoded.number == 9) + #expect(decoded.string == "info decoding") } - func testDecode__when_given_a_value_that_decodes_its_superclass_without_a_superContainer__it_will_attempt_to_decode_a_flat_structure() throws { + @Test func decodingSuperclassWithoutSuperContainerDecodeFlatStructure() throws { let sut = JSValueDecoder() let value: JSObject = [ "number": 20, @@ -96,35 +89,34 @@ final class SuperCodableTests: XCTestCase { ] let decoded = try sut.decode(KeyedSubSuperFlat.self, from: value) - XCTAssertTrue(decoded.bool) - XCTAssertEqual(decoded.number, 20) - XCTAssertEqual(decoded.string, "flat decoding") + #expect(decoded.bool == true) + #expect(decoded.number == 20) + #expect(decoded.string == "flat decoding") } - // MARK: Unkeyed Super Encoding/Decoding - func testEncode__when_given_a_value_that_encodes_its_superclass_with_a_superContainer__it_will_encode_the_super_container_as_a_nested_array() throws { + @Test func encodingUnkeyedSuperEncoderNestedArray() throws { let sut = JSValueEncoder() let value = UnkeyedSubSuper(bool: true) value.number = -3 value.string = "unkeyed encoding" - let encoded = try XCTUnwrap(try sut.encode(value) as? JSArray) - XCTAssertEqual(encoded[0] as? Bool, true) - let nested = try XCTUnwrap(encoded[1] as? JSArray) - XCTAssertEqual(nested[0] as? NSNumber, -3) - XCTAssertEqual(nested[1] as? String, "unkeyed encoding") + let encoded = try #require(try sut.encode(value) as? JSArray) + #expect(encoded[0] as? Bool == true) + let nested = try #require(encoded[1] as? JSArray) + #expect(nested[0] as? NSNumber == -3) + #expect(nested[1] as? String == "unkeyed encoding") } - func testDecode__when_given_a_type_that_decodes_its_superclass_with_a_superContainer__it_will_decode_the_superclass_as_a_nested_array() throws { + @Test func decodingUnkeyedSuperEncoderNestedArray() throws { let sut = JSValueDecoder() let value: JSArray = [ true, [4, "unkeyed decoding"] ] let decoded = try sut.decode(UnkeyedSubSuper.self, from: value) - XCTAssertTrue(decoded.bool) - XCTAssertEqual(decoded.number, 4) - XCTAssertEqual(decoded.string, "unkeyed decoding") + #expect(decoded.bool == true) + #expect(decoded.number == 4) + #expect(decoded.string == "unkeyed decoding") } } diff --git a/ios/Tests/CapacitorTests/URLCodableTests.swift b/ios/Tests/CapacitorTests/URLCodableTests.swift new file mode 100644 index 0000000000..1b5c7645a1 --- /dev/null +++ b/ios/Tests/CapacitorTests/URLCodableTests.swift @@ -0,0 +1,58 @@ +import Foundation +import Testing +import Capacitor + +private let urlString = "https://capacitorjs.com" +private let url = URL(string: urlString)! + +private struct Website: Codable, Equatable { + var url: URL +} + +struct JSValueDecoderURLTests { + let decoder = JSValueDecoder() + + @Test func decodingURLRoot() throws { + let result = try decoder.decode(URL.self, from: urlString) + #expect(result == url) + } + + @Test func decodingURLArray() throws { + let result = try decoder.decode([URL].self, from: [urlString, urlString]) + #expect(result == [url, url]) + } + + @Test func decodingURLStruct() throws { + let result = try decoder.decode(Website.self, from: ["url": urlString]) + #expect(result == .init(url: url)) + } + + @Test func decodingURLFailsWithInvalidString() throws { + let decoder = JSValueDecoder() + #expect(throws: DecodingError.self) { + try decoder.decode(URL.self, from: "🐞://🐞.com/🐞") + } + } +} + +struct JSValueEncoderURLTests { + let encoder = JSValueEncoder() + + @Test func encodingURLRoot() throws { + let rawResult = try encoder.encode(url) + let result = try #require(rawResult as? String) + #expect(result == urlString) + } + + @Test func encodingURLArray() throws { + let rawResult = try encoder.encode([url, url]) + let result = try #require(rawResult as? [String]) + #expect(result == [urlString, urlString]) + } + + @Test func encodingURLStruct() throws { + let rawResult = try encoder.encode(Website(url: url)) + let result = try #require(rawResult as? [String: String]) + #expect(result == ["url": urlString]) + } +} diff --git a/ios/package.json b/ios/package.json index 2bc19350bb..711ecf080a 100644 --- a/ios/package.json +++ b/ios/package.json @@ -13,16 +13,15 @@ "url": "https://github.com/ionic-team/capacitor/issues" }, "files": [ - "Capacitor/Capacitor/", - "CapacitorCordova/CapacitorCordova/", + "Sources/", "Capacitor.podspec", "CapacitorCordova.podspec", "scripts/pods_helpers.rb" ], "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 17,OS=26.0.1' && cd ..", - "xc:build:CapacitorCordova": "cd Capacitor && xcodebuild clean build -workspace Capacitor.xcworkspace -scheme Cordova && cd .." + "verify": "npm run xc:build && npm run xc:test", + "xc:build": "cd .. && xcodebuild build -scheme Capacitor-Package -destination 'generic/platform=iOS Simulator'", + "xc:test": "cd .. && xcodebuild test -scheme Capacitor-Package -destination 'platform=iOS Simulator,name=iPhone 17,OS=26.5' -collect-test-diagnostics never" }, "peerDependencies": { "@capacitor/core": "^9.0.0-alpha.6" diff --git a/swiftlint.config.js b/swiftlint.config.js index 59e40b8907..6c51f7e913 100644 --- a/swiftlint.config.js +++ b/swiftlint.config.js @@ -1,5 +1,5 @@ module.exports = { ...require('@ionic/swiftlint-config'), included: ['${PWD}/ios', '${PWD}/ios-pods-template', '${PWD}/ios-spm-template'], - excluded: ['${PWD}/ios/Capacitor/CapacitorTests', '${PWD}/ios/Capacitor/TestsHostApp', '${PWD}/ios/Frameworks'], + excluded: ['${PWD}/ios/Tests/CapacitorTests', '${PWD}/ios/Frameworks'], };