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..f118252d0a 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/Package.swift b/Package.swift new file mode 100644 index 0000000000..dea7048ce4 --- /dev/null +++ b/Package.swift @@ -0,0 +1,89 @@ +// swift-tools-version: 6.0 +import PackageDescription + +let package = Package( + name: "Capacitor", + platforms: [.iOS(.v16)], + products: [ + .library( + name: "Capacitor", + targets: ["Capacitor", "CapacitorObjC", "CapacitorObjCShims"] + ), + .library( + name: "Cordova", + targets: ["Cordova"] + ), + .library( + name: "CapacitorCordova", + targets: ["Cordova", "CapacitorCordova"] + ) + ], + targets: [ + .target( + name: "CapacitorObjC", + path: "ios/Sources/CapacitorObjC", + publicHeadersPath: "include", + cSettings: [ + .headerSearchPath("include"), + .headerSearchPath("include/Capacitor") + ] + ), + .target( + name: "Capacitor", + dependencies: ["CapacitorObjC"], + path: "ios/Sources/Capacitor", + resources: [ + .copy("assets"), + .copy("PrivacyInfo.xcprivacy") + ], + swiftSettings: [.swiftLanguageMode(.v5)] + ), + .target( + name: "CapacitorObjCShims", + dependencies: ["Capacitor"], + path: "ios/Sources/CapacitorObjCShims", + exclude: ["Capacitor.modulemap"], + publicHeadersPath: "include", + cSettings: [ + .headerSearchPath("include"), + .headerSearchPath("include/Capacitor") + ] + ), + .target( + name: "Cordova", + path: "ios/Sources/Cordova", + exclude: ["CapacitorCordova.modulemap"], + resources: [.copy("PrivacyInfo.xcprivacy")], + publicHeadersPath: "include", + cSettings: [ + .headerSearchPath("include"), + .headerSearchPath("include/Cordova") + ], + linkerSettings: [ + .linkedFramework("UIKit"), + .linkedFramework("WebKit"), + .linkedFramework("MobileCoreServices"), + .linkedFramework("CFNetwork") + ] + ), + .target( + name: "CapacitorCordova", + dependencies: ["Capacitor", "Cordova"], + path: "ios/Sources/CapacitorCordova", + swiftSettings: [.swiftLanguageMode(.v5)] + ), + .testTarget( + name: "CapacitorTests", + dependencies: ["Capacitor"], + path: "ios/Tests/CapacitorTests", + resources: [.copy("Resources/configurations")], + swiftSettings: [.swiftLanguageMode(.v5)] + ), + .testTarget( + name: "CapacitorObjCTests", + dependencies: ["CapacitorObjCShims"], + path: "ios/Tests/CapacitorObjCTests" + ) + ], + swiftLanguageModes: [.v5] +) diff --git a/cli/src/declarations.ts b/cli/src/declarations.ts index 8d1a40e627..7787b01ebb 100644 --- a/cli/src/declarations.ts +++ b/cli/src/declarations.ts @@ -575,6 +575,52 @@ export interface CapacitorConfig { * @since 8.4.0 */ packageOptions?: { [pluginId: string]: PackageOptions }; + + /** + * Override which Capacitor Swift package the generated `Package.swift` depends on. + * + * By default the generated package pins the git tag matching the installed + * `@capacitor/ios` version, which is correct for both stable and pre-release versions + * and matches what CocoaPods resolves. + * + * Set this only when developing against an unreleased Capacitor, such as a local + * checkout or a feature branch. Exactly one of `path`, `branch`, `revision`, `exact`, + * or `from` must be set. `path` points at the repository root (the directory containing + * `Package.swift`) and may be relative to the app. + * + * The `CAPACITOR_IOS_PACKAGE` environment variable takes precedence over this setting, + * so a checkout can be redirected without editing committed configuration. + * + * Note that `branch` and `revision` builds are not reproducible and decouple the native + * code from the `@capacitor/core` JavaScript bridge it is versioned against. + * + * @since 9.0.0 + * @example { "path": "../capacitor" } + * @example { "branch": "next" } + */ + capacitorPackage?: { + /** + * Repository to fetch from. Ignored when `path` is set. + * + * @default 'https://github.com/ionic-team/capacitor' + */ + url?: string; + + /** Path to a local Capacitor repository root. */ + path?: string; + + /** Branch to track. */ + branch?: string; + + /** Exact commit to pin. */ + revision?: string; + + /** Exact version tag to pin. */ + exact?: string; + + /** Minimum version tag, allowing compatible upgrades. */ + from?: string; + }; }; }; }; diff --git a/cli/src/ios/update.ts b/cli/src/ios/update.ts index ca85595c13..29873c37db 100644 --- a/cli/src/ios/update.ts +++ b/cli/src/ios/update.ts @@ -12,6 +12,11 @@ import type { Plugin } from '../plugin'; import { PluginType, getPluginType, getPlugins, printPlugins } from '../plugin'; import { copy as copyTask } from '../tasks/copy'; import { setAllStringIn } from '../tasks/migrate'; +import { + findCapacitorDependencyVersion, + resolveCapacitorPackage, + rewriteCapacitorDependency, +} from '../util/capacitor-package'; import { generateCordovaPodspecs, generateCordovaPackageFiles, @@ -65,16 +70,29 @@ async function updatePluginFiles(config: Config, plugins: Plugin[], deployment: } const validSPMPackages = await checkPluginsForPackageSwift(config, plugins); + const iosPlatformVersion = await getCapacitorPackageVersion(config, config.ios.name); + const majorCapVersion = major(iosPlatformVersion); + const capacitorPackage = await resolveCapacitorPackage(config, 'from'); await Promise.all( validSPMPackages.map(async (plugin) => { - const iosPlatformVersion = await getCapacitorPackageVersion(config, config.ios.name); const packageSwiftPath = join(plugin.rootPath, 'Package.swift'); let content = await readFile(packageSwiftPath, { encoding: 'utf-8' }); - const regex = new RegExp( - 'url:\\s*"https://github.com/ionic-team/capacitor-swift-pm\\.git",\\s*from:\\s*"([^"]+)"', - ); - const version = content.match(regex)?.[1]; - const majorCapVersion = major(iosPlatformVersion); + const version = findCapacitorDependencyVersion(content); + + if (version && major(version) != majorCapVersion) { + logger.warn(`${plugin.id} is built for Capacitor ${major(version)}, it might cause issues`); + } + + if (capacitorPackage.sourceBased) { + // The plugin has to resolve to the same package identity as the app, or SPM ends up with + // two packages that both vend a Capacitor product. + const rewritten = rewriteCapacitorDependency(content, capacitorPackage, plugin.rootPath); + if (rewritten !== content) { + await writeFile(packageSwiftPath, rewritten); + } + return; + } + if (version && major(version) != majorCapVersion) { const preCapVersion = prerelease(iosPlatformVersion); const forceVersion = preCapVersion ? iosPlatformVersion : `${majorCapVersion}.0.0`; @@ -85,7 +103,6 @@ async function updatePluginFiles(config: Config, plugins: Plugin[], deployment: ` from: "${forceVersion}"`, ); await writeFile(packageSwiftPath, content); - logger.warn(`${plugin.id} is built for Capacitor ${major(version)}, it might cause issues`); } }), ); diff --git a/cli/src/util/capacitor-package.ts b/cli/src/util/capacitor-package.ts new file mode 100644 index 0000000000..c1615c1c5f --- /dev/null +++ b/cli/src/util/capacitor-package.ts @@ -0,0 +1,297 @@ +import { existsSync } from 'fs-extra'; +import { isAbsolute, relative, resolve } from 'path'; +import { major, valid } from 'semver'; + +import { getCapacitorPackageVersion } from '../common'; +import type { Config } from '../definitions'; +import { fatal } from '../errors'; + +import { convertToUnixPath } from './fs'; + +/** Capacitor 9 and up builds the iOS platform from source out of the main repo. */ +const SOURCE_PACKAGE_MAJOR = 9; +const SOURCE_PACKAGE_URL = 'https://github.com/ionic-team/capacitor'; +const SOURCE_PACKAGE_IDENTITY = 'capacitor'; + +/** Before Capacitor 9 the platform was consumed as a prebuilt xcframework from a separate repo. */ +const BINARY_PACKAGE_URL = 'https://github.com/ionic-team/capacitor-swift-pm.git'; +const BINARY_PACKAGE_IDENTITY = 'capacitor-swift-pm'; + +const ENV_OVERRIDE = 'CAPACITOR_IOS_PACKAGE'; +const REQUIREMENT_KEYS = ['path', 'branch', 'revision', 'exact', 'from'] as const; + +export type CapacitorRequirement = + | { kind: 'path'; absolutePath: string } + | { kind: 'branch'; branch: string } + | { kind: 'revision'; revision: string } + | { kind: 'exact'; version: string } + | { kind: 'from'; version: string }; + +export interface CapacitorPackage { + /** SPM package identity, as referenced by `.product(name:package:)`. */ + identity: string; + /** Product providing the Cordova compatibility layer. */ + cordovaProduct: string; + /** True when this resolves to the source package (Capacitor 9+). */ + sourceBased: boolean; + url: string; + requirement: CapacitorRequirement; +} + +/** + * Resolves which Capacitor Swift package generated `Package.swift` files should depend on. + * + * Precedence, most specific first: + * 1. the `CAPACITOR_IOS_PACKAGE` environment variable + * 2. `experimental.ios.spm.capacitorPackage` in the Capacitor config + * 3. the git tag matching the installed `@capacitor/ios` version + * + * The environment variable deliberately outranks the config file so a checkout can be pointed at a + * local or branch build without editing (and risking committing) the app's configuration. + * + * `legacyRequirement` only applies to pre-9 projects, where it preserves each caller's existing + * requirement style. Source-based projects always pin `exact`, because the app package and any + * generated plugin packages must agree: a prerelease such as `9.0.0-alpha.6` does not satisfy a + * `from:` range, so mixing the two styles fails to resolve. + */ +export async function resolveCapacitorPackage( + config: Config, + legacyRequirement: 'exact' | 'from' = 'exact', +): Promise { + const version = await getCapacitorPackageVersion(config, config.ios.name); + + if (major(version) < SOURCE_PACKAGE_MAJOR) { + return { + identity: BINARY_PACKAGE_IDENTITY, + cordovaProduct: 'Cordova', + sourceBased: false, + url: BINARY_PACKAGE_URL, + requirement: { kind: legacyRequirement, version }, + }; + } + + const override = resolveOverride(config); + + return { + identity: SOURCE_PACKAGE_IDENTITY, + cordovaProduct: 'CapacitorCordova', + sourceBased: true, + url: override?.url ?? SOURCE_PACKAGE_URL, + requirement: override?.requirement ?? { kind: 'exact', version }, + }; +} + +/** Renders the `.package(...)` entry, with any path made relative to the file being written. */ +export function renderCapacitorPackage(pkg: CapacitorPackage, fromDir: string): string { + if (pkg.requirement.kind === 'path') { + const relPath = convertToUnixPath(relative(fromDir, pkg.requirement.absolutePath)); + // Pin the identity: for a path dependency SPM would otherwise derive it from the directory + // name, which breaks `.product(package:)` when the checkout is not named "capacitor". + return `.package(name: "${pkg.identity}", path: "${relPath}")`; + } + + return `.package(url: "${pkg.url}", ${renderRequirement(pkg.requirement)})`; +} + +/** + * Repoints an existing `Package.swift` at the resolved Capacitor package. + * + * Third-party plugins ship a dependency on `capacitor-swift-pm`. From Capacitor 9 the app depends + * on the source package instead, and SPM treats the two as separate identities that both vend a + * `Capacitor` product — so a plugin left untouched would either fail to resolve or link a second + * copy of the framework. Rewriting keeps the whole graph on one identity. + */ +export function rewriteCapacitorDependency(content: string, pkg: CapacitorPackage, fromDir: string): string { + let rewritten = replacePackageCalls(content, renderCapacitorPackage(pkg, fromDir)); + + for (const identity of [BINARY_PACKAGE_IDENTITY, SOURCE_PACKAGE_IDENTITY]) { + rewritten = rewritten.split(`package: "${identity}"`).join(`package: "${pkg.identity}"`); + } + + return rewritten; +} + +/** Reads the version an existing `Package.swift` pins Capacitor to, if it pins one. */ +export function findCapacitorDependencyVersion(content: string): string | undefined { + for (const call of findPackageCalls(content)) { + if (!referencesCapacitor(call.text)) { + continue; + } + const match = call.text.match(/(?:from|exact):\s*"([^"]+)"/); + if (match) { + return match[1]; + } + } + return undefined; +} + +function referencesCapacitor(call: string): boolean { + return call.includes(BINARY_PACKAGE_IDENTITY) || call.includes(`${SOURCE_PACKAGE_URL}`); +} + +/** Locates `.package(...)` calls, tracking paren depth so nested calls don't terminate the match. */ +function findPackageCalls(content: string): { start: number; end: number; text: string }[] { + const calls: { start: number; end: number; text: string }[] = []; + const marker = '.package('; + let index = content.indexOf(marker); + + while (index !== -1) { + let depth = 0; + let inString = false; + let cursor = index + marker.length - 1; + + for (; cursor < content.length; cursor++) { + const char = content[cursor]; + if (inString) { + if (char === '\\') { + cursor++; + } else if (char === '"') { + inString = false; + } + continue; + } + if (char === '"') { + inString = true; + } else if (char === '(') { + depth++; + } else if (char === ')') { + depth--; + if (depth === 0) { + break; + } + } + } + + if (depth !== 0) { + break; + } + + calls.push({ start: index, end: cursor + 1, text: content.slice(index, cursor + 1) }); + index = content.indexOf(marker, cursor + 1); + } + + return calls; +} + +function replacePackageCalls(content: string, rendered: string): string { + let result = content; + + // Walk backwards so earlier offsets stay valid as we splice. + for (const call of findPackageCalls(content).reverse()) { + if (referencesCapacitor(call.text)) { + result = result.slice(0, call.start) + rendered + result.slice(call.end); + } + } + + return result; +} + +function renderRequirement(requirement: CapacitorRequirement): string { + switch (requirement.kind) { + case 'branch': + return `branch: "${requirement.branch}"`; + case 'revision': + return `revision: "${requirement.revision}"`; + case 'exact': + return `exact: "${requirement.version}"`; + case 'from': + return `from: "${requirement.version}"`; + case 'path': + throw new Error('path requirements are rendered by renderCapacitorPackage'); + } +} + +function resolveOverride(config: Config): { url?: string; requirement: CapacitorRequirement } | undefined { + const baseDir = config.app.rootDir; + + const fromEnv = process.env[ENV_OVERRIDE]?.trim(); + if (fromEnv) { + return { requirement: parseRequirementSpec(fromEnv, baseDir) }; + } + + const fromConfig = config.app.extConfig.experimental?.ios?.spm?.capacitorPackage; + if (!fromConfig) { + return undefined; + } + + const provided = REQUIREMENT_KEYS.filter((key) => fromConfig[key] !== undefined); + if (provided.length === 0) { + fatal( + `experimental.ios.spm.capacitorPackage must set one of: ${REQUIREMENT_KEYS.join(', ')}.\n` + + `Remove the entry to use the version matching the installed @capacitor/ios.`, + ); + } + if (provided.length > 1) { + fatal( + `experimental.ios.spm.capacitorPackage sets more than one of: ${provided.join(', ')}.\n` + `Only one may be set.`, + ); + } + + const key = provided[0]; + const value = String(fromConfig[key]); + + if (key === 'path') { + if (fromConfig.url !== undefined) { + fatal(`experimental.ios.spm.capacitorPackage cannot set both "url" and "path".`); + } + return { requirement: pathRequirement(value, baseDir) }; + } + + return { url: fromConfig.url, requirement: { kind: key, ...requirementValue(key, value) } as CapacitorRequirement }; +} + +function requirementValue(key: (typeof REQUIREMENT_KEYS)[number], value: string) { + switch (key) { + case 'branch': + return { branch: value }; + case 'revision': + return { revision: value }; + default: + return { version: value }; + } +} + +/** + * Parses a `CAPACITOR_IOS_PACKAGE` value. Accepts an explicit `kind:value` form, or infers `path` + * for anything path-shaped and `exact` for a bare version. + */ +function parseRequirementSpec(spec: string, baseDir: string): CapacitorRequirement { + const separator = spec.indexOf(':'); + if (separator > 0) { + const key = spec.slice(0, separator); + const value = spec.slice(separator + 1); + if ((REQUIREMENT_KEYS as readonly string[]).includes(key)) { + if (key === 'path') { + return pathRequirement(value, baseDir); + } + return { + kind: key, + ...requirementValue(key as (typeof REQUIREMENT_KEYS)[number], value), + } as CapacitorRequirement; + } + } + + if (spec.startsWith('.') || isAbsolute(spec)) { + return pathRequirement(spec, baseDir); + } + + if (valid(spec)) { + return { kind: 'exact', version: spec }; + } + + return fatal( + `Could not understand ${ENV_OVERRIDE}="${spec}".\n` + + `Expected one of ${REQUIREMENT_KEYS.map((k) => `${k}:`).join(', ')}, a path, or a version.`, + ); +} + +function pathRequirement(value: string, baseDir: string): CapacitorRequirement { + const absolutePath = resolve(baseDir, value); + if (!existsSync(resolve(absolutePath, 'Package.swift'))) { + fatal( + `No Package.swift found at ${absolutePath}.\n` + + `A local Capacitor package must point at the repository root, not the ios directory.`, + ); + } + return { kind: 'path', absolutePath }; +} diff --git a/cli/src/util/cordova-ios.ts b/cli/src/util/cordova-ios.ts index 4cba270999..30c0e4072b 100644 --- a/cli/src/util/cordova-ios.ts +++ b/cli/src/util/cordova-ios.ts @@ -1,7 +1,6 @@ import { copy, readFile, writeFile, remove } from 'fs-extra'; import { join } from 'path'; -import { getCapacitorPackageVersion } from '../common'; import { needsStaticPod } from '../cordova'; import type { Config } from '../definitions'; import { getMajoriOSVersion } from '../ios/common'; @@ -16,7 +15,7 @@ import { resolvePlugin, } from '../plugin'; import type { Plugin } from '../plugin'; -import { setAllStringIn } from '../tasks/migrate'; +import { renderCapacitorPackage, resolveCapacitorPackage, rewriteCapacitorDependency } from '../util/capacitor-package'; import { extractTemplate } from '../util/template'; const platform = 'ios'; @@ -475,7 +474,7 @@ ${entries.join(',\n')} } export async function generateCordovaPackageFile(p: Plugin, config: Config): Promise { - const iosPlatformVersion = await getCapacitorPackageVersion(config, config.ios.name); + const capacitorPackage = await resolveCapacitorPackage(config, 'from'); const iosVersion = getMajoriOSVersion(config); const headerFiles = getPlatformElement(p, platform, 'header-file'); let headersText = ''; @@ -489,13 +488,8 @@ export async function generateCordovaPackageFile(p: Plugin, config: Config): Pro 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`).replaceAll(`cordova-ios`, capacitorPackage.identity); + content = rewriteCapacitorDependency(content, capacitorPackage, p.rootPath); await writeFile(packageSwiftPath, content); } else { const resources = getPlatformElement(p, platform, 'resource-file'); @@ -535,13 +529,13 @@ let package = Package( ) ], dependencies: [ - .package(url: "https://github.com/ionic-team/capacitor-swift-pm.git", from: "${iosPlatformVersion}")${packageText} + ${renderCapacitorPackage(capacitorPackage, join(config.ios.cordovaPluginsDirAbs, 'sources', p.name))}${packageText} ], targets: [ .target( name: "${p.name}", dependencies: [ - .product(name: "Cordova", package: "capacitor-swift-pm")${binaryDepsText}${productText} + .product(name: "Cordova", package: "${capacitorPackage.identity}")${binaryDepsText}${productText} ], path: "."${resourcesText}${headersText}${cSettingsText}${linkerSettingsText} )${binaryTargetsText} diff --git a/cli/src/util/spm.ts b/cli/src/util/spm.ts index d3c1d113d3..47bf559aeb 100644 --- a/cli/src/util/spm.ts +++ b/cli/src/util/spm.ts @@ -5,7 +5,6 @@ import type { PlistObject } from 'plist'; import { build, parse } from 'plist'; import { extract } from 'tar'; -import { getCapacitorPackageVersion } from '../common'; import { getCordovaPlugins } from '../cordova'; import type { Config } from '../definitions'; import { fatal } from '../errors'; @@ -13,6 +12,7 @@ import { getMajoriOSVersion } from '../ios/common'; import { logger } from '../log'; import type { Plugin } from '../plugin'; import { getPlatformElement, getPluginPlatform, getPluginType, PluginType } from '../plugin'; +import { renderCapacitorPackage, resolveCapacitorPackage } from '../util/capacitor-package'; import { convertToUnixPath } from '../util/fs'; import { runCommand } from '../util/subprocess'; @@ -99,12 +99,13 @@ export async function removeCocoapodsFiles(config: Config): Promise { } export async function generatePackageText(config: Config, plugins: Plugin[]): Promise { - const iosPlatformVersion = await getCapacitorPackageVersion(config, config.ios.name); const iosVersion = getMajoriOSVersion(config); const cordovaPlugins = await getCordovaPlugins(config, 'ios'); const enableCordova = cordovaPlugins.length > 0 || config.app.forceCordova; const packageTraits = config.app.extConfig.experimental?.ios?.spm?.packageTraits ?? {}; const packageOptions = config.app.extConfig.experimental?.ios?.spm?.packageOptions ?? {}; + const capacitorPackage = await resolveCapacitorPackage(config); + const spmDirectory = join(config.ios.nativeProjectDirAbs, 'CapApp-SPM'); const swiftToolsVersion = config.app.extConfig.experimental?.ios?.spm?.swiftToolsVersion ?? '5.9'; let packageSwiftText = `// swift-tools-version: ${swiftToolsVersion} @@ -120,7 +121,7 @@ let package = Package( targets: ["CapApp-SPM"]) ], dependencies: [ - .package(url: "https://github.com/ionic-team/capacitor-swift-pm.git", exact: "${iosPlatformVersion}")`; + ${renderCapacitorPackage(capacitorPackage, spmDirectory)}`; for (const plugin of plugins) { if (getPluginType(plugin, config.ios.name) === PluginType.Cordova) { @@ -165,10 +166,10 @@ let package = Package( .target( name: "CapApp-SPM", dependencies: [ - .product(name: "Capacitor", package: "capacitor-swift-pm")`; + .product(name: "Capacitor", package: "${capacitorPackage.identity}")`; if (enableCordova) { - packageSwiftText += `,\n .product(name: "Cordova", package: "capacitor-swift-pm")`; + packageSwiftText += `,\n .product(name: "${capacitorPackage.cordovaProduct}", package: "${capacitorPackage.identity}")`; } for (const plugin of plugins) { diff --git a/cli/test/capacitor-package.spec.ts b/cli/test/capacitor-package.spec.ts new file mode 100644 index 0000000000..80474bbb5d --- /dev/null +++ b/cli/test/capacitor-package.spec.ts @@ -0,0 +1,270 @@ +import { mkdirSync, mkdtempSync, writeFileSync } from 'fs'; +import { tmpdir } from 'os'; +import { join, resolve } from 'path'; + +import type { Config } from '../src/definitions'; +import { + findCapacitorDependencyVersion, + renderCapacitorPackage, + resolveCapacitorPackage, + rewriteCapacitorDependency, +} from '../src/util/capacitor-package'; + +jest.mock('../src/common', () => ({ + getCapacitorPackageVersion: jest.fn(), +})); + +// eslint-disable-next-line @typescript-eslint/no-var-requires +const { getCapacitorPackageVersion } = require('../src/common'); + +const SPM_DIR = '/app/ios/App/CapApp-SPM'; + +function makeConfig(extConfig: any = {}, rootDir = '/app'): Config { + return { + app: { rootDir, extConfig }, + ios: { name: 'ios' }, + } as any; +} + +describe('capacitor package resolution', () => { + beforeEach(() => { + delete process.env.CAPACITOR_IOS_PACKAGE; + getCapacitorPackageVersion.mockReset(); + }); + + describe('default (no override)', () => { + it('pins the tag matching a stable installed version', async () => { + getCapacitorPackageVersion.mockResolvedValue('9.1.0'); + const pkg = await resolveCapacitorPackage(makeConfig()); + + expect(pkg.sourceBased).toBe(true); + expect(pkg.identity).toBe('capacitor'); + expect(pkg.cordovaProduct).toBe('CapacitorCordova'); + expect(renderCapacitorPackage(pkg, SPM_DIR)).toBe( + '.package(url: "https://github.com/ionic-team/capacitor", exact: "9.1.0")', + ); + }); + + it('pins the tag for a prerelease too, rather than tracking a branch', async () => { + getCapacitorPackageVersion.mockResolvedValue('9.0.0-alpha.6'); + const pkg = await resolveCapacitorPackage(makeConfig()); + + expect(renderCapacitorPackage(pkg, SPM_DIR)).toBe( + '.package(url: "https://github.com/ionic-team/capacitor", exact: "9.0.0-alpha.6")', + ); + }); + + it('uses exact for source-based projects even when the caller asks for from', async () => { + // The app package and generated plugin packages must agree; a prerelease does not satisfy + // a `from:` range, so mixing the two styles would fail to resolve. + getCapacitorPackageVersion.mockResolvedValue('9.0.0-alpha.6'); + const pkg = await resolveCapacitorPackage(makeConfig(), 'from'); + + expect(pkg.requirement).toEqual({ kind: 'exact', version: '9.0.0-alpha.6' }); + }); + }); + + describe('pre-9 projects', () => { + it('keeps using the prebuilt package and the caller-chosen requirement style', async () => { + getCapacitorPackageVersion.mockResolvedValue('8.4.0'); + + const app = await resolveCapacitorPackage(makeConfig(), 'exact'); + expect(app.sourceBased).toBe(false); + expect(app.identity).toBe('capacitor-swift-pm'); + expect(app.cordovaProduct).toBe('Cordova'); + expect(renderCapacitorPackage(app, SPM_DIR)).toBe( + '.package(url: "https://github.com/ionic-team/capacitor-swift-pm.git", exact: "8.4.0")', + ); + + const plugin = await resolveCapacitorPackage(makeConfig(), 'from'); + expect(renderCapacitorPackage(plugin, SPM_DIR)).toBe( + '.package(url: "https://github.com/ionic-team/capacitor-swift-pm.git", from: "8.4.0")', + ); + }); + + it('ignores an override, which only applies to the source package', async () => { + getCapacitorPackageVersion.mockResolvedValue('8.4.0'); + process.env.CAPACITOR_IOS_PACKAGE = 'branch:next'; + + const pkg = await resolveCapacitorPackage(makeConfig()); + expect(pkg.requirement).toEqual({ kind: 'exact', version: '8.4.0' }); + }); + }); + + describe('config override', () => { + beforeEach(() => getCapacitorPackageVersion.mockResolvedValue('9.0.0-alpha.6')); + + it('tracks a branch', async () => { + const pkg = await resolveCapacitorPackage( + makeConfig({ experimental: { ios: { spm: { capacitorPackage: { branch: 'next' } } } } }), + ); + expect(renderCapacitorPackage(pkg, SPM_DIR)).toBe( + '.package(url: "https://github.com/ionic-team/capacitor", branch: "next")', + ); + }); + + it('pins a revision, and honours a custom url', async () => { + const pkg = await resolveCapacitorPackage( + makeConfig({ + experimental: { + ios: { spm: { capacitorPackage: { url: 'https://github.com/me/capacitor', revision: 'abc123' } } }, + }, + }), + ); + expect(renderCapacitorPackage(pkg, SPM_DIR)).toBe( + '.package(url: "https://github.com/me/capacitor", revision: "abc123")', + ); + }); + + it('rejects setting more than one requirement', async () => { + await expect( + resolveCapacitorPackage( + makeConfig({ experimental: { ios: { spm: { capacitorPackage: { branch: 'next', exact: '9.0.0' } } } } }), + ), + ).rejects.toThrow(/more than one/); + }); + + it('rejects an empty requirement', async () => { + await expect( + resolveCapacitorPackage(makeConfig({ experimental: { ios: { spm: { capacitorPackage: {} } } } })), + ).rejects.toThrow(/must set one of/); + }); + }); + + describe('local path override', () => { + let checkout: string; + + beforeEach(() => { + getCapacitorPackageVersion.mockResolvedValue('9.0.0-alpha.6'); + checkout = mkdtempSync(join(tmpdir(), 'cap-pkg-')); + writeFileSync(join(checkout, 'Package.swift'), '// root package'); + }); + + it('renders a path relative to the file being written, with a pinned identity', async () => { + const pkg = await resolveCapacitorPackage( + makeConfig({ experimental: { ios: { spm: { capacitorPackage: { path: checkout } } } } }), + ); + + const rendered = renderCapacitorPackage(pkg, SPM_DIR); + expect(rendered).toContain('.package(name: "capacitor", path: "'); + // A differently-named checkout must still be referenced as "capacitor" by products. + expect(pkg.identity).toBe('capacitor'); + }); + + it('resolves a relative path against the app root', async () => { + const nested = join(checkout, 'app'); + mkdirSync(nested); + const pkg = await resolveCapacitorPackage( + makeConfig({ experimental: { ios: { spm: { capacitorPackage: { path: '..' } } } } }, nested), + ); + + expect(pkg.requirement).toEqual({ kind: 'path', absolutePath: resolve(checkout) }); + }); + + it('rejects a path that is not a package root', async () => { + await expect( + resolveCapacitorPackage( + makeConfig({ experimental: { ios: { spm: { capacitorPackage: { path: join(checkout, 'ios') } } } } }), + ), + ).rejects.toThrow(/No Package.swift found/); + }); + + it('rejects url combined with path', async () => { + await expect( + resolveCapacitorPackage( + makeConfig({ + experimental: { ios: { spm: { capacitorPackage: { url: 'https://example.com', path: checkout } } } }, + }), + ), + ).rejects.toThrow(/cannot set both/); + }); + }); + + describe('environment override', () => { + beforeEach(() => getCapacitorPackageVersion.mockResolvedValue('9.0.0-alpha.6')); + + it('outranks the config file', async () => { + process.env.CAPACITOR_IOS_PACKAGE = 'branch:my-feature'; + const pkg = await resolveCapacitorPackage( + makeConfig({ experimental: { ios: { spm: { capacitorPackage: { branch: 'next' } } } } }), + ); + + expect(pkg.requirement).toEqual({ kind: 'branch', branch: 'my-feature' }); + }); + + it('infers exact from a bare version', async () => { + process.env.CAPACITOR_IOS_PACKAGE = '9.2.0'; + const pkg = await resolveCapacitorPackage(makeConfig()); + + expect(pkg.requirement).toEqual({ kind: 'exact', version: '9.2.0' }); + }); + + it('reports an unparseable value', async () => { + process.env.CAPACITOR_IOS_PACKAGE = 'nonsense'; + await expect(resolveCapacitorPackage(makeConfig())).rejects.toThrow(/Could not understand/); + }); + }); +}); + +describe('rewriting an existing Package.swift', () => { + const pkg = { + identity: 'capacitor', + cordovaProduct: 'CapacitorCordova', + sourceBased: true, + url: 'https://github.com/ionic-team/capacitor', + requirement: { kind: 'exact' as const, version: '9.0.0' }, + }; + + it('repoints a plugin from the prebuilt package to the source package', () => { + const before = `dependencies: [ + .package(url: "https://github.com/ionic-team/capacitor-swift-pm.git", from: "8.0.0") + ], + targets: [ + .target(name: "Plugin", dependencies: [.product(name: "Capacitor", package: "capacitor-swift-pm")]) + ]`; + + const after = rewriteCapacitorDependency(before, pkg, '/plugin'); + + expect(after).toContain('.package(url: "https://github.com/ionic-team/capacitor", exact: "9.0.0")'); + expect(after).toContain('.product(name: "Capacitor", package: "capacitor")'); + expect(after).not.toContain('capacitor-swift-pm'); + }); + + it('leaves unrelated dependencies alone', () => { + const before = `.package(url: "https://github.com/ionic-team/capacitor-swift-pm.git", from: "8.0.0"), + .package(url: "https://github.com/other/thing.git", from: "1.0.0")`; + + const after = rewriteCapacitorDependency(before, pkg, '/plugin'); + expect(after).toContain('.package(url: "https://github.com/other/thing.git", from: "1.0.0")'); + }); + + it('handles a nested requirement without truncating the call', () => { + const before = `.package(url: "https://github.com/ionic-team/capacitor-swift-pm.git", .upToNextMajor(from: "8.0.0"))`; + const after = rewriteCapacitorDependency(before, pkg, '/plugin'); + + expect(after).toBe('.package(url: "https://github.com/ionic-team/capacitor", exact: "9.0.0")'); + }); + + it('is idempotent once already repointed', () => { + const once = rewriteCapacitorDependency( + '.package(url: "https://github.com/ionic-team/capacitor-swift-pm.git", from: "8.0.0")', + pkg, + '/plugin', + ); + expect(rewriteCapacitorDependency(once, pkg, '/plugin')).toBe(once); + }); + + it('reads the pinned version from either requirement style', () => { + expect( + findCapacitorDependencyVersion( + '.package(url: "https://github.com/ionic-team/capacitor-swift-pm.git", from: "8.4.0")', + ), + ).toBe('8.4.0'); + expect( + findCapacitorDependencyVersion('.package(url: "https://github.com/ionic-team/capacitor", exact: "9.0.0")'), + ).toBe('9.0.0'); + expect( + findCapacitorDependencyVersion('.package(url: "https://github.com/other/thing.git", from: "1.0.0")'), + ).toBeUndefined(); + }); +}); 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..943645cc2b 100644 --- a/ios-spm-template/App/App.xcodeproj/project.pbxproj +++ b/ios-spm-template/App/App.xcodeproj/project.pbxproj @@ -11,11 +11,11 @@ 4D22ABE92AF431CB00220026 /* CapApp-SPM in Frameworks */ = {isa = PBXBuildFile; productRef = 4D22ABE82AF431CB00220026 /* CapApp-SPM */; }; 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 */; }; - 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 */ @@ -23,12 +23,12 @@ 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 = ""; }; - 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,10 +64,10 @@ 504EC3061FED79650016851F /* App */ = { isa = PBXGroup; children = ( - 9582B6822FE993A50072D4E8 /* SceneDelegate.swift */, + 9575E846302683BC004C1ED7 /* CapacitorView.swift */, + 9575E844302683A6004C1ED7 /* App.swift */, 50379B222058CBB4000EE86E /* capacitor.config.json */, 504EC3071FED79650016851F /* AppDelegate.swift */, - 504EC30B1FED79650016851F /* Main.storyboard */, 504EC30E1FED79650016851F /* Assets.xcassets */, 504EC3101FED79650016851F /* LaunchScreen.storyboard */, 504EC3131FED79650016851F /* Info.plist */, @@ -146,7 +146,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; @@ -158,22 +157,15 @@ 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; }; /* 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-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/Base.lproj/Main.storyboard b/ios-spm-template/App/App/Base.lproj/Main.storyboard deleted file mode 100644 index b44df7be8f..0000000000 --- a/ios-spm-template/App/App/Base.lproj/Main.storyboard +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - - - - - - - - - - - - - - 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/Info.plist b/ios-spm-template/App/App/Info.plist index fc41ce69bc..22e4257d6b 100644 --- a/ios-spm-template/App/App/Info.plist +++ b/ios-spm-template/App/App/Info.plist @@ -2,7 +2,7 @@ - CAPACITOR_DEBUG + CAPACITOR_DEBUG $(CAPACITOR_DEBUG) CFBundleDevelopmentRegion en @@ -27,26 +27,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-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..bd592eff92 100644 --- a/ios-spm-template/App/CapApp-SPM/Package.swift +++ b/ios-spm-template/App/CapApp-SPM/Package.swift @@ -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", from: "9.0.0") ], 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: "CapacitorCordova", package: "capacitor") ] ) ] diff --git a/ios/Capacitor.podspec b/ios/Capacitor.podspec index 01ce20591e..6c120bc397 100644 --- a/ios/Capacitor.podspec +++ b/ios/Capacitor.podspec @@ -15,9 +15,15 @@ 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", + "#{prefix}Sources/CapacitorObjC/**/*.{h,m}", + "#{prefix}Sources/CapacitorObjCShims/**/*.{h,m}" + ] + # SPM-only shim; CocoaPods generates the real Capacitor-Swift.h for the mixed-language module. + s.exclude_files = ["#{prefix}Sources/CapacitorObjCShims/include/Capacitor/Capacitor-Swift.h"] + s.module_map = "#{prefix}Sources/CapacitorObjCShims/Capacitor.modulemap" + 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 2892ea0722..0000000000 --- a/ios/Capacitor/Capacitor.xcodeproj/project.pbxproj +++ /dev/null @@ -1,1166 +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 */; }; - AA01F00D0000000000000002 /* HttpInterceptorNavigationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA01F00D0000000000000001 /* HttpInterceptorNavigationTests.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 = ""; }; - AA01F00D0000000000000001 /* HttpInterceptorNavigationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HttpInterceptorNavigationTests.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 */, - AA01F00D0000000000000001 /* HttpInterceptorNavigationTests.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 */, - AA01F00D0000000000000002 /* HttpInterceptorNavigationTests.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/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/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/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/PluginCallResult.swift b/ios/Capacitor/Capacitor/PluginCallResult.swift deleted file mode 100644 index a426bbcb30..0000000000 --- a/ios/Capacitor/Capacitor/PluginCallResult.swift +++ /dev/null @@ -1,106 +0,0 @@ -import Foundation - -public typealias PluginCallResultData = [String: Any] - -public enum PluginCallResult { - case dictionary(PluginCallResultData) - - enum SerializationError: Error { - case invalidObject - } - - func jsonRepresentation(includingFields: PluginCallResultData? = nil) throws -> String? { - switch self { - case .dictionary(var dictionary): - if let fields = includingFields { - dictionary.merge(fields) { (current, _) in current } - } - dictionary = prepare(dictionary: dictionary) - guard JSONSerialization.isValidJSONObject(dictionary) else { - throw SerializationError.invalidObject - } - let data = try JSONSerialization.data(withJSONObject: dictionary, options: []) - return String(data: data, encoding: .utf8) - } - } - - private static let formatter = ISO8601DateFormatter() - - private func prepare(dictionary: PluginCallResultData) -> PluginCallResultData { - return dictionary.mapValues { (value) -> Any in - if let date = value as? Date { - return PluginCallResult.formatter.string(from: date) - } else if let aDictionary = value as? PluginCallResultData { - return prepare(dictionary: aDictionary) - } else if let anArray = value as? [Any] { - return prepare(array: anArray) - } - return value - } - } - - private func prepare(array: [Any]) -> [Any] { - return array.map { (value) -> Any in - if let date = value as? Date { - return PluginCallResult.formatter.string(from: date) - } else if let aDictionary = value as? PluginCallResultData { - return prepare(dictionary: aDictionary) - } else if let anArray = value as? [Any] { - return prepare(array: anArray) - } - return value - } - } -} - -@objc public class CAPPluginCallResult: NSObject { - public let resultData: PluginCallResult? - - @objc public var data: PluginCallResultData? { - guard let result = resultData else { - return nil - } - switch result { - case .dictionary(let data): - return data - } - } - - @objc(init:) - public init(_ data: PluginCallResultData?) { - if let data = data { - resultData = .dictionary(data) - } else { - resultData = nil - } - } -} - -@objc public class CAPPluginCallError: NSObject { - @objc public let message: String - @objc public let code: String? - @objc public let error: Error? - public let resultData: PluginCallResult? - - @objc public var data: PluginCallResultData? { - guard let result = resultData else { - return nil - } - switch result { - case .dictionary(let data): - return data - } - } - - @objc(init:code:error:data:) - public init(message: String, code: String?, error: Error?, data: PluginCallResultData?) { - self.message = message - self.code = code - self.error = error - if let data = data { - resultData = .dictionary(["data": data]) - } else { - resultData = nil - } - } -} 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/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/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..b7846595f0 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/Cordova/*.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 100% rename from ios/Capacitor/Capacitor/Array+Capacitor.swift rename to ios/Sources/Capacitor/Array+Capacitor.swift diff --git a/ios/Capacitor/Capacitor/CAPApplicationDelegateProxy.swift b/ios/Sources/Capacitor/CAPApplicationDelegateProxy.swift similarity index 100% rename from ios/Capacitor/Capacitor/CAPApplicationDelegateProxy.swift rename to ios/Sources/Capacitor/CAPApplicationDelegateProxy.swift diff --git a/ios/Capacitor/Capacitor/CAPBridgeDelegate.swift b/ios/Sources/Capacitor/CAPBridgeDelegate.swift similarity index 100% rename from ios/Capacitor/Capacitor/CAPBridgeDelegate.swift rename to ios/Sources/Capacitor/CAPBridgeDelegate.swift 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 100% rename from ios/Capacitor/Capacitor/CAPBridgeViewController.swift rename to ios/Sources/Capacitor/CAPBridgeViewController.swift 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/Capacitor/Capacitor/CAPInstanceConfiguration.swift b/ios/Sources/Capacitor/CAPInstanceConfiguration.swift similarity index 100% rename from ios/Capacitor/Capacitor/CAPInstanceConfiguration.swift rename to ios/Sources/Capacitor/CAPInstanceConfiguration.swift diff --git a/ios/Capacitor/Capacitor/CAPInstanceDescriptor.swift b/ios/Sources/Capacitor/CAPInstanceDescriptor.swift similarity index 100% rename from ios/Capacitor/Capacitor/CAPInstanceDescriptor.swift rename to ios/Sources/Capacitor/CAPInstanceDescriptor.swift diff --git a/ios/Capacitor/Capacitor/CAPInstancePlugin.swift b/ios/Sources/Capacitor/CAPInstancePlugin.swift similarity index 100% rename from ios/Capacitor/Capacitor/CAPInstancePlugin.swift rename to ios/Sources/Capacitor/CAPInstancePlugin.swift 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 100% rename from ios/Capacitor/Capacitor/CAPNotifications.swift rename to ios/Sources/Capacitor/CAPNotifications.swift diff --git a/ios/Sources/Capacitor/CAPPlugin+Bridge.swift b/ios/Sources/Capacitor/CAPPlugin+Bridge.swift new file mode 100644 index 0000000000..1b8ecfd270 --- /dev/null +++ b/ios/Sources/Capacitor/CAPPlugin+Bridge.swift @@ -0,0 +1,106 @@ +import Foundation +import UIKit +import WebKit + +@objc public extension CAPPlugin { + var bridge: CAPBridgeProtocol? { + get { return bridgeRef as? CAPBridgeProtocol } + set { bridgeRef = newValue as? NSObject } + } + + @available(*, deprecated, message: "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.") + @objc(initWithBridge:pluginId:pluginName:) + convenience init(bridge: CAPBridgeProtocol, pluginId: String, pluginName: String) { + self.init() + self.bridge = bridge + self.webView = bridge.webView + self.pluginId = pluginId + self.pluginName = pluginName + self.eventListeners = [:] + self.retainedEventArguments = [:] + self.shouldStringifyDatesInCalls = true + } + + @available(*, deprecated, message: "Use accessors on CAPPluginCall instead. See CAPBridgedJSTypes.h for Obj-C implementations.") + func getBool(_ call: CAPPluginCall, field: String, defaultValue: Bool) -> Bool { + guard let value = call.options[field] as? NSNumber else { return defaultValue } + return value.boolValue + } + + @available(*, deprecated, message: "Use accessors on CAPPluginCall instead. See CAPBridgedJSTypes.h for Obj-C implementations.") + func getString(_ call: CAPPluginCall, field: String, defaultValue: String) -> String? { + return call.options[field] as? String ?? defaultValue + } + + func getConfig() -> PluginConfig { + return bridge?.config.getPluginConfig(pluginName) ?? PluginConfig(config: JSObject()) + } + + func notifyListeners(_ eventName: String, data: [String: Any]?) { + notifyListeners(eventName, data: data, retainUntilConsumed: false) + } + + func notifyListeners(_ eventName: String, data: [String: Any]?, retainUntilConsumed retain: Bool) { + guard let listenersForEvent = eventListeners?.object(forKey: eventName) as? NSArray, + listenersForEvent.count > 0 else { + if retain, let data = data { + let bucket: NSMutableArray + if let existing = retainedEventArguments?.object(forKey: eventName) as? NSMutableArray { + bucket = existing + } else { + bucket = NSMutableArray() + retainedEventArguments?.setObject(bucket, forKey: eventName as NSString) + } + bucket.add(data) + } + return + } + + for case let call as CAPPluginCall in listenersForEvent { + call.successHandler(CAPPluginCallResult(data), call) + } + } + + func removeListener(_ call: CAPPluginCall) { + guard let eventName = call.options["eventName"] as? String, + let callbackId = call.options["callbackId"] as? String else { return } + if let storedCall = bridge?.savedCall(withID: callbackId) { + removeEventListener(eventName, listener: storedCall) + } + bridge?.releaseCall(withID: callbackId) + } + + func removeAllListeners(_ call: CAPPluginCall) { + eventListeners?.removeAllObjects() + call.resolve() + } + + /** + * Default implementation of the capacitor 3.0 permission pattern + */ + func checkPermissions(_ call: CAPPluginCall) { + call.resolve() + } + + func requestPermissions(_ call: CAPPluginCall) { + call.resolve() + } + + /** + * Configure popover sourceRect, sourceView and permittedArrowDirections to show it centered + */ + func setCenteredPopover(_ viewController: UIViewController) { + guard let hostView = bridge?.viewController?.view else { return } + viewController.popoverPresentationController?.sourceRect = CGRect(x: hostView.center.x, y: hostView.center.y, width: 0, height: 0) + viewController.popoverPresentationController?.sourceView = hostView + viewController.popoverPresentationController?.permittedArrowDirections = [] + } + + func setCenteredPopover(_ viewController: UIViewController, size: CGSize) { + guard let hostView = bridge?.viewController?.view else { return } + viewController.popoverPresentationController?.sourceRect = CGRect(x: hostView.center.x, y: hostView.center.y, width: 0, height: 0) + viewController.preferredContentSize = size + viewController.popoverPresentationController?.sourceView = hostView + viewController.popoverPresentationController?.permittedArrowDirections = [] + } +} 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/Capacitor/Capacitor/CAPPluginCall.swift b/ios/Sources/Capacitor/CAPPluginCall.swift similarity index 100% rename from ios/Capacitor/Capacitor/CAPPluginCall.swift rename to ios/Sources/Capacitor/CAPPluginCall.swift diff --git a/ios/Capacitor/Capacitor/CAPPluginMethod.swift b/ios/Sources/Capacitor/CAPPluginMethod.swift similarity index 100% rename from ios/Capacitor/Capacitor/CAPPluginMethod.swift rename to ios/Sources/Capacitor/CAPPluginMethod.swift diff --git a/ios/Sources/Capacitor/CAPSceneDelegateProxy.swift b/ios/Sources/Capacitor/CAPSceneDelegateProxy.swift new file mode 100644 index 0000000000..bcbbba9fac --- /dev/null +++ b/ios/Sources/Capacitor/CAPSceneDelegateProxy.swift @@ -0,0 +1,204 @@ +// +// 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 + ]) + } + + /// 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 99% rename from ios/Capacitor/Capacitor/CapacitorBridge.swift rename to ios/Sources/Capacitor/CapacitorBridge.swift index cf5d08c9ba..485132e30f 100644 --- a/ios/Capacitor/Capacitor/CapacitorBridge.swift +++ b/ios/Sources/Capacitor/CapacitorBridge.swift @@ -438,7 +438,7 @@ open class CapacitorBridge: NSObject, CAPBridgeProtocol { if let result = result { self?.toJs(result: JSResult(call: call, callResult: result), save: pluginCall?.keepAlive ?? false) } else { - self?.toJs(result: JSResult(call: call, result: .dictionary([:])), save: pluginCall?.keepAlive ?? false) + self?.toJs(result: JSResult(call: call, data: [:]), save: pluginCall?.keepAlive ?? false) } }, error: {(error: CAPPluginCallError?) in if let error = error { @@ -448,7 +448,7 @@ open class CapacitorBridge: NSObject, CAPBridgeProtocol { errorMessage: "", errorDescription: "", errorCode: nil, - result: .dictionary([:]))) + data: [:])) } }) 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/Sources/Capacitor/CapacitorObjCExports.swift b/ios/Sources/Capacitor/CapacitorObjCExports.swift new file mode 100644 index 0000000000..0fe87b26a9 --- /dev/null +++ b/ios/Sources/Capacitor/CapacitorObjCExports.swift @@ -0,0 +1,11 @@ +// The Objective-C base classes (CAPPlugin, CAPPluginCall, CAPPluginMethod, CAPBridgedPlugin, +// CAPInstanceDescriptor, CAPInstanceConfiguration) live in the CapacitorObjC target so that they +// compile before the Swift module that subclasses and extends them. Re-export them so the rest of +// this module — and downstream `import Capacitor` consumers — keep seeing these symbols without an +// explicit `import CapacitorObjC`. +// +// Under CocoaPods all of these sources are compiled into a single Capacitor module, so there is no +// CapacitorObjC module to import and the re-export is unnecessary. +#if SWIFT_PACKAGE +@_exported import CapacitorObjC +#endif 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 100% rename from ios/Capacitor/Capacitor/Data+Capacitor.swift rename to ios/Sources/Capacitor/Data+Capacitor.swift 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/Capacitor/Capacitor/JS.swift b/ios/Sources/Capacitor/JS.swift similarity index 84% rename from ios/Capacitor/Capacitor/JS.swift rename to ios/Sources/Capacitor/JS.swift index 52cae13791..7e0b06e70c 100644 --- a/ios/Capacitor/Capacitor/JS.swift +++ b/ios/Sources/Capacitor/JS.swift @@ -44,17 +44,17 @@ private enum SerializationResult: String { internal struct JSResult: JSResultProtocol { let call: JSCall - let result: PluginCallResult? + let data: PluginCallResultData? func jsonPayload() -> String { - guard let result = result else { + guard let data = data else { return SerializationResult.undefined.rawValue } do { - if let payload = try result.jsonRepresentation() { + if let payload = try JSResultSerialization.jsonRepresentation(of: data) { return payload } - } catch PluginCallResult.SerializationError.invalidObject { + } catch JSResultSerialization.SerializationError.invalidObject { CAPLog.print("[Capacitor Plugin Error] - \(call.pluginId) - \(call.method) - Unable to serialize plugin response as JSON." + "Ensure that all data passed to success callback from module method is JSON serializable!") } catch { @@ -67,7 +67,7 @@ internal struct JSResult: JSResultProtocol { internal extension JSResult { init(call: JSCall, callResult: CAPPluginCallResult) { self.call = call - self.result = callResult.resultData + self.data = callResult.data } } @@ -76,7 +76,7 @@ internal struct JSResultError: JSResultProtocol { let errorMessage: String let errorDescription: String let errorCode: String? - let result: PluginCallResult + let data: PluginCallResultData func jsonPayload() -> String { var errorDictionary: [String: Any] = [ @@ -86,11 +86,11 @@ internal struct JSResultError: JSResultProtocol { errorDictionary["code"] = self.errorCode do { - if let payload = try result.jsonRepresentation(includingFields: errorDictionary) { + if let payload = try JSResultSerialization.jsonRepresentation(of: data, includingFields: errorDictionary) { CAPLog.print("ERROR MESSAGE: ", payload.prefix(512)) return payload } - } catch PluginCallResult.SerializationError.invalidObject { + } catch JSResultSerialization.SerializationError.invalidObject { CAPLog.print("[Capacitor Plugin Error] - \(call.pluginId) - \(call.method) - Unable to serialize plugin response as JSON." + "Ensure that all data passed to success callback from module method is JSON serializable!") } catch { @@ -106,6 +106,6 @@ internal extension JSResultError { errorMessage = callError.message errorDescription = callError.error?.localizedDescription ?? "" errorCode = callError.code - result = callError.resultData ?? .dictionary([:]) + data = callError.data ?? [:] } } diff --git a/ios/Capacitor/Capacitor/JSExport.swift b/ios/Sources/Capacitor/JSExport.swift similarity index 96% rename from ios/Capacitor/Capacitor/JSExport.swift rename to ios/Sources/Capacitor/JSExport.swift index c51da733df..83ead2c245 100644 --- a/ios/Capacitor/Capacitor/JSExport.swift +++ b/ios/Sources/Capacitor/JSExport.swift @@ -22,8 +22,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 } diff --git a/ios/Sources/Capacitor/JSResultSerialization.swift b/ios/Sources/Capacitor/JSResultSerialization.swift new file mode 100644 index 0000000000..e6245ca7f6 --- /dev/null +++ b/ios/Sources/Capacitor/JSResultSerialization.swift @@ -0,0 +1,56 @@ +import Foundation + +public typealias PluginCallResultData = [String: Any] + +/// Serializes a plugin call's result dictionary to the JSON string sent back across the bridge, +/// converting `Date` values to ISO8601 strings (recursively through nested dictionaries/arrays). +/// +/// Carries the serialization logic that used to live on the `PluginCallResult` enum, which was +/// replaced by the Objective-C `CAPPluginCallResult`/`CAPPluginCallError` carriers. Those store +/// their payloads as plain dictionaries, so the logic no longer has an enum to hang off. +enum JSResultSerialization { + enum SerializationError: Error { + case invalidObject + } + + private static let formatter = ISO8601DateFormatter() + + static func jsonRepresentation(of dictionary: PluginCallResultData, includingFields: PluginCallResultData? = nil) throws -> String? { + var dictionary = dictionary + if let fields = includingFields { + dictionary.merge(fields) { (current, _) in current } + } + let prepared = prepare(dictionary: dictionary) + guard JSONSerialization.isValidJSONObject(prepared) else { + throw SerializationError.invalidObject + } + let data = try JSONSerialization.data(withJSONObject: prepared, options: []) + return String(data: data, encoding: .utf8) + } + + private static func prepare(dictionary: PluginCallResultData) -> PluginCallResultData { + return dictionary.mapValues { (value) -> Any in + if let date = value as? Date { + return formatter.string(from: date) + } else if let aDictionary = value as? PluginCallResultData { + return prepare(dictionary: aDictionary) + } else if let anArray = value as? [Any] { + return prepare(array: anArray) + } + return value + } + } + + private static func prepare(array: [Any]) -> [Any] { + return array.map { (value) -> Any in + if let date = value as? Date { + return formatter.string(from: date) + } else if let aDictionary = value as? PluginCallResultData { + return prepare(dictionary: aDictionary) + } else if let anArray = value as? [Any] { + return prepare(array: anArray) + } + return value + } + } +} 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 100% rename from ios/Capacitor/Capacitor/NotificationHandlerProtocol.swift rename to ios/Sources/Capacitor/NotificationHandlerProtocol.swift diff --git a/ios/Capacitor/Capacitor/NotificationRouter.swift b/ios/Sources/Capacitor/NotificationRouter.swift similarity index 81% rename from ios/Capacitor/Capacitor/NotificationRouter.swift rename to ios/Sources/Capacitor/NotificationRouter.swift index 99fcbb2550..c1f9e0fa51 100644 --- a/ios/Capacitor/Capacitor/NotificationRouter.swift +++ b/ios/Sources/Capacitor/NotificationRouter.swift @@ -1,11 +1,20 @@ import Foundation @objc(CAPNotificationRouter) public class NotificationRouter: NSObject, UNUserNotificationCenterDelegate { + // UNUserNotificationCenter.current() raises when the process has no application bundle, which + // is the case in a host-less unit test runner and some extension contexts. There is no + // notification center to register with there, so treat it as unavailable rather than trapping. + private static var isNotificationCenterAvailable: Bool { + return ["app", "appex"].contains(Bundle.main.bundleURL.pathExtension) + } + var handleApplicationNotifications: Bool { get { + guard Self.isNotificationCenterAvailable else { return false } return UNUserNotificationCenter.current().delegate === self } set { + guard Self.isNotificationCenterAvailable else { return } let center = UNUserNotificationCenter.current() if newValue { 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 100% rename from ios/Capacitor/Capacitor/Plugins/CapacitorCookieManager.swift rename to ios/Sources/Capacitor/Plugins/CapacitorCookieManager.swift 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 100% rename from ios/Capacitor/Capacitor/Plugins/SystemBars.swift rename to ios/Sources/Capacitor/Plugins/SystemBars.swift 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 100% rename from ios/Capacitor/Capacitor/UIColor.swift rename to ios/Sources/Capacitor/UIColor.swift diff --git a/ios/Capacitor/Capacitor/WKWebView+Capacitor.swift b/ios/Sources/Capacitor/WKWebView+Capacitor.swift similarity index 100% rename from ios/Capacitor/Capacitor/WKWebView+Capacitor.swift rename to ios/Sources/Capacitor/WKWebView+Capacitor.swift diff --git a/ios/Capacitor/Capacitor/WebViewAssetHandler.swift b/ios/Sources/Capacitor/WebViewAssetHandler.swift similarity index 100% rename from ios/Capacitor/Capacitor/WebViewAssetHandler.swift rename to ios/Sources/Capacitor/WebViewAssetHandler.swift 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 95% rename from ios/CapacitorCordova/CapacitorCordova/Classes/Public/Plugin.swift rename to ios/Sources/CapacitorCordova/Plugin.swift index d58c4ca33f..f7003f6963 100644 --- a/ios/CapacitorCordova/CapacitorCordova/Classes/Public/Plugin.swift +++ b/ios/Sources/CapacitorCordova/Plugin.swift @@ -1,4 +1,9 @@ import Capacitor +// Under CocoaPods this file is compiled into the Cordova module itself, so importing it would be a +// self-import. Under SPM the Swift and Objective-C halves are separate targets. +#if SWIFT_PACKAGE +import Cordova +#endif @objc(CordovaPlugin) public class CordovaPlugin: CAPPlugin, CAPBridgedPlugin { diff --git a/ios/Capacitor/Capacitor/CAPInstanceConfiguration.m b/ios/Sources/CapacitorObjC/CAPInstanceConfiguration.m similarity index 92% rename from ios/Capacitor/Capacitor/CAPInstanceConfiguration.m rename to ios/Sources/CapacitorObjC/CAPInstanceConfiguration.m index d6b7785e34..0f822f3a4c 100644 --- a/ios/Capacitor/Capacitor/CAPInstanceConfiguration.m +++ b/ios/Sources/CapacitorObjC/CAPInstanceConfiguration.m @@ -1,5 +1,13 @@ #import "CAPInstanceConfiguration.h" -#import +#import "CAPInstanceDescriptor.h" + +// Implemented in Swift (CAPInstanceDescriptor.swift), which can't be imported here without a +// circular dependency. Declared locally rather than in the header so Swift doesn't see a +// redeclaration. +@interface CAPInstanceDescriptor (SwiftVended) +@property (nonatomic, readonly) BOOL cordovaDeployDisabled; +- (void)normalize; +@end @interface CAPInstanceConfiguration (Internal) - (instancetype)initWithConfiguration:(CAPInstanceConfiguration*)configuration andLocation:(NSURL*)location; diff --git a/ios/Capacitor/Capacitor/CAPInstanceDescriptor.m b/ios/Sources/CapacitorObjC/CAPInstanceDescriptor.m similarity index 98% rename from ios/Capacitor/Capacitor/CAPInstanceDescriptor.m rename to ios/Sources/CapacitorObjC/CAPInstanceDescriptor.m index acdbc08caf..a619866993 100644 --- a/ios/Capacitor/Capacitor/CAPInstanceDescriptor.m +++ b/ios/Sources/CapacitorObjC/CAPInstanceDescriptor.m @@ -1,5 +1,4 @@ #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 diff --git a/ios/Sources/CapacitorObjC/CAPPlugin.m b/ios/Sources/CapacitorObjC/CAPPlugin.m new file mode 100644 index 0000000000..bb272541df --- /dev/null +++ b/ios/Sources/CapacitorObjC/CAPPlugin.m @@ -0,0 +1,100 @@ +#import "CAPPlugin.h" +#import "CAPPluginCall.h" +#import + +// Implemented in Swift (CAPPlugin+Bridge.swift), which can't be imported here without a circular +// dependency. Declared locally rather than in the header so Swift doesn't see a redeclaration. +@interface CAPPlugin (SwiftVended) +- (void)notifyListeners:(NSString* _Nonnull)eventName data:(NSDictionary* _Nullable)data; +@end + +@implementation CAPPlugin + +- (instancetype)init { + if ((self = [super init])) { + _pluginId = @""; + _pluginName = @""; + _eventListeners = [[NSMutableDictionary alloc] init]; + _retainedEventArguments = [[NSMutableDictionary alloc] init]; + _shouldStringifyDatesInCalls = YES; + } + return self; +} + +-(NSString *) getId { + return 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)addListener:(CAPPluginCall *)call { + NSString *eventName = [call.options objectForKey:@"eventName"]; + [call setKeepAlive:TRUE]; + [self addEventListener:eventName listener:call]; +} + +- (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; +} + +-(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.m b/ios/Sources/CapacitorObjC/CAPPluginCall.m similarity index 100% rename from ios/Capacitor/Capacitor/CAPPluginCall.m rename to ios/Sources/CapacitorObjC/CAPPluginCall.m diff --git a/ios/Sources/CapacitorObjC/CAPPluginCallResult.m b/ios/Sources/CapacitorObjC/CAPPluginCallResult.m new file mode 100644 index 0000000000..297f7561f3 --- /dev/null +++ b/ios/Sources/CapacitorObjC/CAPPluginCallResult.m @@ -0,0 +1,29 @@ +#import "CAPPluginCallResult.h" + +@implementation CAPPluginCallResult + +- (instancetype)init:(NSDictionary *)data { + if ((self = [super init])) { + _data = data; + } + return self; +} + +@end + +@implementation CAPPluginCallError + +- (instancetype)init:(NSString *)message + code:(NSString *)code + error:(NSError *)error + data:(NSDictionary *)data { + if ((self = [super init])) { + _message = message; + _code = code; + _error = error; + _data = data ? @{@"data": data} : nil; + } + return self; +} + +@end diff --git a/ios/Capacitor/Capacitor/CAPPluginMethod.m b/ios/Sources/CapacitorObjC/CAPPluginMethod.m similarity index 97% rename from ios/Capacitor/Capacitor/CAPPluginMethod.m rename to ios/Sources/CapacitorObjC/CAPPluginMethod.m index d765540e92..8fc009d6ea 100644 --- a/ios/Capacitor/Capacitor/CAPPluginMethod.m +++ b/ios/Sources/CapacitorObjC/CAPPluginMethod.m @@ -1,4 +1,3 @@ -#import #import "CAPPluginMethod.h" typedef void(^CAPCallback)(id _arg, NSInteger index); diff --git a/ios/Capacitor/Capacitor/CAPBridgedPlugin.h b/ios/Sources/CapacitorObjC/include/Capacitor/CAPBridgedPlugin.h similarity index 100% rename from ios/Capacitor/Capacitor/CAPBridgedPlugin.h rename to ios/Sources/CapacitorObjC/include/Capacitor/CAPBridgedPlugin.h diff --git a/ios/Capacitor/Capacitor/CAPInstanceConfiguration.h b/ios/Sources/CapacitorObjC/include/Capacitor/CAPInstanceConfiguration.h similarity index 100% rename from ios/Capacitor/Capacitor/CAPInstanceConfiguration.h rename to ios/Sources/CapacitorObjC/include/Capacitor/CAPInstanceConfiguration.h diff --git a/ios/Capacitor/Capacitor/CAPInstanceDescriptor.h b/ios/Sources/CapacitorObjC/include/Capacitor/CAPInstanceDescriptor.h similarity index 100% rename from ios/Capacitor/Capacitor/CAPInstanceDescriptor.h rename to ios/Sources/CapacitorObjC/include/Capacitor/CAPInstanceDescriptor.h diff --git a/ios/Capacitor/Capacitor/CAPPlugin.h b/ios/Sources/CapacitorObjC/include/Capacitor/CAPPlugin.h similarity index 56% rename from ios/Capacitor/Capacitor/CAPPlugin.h rename to ios/Sources/CapacitorObjC/include/Capacitor/CAPPlugin.h index f22d9be2a0..10498d89ba 100644 --- a/ios/Capacitor/Capacitor/CAPPlugin.h +++ b/ios/Sources/CapacitorObjC/include/Capacitor/CAPPlugin.h @@ -1,36 +1,25 @@ #import #import -@protocol CAPBridgeProtocol; @class CAPPluginCall; -@class PluginConfig; - @interface CAPPlugin : NSObject @property (nonatomic, weak, nullable) WKWebView *webView; -@property (nonatomic, weak, nullable) id bridge; +// Untyped backing storage for the bridge. The typed `bridge` accessor (`id`) is +// vended from Swift, so this target never has to reference the Swift-defined CAPBridgeProtocol. +@property (nonatomic, weak, nullable) NSObject *bridgeRef; @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. @@ -49,11 +38,6 @@ // 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/CAPPluginCall.h b/ios/Sources/CapacitorObjC/include/Capacitor/CAPPluginCall.h similarity index 95% rename from ios/Capacitor/Capacitor/CAPPluginCall.h rename to ios/Sources/CapacitorObjC/include/Capacitor/CAPPluginCall.h index 129dba7ff2..2dee66df0a 100644 --- a/ios/Capacitor/Capacitor/CAPPluginCall.h +++ b/ios/Sources/CapacitorObjC/include/Capacitor/CAPPluginCall.h @@ -1,8 +1,7 @@ #import +#import "CAPPluginCallResult.h" @class CAPPluginCall; -@class CAPPluginCallResult; -@class CAPPluginCallError; typedef void(^CAPPluginCallSuccessHandler)(CAPPluginCallResult *result, CAPPluginCall* call); typedef void(^CAPPluginCallErrorHandler)(CAPPluginCallError *error); diff --git a/ios/Sources/CapacitorObjC/include/Capacitor/CAPPluginCallResult.h b/ios/Sources/CapacitorObjC/include/Capacitor/CAPPluginCallResult.h new file mode 100644 index 0000000000..2e3be1576e --- /dev/null +++ b/ios/Sources/CapacitorObjC/include/Capacitor/CAPPluginCallResult.h @@ -0,0 +1,28 @@ +// These carriers are Objective-C rather than Swift because CAPPluginCall's successHandler / +// errorHandler are block-typed properties that take them as parameters. A forward declaration is +// not enough for Swift to import a block type, and Swift cannot resolve one against a class it is +// itself in the middle of defining, so the concrete definitions must precede the Swift module. +#import + +@interface CAPPluginCallResult : NSObject + +@property (nonatomic, readonly, nullable) NSDictionary *data; + +- (nonnull instancetype)init:(nullable NSDictionary *)data; + +@end + +@interface CAPPluginCallError : NSObject + +@property (nonatomic, readonly, nonnull) NSString *message; +@property (nonatomic, readonly, nullable) NSString *code; +@property (nonatomic, readonly, nullable) NSError *error; +@property (nonatomic, readonly, nullable) NSDictionary *data; + +- (nonnull instancetype)init:(nonnull NSString *)message + code:(nullable NSString *)code + error:(nullable NSError *)error + data:(nullable NSDictionary *)data + NS_SWIFT_NAME(init(message:code:error:data:)); + +@end diff --git a/ios/Capacitor/Capacitor/CAPPluginMethod.h b/ios/Sources/CapacitorObjC/include/Capacitor/CAPPluginMethod.h similarity index 100% rename from ios/Capacitor/Capacitor/CAPPluginMethod.h rename to ios/Sources/CapacitorObjC/include/Capacitor/CAPPluginMethod.h diff --git a/ios/Capacitor/Capacitor/CAPBridgedJSTypes.m b/ios/Sources/CapacitorObjCShims/CAPBridgedJSTypes.m similarity index 100% rename from ios/Capacitor/Capacitor/CAPBridgedJSTypes.m rename to ios/Sources/CapacitorObjCShims/CAPBridgedJSTypes.m diff --git a/ios/Capacitor/Capacitor/Capacitor.modulemap b/ios/Sources/CapacitorObjCShims/Capacitor.modulemap similarity index 100% rename from ios/Capacitor/Capacitor/Capacitor.modulemap rename to ios/Sources/CapacitorObjCShims/Capacitor.modulemap diff --git a/ios/Capacitor/Capacitor/UIStatusBarManager+CAPHandleTapAction.m b/ios/Sources/CapacitorObjCShims/UIStatusBarManager+CAPHandleTapAction.m similarity index 100% rename from ios/Capacitor/Capacitor/UIStatusBarManager+CAPHandleTapAction.m rename to ios/Sources/CapacitorObjCShims/UIStatusBarManager+CAPHandleTapAction.m diff --git a/ios/Capacitor/Capacitor/WKWebView+Capacitor.m b/ios/Sources/CapacitorObjCShims/WKWebView+Capacitor.m similarity index 100% rename from ios/Capacitor/Capacitor/WKWebView+Capacitor.m rename to ios/Sources/CapacitorObjCShims/WKWebView+Capacitor.m diff --git a/ios/Capacitor/Capacitor/CAPBridgedJSTypes.h b/ios/Sources/CapacitorObjCShims/include/Capacitor/CAPBridgedJSTypes.h similarity index 100% rename from ios/Capacitor/Capacitor/CAPBridgedJSTypes.h rename to ios/Sources/CapacitorObjCShims/include/Capacitor/CAPBridgedJSTypes.h diff --git a/ios/Sources/CapacitorObjCShims/include/Capacitor/Capacitor-Swift.h b/ios/Sources/CapacitorObjCShims/include/Capacitor/Capacitor-Swift.h new file mode 100644 index 0000000000..3176162636 --- /dev/null +++ b/ios/Sources/CapacitorObjCShims/include/Capacitor/Capacitor-Swift.h @@ -0,0 +1,9 @@ +// SPM-only shim. Under CocoaPods, Capacitor is one mixed-language module and the compiler +// generates a real exposing the Swift interface to Objective-C; this +// file is excluded from the pod so it can't clobber it (see Capacitor.podspec). +// +// Under SPM the Swift module is separate and its generated header is not reachable at that path, so +// this shim provides the import path and surfaces the same interface via a module import. +#if !__building_module(Capacitor) +@import Capacitor; +#endif diff --git a/ios/Capacitor/Capacitor/Capacitor.h b/ios/Sources/CapacitorObjCShims/include/Capacitor/Capacitor.h similarity index 53% rename from ios/Capacitor/Capacitor/Capacitor.h rename to ios/Sources/CapacitorObjCShims/include/Capacitor/Capacitor.h index 7170982981..d7bed7a9fd 100644 --- a/ios/Capacitor/Capacitor/Capacitor.h +++ b/ios/Sources/CapacitorObjCShims/include/Capacitor/Capacitor.h @@ -13,3 +13,11 @@ FOUNDATION_EXPORT const unsigned char CapacitorVersionString[]; #import #import +// Several CAPPlugin members (bridge, getConfig, notifyListeners:, checkPermissions:, ...) are vended +// from Swift, so importing the module here keeps the umbrella a complete view of CAPPlugin for +// Objective-C plugin authors. Skipped while the module itself is being built, which is the only +// case where this would be circular. +#if !__building_module(Capacitor) +@import Capacitor; +#endif + 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 100% rename from ios/CapacitorCordova/CapacitorCordova/Classes/Public/CDVWebViewProcessPoolFactory.m rename to ios/Sources/Cordova/CDVWebViewProcessPoolFactory.m 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/Cordova/AppDelegate.h similarity index 100% rename from ios/CapacitorCordova/CapacitorCordova/Classes/Public/AppDelegate.h rename to ios/Sources/Cordova/include/Cordova/AppDelegate.h diff --git a/ios/CapacitorCordova/CapacitorCordova/Classes/Public/CDV.h b/ios/Sources/Cordova/include/Cordova/CDV.h similarity index 100% rename from ios/CapacitorCordova/CapacitorCordova/Classes/Public/CDV.h rename to ios/Sources/Cordova/include/Cordova/CDV.h diff --git a/ios/CapacitorCordova/CapacitorCordova/Classes/Public/CDVAvailability.h b/ios/Sources/Cordova/include/Cordova/CDVAvailability.h similarity index 100% rename from ios/CapacitorCordova/CapacitorCordova/Classes/Public/CDVAvailability.h rename to ios/Sources/Cordova/include/Cordova/CDVAvailability.h diff --git a/ios/CapacitorCordova/CapacitorCordova/Classes/Public/CDVAvailabilityDeprecated.h b/ios/Sources/Cordova/include/Cordova/CDVAvailabilityDeprecated.h similarity index 100% rename from ios/CapacitorCordova/CapacitorCordova/Classes/Public/CDVAvailabilityDeprecated.h rename to ios/Sources/Cordova/include/Cordova/CDVAvailabilityDeprecated.h diff --git a/ios/CapacitorCordova/CapacitorCordova/Classes/Public/CDVCommandDelegate.h b/ios/Sources/Cordova/include/Cordova/CDVCommandDelegate.h similarity index 100% rename from ios/CapacitorCordova/CapacitorCordova/Classes/Public/CDVCommandDelegate.h rename to ios/Sources/Cordova/include/Cordova/CDVCommandDelegate.h diff --git a/ios/CapacitorCordova/CapacitorCordova/Classes/Public/CDVCommandDelegateImpl.h b/ios/Sources/Cordova/include/Cordova/CDVCommandDelegateImpl.h similarity index 100% rename from ios/CapacitorCordova/CapacitorCordova/Classes/Public/CDVCommandDelegateImpl.h rename to ios/Sources/Cordova/include/Cordova/CDVCommandDelegateImpl.h diff --git a/ios/CapacitorCordova/CapacitorCordova/Classes/Public/CDVConfigParser.h b/ios/Sources/Cordova/include/Cordova/CDVConfigParser.h similarity index 100% rename from ios/CapacitorCordova/CapacitorCordova/Classes/Public/CDVConfigParser.h rename to ios/Sources/Cordova/include/Cordova/CDVConfigParser.h diff --git a/ios/CapacitorCordova/CapacitorCordova/Classes/Public/CDVInvokedUrlCommand.h b/ios/Sources/Cordova/include/Cordova/CDVInvokedUrlCommand.h similarity index 100% rename from ios/CapacitorCordova/CapacitorCordova/Classes/Public/CDVInvokedUrlCommand.h rename to ios/Sources/Cordova/include/Cordova/CDVInvokedUrlCommand.h diff --git a/ios/CapacitorCordova/CapacitorCordova/Classes/Public/CDVPlugin+Resources.h b/ios/Sources/Cordova/include/Cordova/CDVPlugin+Resources.h similarity index 100% rename from ios/CapacitorCordova/CapacitorCordova/Classes/Public/CDVPlugin+Resources.h rename to ios/Sources/Cordova/include/Cordova/CDVPlugin+Resources.h diff --git a/ios/CapacitorCordova/CapacitorCordova/Classes/Public/CDVPlugin.h b/ios/Sources/Cordova/include/Cordova/CDVPlugin.h similarity index 100% rename from ios/CapacitorCordova/CapacitorCordova/Classes/Public/CDVPlugin.h rename to ios/Sources/Cordova/include/Cordova/CDVPlugin.h diff --git a/ios/CapacitorCordova/CapacitorCordova/Classes/Public/CDVPluginManager.h b/ios/Sources/Cordova/include/Cordova/CDVPluginManager.h similarity index 100% rename from ios/CapacitorCordova/CapacitorCordova/Classes/Public/CDVPluginManager.h rename to ios/Sources/Cordova/include/Cordova/CDVPluginManager.h diff --git a/ios/CapacitorCordova/CapacitorCordova/Classes/Public/CDVPluginResult.h b/ios/Sources/Cordova/include/Cordova/CDVPluginResult.h similarity index 100% rename from ios/CapacitorCordova/CapacitorCordova/Classes/Public/CDVPluginResult.h rename to ios/Sources/Cordova/include/Cordova/CDVPluginResult.h diff --git a/ios/CapacitorCordova/CapacitorCordova/Classes/Public/CDVScreenOrientationDelegate.h b/ios/Sources/Cordova/include/Cordova/CDVScreenOrientationDelegate.h similarity index 100% rename from ios/CapacitorCordova/CapacitorCordova/Classes/Public/CDVScreenOrientationDelegate.h rename to ios/Sources/Cordova/include/Cordova/CDVScreenOrientationDelegate.h diff --git a/ios/CapacitorCordova/CapacitorCordova/Classes/Public/CDVURLProtocol.h b/ios/Sources/Cordova/include/Cordova/CDVURLProtocol.h similarity index 100% rename from ios/CapacitorCordova/CapacitorCordova/Classes/Public/CDVURLProtocol.h rename to ios/Sources/Cordova/include/Cordova/CDVURLProtocol.h diff --git a/ios/CapacitorCordova/CapacitorCordova/Classes/Public/CDVViewController.h b/ios/Sources/Cordova/include/Cordova/CDVViewController.h similarity index 100% rename from ios/CapacitorCordova/CapacitorCordova/Classes/Public/CDVViewController.h rename to ios/Sources/Cordova/include/Cordova/CDVViewController.h diff --git a/ios/CapacitorCordova/CapacitorCordova/Classes/Public/CDVWebViewProcessPoolFactory.h b/ios/Sources/Cordova/include/Cordova/CDVWebViewProcessPoolFactory.h similarity index 100% rename from ios/CapacitorCordova/CapacitorCordova/Classes/Public/CDVWebViewProcessPoolFactory.h rename to ios/Sources/Cordova/include/Cordova/CDVWebViewProcessPoolFactory.h diff --git a/ios/CapacitorCordova/CapacitorCordova/Classes/Public/NSDictionary+CordovaPreferences.h b/ios/Sources/Cordova/include/Cordova/NSDictionary+CordovaPreferences.h similarity index 100% rename from ios/CapacitorCordova/CapacitorCordova/Classes/Public/NSDictionary+CordovaPreferences.h rename to ios/Sources/Cordova/include/Cordova/NSDictionary+CordovaPreferences.h diff --git a/ios/Capacitor/CapacitorTests/PluginCallAccessorTests.m b/ios/Tests/CapacitorObjCTests/PluginCallAccessorTests.m similarity index 99% rename from ios/Capacitor/CapacitorTests/PluginCallAccessorTests.m rename to ios/Tests/CapacitorObjCTests/PluginCallAccessorTests.m index 4d665aeec1..d35f4f4736 100644 --- a/ios/Capacitor/CapacitorTests/PluginCallAccessorTests.m +++ b/ios/Tests/CapacitorObjCTests/PluginCallAccessorTests.m @@ -1,7 +1,6 @@ #import #import #import -#import "CapacitorTests-Swift.h" // interface for this class @interface PluginCallAccessorTests : XCTestCase 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..85703ace32 --- /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 JSResultSerialization.jsonRepresentation(of: ["date": unserializedDictionary["testDateObject"]!]) + #expect(result == "{\"date\":\"\(unserializedDictionary["testDateString"] as! String)\"}") + } + + @Test func testResultMerging() throws { + let result = try JSResultSerialization.jsonRepresentation(of: ["number": 1], 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/CAPPluginTests.swift b/ios/Tests/CapacitorTests/CAPPluginTests.swift new file mode 100644 index 0000000000..ac0a1ce00d --- /dev/null +++ b/ios/Tests/CapacitorTests/CAPPluginTests.swift @@ -0,0 +1,91 @@ +import Foundation +import Testing +@testable import Capacitor + +struct CAPPluginTests { + private final class Recorder { + private(set) var received: [PluginCallResultData] = [] + func record(_ data: PluginCallResultData) { + received.append(data) + } + } + + private static func makeCall() -> (call: CAPPluginCall, recorder: Recorder) { + let recorder = Recorder() + let call: CAPPluginCall = CAPPluginCall(callbackId: "test", methodName: "test", options: [:], success: { result, _ in + recorder.record(result?.data ?? [:]) + }, error: { _ in }) + return (call, recorder) + } + + @Test func notifyListenersDeliversToActiveListener() { + let plugin = CAPPlugin() + let (call, recorder) = Self.makeCall() + plugin.addEventListener("myEvent", listener: call) + + plugin.notifyListeners("myEvent", data: ["value": "hello"]) + + #expect(recorder.received.count == 1) + #expect(recorder.received.first?["value"] as? String == "hello") + } + + @Test func removeEventListenerStopsDelivery() { + let plugin = CAPPlugin() + let (call, recorder) = Self.makeCall() + plugin.addEventListener("myEvent", listener: call) + plugin.removeEventListener("myEvent", listener: call) + + plugin.notifyListeners("myEvent", data: ["value": "hello"]) + + #expect(recorder.received.isEmpty) + } + + @Test func hasListenersReflectsAddAndRemove() { + let plugin = CAPPlugin() + let (call, _) = Self.makeCall() + #expect(plugin.hasListeners("myEvent") == false) + + plugin.addEventListener("myEvent", listener: call) + #expect(plugin.hasListeners("myEvent") == true) + + plugin.removeEventListener("myEvent", listener: call) + #expect(plugin.hasListeners("myEvent") == false) + } + + @Test func notifyListenersWithoutListenersAndNoRetainDropsEvent() { + let plugin = CAPPlugin() + plugin.notifyListeners("myEvent", data: ["value": "hello"], retainUntilConsumed: false) + + let (call, recorder) = Self.makeCall() + plugin.addEventListener("myEvent", listener: call) + + #expect(recorder.received.isEmpty) + } + + @Test func notifyListenersWithoutListenersAndRetainReplaysOnAttach() { + let plugin = CAPPlugin() + plugin.notifyListeners("myEvent", data: ["value": "hello"], retainUntilConsumed: true) + + let (call, recorder) = Self.makeCall() + plugin.addEventListener("myEvent", listener: call) + + #expect(recorder.received.count == 1) + #expect(recorder.received.first?["value"] as? String == "hello") + } + + @Test func notifyListenersAfterListenerRemovedStillRetainsAndReplaysOnReattach() { + let plugin = CAPPlugin() + let (firstCall, firstRecorder) = Self.makeCall() + plugin.addEventListener("myEvent", listener: firstCall) + plugin.removeEventListener("myEvent", listener: firstCall) + + plugin.notifyListeners("myEvent", data: ["value": "hello"], retainUntilConsumed: true) + + let (secondCall, secondRecorder) = Self.makeCall() + plugin.addEventListener("myEvent", listener: secondCall) + + #expect(firstRecorder.received.isEmpty) + #expect(secondRecorder.received.count == 1) + #expect(secondRecorder.received.first?["value"] as? String == "hello") + } +} diff --git a/ios/Capacitor/CapacitorTests/CapacitorTests.swift b/ios/Tests/CapacitorTests/CapacitorTests.swift similarity index 100% rename from ios/Capacitor/CapacitorTests/CapacitorTests.swift rename to ios/Tests/CapacitorTests/CapacitorTests.swift 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/Capacitor/CapacitorTests/HttpInterceptorNavigationTests.swift b/ios/Tests/CapacitorTests/HttpInterceptorNavigationTests.swift similarity index 86% rename from ios/Capacitor/CapacitorTests/HttpInterceptorNavigationTests.swift rename to ios/Tests/CapacitorTests/HttpInterceptorNavigationTests.swift index ebd14d3ce6..b7dac2455b 100644 --- a/ios/Capacitor/CapacitorTests/HttpInterceptorNavigationTests.swift +++ b/ios/Tests/CapacitorTests/HttpInterceptorNavigationTests.swift @@ -5,6 +5,11 @@ import XCTest private class StubFrameInfo: WKFrameInfo { override var isMainFrame: Bool { false } + + // WKFrameInfo has no public initializer, so super.init() leaves WebKit's internal state + // unset and -[WKFrameInfo dealloc] then dereferences garbage. Keeping a single instance + // alive for the process avoids ever deallocating one. + static let shared = StubFrameInfo() } private class StubNavigationAction: WKNavigationAction { @@ -12,7 +17,7 @@ private class StubNavigationAction: WKNavigationAction { private let stubbedTargetFrame: WKFrameInfo? init(url: String, subframe: Bool = false) { self.stubbedRequest = URLRequest(url: URL(string: url)!) - self.stubbedTargetFrame = subframe ? StubFrameInfo() : nil + self.stubbedTargetFrame = subframe ? StubFrameInfo.shared : nil super.init() } override var request: URLRequest { stubbedRequest } 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/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..1aa29f1895 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', '${PWD}/ios/Frameworks', '${PWD}/.build', '${PWD}/ios/.build'], };