init
This commit is contained in:
23
node_modules/@capacitor/ios/Capacitor.podspec
generated
vendored
Normal file
23
node_modules/@capacitor/ios/Capacitor.podspec
generated
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
require 'json'
|
||||
package = JSON.parse(File.read(File.join(__dir__, 'package.json')))
|
||||
prefix = if ENV['NATIVE_PUBLISH'] == 'true'
|
||||
'ios/'
|
||||
else
|
||||
''
|
||||
end
|
||||
|
||||
Pod::Spec.new do |s|
|
||||
s.name = 'Capacitor'
|
||||
s.version = package['version']
|
||||
s.summary = 'Capacitor for iOS'
|
||||
s.license = 'MIT'
|
||||
s.homepage = 'https://capacitorjs.com/'
|
||||
s.ios.deployment_target = '14.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", "#{prefix}Capacitor/Capacitor/PrivacyInfo.xcprivacy"]
|
||||
s.dependency 'CapacitorCordova'
|
||||
s.swift_version = '5.1'
|
||||
end
|
||||
51
node_modules/@capacitor/ios/Capacitor/Capacitor/AppUUID.swift
generated
vendored
Normal file
51
node_modules/@capacitor/ios/Capacitor/Capacitor/AppUUID.swift
generated
vendored
Normal file
@@ -0,0 +1,51 @@
|
||||
import CommonCrypto
|
||||
import Foundation
|
||||
|
||||
private func hexString(_ iterator: Array<UInt8>.Iterator) -> String {
|
||||
return iterator.map { String(format: "%02x", $0) }.joined()
|
||||
}
|
||||
|
||||
extension Data {
|
||||
public var sha256: String {
|
||||
var digest = [UInt8](repeating: 0, count: Int(CC_SHA256_DIGEST_LENGTH))
|
||||
self.withUnsafeBytes { bytes in
|
||||
_ = CC_SHA256(bytes.baseAddress, CC_LONG(self.count), &digest)
|
||||
}
|
||||
return hexString(digest.makeIterator())
|
||||
}
|
||||
}
|
||||
|
||||
public class AppUUID {
|
||||
private static let key: String = "CapacitorAppUUID"
|
||||
|
||||
public static func getAppUUID() -> String {
|
||||
assertAppUUID()
|
||||
return readUUID()
|
||||
}
|
||||
|
||||
public static func regenerateAppUUID() {
|
||||
let uuid = generateUUID()
|
||||
writeUUID(uuid)
|
||||
}
|
||||
|
||||
private static func assertAppUUID() {
|
||||
let uuid = readUUID()
|
||||
if uuid == "" {
|
||||
regenerateAppUUID()
|
||||
}
|
||||
}
|
||||
|
||||
private static func generateUUID() -> String {
|
||||
let uuid: String = UUID.init().uuidString
|
||||
return uuid.data(using: .utf8)!.sha256
|
||||
}
|
||||
|
||||
private static func readUUID() -> String {
|
||||
KeyValueStore.standard[key] ?? ""
|
||||
}
|
||||
|
||||
private static func writeUUID(_ uuid: String) {
|
||||
KeyValueStore.standard[key] = uuid
|
||||
}
|
||||
|
||||
}
|
||||
31
node_modules/@capacitor/ios/Capacitor/Capacitor/Array+Capacitor.swift
generated
vendored
Normal file
31
node_modules/@capacitor/ios/Capacitor/Capacitor/Array+Capacitor.swift
generated
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
// convenience wrappers to transform Arrays between NSNull and Optional values, for interoperability with Obj-C
|
||||
extension Array: CapacitorExtension {}
|
||||
extension CapacitorExtensionTypeWrapper where T == [JSValue] {
|
||||
public func replacingNullValues() -> [JSValue?] {
|
||||
return baseType.map({ (value) -> JSValue? in
|
||||
if value is NSNull {
|
||||
return nil
|
||||
}
|
||||
return value
|
||||
})
|
||||
}
|
||||
|
||||
public func replacingOptionalValues() -> [JSValue] {
|
||||
return baseType
|
||||
}
|
||||
}
|
||||
|
||||
extension CapacitorExtensionTypeWrapper where T == [JSValue?] {
|
||||
public func replacingNullValues() -> [JSValue?] {
|
||||
return baseType
|
||||
}
|
||||
|
||||
public func replacingOptionalValues() -> [JSValue] {
|
||||
return baseType.map({ (value) -> JSValue in
|
||||
if let value = value {
|
||||
return value
|
||||
}
|
||||
return NSNull()
|
||||
})
|
||||
}
|
||||
}
|
||||
32
node_modules/@capacitor/ios/Capacitor/Capacitor/CAPApplicationDelegateProxy.swift
generated
vendored
Normal file
32
node_modules/@capacitor/ios/Capacitor/Capacitor/CAPApplicationDelegateProxy.swift
generated
vendored
Normal file
@@ -0,0 +1,32 @@
|
||||
import Foundation
|
||||
|
||||
@objc(CAPApplicationDelegateProxy)
|
||||
public class ApplicationDelegateProxy: NSObject, UIApplicationDelegate {
|
||||
public static let shared = ApplicationDelegateProxy()
|
||||
|
||||
public private(set) var lastURL: URL?
|
||||
|
||||
public func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey: Any] = [:]) -> Bool {
|
||||
NotificationCenter.default.post(name: .capacitorOpenURL, object: [
|
||||
"url": url,
|
||||
"options": options
|
||||
])
|
||||
NotificationCenter.default.post(name: NSNotification.Name.CDVPluginHandleOpenURL, object: url)
|
||||
lastURL = url
|
||||
return true
|
||||
}
|
||||
|
||||
public func application(_ application: UIApplication, continue userActivity: NSUserActivity, restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void) -> Bool {
|
||||
// TODO: Support other types, emit to rest of plugins
|
||||
if userActivity.activityType != NSUserActivityTypeBrowsingWeb || userActivity.webpageURL == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
let url = userActivity.webpageURL
|
||||
lastURL = url
|
||||
NotificationCenter.default.post(name: .capacitorOpenUniversalLink, object: [
|
||||
"url": url
|
||||
])
|
||||
return true
|
||||
}
|
||||
}
|
||||
25
node_modules/@capacitor/ios/Capacitor/Capacitor/CAPBridge.swift
generated
vendored
Normal file
25
node_modules/@capacitor/ios/Capacitor/Capacitor/CAPBridge.swift
generated
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
import Foundation
|
||||
|
||||
// the @available compiler directive does not provide an easy way to split apart string literals, so ignore the line length
|
||||
// swiftlint:disable line_length
|
||||
@available(*, deprecated, message: "'statusBarTappedNotification' has been moved to Notification.Name.capacitorStatusBarTapped. 'getLastUrl' and application delegate methods have been moved to ApplicationDelegateProxy.")
|
||||
// swiftlint:enable line_length
|
||||
@objc public class CAPBridge: NSObject {
|
||||
@objc public static let statusBarTappedNotification = Notification(name: .capacitorStatusBarTapped)
|
||||
|
||||
public static func getLastUrl() -> URL? {
|
||||
return ApplicationDelegateProxy.shared.lastURL
|
||||
}
|
||||
|
||||
public static func handleOpenUrl(_ url: URL, _ options: [UIApplication.OpenURLOptionsKey: Any]) -> Bool {
|
||||
return ApplicationDelegateProxy.shared.application(UIApplication.shared, open: url, options: options)
|
||||
}
|
||||
|
||||
public static func handleContinueActivity(_ userActivity: NSUserActivity, _ restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void) -> Bool {
|
||||
return ApplicationDelegateProxy.shared.application(UIApplication.shared, continue: userActivity, restorationHandler: restorationHandler)
|
||||
}
|
||||
|
||||
public static func handleAppBecameActive(_ application: UIApplication) {
|
||||
// no-op for now
|
||||
}
|
||||
}
|
||||
6
node_modules/@capacitor/ios/Capacitor/Capacitor/CAPBridgeDelegate.swift
generated
vendored
Normal file
6
node_modules/@capacitor/ios/Capacitor/Capacitor/CAPBridgeDelegate.swift
generated
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
import Foundation
|
||||
|
||||
public protocol CAPBridgeDelegate: AnyObject {
|
||||
var bridgedWebView: WKWebView? { get }
|
||||
var bridgedViewController: UIViewController? { get }
|
||||
}
|
||||
148
node_modules/@capacitor/ios/Capacitor/Capacitor/CAPBridgeProtocol.swift
generated
vendored
Normal file
148
node_modules/@capacitor/ios/Capacitor/Capacitor/CAPBridgeProtocol.swift
generated
vendored
Normal file
@@ -0,0 +1,148 @@
|
||||
import Foundation
|
||||
import WebKit
|
||||
|
||||
@objc public protocol CAPBridgeProtocol: NSObjectProtocol {
|
||||
// MARK: - Environment Properties
|
||||
var viewController: UIViewController? { get }
|
||||
var config: InstanceConfiguration { get }
|
||||
var webView: WKWebView? { get }
|
||||
var notificationRouter: NotificationRouter { get }
|
||||
var isSimEnvironment: Bool { get }
|
||||
var isDevEnvironment: Bool { get }
|
||||
var userInterfaceStyle: UIUserInterfaceStyle { get }
|
||||
var autoRegisterPlugins: Bool { get }
|
||||
var statusBarVisible: Bool { get set }
|
||||
var statusBarStyle: UIStatusBarStyle { get set }
|
||||
var statusBarAnimation: UIStatusBarAnimation { get set }
|
||||
|
||||
// MARK: - Deprecated
|
||||
@available(*, deprecated, renamed: "webView")
|
||||
func getWebView() -> WKWebView?
|
||||
|
||||
@available(*, deprecated, renamed: "isSimEnvironment")
|
||||
func isSimulator() -> Bool
|
||||
|
||||
@available(*, deprecated, renamed: "isDevEnvironment")
|
||||
func isDevMode() -> Bool
|
||||
|
||||
@available(*, deprecated, renamed: "statusBarVisible")
|
||||
func getStatusBarVisible() -> Bool
|
||||
|
||||
@available(*, deprecated, renamed: "statusBarStyle")
|
||||
func getStatusBarStyle() -> UIStatusBarStyle
|
||||
|
||||
@available(*, deprecated, renamed: "userInterfaceStyle")
|
||||
func getUserInterfaceStyle() -> UIUserInterfaceStyle
|
||||
|
||||
@available(*, deprecated, message: "Moved - equivalent is found on config.localURL")
|
||||
func getLocalUrl() -> String
|
||||
|
||||
@available(*, deprecated, renamed: "savedCall(withID:)")
|
||||
func getSavedCall(_ callbackId: String) -> CAPPluginCall?
|
||||
|
||||
@available(*, deprecated, renamed: "releaseCall(withID:)")
|
||||
func releaseCall(callbackId: String)
|
||||
|
||||
// MARK: - Plugin Access
|
||||
func plugin(withName: String) -> CAPPlugin?
|
||||
|
||||
// MARK: - Call Management
|
||||
func saveCall(_ call: CAPPluginCall)
|
||||
func savedCall(withID: String) -> CAPPluginCall?
|
||||
func releaseCall(_ call: CAPPluginCall)
|
||||
func releaseCall(withID: String)
|
||||
|
||||
// MARK: - JavaScript Handling
|
||||
// `js` is a short name but needs to be preserved for backwards compatibility.
|
||||
// swiftlint:disable identifier_name
|
||||
func evalWithPlugin(_ plugin: CAPPlugin, js: String)
|
||||
func eval(js: String)
|
||||
// swiftlint:enable identifier_name
|
||||
|
||||
@objc optional func injectScriptBeforeLoad(path: String)
|
||||
|
||||
func triggerJSEvent(eventName: String, target: String)
|
||||
func triggerJSEvent(eventName: String, target: String, data: String)
|
||||
|
||||
func triggerWindowJSEvent(eventName: String)
|
||||
func triggerWindowJSEvent(eventName: String, data: String)
|
||||
|
||||
func triggerDocumentJSEvent(eventName: String)
|
||||
func triggerDocumentJSEvent(eventName: String, data: String)
|
||||
|
||||
// MARK: - Paths, Files, Assets
|
||||
func localURL(fromWebURL webURL: URL?) -> URL?
|
||||
func portablePath(fromLocalURL localURL: URL?) -> URL?
|
||||
func setServerBasePath(_ path: String)
|
||||
|
||||
// MARK: - Plugins
|
||||
func registerPluginType(_ pluginType: CAPPlugin.Type)
|
||||
func registerPluginInstance(_ pluginInstance: CAPPlugin)
|
||||
|
||||
// MARK: - View Presentation
|
||||
func showAlertWith(title: String, message: String, buttonTitle: String)
|
||||
func presentVC(_ viewControllerToPresent: UIViewController, animated flag: Bool, completion: (() -> Void)?)
|
||||
func dismissVC(animated flag: Bool, completion: (() -> Void)?)
|
||||
}
|
||||
|
||||
/*
|
||||
Extensions to Obj-C protocols are not exposed to Obj-C code because of limitations in the runtime.
|
||||
Therefore these methods are implicitly Swift-only.
|
||||
|
||||
The deprecated methods are declared here because they can be defined without colliding with the synthesized Obj-C setters
|
||||
for the respective properties (e.g. `setStatusBarVisible:` for 'statusBarVisible`).
|
||||
*/
|
||||
extension CAPBridgeProtocol {
|
||||
// variadic parameters cannot be exposed to Obj-C
|
||||
@available(*, deprecated, message: "Use CAPLog directly")
|
||||
public func modulePrint(_ plugin: CAPPlugin, _ items: Any...) {
|
||||
let output = items.map { String(describing: $0) }.joined(separator: " ")
|
||||
CAPLog.print("⚡️ ", plugin.pluginId, "-", output)
|
||||
}
|
||||
|
||||
// default arguments are not permitted in protocol declarations
|
||||
public func alert(_ title: String, _ message: String, _ buttonTitle: String = "OK") {
|
||||
showAlertWith(title: title, message: message, buttonTitle: buttonTitle)
|
||||
}
|
||||
|
||||
@available(*, deprecated, renamed: "statusBarVisible")
|
||||
public func setStatusBarVisible(_ visible: Bool) {
|
||||
statusBarVisible = visible
|
||||
}
|
||||
|
||||
@available(*, deprecated, renamed: "statusBarStyle")
|
||||
public func setStatusBarStyle(_ style: UIStatusBarStyle) {
|
||||
statusBarStyle = style
|
||||
}
|
||||
|
||||
@available(*, deprecated, renamed: "statusBarAnimation")
|
||||
public func setStatusBarAnimation(_ animation: UIStatusBarAnimation) {
|
||||
statusBarAnimation = animation
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Error(s) potentially exported by the bridge.
|
||||
*/
|
||||
public enum CapacitorBridgeError: Error {
|
||||
case errorExportingCoreJS
|
||||
}
|
||||
|
||||
extension CapacitorBridgeError: CustomNSError {
|
||||
public static var errorDomain: String { "CapacitorBridge" }
|
||||
public var errorCode: Int {
|
||||
switch self {
|
||||
case .errorExportingCoreJS:
|
||||
return 0
|
||||
}
|
||||
}
|
||||
public var errorUserInfo: [String: Any] {
|
||||
return ["info": String(describing: self)]
|
||||
}
|
||||
}
|
||||
|
||||
extension CapacitorBridgeError: LocalizedError {
|
||||
public var errorDescription: String? {
|
||||
return NSLocalizedString("Unable to export JavaScript bridge code to webview", comment: "Capacitor bridge initialization error")
|
||||
}
|
||||
}
|
||||
6
node_modules/@capacitor/ios/Capacitor/Capacitor/CAPBridgeViewController+CDVScreenOrientationDelegate.h
generated
vendored
Normal file
6
node_modules/@capacitor/ios/Capacitor/Capacitor/CAPBridgeViewController+CDVScreenOrientationDelegate.h
generated
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
#import <Capacitor/Capacitor-Swift.h>
|
||||
|
||||
@interface CAPBridgeViewController (CDVScreenOrientationDelegate) <CDVScreenOrientationDelegate>
|
||||
|
||||
@end
|
||||
|
||||
5
node_modules/@capacitor/ios/Capacitor/Capacitor/CAPBridgeViewController+CDVScreenOrientationDelegate.m
generated
vendored
Normal file
5
node_modules/@capacitor/ios/Capacitor/Capacitor/CAPBridgeViewController+CDVScreenOrientationDelegate.m
generated
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
#import "CAPBridgeViewController+CDVScreenOrientationDelegate.h"
|
||||
|
||||
@implementation CAPBridgeViewController (CDVScreenOrientationDelegate)
|
||||
|
||||
@end
|
||||
390
node_modules/@capacitor/ios/Capacitor/Capacitor/CAPBridgeViewController.swift
generated
vendored
Normal file
390
node_modules/@capacitor/ios/Capacitor/Capacitor/CAPBridgeViewController.swift
generated
vendored
Normal file
@@ -0,0 +1,390 @@
|
||||
import UIKit
|
||||
import WebKit
|
||||
import Cordova
|
||||
|
||||
@objc open class CAPBridgeViewController: UIViewController {
|
||||
private var capacitorBridge: CapacitorBridge?
|
||||
public final var bridge: CAPBridgeProtocol? {
|
||||
return capacitorBridge
|
||||
}
|
||||
|
||||
public fileprivate(set) var webView: WKWebView?
|
||||
|
||||
public var isStatusBarVisible = true
|
||||
public var statusBarStyle: UIStatusBarStyle = .default
|
||||
public var statusBarAnimation: UIStatusBarAnimation = .fade
|
||||
@objc public var supportedOrientations: [Int] = []
|
||||
|
||||
public lazy final var isNewBinary: Bool = {
|
||||
if let curVersionCode = Bundle.main.infoDictionary?["CFBundleVersion"] as? String,
|
||||
let curVersionName = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String {
|
||||
if let lastVersionCode = KeyValueStore.standard["lastBinaryVersionCode", as: String.self],
|
||||
let lastVersionName = KeyValueStore.standard["lastBinaryVersionName", as: String.self] {
|
||||
return curVersionCode != lastVersionCode || curVersionName != lastVersionName
|
||||
}
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}()
|
||||
|
||||
// TODO: Remove in Capacitor 8 after moving status bar plugin extensions code
|
||||
@objc func handleViewDidAppear() {
|
||||
if bridge?.config.hasInitialFocus ?? true {
|
||||
self.webView?.becomeFirstResponder()
|
||||
}
|
||||
}
|
||||
|
||||
deinit {
|
||||
NotificationCenter.default.removeObserver(self)
|
||||
}
|
||||
|
||||
override public final func loadView() {
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(self.handleViewDidAppear), name: Notification.Name(rawValue: "CapacitorViewDidAppear"), object: nil)
|
||||
// load the configuration and set the logging flag
|
||||
let configDescriptor = instanceDescriptor()
|
||||
let configuration = InstanceConfiguration(with: configDescriptor, isDebug: CapacitorBridge.isDevEnvironment)
|
||||
CAPLog.enableLogging = configuration.loggingEnabled
|
||||
logWarnings(for: configDescriptor)
|
||||
|
||||
setStatusBarDefaults()
|
||||
setScreenOrientationDefaults()
|
||||
|
||||
// get the web view
|
||||
let assetHandler = WebViewAssetHandler(router: router())
|
||||
assetHandler.setAssetPath(configuration.appLocation.path)
|
||||
assetHandler.setServerUrl(configuration.serverURL)
|
||||
let delegationHandler = WebViewDelegationHandler()
|
||||
prepareWebView(with: configuration, assetHandler: assetHandler, delegationHandler: delegationHandler)
|
||||
view = webView
|
||||
// create the bridge
|
||||
capacitorBridge = CapacitorBridge(with: configuration,
|
||||
delegate: self,
|
||||
cordovaConfiguration: configDescriptor.cordovaConfiguration,
|
||||
assetHandler: assetHandler,
|
||||
delegationHandler: delegationHandler)
|
||||
capacitorDidLoad()
|
||||
|
||||
if configDescriptor.instanceType == .fixed {
|
||||
updateBinaryVersion()
|
||||
}
|
||||
}
|
||||
|
||||
override open func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
loadWebView()
|
||||
}
|
||||
|
||||
override open func viewDidAppear(_ animated: Bool) {
|
||||
super.viewDidAppear(animated)
|
||||
if bridge?.config.hasInitialFocus ?? true {
|
||||
self.webView?.becomeFirstResponder()
|
||||
}
|
||||
}
|
||||
|
||||
override open func canPerformUnwindSegueAction(_ action: Selector, from fromViewController: UIViewController, withSender sender: Any) -> Bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// MARK: - Initialization
|
||||
|
||||
/**
|
||||
The InstanceDescriptor that should be used for the Capacitor environment.
|
||||
|
||||
- Returns: `InstanceDescriptor`
|
||||
|
||||
- Note: This is called early in the View Controller's lifecycle. Not all properties will be set at invocation.
|
||||
*/
|
||||
open func instanceDescriptor() -> InstanceDescriptor {
|
||||
let descriptor = InstanceDescriptor.init()
|
||||
if !isNewBinary && !descriptor.cordovaDeployDisabled {
|
||||
if let persistedPath = KeyValueStore.standard["serverBasePath", as: String.self], !persistedPath.isEmpty {
|
||||
if let libPath = NSSearchPathForDirectoriesInDomains(.libraryDirectory, .userDomainMask, true).first {
|
||||
descriptor.appLocation = URL(fileURLWithPath: libPath, isDirectory: true)
|
||||
.appendingPathComponent("NoCloud")
|
||||
.appendingPathComponent("ionic_built_snapshots")
|
||||
.appendingPathComponent(URL(fileURLWithPath: persistedPath, isDirectory: true).lastPathComponent)
|
||||
}
|
||||
}
|
||||
}
|
||||
return descriptor
|
||||
}
|
||||
|
||||
open func router() -> Router {
|
||||
return CapacitorRouter()
|
||||
}
|
||||
|
||||
/**
|
||||
The WKWebViewConfiguration to use for the webview.
|
||||
|
||||
- Parameter instanceConfiguration: the configuration that will define the capacitor environment.
|
||||
|
||||
- Returns: `WKWebViewConfiguration`
|
||||
|
||||
It is recommended to call super's implementation and modify the result, rather than creating a new object.
|
||||
*/
|
||||
open func webViewConfiguration(for instanceConfiguration: InstanceConfiguration) -> WKWebViewConfiguration {
|
||||
let webViewConfiguration = WKWebViewConfiguration()
|
||||
webViewConfiguration.websiteDataStore.httpCookieStore.add(CapacitorWKCookieObserver())
|
||||
webViewConfiguration.allowsInlineMediaPlayback = true
|
||||
webViewConfiguration.suppressesIncrementalRendering = false
|
||||
webViewConfiguration.allowsAirPlayForMediaPlayback = true
|
||||
webViewConfiguration.mediaTypesRequiringUserActionForPlayback = []
|
||||
webViewConfiguration.limitsNavigationsToAppBoundDomains = instanceConfiguration.limitsNavigationsToAppBoundDomains
|
||||
if #available(iOS 15.4, *) {
|
||||
webViewConfiguration.preferences.isElementFullscreenEnabled = true
|
||||
}
|
||||
if let appendUserAgent = instanceConfiguration.appendedUserAgentString {
|
||||
if let appName = webViewConfiguration.applicationNameForUserAgent {
|
||||
webViewConfiguration.applicationNameForUserAgent = "\(appName) \(appendUserAgent)"
|
||||
} else {
|
||||
webViewConfiguration.applicationNameForUserAgent = appendUserAgent
|
||||
}
|
||||
}
|
||||
if let preferredContentMode = instanceConfiguration.preferredContentMode {
|
||||
var mode = WKWebpagePreferences.ContentMode.recommended
|
||||
if preferredContentMode == "mobile" {
|
||||
mode = WKWebpagePreferences.ContentMode.mobile
|
||||
} else if preferredContentMode == "desktop" {
|
||||
mode = WKWebpagePreferences.ContentMode.desktop
|
||||
}
|
||||
webViewConfiguration.defaultWebpagePreferences.preferredContentMode = mode
|
||||
}
|
||||
return webViewConfiguration
|
||||
}
|
||||
|
||||
/**
|
||||
Returns a WKWebView initialized with the frame and configuration.
|
||||
|
||||
Subclasses can override this method to return a subclass of WKWebView if needed.
|
||||
*/
|
||||
open func webView(with frame: CGRect, configuration: WKWebViewConfiguration) -> WKWebView {
|
||||
return WKWebView(frame: frame, configuration: configuration)
|
||||
}
|
||||
|
||||
/**
|
||||
Allows any additional configuration to be performed. The `webView` and `bridge` properties will be set by this point.
|
||||
|
||||
- Note: This is called before the webview has been added to the view hierarchy. Not all operations may be possible at
|
||||
this time.
|
||||
*/
|
||||
open func capacitorDidLoad() {
|
||||
}
|
||||
|
||||
public final func loadWebView() {
|
||||
guard let bridge = capacitorBridge else {
|
||||
return
|
||||
}
|
||||
|
||||
guard FileManager.default.fileExists(atPath: bridge.config.appStartFileURL.path) else {
|
||||
fatalLoadError()
|
||||
}
|
||||
|
||||
let url = bridge.config.appStartServerURL
|
||||
CAPLog.print("⚡️ Loading app at \(url.absoluteString)...")
|
||||
bridge.webViewDelegationHandler.willLoadWebview(webView)
|
||||
_ = webView?.load(URLRequest(url: url))
|
||||
}
|
||||
|
||||
// MARK: - System Integration
|
||||
|
||||
open func setStatusBarDefaults() {
|
||||
if let plist = Bundle.main.infoDictionary {
|
||||
if let statusBarHidden = plist["UIStatusBarHidden"] as? Bool {
|
||||
if statusBarHidden {
|
||||
self.isStatusBarVisible = false
|
||||
}
|
||||
}
|
||||
if let statusBarStyle = plist["UIStatusBarStyle"] as? String {
|
||||
if statusBarStyle == "UIStatusBarStyleDarkContent" {
|
||||
self.statusBarStyle = .darkContent
|
||||
} else if statusBarStyle != "UIStatusBarStyleDefault" {
|
||||
self.statusBarStyle = .lightContent
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
open func setScreenOrientationDefaults() {
|
||||
if let plist = Bundle.main.infoDictionary {
|
||||
if let orientations = plist["UISupportedInterfaceOrientations"] as? [String] {
|
||||
for orientation in orientations {
|
||||
if orientation == "UIInterfaceOrientationPortrait" {
|
||||
self.supportedOrientations.append(UIInterfaceOrientation.portrait.rawValue)
|
||||
}
|
||||
if orientation == "UIInterfaceOrientationPortraitUpsideDown" {
|
||||
self.supportedOrientations.append(UIInterfaceOrientation.portraitUpsideDown.rawValue)
|
||||
}
|
||||
if orientation == "UIInterfaceOrientationLandscapeLeft" {
|
||||
self.supportedOrientations.append(UIInterfaceOrientation.landscapeLeft.rawValue)
|
||||
}
|
||||
if orientation == "UIInterfaceOrientationLandscapeRight" {
|
||||
self.supportedOrientations.append(UIInterfaceOrientation.landscapeRight.rawValue)
|
||||
}
|
||||
}
|
||||
if self.supportedOrientations.count == 0 {
|
||||
self.supportedOrientations.append(UIInterfaceOrientation.portrait.rawValue)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override open var prefersStatusBarHidden: Bool {
|
||||
return !isStatusBarVisible
|
||||
}
|
||||
|
||||
override open var preferredStatusBarStyle: UIStatusBarStyle {
|
||||
return statusBarStyle
|
||||
}
|
||||
|
||||
override open var preferredStatusBarUpdateAnimation: UIStatusBarAnimation {
|
||||
return statusBarAnimation
|
||||
}
|
||||
|
||||
open func setStatusBarVisible(_ isStatusBarVisible: Bool) {
|
||||
self.isStatusBarVisible = isStatusBarVisible
|
||||
UIView.animate(withDuration: 0.2, animations: {
|
||||
self.setNeedsStatusBarAppearanceUpdate()
|
||||
})
|
||||
}
|
||||
|
||||
open func setStatusBarStyle(_ statusBarStyle: UIStatusBarStyle) {
|
||||
self.statusBarStyle = statusBarStyle
|
||||
UIView.animate(withDuration: 0.2, animations: {
|
||||
self.setNeedsStatusBarAppearanceUpdate()
|
||||
})
|
||||
}
|
||||
|
||||
open func setStatusBarAnimation(_ statusBarAnimation: UIStatusBarAnimation) {
|
||||
self.statusBarAnimation = statusBarAnimation
|
||||
}
|
||||
|
||||
override open var supportedInterfaceOrientations: UIInterfaceOrientationMask {
|
||||
var ret = 0
|
||||
if self.supportedOrientations.contains(UIInterfaceOrientation.portrait.rawValue) {
|
||||
ret = ret | (1 << UIInterfaceOrientation.portrait.rawValue)
|
||||
}
|
||||
if self.supportedOrientations.contains(UIInterfaceOrientation.portraitUpsideDown.rawValue) {
|
||||
ret = ret | (1 << UIInterfaceOrientation.portraitUpsideDown.rawValue)
|
||||
}
|
||||
if self.supportedOrientations.contains(UIInterfaceOrientation.landscapeRight.rawValue) {
|
||||
ret = ret | (1 << UIInterfaceOrientation.landscapeRight.rawValue)
|
||||
}
|
||||
if self.supportedOrientations.contains(UIInterfaceOrientation.landscapeLeft.rawValue) {
|
||||
ret = ret | (1 << UIInterfaceOrientation.landscapeLeft.rawValue)
|
||||
}
|
||||
return UIInterfaceOrientationMask.init(rawValue: UInt(ret))
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Application Path
|
||||
|
||||
extension CAPBridgeViewController {
|
||||
@objc public func getServerBasePath() -> String {
|
||||
return bridge?.config.appLocation.path ?? ""
|
||||
}
|
||||
|
||||
@objc public func setServerBasePath(path: String) {
|
||||
guard let capBridge = capacitorBridge else { return }
|
||||
capBridge.setServerBasePath(path)
|
||||
DispatchQueue.main.async { [weak self] in
|
||||
_ = self?.webView?.load(URLRequest(url: capBridge.config.serverURL))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Private
|
||||
|
||||
extension CAPBridgeViewController {
|
||||
private func prepareWebView(with configuration: InstanceConfiguration, assetHandler: WebViewAssetHandler, delegationHandler: WebViewDelegationHandler) {
|
||||
// set the cookie policy
|
||||
HTTPCookieStorage.shared.cookieAcceptPolicy = HTTPCookie.AcceptPolicy.always
|
||||
// setup the web view configuration
|
||||
let webConfig = webViewConfiguration(for: configuration)
|
||||
webConfig.setURLSchemeHandler(assetHandler, forURLScheme: configuration.localURL.scheme ?? InstanceDescriptorDefaults.scheme)
|
||||
webConfig.userContentController = delegationHandler.contentController
|
||||
// create the web view and set its properties
|
||||
let aWebView = webView(with: .zero, configuration: webConfig)
|
||||
aWebView.scrollView.bounces = false
|
||||
aWebView.scrollView.contentInsetAdjustmentBehavior = configuration.contentInsetAdjustmentBehavior
|
||||
aWebView.allowsLinkPreview = configuration.allowLinkPreviews
|
||||
aWebView.scrollView.isScrollEnabled = configuration.scrollingEnabled
|
||||
if let overrideUserAgent = configuration.overridenUserAgentString {
|
||||
aWebView.customUserAgent = overrideUserAgent
|
||||
}
|
||||
if let backgroundColor = configuration.backgroundColor {
|
||||
aWebView.backgroundColor = backgroundColor
|
||||
aWebView.scrollView.backgroundColor = backgroundColor
|
||||
} else {
|
||||
// Use the system background colors if background is not set by user
|
||||
aWebView.backgroundColor = UIColor.systemBackground
|
||||
aWebView.scrollView.backgroundColor = UIColor.systemBackground
|
||||
}
|
||||
aWebView.capacitor.setKeyboardShouldRequireUserInteraction(false)
|
||||
// set our ivar
|
||||
webView = aWebView
|
||||
// set our delegates
|
||||
aWebView.uiDelegate = delegationHandler
|
||||
aWebView.navigationDelegate = delegationHandler
|
||||
if !configuration.zoomingEnabled {
|
||||
aWebView.scrollView.delegate = delegationHandler
|
||||
}
|
||||
}
|
||||
|
||||
private func updateBinaryVersion() {
|
||||
guard isNewBinary else {
|
||||
return
|
||||
}
|
||||
guard let versionCode = Bundle.main.infoDictionary?["CFBundleVersion"] as? String,
|
||||
let versionName = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String else {
|
||||
return
|
||||
}
|
||||
let store = KeyValueStore.standard
|
||||
store["lastBinaryVersionCode"] = versionCode
|
||||
store["lastBinaryVersionName"] = versionName
|
||||
store["serverBasePath"] = nil as String?
|
||||
}
|
||||
|
||||
private func logWarnings(for descriptor: InstanceDescriptor) {
|
||||
if descriptor.warnings.contains(.missingAppDir) {
|
||||
CAPLog.print("⚡️ ERROR: Unable to find application directory at: \"\(descriptor.appLocation.absoluteString)\"!")
|
||||
}
|
||||
if descriptor.instanceType == .fixed {
|
||||
if descriptor.warnings.contains(.missingFile) {
|
||||
CAPLog.print("Unable to find capacitor.config.json, make sure it exists and run npx cap copy.")
|
||||
}
|
||||
if descriptor.warnings.contains(.invalidFile) {
|
||||
CAPLog.print("Unable to parse capacitor.config.json. Make sure it's valid JSON.")
|
||||
}
|
||||
if descriptor.warnings.contains(.missingCordovaFile) {
|
||||
CAPLog.print("Unable to find config.xml, make sure it exists and run npx cap copy.")
|
||||
}
|
||||
if descriptor.warnings.contains(.invalidCordovaFile) {
|
||||
CAPLog.print("Unable to parse config.xml. Make sure it's valid XML.")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func printLoadError() {
|
||||
let fullStartPath = bridge?.config.appStartFileURL.path ?? ""
|
||||
|
||||
CAPLog.print("⚡️ ERROR: Unable to load \(fullStartPath)")
|
||||
CAPLog.print("⚡️ This file is the root of your web app and must exist before")
|
||||
CAPLog.print("⚡️ Capacitor can run. Ensure you've run capacitor copy at least")
|
||||
CAPLog.print("⚡️ or, if embedding, that this directory exists as a resource directory.")
|
||||
}
|
||||
|
||||
private func fatalLoadError() -> Never {
|
||||
printLoadError()
|
||||
exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
extension CAPBridgeViewController: CAPBridgeDelegate {
|
||||
public var bridgedWebView: WKWebView? {
|
||||
return webView
|
||||
}
|
||||
|
||||
public var bridgedViewController: UIViewController? {
|
||||
return self
|
||||
}
|
||||
}
|
||||
18
node_modules/@capacitor/ios/Capacitor/Capacitor/CAPBridgedJSTypes.h
generated
vendored
Normal file
18
node_modules/@capacitor/ios/Capacitor/Capacitor/CAPBridgedJSTypes.h
generated
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
// Convenience methods for bridging to/from JavaScript types. Deliberately hidden from
|
||||
// Swift by omission (to avoid collisions with Swift protocols), use
|
||||
// `#import <Capacitor/CAPBridgedJSTypes.h>` if working in Objective-C.
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <Capacitor/Capacitor-Swift.h>
|
||||
|
||||
@protocol BridgedJSValueContainerImplementation <NSObject>
|
||||
@required
|
||||
- (NSString * _Nullable)getString:(NSString * _Nonnull)key defaultValue:(NSString * _Nullable)defaultValue;
|
||||
- (NSDate * _Nullable)getDate:(NSString * _Nonnull)key defaultValue:(NSDate * _Nullable)defaultValue;
|
||||
- (NSDictionary * _Nullable)getObject:(NSString * _Nonnull)key defaultValue:(NSDictionary * _Nullable)defaultValue;
|
||||
- (NSNumber * _Nullable)getNumber:(NSString * _Nonnull)key defaultValue:(NSNumber * _Nullable)defaultValue;
|
||||
- (BOOL)getBool:(NSString * _Nonnull)key defaultValue:(BOOL)defaultValue;
|
||||
@end
|
||||
|
||||
@interface CAPPluginCall (BridgedJSProtocol) <BridgedJSValueContainerImplementation>
|
||||
@end
|
||||
43
node_modules/@capacitor/ios/Capacitor/Capacitor/CAPBridgedJSTypes.m
generated
vendored
Normal file
43
node_modules/@capacitor/ios/Capacitor/Capacitor/CAPBridgedJSTypes.m
generated
vendored
Normal file
@@ -0,0 +1,43 @@
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "CAPBridgedJSTypes.h"
|
||||
|
||||
@implementation CAPPluginCall (BridgedJSProtocol)
|
||||
- (NSString * _Nullable)getString:(NSString * _Nonnull)key defaultValue:(NSString * _Nullable)defaultValue {
|
||||
id value = [[self dictionaryRepresentation] objectForKey:key];
|
||||
if (value != nil && [value isKindOfClass:[NSString class]]) {
|
||||
return value;
|
||||
}
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
- (NSDate * _Nullable)getDate:(NSString * _Nonnull)key defaultValue:(NSDate * _Nullable)defaultValue {
|
||||
id value = [[self dictionaryRepresentation] objectForKey:key];
|
||||
if (value != nil && [value isKindOfClass:[NSDate class]]) {
|
||||
return value;
|
||||
}
|
||||
else if (value != nil && [value isKindOfClass:[NSString class]]) {
|
||||
return [[[self class] jsDateFormatter] dateFromString:value];
|
||||
}
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
- (NSDictionary * _Nullable)getObject:(NSString * _Nonnull)key defaultValue:(NSDictionary * _Nullable)defaultValue {
|
||||
id value = [[self dictionaryRepresentation] objectForKey:key];
|
||||
if (value != nil && [value isKindOfClass:[NSDictionary class]]) {
|
||||
return value;
|
||||
}
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
- (NSNumber * _Nullable)getNumber:(NSString * _Nonnull)key defaultValue:(NSNumber * _Nullable)defaultValue {
|
||||
id value = [[self dictionaryRepresentation] objectForKey:key];
|
||||
if (value != nil && [value isKindOfClass:[NSNumber class]]) {
|
||||
return value;
|
||||
}
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
- (BOOL)getBool:(NSString * _Nonnull)key defaultValue:(BOOL)defaultValue {
|
||||
return [[self getNumber:key defaultValue:[NSNumber numberWithBool:defaultValue]] boolValue];
|
||||
}
|
||||
@end
|
||||
13
node_modules/@capacitor/ios/Capacitor/Capacitor/CAPBridgedPlugin+getMethod.swift
generated
vendored
Normal file
13
node_modules/@capacitor/ios/Capacitor/Capacitor/CAPBridgedPlugin+getMethod.swift
generated
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
//
|
||||
// CAPBridgedPlugin+getMethod.swift
|
||||
// Capacitor
|
||||
//
|
||||
// Created by Steven Sherry on 3/1/23.
|
||||
// Copyright © 2023 Drifty Co. All rights reserved.
|
||||
//
|
||||
|
||||
extension CAPBridgedPlugin {
|
||||
func getMethod(named name: String) -> CAPPluginMethod? {
|
||||
pluginMethods.first { $0.name == name }
|
||||
}
|
||||
}
|
||||
41
node_modules/@capacitor/ios/Capacitor/Capacitor/CAPBridgedPlugin.h
generated
vendored
Normal file
41
node_modules/@capacitor/ios/Capacitor/Capacitor/CAPBridgedPlugin.h
generated
vendored
Normal file
@@ -0,0 +1,41 @@
|
||||
#import "CAPPluginMethod.h"
|
||||
|
||||
#if defined(__cplusplus)
|
||||
#define CAP_EXTERN extern "C" __attribute__((visibility("default")))
|
||||
#else
|
||||
#define CAP_EXTERN extern __attribute__((visibility("default")))
|
||||
#endif
|
||||
|
||||
#define CAPPluginReturnNone @"none"
|
||||
#define CAPPluginReturnCallback @"callback"
|
||||
#define CAPPluginReturnPromise @"promise"
|
||||
|
||||
@class CAPPluginCall;
|
||||
@class CAPPlugin;
|
||||
|
||||
@protocol CAPBridgedPlugin <NSObject>
|
||||
@property (nonnull, readonly) NSString *identifier;
|
||||
@property (nonnull, readonly) NSString *jsName;
|
||||
@property (nonnull, readonly) NSArray<CAPPluginMethod *> *pluginMethods;
|
||||
@end
|
||||
|
||||
#define CAP_PLUGIN_CONFIG(plugin_id, js_name) \
|
||||
- (NSString *)identifier { return @#plugin_id; } \
|
||||
- (NSString *)jsName { return @js_name; }
|
||||
#define CAP_PLUGIN_METHOD(method_name, method_return_type) \
|
||||
[methods addObject:[[CAPPluginMethod alloc] initWithName:@#method_name returnType:method_return_type]]
|
||||
|
||||
#define CAP_PLUGIN(objc_name, js_name, methods_body) \
|
||||
@interface objc_name : NSObject \
|
||||
@end \
|
||||
@interface objc_name (CAPPluginCategory) <CAPBridgedPlugin> \
|
||||
@end \
|
||||
@implementation objc_name (CAPPluginCategory) \
|
||||
- (NSArray *)pluginMethods { \
|
||||
NSMutableArray *methods = [NSMutableArray new]; \
|
||||
methods_body \
|
||||
return methods; \
|
||||
} \
|
||||
CAP_PLUGIN_CONFIG(objc_name, js_name) \
|
||||
@end
|
||||
|
||||
14
node_modules/@capacitor/ios/Capacitor/Capacitor/CAPFile.swift
generated
vendored
Normal file
14
node_modules/@capacitor/ios/Capacitor/Capacitor/CAPFile.swift
generated
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
/**
|
||||
* CAPFileManager helps map file schemes to physical files, whether they are on
|
||||
* disk, in a bundle, or in another location.
|
||||
*/
|
||||
@objc public class CAPFileManager: NSObject {
|
||||
@available(*, deprecated, message: "Use portablePath(fromLocalURL:) on the Bridge")
|
||||
public static func getPortablePath(host: String, uri: URL?) -> String? {
|
||||
if let uri = uri {
|
||||
let uriWithoutFile = uri.absoluteString.replacingOccurrences(of: "file://", with: "")
|
||||
return host + CapacitorBridge.fileStartIdentifier + uriWithoutFile
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
38
node_modules/@capacitor/ios/Capacitor/Capacitor/CAPInstanceConfiguration.h
generated
vendored
Normal file
38
node_modules/@capacitor/ios/Capacitor/Capacitor/CAPInstanceConfiguration.h
generated
vendored
Normal file
@@ -0,0 +1,38 @@
|
||||
#ifndef CAPInstanceConfiguration_h
|
||||
#define CAPInstanceConfiguration_h
|
||||
|
||||
@import UIKit;
|
||||
|
||||
@class CAPInstanceDescriptor;
|
||||
|
||||
NS_SWIFT_NAME(InstanceConfiguration)
|
||||
@interface CAPInstanceConfiguration: NSObject
|
||||
@property (nonatomic, readonly, nullable) NSString *appendedUserAgentString;
|
||||
@property (nonatomic, readonly, nullable) NSString *overridenUserAgentString;
|
||||
@property (nonatomic, readonly, nullable) UIColor *backgroundColor;
|
||||
@property (nonatomic, readonly, nonnull) NSArray<NSString*> *allowedNavigationHostnames;
|
||||
@property (nonatomic, readonly, nonnull) NSURL *localURL;
|
||||
@property (nonatomic, readonly, nonnull) NSURL *serverURL;
|
||||
@property (nonatomic, readonly, nullable) NSString *errorPath;
|
||||
@property (nonatomic, readonly, nonnull) NSDictionary *pluginConfigurations;
|
||||
@property (nonatomic, readonly) BOOL loggingEnabled;
|
||||
@property (nonatomic, readonly) BOOL scrollingEnabled;
|
||||
@property (nonatomic, readonly) BOOL zoomingEnabled;
|
||||
@property (nonatomic, readonly) BOOL allowLinkPreviews;
|
||||
@property (nonatomic, readonly) BOOL handleApplicationNotifications;
|
||||
@property (nonatomic, readonly) BOOL isWebDebuggable;
|
||||
@property (nonatomic, readonly) BOOL hasInitialFocus;
|
||||
@property (nonatomic, readonly) BOOL cordovaDeployDisabled;
|
||||
@property (nonatomic, readonly) UIScrollViewContentInsetAdjustmentBehavior contentInsetAdjustmentBehavior;
|
||||
@property (nonatomic, readonly, nonnull) NSURL *appLocation;
|
||||
@property (nonatomic, readonly, nullable) NSString *appStartPath;
|
||||
@property (nonatomic, readonly) BOOL limitsNavigationsToAppBoundDomains;
|
||||
@property (nonatomic, readonly, nullable) NSString *preferredContentMode;
|
||||
|
||||
@property (nonatomic, readonly, nonnull) NSDictionary *legacyConfig DEPRECATED_MSG_ATTRIBUTE("Use direct properties instead");
|
||||
|
||||
- (instancetype _Nonnull)initWithDescriptor:(CAPInstanceDescriptor* _Nonnull)descriptor isDebug:(BOOL)debug NS_SWIFT_NAME(init(with:isDebug:));
|
||||
- (instancetype _Nonnull)updatingAppLocation:(NSURL* _Nonnull)location NS_SWIFT_NAME(updatingAppLocation(_:));
|
||||
@end
|
||||
|
||||
#endif /* CAPInstanceConfiguration_h */
|
||||
93
node_modules/@capacitor/ios/Capacitor/Capacitor/CAPInstanceConfiguration.m
generated
vendored
Normal file
93
node_modules/@capacitor/ios/Capacitor/Capacitor/CAPInstanceConfiguration.m
generated
vendored
Normal file
@@ -0,0 +1,93 @@
|
||||
#import "CAPInstanceConfiguration.h"
|
||||
#import <Capacitor/Capacitor-Swift.h>
|
||||
|
||||
@interface CAPInstanceConfiguration (Internal)
|
||||
- (instancetype)initWithConfiguration:(CAPInstanceConfiguration*)configuration andLocation:(NSURL*)location;
|
||||
@end
|
||||
|
||||
|
||||
@implementation CAPInstanceConfiguration
|
||||
|
||||
- (instancetype)initWithDescriptor:(CAPInstanceDescriptor *)descriptor isDebug:(BOOL)debug {
|
||||
if (self = [super init]) {
|
||||
// first, give the descriptor a chance to make itself internally consistent
|
||||
[descriptor normalize];
|
||||
// now copy the simple properties
|
||||
_appendedUserAgentString = descriptor.appendedUserAgentString;
|
||||
_overridenUserAgentString = descriptor.overridenUserAgentString;
|
||||
_backgroundColor = descriptor.backgroundColor;
|
||||
_allowedNavigationHostnames = descriptor.allowedNavigationHostnames;
|
||||
switch (descriptor.loggingBehavior) {
|
||||
case CAPInstanceLoggingBehaviorProduction:
|
||||
_loggingEnabled = true;
|
||||
break;
|
||||
case CAPInstanceLoggingBehaviorDebug:
|
||||
_loggingEnabled = debug;
|
||||
break;
|
||||
default:
|
||||
_loggingEnabled = false;
|
||||
break;
|
||||
}
|
||||
_scrollingEnabled = descriptor.scrollingEnabled;
|
||||
_zoomingEnabled = descriptor.zoomingEnabled;
|
||||
_allowLinkPreviews = descriptor.allowLinkPreviews;
|
||||
_handleApplicationNotifications = descriptor.handleApplicationNotifications;
|
||||
_contentInsetAdjustmentBehavior = descriptor.contentInsetAdjustmentBehavior;
|
||||
_appLocation = descriptor.appLocation;
|
||||
_appStartPath = descriptor.appStartPath;
|
||||
_limitsNavigationsToAppBoundDomains = descriptor.limitsNavigationsToAppBoundDomains;
|
||||
_preferredContentMode = descriptor.preferredContentMode;
|
||||
_pluginConfigurations = descriptor.pluginConfigurations;
|
||||
_isWebDebuggable = descriptor.isWebDebuggable;
|
||||
_hasInitialFocus = descriptor.hasInitialFocus;
|
||||
_legacyConfig = descriptor.legacyConfig;
|
||||
// construct the necessary URLs
|
||||
_localURL = [[NSURL alloc] initWithString:[NSString stringWithFormat:@"%@://%@", descriptor.urlScheme, descriptor.urlHostname]];
|
||||
if (descriptor.serverURL != nil) {
|
||||
_serverURL = [[NSURL alloc] initWithString:(descriptor.serverURL)];
|
||||
}
|
||||
else {
|
||||
_serverURL = _localURL;
|
||||
}
|
||||
_errorPath = descriptor.errorPath;
|
||||
// extract the one value we care about from the cordova configuration
|
||||
_cordovaDeployDisabled = [descriptor cordovaDeployDisabled];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (instancetype)initWithConfiguration:(CAPInstanceConfiguration*)configuration andLocation:(NSURL*)location {
|
||||
if (self = [super init]) {
|
||||
_appendedUserAgentString = [[configuration appendedUserAgentString] copy];
|
||||
_overridenUserAgentString = [[configuration overridenUserAgentString] copy];
|
||||
_backgroundColor = configuration.backgroundColor;
|
||||
_allowedNavigationHostnames = [[configuration allowedNavigationHostnames] copy];
|
||||
_localURL = [[configuration localURL] copy];
|
||||
_serverURL = [[configuration serverURL] copy];
|
||||
_errorPath = [[configuration errorPath] copy];
|
||||
_pluginConfigurations = [[configuration pluginConfigurations] copy];
|
||||
_loggingEnabled = configuration.loggingEnabled;
|
||||
_scrollingEnabled = configuration.scrollingEnabled;
|
||||
_zoomingEnabled = configuration.zoomingEnabled;
|
||||
_allowLinkPreviews = configuration.allowLinkPreviews;
|
||||
_handleApplicationNotifications = configuration.handleApplicationNotifications;
|
||||
_isWebDebuggable = configuration.isWebDebuggable;
|
||||
_hasInitialFocus = configuration.hasInitialFocus;
|
||||
_cordovaDeployDisabled = configuration.cordovaDeployDisabled;
|
||||
_contentInsetAdjustmentBehavior = configuration.contentInsetAdjustmentBehavior;
|
||||
// we don't care about internal usage of deprecated APIs and the framework should build cleanly
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
||||
_legacyConfig = [[configuration legacyConfig] copy];
|
||||
#pragma clang diagnostic pop
|
||||
_appStartPath = configuration.appStartPath;
|
||||
_appLocation = [location copy];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (instancetype)updatingAppLocation:(NSURL*)location {
|
||||
return [[CAPInstanceConfiguration alloc] initWithConfiguration:self andLocation:location];
|
||||
}
|
||||
|
||||
@end
|
||||
78
node_modules/@capacitor/ios/Capacitor/Capacitor/CAPInstanceConfiguration.swift
generated
vendored
Normal file
78
node_modules/@capacitor/ios/Capacitor/Capacitor/CAPInstanceConfiguration.swift
generated
vendored
Normal file
@@ -0,0 +1,78 @@
|
||||
import Foundation
|
||||
|
||||
extension InstanceConfiguration {
|
||||
@objc public var appStartFileURL: URL {
|
||||
if let path = appStartPath {
|
||||
return appLocation.appendingPathComponent(path)
|
||||
}
|
||||
return appLocation
|
||||
}
|
||||
|
||||
@objc public var appStartServerURL: URL {
|
||||
if let path = appStartPath {
|
||||
return serverURL.appendingPathComponent(path)
|
||||
}
|
||||
return serverURL
|
||||
}
|
||||
|
||||
@objc public var errorPathURL: URL? {
|
||||
guard let errorPath = errorPath else {
|
||||
return nil
|
||||
}
|
||||
|
||||
return localURL.appendingPathComponent(errorPath)
|
||||
}
|
||||
|
||||
@available(*, deprecated, message: "Use getPluginConfig")
|
||||
@objc public func getPluginConfigValue(_ pluginId: String, _ configKey: String) -> Any? {
|
||||
return (pluginConfigurations as? JSObject)?[keyPath: KeyPath("\(pluginId).\(configKey)")]
|
||||
}
|
||||
|
||||
@objc public func getPluginConfig(_ pluginId: String) -> PluginConfig {
|
||||
if let cfg = (pluginConfigurations as? JSObject)?[keyPath: KeyPath("\(pluginId)")] as? JSObject {
|
||||
return PluginConfig(config: cfg)
|
||||
}
|
||||
return PluginConfig(config: JSObject())
|
||||
}
|
||||
|
||||
@objc public func shouldAllowNavigation(to host: String) -> Bool {
|
||||
for hostname in allowedNavigationHostnames {
|
||||
if doesHost(host, match: hostname) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
@available(*, deprecated, message: "Use direct property accessors")
|
||||
@objc public func getValue(_ key: String) -> Any? {
|
||||
return (legacyConfig as? JSObject)?[keyPath: KeyPath(key)]
|
||||
}
|
||||
|
||||
@available(*, deprecated, message: "Use direct property accessors")
|
||||
@objc public func getString(_ key: String) -> String? {
|
||||
return (legacyConfig as? JSObject)?[keyPath: KeyPath(key)] as? String
|
||||
}
|
||||
|
||||
// MARK: - Private
|
||||
|
||||
private func doesHost(_ host: String, match pattern: String) -> Bool {
|
||||
// bail early in the simple case
|
||||
if pattern == "*" {
|
||||
return true
|
||||
}
|
||||
// break apart the pieces
|
||||
var hostComponents = host.lowercased().split(separator: ".")
|
||||
var patternComponents = pattern.lowercased().split(separator: ".")
|
||||
guard hostComponents.count == patternComponents.count else {
|
||||
return false
|
||||
}
|
||||
// remove any wildcard segments
|
||||
for wildcard in patternComponents.enumerated().reversed().filter({ $0.element == "*" }) {
|
||||
hostComponents.remove(at: wildcard.offset)
|
||||
patternComponents.remove(at: wildcard.offset)
|
||||
}
|
||||
// match with what's left
|
||||
return hostComponents == patternComponents
|
||||
}
|
||||
}
|
||||
167
node_modules/@capacitor/ios/Capacitor/Capacitor/CAPInstanceDescriptor.h
generated
vendored
Normal file
167
node_modules/@capacitor/ios/Capacitor/Capacitor/CAPInstanceDescriptor.h
generated
vendored
Normal file
@@ -0,0 +1,167 @@
|
||||
#ifndef CAPInstanceDescriptor_h
|
||||
#define CAPInstanceDescriptor_h
|
||||
|
||||
@import UIKit;
|
||||
@import Cordova;
|
||||
|
||||
typedef NS_ENUM(NSInteger, CAPInstanceType) {
|
||||
CAPInstanceTypeFixed NS_SWIFT_NAME(fixed),
|
||||
CAPInstanceTypeVariable NS_SWIFT_NAME(variable)
|
||||
} NS_SWIFT_NAME(InstanceType);
|
||||
|
||||
typedef NS_OPTIONS(NSUInteger, CAPInstanceWarning) {
|
||||
CAPInstanceWarningMissingAppDir NS_SWIFT_NAME(missingAppDir) = 1 << 0,
|
||||
CAPInstanceWarningMissingFile NS_SWIFT_NAME(missingFile) = 1 << 1,
|
||||
CAPInstanceWarningInvalidFile NS_SWIFT_NAME(invalidFile) = 1 << 2,
|
||||
CAPInstanceWarningMissingCordovaFile NS_SWIFT_NAME(missingCordovaFile) = 1 << 3,
|
||||
CAPInstanceWarningInvalidCordovaFile NS_SWIFT_NAME(invalidCordovaFile) = 1 << 4
|
||||
} NS_SWIFT_NAME(InstanceWarning);
|
||||
|
||||
typedef NS_OPTIONS(NSUInteger, CAPInstanceLoggingBehavior) {
|
||||
CAPInstanceLoggingBehaviorNone NS_SWIFT_NAME(none) = 1 << 0,
|
||||
CAPInstanceLoggingBehaviorDebug NS_SWIFT_NAME(debug) = 1 << 1,
|
||||
CAPInstanceLoggingBehaviorProduction NS_SWIFT_NAME(production) = 1 << 2,
|
||||
} NS_SWIFT_NAME(InstanceLoggingBehavior);
|
||||
|
||||
extern NSString * _Nonnull const CAPInstanceDescriptorDefaultScheme NS_SWIFT_UNAVAILABLE("Use InstanceDescriptorDefaults");
|
||||
extern NSString * _Nonnull const CAPInstanceDescriptorDefaultHostname NS_SWIFT_UNAVAILABLE("Use InstanceDescriptorDefaults");
|
||||
|
||||
NS_SWIFT_NAME(InstanceDescriptor)
|
||||
@interface CAPInstanceDescriptor : NSObject
|
||||
/**
|
||||
@brief A value to append to the @c User-Agent string. Ignored if @c overridenUserAgentString is set.
|
||||
@discussion Set by @c appendUserAgent in the configuration file.
|
||||
*/
|
||||
@property (nonatomic, copy, nullable) NSString *appendedUserAgentString;
|
||||
/**
|
||||
@brief A value that will completely replace the @c User-Agent string. Overrides @c appendedUserAgentString.
|
||||
@discussion Set by @c overrideUserAgent in the configuration file.
|
||||
*/
|
||||
@property (nonatomic, copy, nullable) NSString *overridenUserAgentString;
|
||||
/**
|
||||
@brief The background color to set on the web view where content is not visible.
|
||||
@discussion Set by @c backgroundColor in the configuration file.
|
||||
*/
|
||||
@property (nonatomic, retain, nullable) UIColor *backgroundColor;
|
||||
/**
|
||||
@brief Hostnames to which the web view is allowed to navigate without opening an external browser.
|
||||
@discussion Set by @c allowNavigation in the configuration file.
|
||||
*/
|
||||
@property (nonatomic, copy, nonnull) NSArray<NSString*> *allowedNavigationHostnames;
|
||||
/**
|
||||
@brief The scheme that will be used for the server URL.
|
||||
@discussion Defaults to @c capacitor. Set by @c server.iosScheme in the configuration file.
|
||||
*/
|
||||
@property (nonatomic, copy, nullable) NSString *urlScheme;
|
||||
/**
|
||||
@brief The path to a local html page to display in case of errors.
|
||||
@discussion Defaults to nil.
|
||||
*/
|
||||
@property (nonatomic, copy, nullable) NSString *errorPath;
|
||||
/**
|
||||
@brief The hostname that will be used for the server URL.
|
||||
@discussion Defaults to @c localhost. Set by @c server.hostname in the configuration file.
|
||||
*/
|
||||
@property (nonatomic, copy, nullable) NSString *urlHostname;
|
||||
/**
|
||||
@brief The fully formed URL that will be used as the server URL.
|
||||
@discussion Defaults to nil, in which case the server URL will be constructed from @c urlScheme and @c urlHostname. If set, it will override the other properties. Set by @c server.url in the configuration file.
|
||||
*/
|
||||
@property (nonatomic, copy, nullable) NSString *serverURL;
|
||||
/**
|
||||
@brief The JSON dictionary that contains the plugin-specific configuration information.
|
||||
@discussion Set by @c plugins in the configuration file.
|
||||
*/
|
||||
@property (nonatomic, retain, nonnull) NSDictionary *pluginConfigurations;
|
||||
/**
|
||||
@brief The build configurations under which logging should be enabled.
|
||||
@discussion Defaults to @c debug. Set by @c loggingBehavior in the configuration file.
|
||||
*/
|
||||
@property (nonatomic, assign) CAPInstanceLoggingBehavior loggingBehavior;
|
||||
/**
|
||||
@brief Whether or not the web view can scroll.
|
||||
@discussion Set by @c ios.scrollEnabled in the configuration file. Corresponds to @c isScrollEnabled on WKWebView.
|
||||
*/
|
||||
@property (nonatomic, assign) BOOL scrollingEnabled;
|
||||
/**
|
||||
@brief Whether or not the web view can zoom.
|
||||
@discussion Set by @c zoomEnabled in the configuration file.
|
||||
*/
|
||||
@property (nonatomic, assign) BOOL zoomingEnabled;
|
||||
/**
|
||||
@brief Whether or not the web view will preview links.
|
||||
@discussion Set by @c ios.allowsLinkPreview in the configuration file. Corresponds to @c allowsLinkPreview on WKWebView.
|
||||
*/
|
||||
@property (nonatomic, assign) BOOL allowLinkPreviews;
|
||||
/**
|
||||
@brief Whether or not the Capacitor runtime will set itself as the @c UNUserNotificationCenter delegate.
|
||||
@discussion Defaults to @c true. Required to be @c true for notification plugins to work correctly. Set to @c false if your application will handle notifications independently.
|
||||
*/
|
||||
@property (nonatomic, assign) BOOL handleApplicationNotifications;
|
||||
/**
|
||||
@brief Enables web debugging by setting isInspectable of @c WKWebView to @c true on iOS 16.4 and greater
|
||||
@discussion Defaults to true in debug mode and false in production
|
||||
*/
|
||||
@property (nonatomic, assign) BOOL isWebDebuggable;
|
||||
/**
|
||||
@brief Whether or not the webview will have focus.
|
||||
@discussion Defaults to @c true. Set by @c ios.initialFocus in the configuration file.
|
||||
*/
|
||||
@property (nonatomic, assign) BOOL hasInitialFocus;
|
||||
|
||||
/**
|
||||
@brief How the web view will inset its content
|
||||
@discussion Set by @c ios.contentInset in the configuration file. Corresponds to @c contentInsetAdjustmentBehavior on WKWebView.
|
||||
*/
|
||||
@property (nonatomic, assign) UIScrollViewContentInsetAdjustmentBehavior contentInsetAdjustmentBehavior;
|
||||
/**
|
||||
@brief The base file URL from which Capacitor will load resources
|
||||
@discussion Defaults to @c public/ located at the root of the application bundle.
|
||||
*/
|
||||
@property (nonatomic, copy, nonnull) NSURL *appLocation;
|
||||
/**
|
||||
@brief The path (relative to @c appLocation) which Capacitor will use for the inital URL at launch.
|
||||
@discussion Defaults to nil, in which case Capacitor will attempt to load @c index.html.
|
||||
*/
|
||||
@property (nonatomic, copy, nullable) NSString *appStartPath;
|
||||
/**
|
||||
@brief Whether or not the Capacitor WebView will limit the navigation to @c WKAppBoundDomains listed in the Info.plist.
|
||||
@discussion Defaults to @c false. Set by @c ios.limitsNavigationsToAppBoundDomains in the configuration file. Required to be @c true for plugins to work if the app includes @c WKAppBoundDomains in the Info.plist.
|
||||
*/
|
||||
@property (nonatomic, assign) BOOL limitsNavigationsToAppBoundDomains;
|
||||
/**
|
||||
@brief The content mode for the web view to use when it loads and renders web content.
|
||||
@discussion Defaults to @c recommended. Set by @c ios.preferredContentMode in the configuration file.
|
||||
*/
|
||||
@property (nonatomic, copy, nullable) NSString *preferredContentMode;
|
||||
/**
|
||||
@brief The parser used to load the cofiguration for Cordova plugins.
|
||||
*/
|
||||
@property (nonatomic, copy, nonnull) CDVConfigParser *cordovaConfiguration;
|
||||
/**
|
||||
@brief Warnings generated during initialization.
|
||||
*/
|
||||
@property (nonatomic, assign) CAPInstanceWarning warnings;
|
||||
/**
|
||||
@brief The type of instance.
|
||||
*/
|
||||
@property (nonatomic, readonly) CAPInstanceType instanceType;
|
||||
/**
|
||||
@brief The JSON dictionary representing the contents of the configuration file.
|
||||
@warning Deprecated. Do not use.
|
||||
*/
|
||||
@property (nonatomic, retain, nonnull) NSDictionary *legacyConfig;
|
||||
/**
|
||||
@brief Initialize the descriptor with the default environment. This assumes that the application was built with the help of the Capacitor CLI and that that the web app is located inside the application bundle at @c public/.
|
||||
*/
|
||||
- (instancetype _Nonnull)initAsDefault NS_SWIFT_NAME(init());
|
||||
/**
|
||||
@brief Initialize the descriptor for use in other contexts. The app location is the one required parameter.
|
||||
@param appURL The location of the folder containing the web app.
|
||||
@param configURL The location of the Capacitor configuration file.
|
||||
@param cordovaURL The location of the Cordova configuration file.
|
||||
*/
|
||||
- (instancetype _Nonnull)initAtLocation:(NSURL* _Nonnull)appURL configuration:(NSURL* _Nullable)configURL cordovaConfiguration:(NSURL* _Nullable)cordovaURL NS_SWIFT_NAME(init(at:configuration:cordovaConfiguration:));
|
||||
@end
|
||||
|
||||
#endif /* CAPInstanceDescriptor_h */
|
||||
56
node_modules/@capacitor/ios/Capacitor/Capacitor/CAPInstanceDescriptor.m
generated
vendored
Normal file
56
node_modules/@capacitor/ios/Capacitor/Capacitor/CAPInstanceDescriptor.m
generated
vendored
Normal file
@@ -0,0 +1,56 @@
|
||||
#import "CAPInstanceDescriptor.h"
|
||||
#import <Capacitor/Capacitor-Swift.h>
|
||||
|
||||
// Swift extensions marked as @objc and internal are available to the Obj-C runtime but are not available at compile time.
|
||||
// so we need this declaration to avoid compiler complaints
|
||||
@interface CAPInstanceDescriptor (InternalSwiftExtension)
|
||||
- (void)_parseConfigurationAt:(NSURL *)configURL cordovaConfiguration:(NSURL *)cordovaURL;
|
||||
@end
|
||||
|
||||
NSString* const CAPInstanceDescriptorDefaultScheme = @"capacitor";
|
||||
NSString* const CAPInstanceDescriptorDefaultHostname = @"localhost";
|
||||
|
||||
@implementation CAPInstanceDescriptor
|
||||
- (instancetype)initAsDefault {
|
||||
if (self = [super init]) {
|
||||
_instanceType = CAPInstanceTypeFixed;
|
||||
[self _setDefaultsWithAppLocation:[[NSBundle mainBundle] URLForResource:@"public" withExtension:nil]];
|
||||
[self _parseConfigurationAt:[[NSBundle mainBundle] URLForResource:@"capacitor.config" withExtension:@"json"] cordovaConfiguration:[[NSBundle mainBundle] URLForResource:@"config" withExtension:@"xml"]];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (instancetype)initAtLocation:(NSURL*)appURL configuration:(NSURL*)configURL cordovaConfiguration:(NSURL*)cordovaURL {
|
||||
if (self = [super init]) {
|
||||
_instanceType = CAPInstanceTypeVariable;
|
||||
[self _setDefaultsWithAppLocation:appURL];
|
||||
[self _parseConfigurationAt:configURL cordovaConfiguration:cordovaURL];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)_setDefaultsWithAppLocation:(NSURL*)location {
|
||||
_allowedNavigationHostnames = @[];
|
||||
_urlScheme = CAPInstanceDescriptorDefaultScheme;
|
||||
_urlHostname = CAPInstanceDescriptorDefaultHostname;
|
||||
_pluginConfigurations = @{};
|
||||
_legacyConfig = @{};
|
||||
_loggingBehavior = CAPInstanceLoggingBehaviorDebug;
|
||||
_scrollingEnabled = YES;
|
||||
_zoomingEnabled = NO;
|
||||
_allowLinkPreviews = YES;
|
||||
_handleApplicationNotifications = YES;
|
||||
_isWebDebuggable = NO;
|
||||
_hasInitialFocus = YES;
|
||||
_contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;
|
||||
_appLocation = location;
|
||||
_limitsNavigationsToAppBoundDomains = FALSE;
|
||||
_cordovaConfiguration = [[CDVConfigParser alloc] init];
|
||||
_warnings = 0;
|
||||
if (location == nil) {
|
||||
_warnings |= CAPInstanceWarningMissingAppDir;
|
||||
// location is nil so assume it was supposed to be the default
|
||||
_appLocation = [[[NSBundle mainBundle] resourceURL] URLByAppendingPathComponent:@"public"];
|
||||
}
|
||||
}
|
||||
@end
|
||||
198
node_modules/@capacitor/ios/Capacitor/Capacitor/CAPInstanceDescriptor.swift
generated
vendored
Normal file
198
node_modules/@capacitor/ios/Capacitor/Capacitor/CAPInstanceDescriptor.swift
generated
vendored
Normal file
@@ -0,0 +1,198 @@
|
||||
import Foundation
|
||||
|
||||
public enum InstanceDescriptorDefaults {
|
||||
public static let scheme = "capacitor"
|
||||
public static let hostname = "localhost"
|
||||
}
|
||||
|
||||
private extension InstanceLoggingBehavior {
|
||||
static func behavior(from: String) -> InstanceLoggingBehavior? {
|
||||
switch from.lowercased() {
|
||||
case "none":
|
||||
return InstanceLoggingBehavior.none
|
||||
case "debug":
|
||||
return InstanceLoggingBehavior.debug
|
||||
case "production":
|
||||
return InstanceLoggingBehavior.production
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
The purpose of this function is to hide the messy details of parsing the configuration(s) so
|
||||
the complexity is worth it. And the name starts with an underscore to match the convention of
|
||||
private APIs in Obj-C (from which it is called).
|
||||
*/
|
||||
internal extension InstanceDescriptor {
|
||||
// swiftlint:disable cyclomatic_complexity
|
||||
// swiftlint:disable function_body_length
|
||||
// swiftlint:disable:next identifier_name
|
||||
@objc func _parseConfiguration(at capacitorURL: URL?, cordovaConfiguration cordovaURL: URL?) {
|
||||
// sanity check that the app directory is valid
|
||||
var isDirectory: ObjCBool = ObjCBool(false)
|
||||
if warnings.contains(.missingAppDir) == false,
|
||||
FileManager.default.fileExists(atPath: appLocation.path, isDirectory: &isDirectory) == false || isDirectory.boolValue == false {
|
||||
warnings.update(with: .missingAppDir)
|
||||
}
|
||||
|
||||
// parse the capacitor configuration
|
||||
var config: JSObject?
|
||||
if let capacitorURL = capacitorURL,
|
||||
FileManager.default.fileExists(atPath: capacitorURL.path, isDirectory: &isDirectory),
|
||||
isDirectory.boolValue == false {
|
||||
do {
|
||||
let contents = try Data(contentsOf: capacitorURL)
|
||||
config = JSTypes.coerceDictionaryToJSObject(try JSONSerialization.jsonObject(with: contents) as? [String: Any])
|
||||
} catch {
|
||||
warnings.update(with: .invalidFile)
|
||||
}
|
||||
} else {
|
||||
warnings.update(with: .missingFile)
|
||||
}
|
||||
|
||||
// parse the cordova configuration
|
||||
var configParser: XMLParser?
|
||||
if let cordovaURL = cordovaURL,
|
||||
FileManager.default.fileExists(atPath: cordovaURL.path, isDirectory: &isDirectory),
|
||||
isDirectory.boolValue == false {
|
||||
configParser = XMLParser(contentsOf: cordovaURL)
|
||||
} else {
|
||||
warnings.update(with: .missingCordovaFile)
|
||||
// we don't want to break up string literals
|
||||
// swiftlint:disable:next line_length
|
||||
if let cordovaXML = "<?xml version='1.0' encoding='utf-8'?><widget version=\"1.0.0\" xmlns=\"http://www.w3.org/ns/widgets\" xmlns:cdv=\"http://cordova.apache.org/ns/1.0\"><access origin=\"*\" /></widget>".data(using: .utf8) {
|
||||
configParser = XMLParser(data: cordovaXML)
|
||||
}
|
||||
}
|
||||
configParser?.delegate = cordovaConfiguration
|
||||
configParser?.parse()
|
||||
|
||||
// extract our configuration values
|
||||
if let config = config {
|
||||
// to be removed
|
||||
legacyConfig = config
|
||||
|
||||
if let agentString = (config[keyPath: "ios.appendUserAgent"] as? String) ?? (config[keyPath: "appendUserAgent"] as? String) {
|
||||
appendedUserAgentString = agentString
|
||||
}
|
||||
if let agentString = (config[keyPath: "ios.overrideUserAgent"] as? String) ?? (config[keyPath: "overrideUserAgent"] as? String) {
|
||||
overridenUserAgentString = agentString
|
||||
}
|
||||
if let colorString = (config[keyPath: "ios.backgroundColor"] as? String) ?? (config[keyPath: "backgroundColor"] as? String),
|
||||
let color = UIColor.capacitor.color(fromHex: colorString) {
|
||||
backgroundColor = color
|
||||
}
|
||||
if let allowNav = config[keyPath: "server.allowNavigation"] as? [String] {
|
||||
allowedNavigationHostnames = allowNav
|
||||
}
|
||||
if let scheme = (config[keyPath: "server.iosScheme"] as? String)?.lowercased() {
|
||||
urlScheme = scheme
|
||||
}
|
||||
if let host = config[keyPath: "server.hostname"] as? String {
|
||||
urlHostname = host
|
||||
}
|
||||
if let urlString = config[keyPath: "server.url"] as? String {
|
||||
serverURL = urlString
|
||||
}
|
||||
if let errorPathString = (config[keyPath: "server.errorPath"] as? String) {
|
||||
errorPath = errorPathString
|
||||
}
|
||||
if let insetBehavior = config[keyPath: "ios.contentInset"] as? String {
|
||||
let availableInsets: [String: UIScrollView.ContentInsetAdjustmentBehavior] = ["automatic": .automatic,
|
||||
"scrollableAxes": .scrollableAxes,
|
||||
"never": .never,
|
||||
"always": .always]
|
||||
if let option = availableInsets[insetBehavior] {
|
||||
contentInsetAdjustmentBehavior = option
|
||||
}
|
||||
}
|
||||
if let allowPreviews = config[keyPath: "ios.allowsLinkPreview"] as? Bool {
|
||||
allowLinkPreviews = allowPreviews
|
||||
}
|
||||
if let scrollEnabled = config[keyPath: "ios.scrollEnabled"] as? Bool {
|
||||
scrollingEnabled = scrollEnabled
|
||||
}
|
||||
if let zoomEnabled = (config[keyPath: "ios.zoomEnabled"] as? Bool) ?? (config[keyPath: "zoomEnabled"] as? Bool) {
|
||||
zoomingEnabled = zoomEnabled
|
||||
}
|
||||
if let pluginConfig = config[keyPath: "plugins"] as? JSObject {
|
||||
pluginConfigurations = pluginConfig
|
||||
}
|
||||
if let value = (config[keyPath: "ios.loggingBehavior"] as? String) ?? (config[keyPath: "loggingBehavior"] as? String) {
|
||||
if let behavior = InstanceLoggingBehavior.behavior(from: value) {
|
||||
loggingBehavior = behavior
|
||||
}
|
||||
}
|
||||
if let limitsNavigations = config[keyPath: "ios.limitsNavigationsToAppBoundDomains"] as? Bool {
|
||||
limitsNavigationsToAppBoundDomains = limitsNavigations
|
||||
}
|
||||
if let preferredMode = (config[keyPath: "ios.preferredContentMode"] as? String) {
|
||||
preferredContentMode = preferredMode
|
||||
}
|
||||
if let handleNotifications = config[keyPath: "ios.handleApplicationNotifications"] as? Bool {
|
||||
handleApplicationNotifications = handleNotifications
|
||||
}
|
||||
if let webContentsDebuggingEnabled = config[keyPath: "ios.webContentsDebuggingEnabled"] as? Bool {
|
||||
isWebDebuggable = webContentsDebuggingEnabled
|
||||
} else {
|
||||
#if DEBUG
|
||||
isWebDebuggable = true
|
||||
#else
|
||||
// this is needed for SPM xcframework Capacitor. Can eventually be removed when the SPM package moves to being source-based.
|
||||
if let debugValue = Bundle.main.object(forInfoDictionaryKey: "CAPACITOR_DEBUG") as? String, debugValue == "true" {
|
||||
isWebDebuggable = true
|
||||
}
|
||||
#endif
|
||||
}
|
||||
if let initialFocus = (config[keyPath: "ios.initialFocus"] as? Bool) ?? (config[keyPath: "initialFocus"] as? Bool) {
|
||||
hasInitialFocus = initialFocus
|
||||
}
|
||||
if let startPath = (config[keyPath: "server.appStartPath"] as? String) {
|
||||
appStartPath = startPath
|
||||
}
|
||||
}
|
||||
}
|
||||
// swiftlint:enable cyclomatic_complexity
|
||||
// swiftlint:enable function_body_length
|
||||
}
|
||||
|
||||
extension InstanceDescriptor {
|
||||
@objc public var cordovaDeployDisabled: Bool {
|
||||
return (cordovaConfiguration.settings?["DisableDeploy".lowercased()] as? NSString)?.boolValue ?? false
|
||||
}
|
||||
|
||||
@objc public func normalize() {
|
||||
// first, make sure the scheme is valid
|
||||
var schemeValid = false
|
||||
if let scheme = urlScheme, WKWebView.handlesURLScheme(scheme) == false,
|
||||
scheme.range(of: "^[a-z][a-z0-9.+-]*$", options: [.regularExpression, .caseInsensitive], range: nil, locale: nil) != nil {
|
||||
schemeValid = true
|
||||
}
|
||||
if !schemeValid {
|
||||
// reset to the default
|
||||
urlScheme = InstanceDescriptorDefaults.scheme
|
||||
}
|
||||
// make sure we have a hostname
|
||||
if urlHostname == nil {
|
||||
urlHostname = InstanceDescriptorDefaults.hostname
|
||||
}
|
||||
// now validate the server.url
|
||||
var urlValid = false
|
||||
if let server = serverURL, URL(string: server) != nil {
|
||||
urlValid = true
|
||||
}
|
||||
if !urlValid {
|
||||
serverURL = nil
|
||||
}
|
||||
// reset the path if it's not valid
|
||||
if let path = appStartPath?.trimmingCharacters(in: .whitespacesAndNewlines), path.isEmpty {
|
||||
appStartPath = nil
|
||||
}
|
||||
// if the plugin configuration was programmatically modified, the necessary type information may have been lost.
|
||||
// so perform a coercion here to make sure that casting will work as expected
|
||||
pluginConfigurations = JSTypes.coerceDictionaryToJSObject(pluginConfigurations) ?? [:]
|
||||
legacyConfig = JSTypes.coerceDictionaryToJSObject(legacyConfig) ?? [:]
|
||||
}
|
||||
}
|
||||
10
node_modules/@capacitor/ios/Capacitor/Capacitor/CAPInstancePlugin.swift
generated
vendored
Normal file
10
node_modules/@capacitor/ios/Capacitor/Capacitor/CAPInstancePlugin.swift
generated
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
//
|
||||
// CAPInstancePlugin.swift
|
||||
// Capacitor
|
||||
//
|
||||
// Created by Steven Sherry on 11/21/22.
|
||||
// Copyright © 2022 Drifty Co. All rights reserved.
|
||||
//
|
||||
|
||||
/// A CAPPlugin subclass meant to be explicitly initialized by the caller and not the bridge.
|
||||
@objc open class CAPInstancePlugin: CAPPlugin {}
|
||||
11
node_modules/@capacitor/ios/Capacitor/Capacitor/CAPLog.swift
generated
vendored
Normal file
11
node_modules/@capacitor/ios/Capacitor/Capacitor/CAPLog.swift
generated
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
public class CAPLog {
|
||||
public static var enableLogging: Bool = true
|
||||
|
||||
public static func print(_ items: Any..., separator: String = " ", terminator: String = "\n") {
|
||||
if enableLogging {
|
||||
for (itemIndex, item) in items.enumerated() {
|
||||
Swift.print("\(item)".prefix(4068), terminator: itemIndex == items.count - 1 ? terminator : separator)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
65
node_modules/@capacitor/ios/Capacitor/Capacitor/CAPNotifications.swift
generated
vendored
Normal file
65
node_modules/@capacitor/ios/Capacitor/Capacitor/CAPNotifications.swift
generated
vendored
Normal file
@@ -0,0 +1,65 @@
|
||||
/**
|
||||
Notificaton types for NotificationCenter and NSNotificationCenter
|
||||
|
||||
We want to include `capacitor` in the name(s) to uniquely identify these even though it can make the names long
|
||||
and the deprecated notifications are only here for backwards compatibility.
|
||||
*/
|
||||
// swiftlint:disable identifier_name
|
||||
extension Notification.Name {
|
||||
public static let capacitorOpenURL = Notification.Name(rawValue: "CapacitorOpenURLNotification")
|
||||
public static let capacitorOpenUniversalLink = Notification.Name(rawValue: "CapacitorOpenUniversalLinkNotification")
|
||||
public static let capacitorContinueActivity = Notification.Name(rawValue: "CapacitorContinueActivityNotification")
|
||||
public static let capacitorDidRegisterForRemoteNotifications =
|
||||
Notification.Name(rawValue: "CapacitorDidRegisterForRemoteNotificationsNotification")
|
||||
public static let capacitorDidFailToRegisterForRemoteNotifications =
|
||||
Notification.Name(rawValue: "CapacitorDidFailToRegisterForRemoteNotificationsNotification")
|
||||
public static let capacitorDecidePolicyForNavigationAction =
|
||||
Notification.Name(rawValue: "CapacitorDecidePolicyForNavigationActionNotification")
|
||||
public static let capacitorStatusBarTapped = Notification.Name(rawValue: "CapacitorStatusBarTappedNotification")
|
||||
}
|
||||
|
||||
@objc extension NSNotification {
|
||||
public static let capacitorOpenURL = Notification.Name.capacitorOpenURL
|
||||
public static let capacitorOpenUniversalLink = Notification.Name.capacitorOpenUniversalLink
|
||||
public static let capacitorContinueActivity = Notification.Name.capacitorContinueActivity
|
||||
public static let capacitorDidRegisterForRemoteNotifications = Notification.Name.capacitorDidRegisterForRemoteNotifications
|
||||
public static let capacitorDidFailToRegisterForRemoteNotifications = Notification.Name.capacitorDidFailToRegisterForRemoteNotifications
|
||||
public static let capacitorDecidePolicyForNavigationAction = Notification.Name.capacitorDecidePolicyForNavigationAction
|
||||
public static let capacitorStatusBarTapped = Notification.Name.capacitorStatusBarTapped
|
||||
}
|
||||
|
||||
/**
|
||||
Deprecated, will be removed
|
||||
*/
|
||||
@objc public enum CAPNotifications: Int {
|
||||
@available(*, deprecated, message: "renamed to 'Notification.Name.capacitorOpenURL'")
|
||||
case URLOpen
|
||||
@available(*, deprecated, message: "renamed to 'Notification.Name.capacitorOpenUniversalLink'")
|
||||
case UniversalLinkOpen
|
||||
@available(*, deprecated, message: "Notification.Name.capacitorContinueActivity'")
|
||||
case ContinueActivity
|
||||
@available(*, deprecated, message: "renamed to 'Notification.Name.capacitorDidRegisterForRemoteNotifications'")
|
||||
case DidRegisterForRemoteNotificationsWithDeviceToken
|
||||
@available(*, deprecated, message: "renamed to 'Notification.Name.capacitorDidFailToRegisterForRemoteNotifications'")
|
||||
case DidFailToRegisterForRemoteNotificationsWithError
|
||||
@available(*, deprecated, message: "renamed to 'Notification.Name.capacitorDecidePolicyForNavigationAction'")
|
||||
case DecidePolicyForNavigationAction
|
||||
|
||||
public func name() -> String {
|
||||
switch self {
|
||||
case .URLOpen:
|
||||
return Notification.Name.capacitorOpenURL.rawValue
|
||||
case .UniversalLinkOpen:
|
||||
return Notification.Name.capacitorOpenUniversalLink.rawValue
|
||||
case .ContinueActivity:
|
||||
return Notification.Name.capacitorContinueActivity.rawValue
|
||||
case .DidRegisterForRemoteNotificationsWithDeviceToken:
|
||||
return Notification.Name.capacitorDidRegisterForRemoteNotifications.rawValue
|
||||
case .DidFailToRegisterForRemoteNotificationsWithError:
|
||||
return Notification.Name.capacitorDidFailToRegisterForRemoteNotifications.rawValue
|
||||
case .DecidePolicyForNavigationAction:
|
||||
return Notification.Name.capacitorDecidePolicyForNavigationAction.rawValue
|
||||
}
|
||||
}
|
||||
}
|
||||
// swiftlint:enable identifier_name
|
||||
20
node_modules/@capacitor/ios/Capacitor/Capacitor/CAPPlugin+LoadInstance.swift
generated
vendored
Normal file
20
node_modules/@capacitor/ios/Capacitor/Capacitor/CAPPlugin+LoadInstance.swift
generated
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
//
|
||||
// CAPPlugin+LoadInstance.swift
|
||||
// Capacitor
|
||||
//
|
||||
// Created by Steven Sherry on 11/9/22.
|
||||
// Copyright © 2022 Drifty Co. All rights reserved.
|
||||
//
|
||||
|
||||
extension CAPBridgedPlugin where Self: CAPPlugin {
|
||||
func load(on bridge: CAPBridgeProtocol) {
|
||||
self.bridge = bridge
|
||||
webView = bridge.webView
|
||||
shouldStringifyDatesInCalls = true
|
||||
retainedEventArguments = [:]
|
||||
eventListeners = [:]
|
||||
pluginId = identifier
|
||||
pluginName = jsName
|
||||
load()
|
||||
}
|
||||
}
|
||||
55
node_modules/@capacitor/ios/Capacitor/Capacitor/CAPPlugin.h
generated
vendored
Normal file
55
node_modules/@capacitor/ios/Capacitor/Capacitor/CAPPlugin.h
generated
vendored
Normal file
@@ -0,0 +1,55 @@
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <WebKit/WebKit.h>
|
||||
|
||||
@protocol CAPBridgeProtocol;
|
||||
@class CAPPluginCall;
|
||||
|
||||
@class PluginConfig;
|
||||
|
||||
@interface CAPPlugin : NSObject
|
||||
|
||||
@property (nonatomic, weak, nullable) WKWebView *webView;
|
||||
@property (nonatomic, weak, nullable) id<CAPBridgeProtocol> bridge;
|
||||
@property (nonatomic, strong, nonnull) NSString *pluginId;
|
||||
@property (nonatomic, strong, nonnull) NSString *pluginName;
|
||||
@property (nonatomic, strong, nullable) NSMutableDictionary<NSString *, NSMutableArray<CAPPluginCall *>*> *eventListeners;
|
||||
@property (nonatomic, strong, nullable) NSMutableDictionary<NSString *, NSMutableArray<id> *> *retainedEventArguments;
|
||||
@property (nonatomic, assign) BOOL shouldStringifyDatesInCalls;
|
||||
|
||||
- (instancetype _Nonnull) initWithBridge:(id<CAPBridgeProtocol> _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<NSString *, id>* _Nullable)data;
|
||||
- (void)notifyListeners:(NSString* _Nonnull)eventName data:(NSDictionary<NSString *, id>* _Nullable)data retainUntilConsumed:(BOOL)retain;
|
||||
- (NSArray<CAPPluginCall *>* _Nullable)getListeners:(NSString* _Nonnull)eventName;
|
||||
- (BOOL)hasListeners:(NSString* _Nonnull)eventName;
|
||||
- (void)addListener:(CAPPluginCall* _Nonnull)call;
|
||||
- (void)removeListener:(CAPPluginCall* _Nonnull)call;
|
||||
- (void)removeAllListeners:(CAPPluginCall* _Nonnull)call;
|
||||
/**
|
||||
* Default implementation of the capacitor 3.0 permission pattern
|
||||
*/
|
||||
- (void)checkPermissions:(CAPPluginCall* _Nonnull)call;
|
||||
- (void)requestPermissions:(CAPPluginCall* _Nonnull)call;
|
||||
/**
|
||||
* Give the plugins a chance to take control when a URL is about to be loaded in the WebView.
|
||||
* Returning true causes the WebView to abort loading the URL.
|
||||
* Returning false causes the WebView to continue loading the URL.
|
||||
* Returning nil will defer to the default Capacitor policy
|
||||
*/
|
||||
- (NSNumber* _Nullable)shouldOverrideLoad:(WKNavigationAction* _Nonnull)navigationAction;
|
||||
|
||||
// Called after init if the plugin wants to do
|
||||
// some loading so the plugin author doesn't
|
||||
// need to override init()
|
||||
-(void)load;
|
||||
-(NSString* _Nonnull)getId;
|
||||
-(BOOL)getBool:(CAPPluginCall* _Nonnull) call field:(NSString* _Nonnull)field defaultValue:(BOOL)defaultValue DEPRECATED_MSG_ATTRIBUTE("Use accessors on CAPPluginCall instead. See CAPBridgedJSTypes.h for Obj-C implementations.");
|
||||
-(NSString* _Nullable)getString:(CAPPluginCall* _Nonnull)call field:(NSString* _Nonnull)field defaultValue:(NSString* _Nonnull)defaultValue DEPRECATED_MSG_ATTRIBUTE("Use accessors on CAPPluginCall instead. See CAPBridgedJSTypes.h for Obj-C implementations.");
|
||||
-(id _Nullable)getConfigValue:(NSString* _Nonnull)key __deprecated_msg("use getConfig() and access config values using the methods available depending on the type.");
|
||||
-(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
|
||||
175
node_modules/@capacitor/ios/Capacitor/Capacitor/CAPPlugin.m
generated
vendored
Normal file
175
node_modules/@capacitor/ios/Capacitor/Capacitor/CAPPlugin.m
generated
vendored
Normal file
@@ -0,0 +1,175 @@
|
||||
#import "CAPPlugin.h"
|
||||
#import "CAPBridgedJSTypes.h"
|
||||
#import <Capacitor/Capacitor-Swift.h>
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@implementation CAPPlugin
|
||||
|
||||
-(instancetype) initWithBridge:(id<CAPBridgeProtocol>)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];
|
||||
}
|
||||
|
||||
-(id)getConfigValue:(NSString *)key __deprecated {
|
||||
return [self.bridge.config getPluginConfigValue:self.pluginName :key];
|
||||
}
|
||||
|
||||
-(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<NSString *,id> *)data {
|
||||
[self notifyListeners:eventName data:data retainUntilConsumed:NO];
|
||||
}
|
||||
|
||||
- (void)notifyListeners:(NSString *)eventName data:(NSDictionary<NSString *,id> *)data retainUntilConsumed:(BOOL)retain {
|
||||
NSArray<CAPPluginCall *> *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<CAPPluginCall *>*)getListeners:(NSString *)eventName {
|
||||
NSArray<CAPPluginCall *>* listeners = [self.eventListeners objectForKey:eventName];
|
||||
return listeners;
|
||||
}
|
||||
|
||||
- (BOOL)hasListeners:(NSString *)eventName {
|
||||
NSArray<CAPPluginCall *>* 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;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
25
node_modules/@capacitor/ios/Capacitor/Capacitor/CAPPluginCall.h
generated
vendored
Normal file
25
node_modules/@capacitor/ios/Capacitor/Capacitor/CAPPluginCall.h
generated
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@class CAPPluginCall;
|
||||
@class CAPPluginCallResult;
|
||||
@class CAPPluginCallError;
|
||||
|
||||
typedef void(^CAPPluginCallSuccessHandler)(CAPPluginCallResult *result, CAPPluginCall* call);
|
||||
typedef void(^CAPPluginCallErrorHandler)(CAPPluginCallError *error);
|
||||
|
||||
@interface CAPPluginCall : NSObject
|
||||
|
||||
@property (nonatomic, assign) BOOL isSaved DEPRECATED_MSG_ATTRIBUTE("Use 'keepAlive' instead.");
|
||||
@property (nonatomic, assign) BOOL keepAlive;
|
||||
@property (nonatomic, strong) NSString *callbackId;
|
||||
@property (nonatomic, strong) NSString *methodName;
|
||||
@property (nonatomic, strong) NSDictionary *options;
|
||||
@property (nonatomic, copy) CAPPluginCallSuccessHandler successHandler;
|
||||
@property (nonatomic, copy) CAPPluginCallErrorHandler errorHandler;
|
||||
|
||||
- (instancetype)initWithCallbackId:(NSString *)callbackId options:(NSDictionary *)options success:(CAPPluginCallSuccessHandler)success error:(CAPPluginCallErrorHandler)error DEPRECATED_MSG_ATTRIBUTE("Specify the method name as well.");
|
||||
|
||||
- (instancetype)initWithCallbackId:(NSString *)callbackId methodName:(NSString *)methodName options:(NSDictionary *)options success:(CAPPluginCallSuccessHandler)success error:(CAPPluginCallErrorHandler)error;
|
||||
|
||||
- (void)save DEPRECATED_MSG_ATTRIBUTE("Use the 'keepAlive' property instead.");
|
||||
@end
|
||||
36
node_modules/@capacitor/ios/Capacitor/Capacitor/CAPPluginCall.m
generated
vendored
Normal file
36
node_modules/@capacitor/ios/Capacitor/Capacitor/CAPPluginCall.m
generated
vendored
Normal file
@@ -0,0 +1,36 @@
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "CAPPluginCall.h"
|
||||
|
||||
@implementation CAPPluginCall
|
||||
|
||||
- (instancetype)initWithCallbackId:(NSString *)callbackId options:(NSDictionary *)options success:(CAPPluginCallSuccessHandler) success error:(CAPPluginCallErrorHandler) error __deprecated {
|
||||
self.callbackId = callbackId;
|
||||
self.methodName = @"";
|
||||
self.options = options;
|
||||
self.successHandler = success;
|
||||
self.errorHandler = error;
|
||||
return self;
|
||||
}
|
||||
|
||||
- (instancetype)initWithCallbackId:(NSString *)callbackId methodName:(NSString *)methodName options:(NSDictionary *)options success:(CAPPluginCallSuccessHandler) success error:(CAPPluginCallErrorHandler) error {
|
||||
self.callbackId = callbackId;
|
||||
self.methodName = methodName;
|
||||
self.options = options;
|
||||
self.successHandler = success;
|
||||
self.errorHandler = error;
|
||||
return self;
|
||||
}
|
||||
|
||||
- (BOOL)isSaved {
|
||||
return self.keepAlive;
|
||||
}
|
||||
|
||||
- (void)setIsSaved:(BOOL)saved {
|
||||
self.keepAlive = saved;
|
||||
}
|
||||
|
||||
- (void)save {
|
||||
self.keepAlive = true;
|
||||
}
|
||||
|
||||
@end
|
||||
97
node_modules/@capacitor/ios/Capacitor/Capacitor/CAPPluginCall.swift
generated
vendored
Normal file
97
node_modules/@capacitor/ios/Capacitor/Capacitor/CAPPluginCall.swift
generated
vendored
Normal file
@@ -0,0 +1,97 @@
|
||||
import Foundation
|
||||
|
||||
@available(*, deprecated, renamed: "PluginCallResultData")
|
||||
public typealias PluginCallErrorData = [String: Any]
|
||||
@available(*, deprecated, renamed: "PluginCallResultData")
|
||||
public typealias PluginResultData = [String: Any]
|
||||
|
||||
/**
|
||||
* Swift niceties for CAPPluginCall
|
||||
*/
|
||||
|
||||
extension CAPPluginCall: JSValueContainer {
|
||||
public var jsObjectRepresentation: JSObject {
|
||||
return options as? JSObject ?? [:]
|
||||
}
|
||||
}
|
||||
|
||||
@objc extension CAPPluginCall: BridgedJSValueContainer {
|
||||
public var dictionaryRepresentation: NSDictionary {
|
||||
return options as NSDictionary
|
||||
}
|
||||
|
||||
public static var jsDateFormatter: ISO8601DateFormatter = {
|
||||
return ISO8601DateFormatter()
|
||||
}()
|
||||
}
|
||||
|
||||
@objc public extension CAPPluginCall {
|
||||
@available(*, deprecated, message: "Presence of a key should not be considered significant. Use typed accessors to check the value instead.")
|
||||
func hasOption(_ key: String) -> Bool {
|
||||
guard let value = options[key] else {
|
||||
return false
|
||||
}
|
||||
return !(value is NSNull)
|
||||
}
|
||||
|
||||
func resolve() {
|
||||
successHandler(CAPPluginCallResult(nil), self)
|
||||
}
|
||||
|
||||
func resolve(_ data: PluginCallResultData = [:]) {
|
||||
successHandler(CAPPluginCallResult(data), self)
|
||||
}
|
||||
|
||||
func reject(_ message: String, _ code: String? = nil, _ error: Error? = nil, _ data: PluginCallResultData? = nil) {
|
||||
errorHandler(CAPPluginCallError(message: message, code: code, error: error, data: data))
|
||||
}
|
||||
|
||||
func unimplemented() {
|
||||
unimplemented("not implemented")
|
||||
}
|
||||
|
||||
func unimplemented(_ message: String) {
|
||||
errorHandler(CAPPluginCallError(message: message, code: "UNIMPLEMENTED", error: nil, data: [:]))
|
||||
}
|
||||
|
||||
func unavailable() {
|
||||
unavailable("not available")
|
||||
}
|
||||
|
||||
func unavailable(_ message: String) {
|
||||
errorHandler(CAPPluginCallError(message: message, code: "UNAVAILABLE", error: nil, data: [:]))
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: Codable Support
|
||||
public extension CAPPluginCall {
|
||||
/// Encodes the given value to a ``JSObject`` and resolves the call. If an error is thrown during encoding, ``reject(_:_:_:_:)`` is called.
|
||||
/// - Parameters:
|
||||
/// - data: The value to encode
|
||||
/// - encoder: The encoder to use. Defaults to `JSValueEncoder()`
|
||||
/// - messageForRejectionFromError: A closure that takes the error thrown from ``JSValueEncoder/encodeJSObject(_:)``
|
||||
/// and returns a string to be provided to ``reject(_:_:_:_:)``. Defaults to a function that returns "Failed encoding response".
|
||||
func resolve<T: Encodable>(
|
||||
with data: T,
|
||||
encoder: JSValueEncoder = JSValueEncoder(),
|
||||
messageForRejectionFromError: (Error) -> String = { _ in "Failed encoding response" }
|
||||
) {
|
||||
do {
|
||||
let encoded = try encoder.encodeJSObject(data)
|
||||
resolve(encoded)
|
||||
} catch {
|
||||
let message = messageForRejectionFromError(error)
|
||||
reject(message, nil, error)
|
||||
}
|
||||
}
|
||||
|
||||
/// Decodes the options to the given type.
|
||||
/// - Parameters:
|
||||
/// - type: The type to decode to.
|
||||
/// - decoder: The decoder to use. Defaults to `JSValueDecoder()`.
|
||||
/// - Throws: If the options cannot be decoded.
|
||||
/// - Returns: The decoded value.
|
||||
func decode<T: Decodable>(_ type: T.Type, decoder: JSValueDecoder = JSValueDecoder()) throws -> T {
|
||||
try decoder.decode(type, from: options as? JSObject ?? [:])
|
||||
}
|
||||
}
|
||||
36
node_modules/@capacitor/ios/Capacitor/Capacitor/CAPPluginMethod.h
generated
vendored
Normal file
36
node_modules/@capacitor/ios/Capacitor/Capacitor/CAPPluginMethod.h
generated
vendored
Normal file
@@ -0,0 +1,36 @@
|
||||
#import "CAPPluginCall.h"
|
||||
#import "CAPPlugin.h"
|
||||
|
||||
typedef enum {
|
||||
CAPPluginMethodArgumentNotNullable,
|
||||
CAPPluginMethodArgumentNullable
|
||||
} CAPPluginMethodArgumentNullability;
|
||||
|
||||
typedef NSString CAPPluginReturnType;
|
||||
|
||||
/**
|
||||
* Represents a single argument to a plugin method.
|
||||
*/
|
||||
@interface CAPPluginMethodArgument : NSObject
|
||||
|
||||
@property (nonatomic, copy) NSString *name;
|
||||
@property (nonatomic, assign) CAPPluginMethodArgumentNullability nullability;
|
||||
|
||||
- (instancetype)initWithName:(NSString *)name nullability:(CAPPluginMethodArgumentNullability)nullability type:(NSString *)type;
|
||||
|
||||
@end
|
||||
|
||||
/**
|
||||
* Represents a method that a plugin supports, with the ability
|
||||
* to compute selectors and invoke the method.
|
||||
*/
|
||||
@interface CAPPluginMethod : NSObject
|
||||
|
||||
@property (nonatomic, assign) SEL selector;
|
||||
@property (nonatomic, strong) NSString *name; // Raw method name
|
||||
@property (nonatomic, strong) CAPPluginReturnType *returnType; // Return type of method (i.e. callback/promise/sync)
|
||||
|
||||
- (instancetype)initWithName:(NSString *)name returnType:(CAPPluginReturnType *)returnType;
|
||||
- (instancetype)initWithSelector:(SEL)selector returnType:(CAPPluginReturnType *)returnType;
|
||||
|
||||
@end
|
||||
44
node_modules/@capacitor/ios/Capacitor/Capacitor/CAPPluginMethod.m
generated
vendored
Normal file
44
node_modules/@capacitor/ios/Capacitor/Capacitor/CAPPluginMethod.m
generated
vendored
Normal file
@@ -0,0 +1,44 @@
|
||||
#import <Capacitor/Capacitor-Swift.h>
|
||||
#import "CAPPluginMethod.h"
|
||||
|
||||
typedef void(^CAPCallback)(id _arg, NSInteger index);
|
||||
|
||||
@implementation CAPPluginMethodArgument
|
||||
|
||||
- (instancetype)initWithName:(NSString *)name nullability:(CAPPluginMethodArgumentNullability)nullability type:(NSString *)type {
|
||||
self.name = name;
|
||||
self.nullability = nullability;
|
||||
return self;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation CAPPluginMethod {
|
||||
// NSInvocation's retainArguments doesn't work with our arguments
|
||||
// so we have to retain args manually
|
||||
NSMutableArray *_manualRetainArgs;
|
||||
// Retain invocation instance
|
||||
NSInvocation *_invocation;
|
||||
NSMutableArray *_methodArgumentCallbacks;
|
||||
CAPPluginCall *_call;
|
||||
SEL _selector;
|
||||
}
|
||||
|
||||
-(instancetype)initWithName:(NSString *)name returnType:(CAPPluginReturnType *)returnType {
|
||||
self.name = name;
|
||||
self.selector = NSSelectorFromString([name stringByAppendingString:@":"]);
|
||||
self.returnType = returnType;
|
||||
return self;
|
||||
}
|
||||
|
||||
-(instancetype)initWithSelector:(SEL) selector returnType:(CAPPluginReturnType *)returnType {
|
||||
// need to drop the : from the selector string
|
||||
NSString* rawSelString = NSStringFromSelector(selector);
|
||||
self.name = [rawSelString substringToIndex:[rawSelString length] - 1];
|
||||
self.selector = selector;
|
||||
self.returnType = returnType;
|
||||
return self;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
17
node_modules/@capacitor/ios/Capacitor/Capacitor/CAPPluginMethod.swift
generated
vendored
Normal file
17
node_modules/@capacitor/ios/Capacitor/Capacitor/CAPPluginMethod.swift
generated
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
//
|
||||
// CAPPluginMethod.swift
|
||||
// Capacitor
|
||||
//
|
||||
// Created by Steven Sherry on 4/18/24.
|
||||
// Copyright © 2024 Drifty Co. All rights reserved.
|
||||
//
|
||||
|
||||
extension CAPPluginMethod {
|
||||
public enum ReturnType: String {
|
||||
case promise, callback, none
|
||||
}
|
||||
|
||||
public convenience init(_ selector: Selector, returnType: ReturnType = .promise) {
|
||||
self.init(selector: selector, returnType: returnType.rawValue)
|
||||
}
|
||||
}
|
||||
15
node_modules/@capacitor/ios/Capacitor/Capacitor/Capacitor.h
generated
vendored
Normal file
15
node_modules/@capacitor/ios/Capacitor/Capacitor/Capacitor.h
generated
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
//! Project version number for bridge.
|
||||
FOUNDATION_EXPORT double CapacitorVersionNumber;
|
||||
|
||||
//! Project version string for bridge.
|
||||
FOUNDATION_EXPORT const unsigned char CapacitorVersionString[];
|
||||
|
||||
#import <Capacitor/CAPPlugin.h>
|
||||
#import <Capacitor/CAPPluginCall.h>
|
||||
#import <Capacitor/CAPBridgedPlugin.h>
|
||||
#import <Capacitor/CAPPluginMethod.h>
|
||||
#import <Capacitor/CAPInstanceDescriptor.h>
|
||||
#import <Capacitor/CAPInstanceConfiguration.h>
|
||||
|
||||
8
node_modules/@capacitor/ios/Capacitor/Capacitor/Capacitor.modulemap
generated
vendored
Normal file
8
node_modules/@capacitor/ios/Capacitor/Capacitor/Capacitor.modulemap
generated
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
framework module Capacitor {
|
||||
umbrella header "Capacitor.h"
|
||||
exclude header "CAPBridgedJSTypes.h"
|
||||
exclude header "CAPBridgeViewController+CDVScreenOrientationDelegate.h"
|
||||
|
||||
export *
|
||||
module * { export * }
|
||||
}
|
||||
768
node_modules/@capacitor/ios/Capacitor/Capacitor/CapacitorBridge.swift
generated
vendored
Normal file
768
node_modules/@capacitor/ios/Capacitor/Capacitor/CapacitorBridge.swift
generated
vendored
Normal file
@@ -0,0 +1,768 @@
|
||||
import Foundation
|
||||
import Dispatch
|
||||
import WebKit
|
||||
import Cordova
|
||||
|
||||
internal typealias CapacitorPlugin = CAPPlugin & CAPBridgedPlugin
|
||||
|
||||
struct RegistrationList: Codable {
|
||||
let packageClassList: Set<String>
|
||||
}
|
||||
|
||||
/**
|
||||
An internal class adopting a public protocol means that we have a lot of `public` methods
|
||||
but that is by design not a mistake. And since the bridge is the center of the whole project
|
||||
its size/complexity is unavoidable.
|
||||
|
||||
Quiet these warnings for the whole file.
|
||||
*/
|
||||
// swiftlint:disable lower_acl_than_parent
|
||||
// swiftlint:disable file_length
|
||||
// swiftlint:disable type_body_length
|
||||
open class CapacitorBridge: NSObject, CAPBridgeProtocol {
|
||||
|
||||
// this decision is needed before the bridge is instantiated,
|
||||
// so we need a class property to avoid duplication
|
||||
public static var isDevEnvironment: Bool {
|
||||
#if DEBUG
|
||||
return true
|
||||
#else
|
||||
// this is needed for SPM xcframework Capacitor. Can eventually be removed when the SPM package moves to being source-based.
|
||||
if let debugValue = Bundle.main.object(forInfoDictionaryKey: "CAPACITOR_DEBUG") as? String, debugValue == "true" {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
#endif
|
||||
}
|
||||
|
||||
// MARK: - CAPBridgeProtocol: Properties
|
||||
|
||||
public var webView: WKWebView? {
|
||||
return bridgeDelegate?.bridgedWebView
|
||||
}
|
||||
|
||||
public let autoRegisterPlugins: Bool
|
||||
|
||||
public var notificationRouter: NotificationRouter
|
||||
|
||||
public var isSimEnvironment: Bool {
|
||||
#if targetEnvironment(simulator)
|
||||
return true
|
||||
#else
|
||||
return false
|
||||
#endif
|
||||
}
|
||||
|
||||
public var isDevEnvironment: Bool {
|
||||
return CapacitorBridge.isDevEnvironment
|
||||
}
|
||||
|
||||
public var userInterfaceStyle: UIUserInterfaceStyle {
|
||||
return viewController?.traitCollection.userInterfaceStyle ?? .unspecified
|
||||
}
|
||||
|
||||
public var statusBarVisible: Bool {
|
||||
get {
|
||||
return !(viewController?.prefersStatusBarHidden ?? true)
|
||||
}
|
||||
set {
|
||||
DispatchQueue.main.async { [weak self] in
|
||||
(self?.viewController as? CAPBridgeViewController)?.setStatusBarVisible(newValue)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public var statusBarStyle: UIStatusBarStyle {
|
||||
get {
|
||||
return viewController?.preferredStatusBarStyle ?? .default
|
||||
}
|
||||
set {
|
||||
DispatchQueue.main.async { [weak self] in
|
||||
(self?.viewController as? CAPBridgeViewController)?.setStatusBarStyle(newValue)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public var statusBarAnimation: UIStatusBarAnimation {
|
||||
get {
|
||||
return (viewController as? CAPBridgeViewController)?.statusBarAnimation ?? .slide
|
||||
}
|
||||
set {
|
||||
DispatchQueue.main.async { [weak self] in
|
||||
(self?.viewController as? CAPBridgeViewController)?.setStatusBarAnimation(newValue)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var tmpWindow: UIWindow?
|
||||
static let tmpVCAppeared = Notification(name: Notification.Name(rawValue: "tmpViewControllerAppeared"))
|
||||
public static let capacitorSite = "https://capacitorjs.com/"
|
||||
public static let fileStartIdentifier = "/_capacitor_file_"
|
||||
public static let httpInterceptorStartIdentifier = "/_capacitor_http_interceptor_"
|
||||
@available(*, deprecated, message: "`httpsInterceptorStartIdentifier` is no longer required. All proxied requests are handled via `httpInterceptorStartIdentifier` instead")
|
||||
public static let httpsInterceptorStartIdentifier = "/_capacitor_https_interceptor_"
|
||||
public static let httpInterceptorUrlParam = "u"
|
||||
public static let defaultScheme = "capacitor"
|
||||
|
||||
public private(set) var webViewAssetHandler: WebViewAssetHandler
|
||||
public private(set) var webViewDelegationHandler: WebViewDelegationHandler
|
||||
public private(set) weak var bridgeDelegate: CAPBridgeDelegate?
|
||||
@objc public var viewController: UIViewController? {
|
||||
return bridgeDelegate?.bridgedViewController
|
||||
}
|
||||
|
||||
var lastPlugin: CAPPlugin?
|
||||
|
||||
@objc public var config: InstanceConfiguration
|
||||
// Map of all loaded and instantiated plugins by pluginId -> instance
|
||||
var plugins = [String: CapacitorPlugin]()
|
||||
// Manager for getting Cordova plugins
|
||||
var cordovaPluginManager: CDVPluginManager?
|
||||
// Calls we are storing to resolve later
|
||||
var storedCalls = ConcurrentDictionary<CAPPluginCall>()
|
||||
// Whether to inject the Cordova files
|
||||
private var injectCordovaFiles = false
|
||||
private var cordovaParser: CDVConfigParser?
|
||||
private var injectMiscFiles: [String] = []
|
||||
private var canInjectJS: Bool = true
|
||||
|
||||
// Background dispatch queue for plugin calls
|
||||
open private(set) var dispatchQueue = DispatchQueue(label: "bridge")
|
||||
// Array of block based observers
|
||||
var observers: [NSObjectProtocol] = []
|
||||
|
||||
// MARK: - CAPBridgeProtocol: Deprecated
|
||||
|
||||
public func getWebView() -> WKWebView? {
|
||||
return webView
|
||||
}
|
||||
|
||||
public func isSimulator() -> Bool {
|
||||
return isSimEnvironment
|
||||
}
|
||||
|
||||
public func isDevMode() -> Bool {
|
||||
return isDevEnvironment
|
||||
}
|
||||
|
||||
public func getStatusBarVisible() -> Bool {
|
||||
return statusBarVisible
|
||||
}
|
||||
|
||||
@nonobjc public func setStatusBarVisible(_ visible: Bool) {
|
||||
statusBarVisible = visible
|
||||
}
|
||||
|
||||
public func getStatusBarStyle() -> UIStatusBarStyle {
|
||||
return statusBarStyle
|
||||
}
|
||||
@nonobjc public func setStatusBarStyle(_ style: UIStatusBarStyle) {
|
||||
statusBarStyle = style
|
||||
}
|
||||
|
||||
public func getUserInterfaceStyle() -> UIUserInterfaceStyle {
|
||||
return userInterfaceStyle
|
||||
}
|
||||
|
||||
public func getLocalUrl() -> String {
|
||||
return config.localURL.absoluteString
|
||||
}
|
||||
|
||||
@nonobjc public func setStatusBarAnimation(_ animation: UIStatusBarAnimation) {
|
||||
statusBarAnimation = animation
|
||||
}
|
||||
|
||||
public func setServerBasePath(_ path: String) {
|
||||
let url = URL(fileURLWithPath: path, isDirectory: true)
|
||||
guard FileManager.default.fileExists(atPath: url.path) else { return }
|
||||
config = config.updatingAppLocation(url)
|
||||
webViewAssetHandler.setAssetPath(url.path)
|
||||
}
|
||||
|
||||
// MARK: - Static Methods
|
||||
|
||||
/**
|
||||
Print a hopefully informative error message to the log when something
|
||||
particularly dreadful happens.
|
||||
*/
|
||||
static func fatalError(_ error: Error, _ originalError: Error) {
|
||||
CAPLog.print("⚡️ ❌ Capacitor: FATAL ERROR")
|
||||
CAPLog.print("⚡️ ❌ Error was: ", originalError.localizedDescription)
|
||||
switch error {
|
||||
case CapacitorBridgeError.errorExportingCoreJS:
|
||||
CAPLog.print("⚡️ ❌ Unable to export required Bridge JavaScript. Bridge will not function.")
|
||||
CAPLog.print("⚡️ ❌ You should run \"npx capacitor copy\" to ensure the Bridge JS is added to your project.")
|
||||
if let wke = originalError as? WKError {
|
||||
CAPLog.print("⚡️ ❌ ", wke.userInfo)
|
||||
}
|
||||
default:
|
||||
CAPLog.print("⚡️ ❌ Unknown error")
|
||||
}
|
||||
|
||||
CAPLog.print("⚡️ ❌ Please verify your installation or file an issue")
|
||||
}
|
||||
|
||||
// MARK: - Initialization
|
||||
|
||||
public init(with configuration: InstanceConfiguration, delegate bridgeDelegate: CAPBridgeDelegate, cordovaConfiguration: CDVConfigParser, assetHandler: WebViewAssetHandler, delegationHandler: WebViewDelegationHandler, autoRegisterPlugins: Bool = true) {
|
||||
self.bridgeDelegate = bridgeDelegate
|
||||
self.webViewAssetHandler = assetHandler
|
||||
self.webViewDelegationHandler = delegationHandler
|
||||
self.config = configuration
|
||||
self.cordovaParser = cordovaConfiguration
|
||||
self.notificationRouter = NotificationRouter()
|
||||
self.notificationRouter.handleApplicationNotifications = configuration.handleApplicationNotifications
|
||||
self.autoRegisterPlugins = autoRegisterPlugins
|
||||
super.init()
|
||||
|
||||
self.webViewDelegationHandler.bridge = self
|
||||
|
||||
exportCoreJS(localUrl: configuration.localURL.absoluteString)
|
||||
registerPlugins()
|
||||
setupCordovaCompatibility()
|
||||
exportMiscJS()
|
||||
canInjectJS = false
|
||||
observers.append(NotificationCenter.default.addObserver(forName: type(of: self).tmpVCAppeared.name, object: .none, queue: .none) { [weak self] _ in
|
||||
self?.tmpWindow = nil
|
||||
})
|
||||
|
||||
self.setupWebDebugging(configuration: configuration)
|
||||
}
|
||||
|
||||
deinit {
|
||||
// the message handler needs to removed to avoid any retain cycles
|
||||
webViewDelegationHandler.cleanUp()
|
||||
for observer in observers {
|
||||
NotificationCenter.default.removeObserver(observer)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Plugins
|
||||
/**
|
||||
Export core JavaScript to the webview
|
||||
*/
|
||||
func exportCoreJS(localUrl: String) {
|
||||
do {
|
||||
try JSExport.exportCapacitorGlobalJS(userContentController: webViewDelegationHandler.contentController,
|
||||
isDebug: isDevEnvironment,
|
||||
loggingEnabled: config.loggingEnabled,
|
||||
localUrl: localUrl)
|
||||
try JSExport.exportBridgeJS(userContentController: webViewDelegationHandler.contentController)
|
||||
} catch {
|
||||
type(of: self).fatalError(error, error)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Export misc JavaScript to the webview
|
||||
*/
|
||||
func exportMiscJS() {
|
||||
JSExport.exportMiscFileJS(paths: injectMiscFiles, userContentController: webViewDelegationHandler.contentController)
|
||||
injectMiscFiles.removeAll()
|
||||
}
|
||||
|
||||
/**
|
||||
Set up our Cordova compat by loading all known Cordova plugins and injecting their JS.
|
||||
*/
|
||||
func setupCordovaCompatibility() {
|
||||
if injectCordovaFiles {
|
||||
exportCordovaJS()
|
||||
registerCordovaPlugins()
|
||||
} else {
|
||||
observers.append(NotificationCenter.default.addObserver(forName: UIApplication.willEnterForegroundNotification, object: nil, queue: OperationQueue.main) { [weak self] (_) in
|
||||
self?.triggerDocumentJSEvent(eventName: "resume")
|
||||
})
|
||||
observers.append(NotificationCenter.default.addObserver(forName: UIApplication.didEnterBackgroundNotification, object: nil, queue: OperationQueue.main) { [weak self] (_) in
|
||||
self?.triggerDocumentJSEvent(eventName: "pause")
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Export the core Cordova JS runtime
|
||||
*/
|
||||
func exportCordovaJS() {
|
||||
do {
|
||||
try JSExport.exportCordovaJS(userContentController: webViewDelegationHandler.contentController)
|
||||
} catch {
|
||||
type(of: self).fatalError(error, error)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Reset the state of the bridge between navigations to avoid
|
||||
sending data back to the page from a previous page.
|
||||
*/
|
||||
func reset() {
|
||||
storedCalls.withLock { $0.removeAll() }
|
||||
removeAllPluginListeners()
|
||||
}
|
||||
|
||||
/**
|
||||
Register all plugins that have been declared
|
||||
*/
|
||||
func registerPlugins() {
|
||||
var pluginList: [AnyClass] = [CAPHttpPlugin.self, CAPConsolePlugin.self, CAPWebViewPlugin.self, CAPCookiesPlugin.self]
|
||||
|
||||
if autoRegisterPlugins {
|
||||
do {
|
||||
if let pluginJSON = Bundle.main.url(forResource: "capacitor.config", withExtension: "json") {
|
||||
let pluginData = try Data(contentsOf: pluginJSON)
|
||||
let registrationList = try JSONDecoder().decode(RegistrationList.self, from: pluginData)
|
||||
|
||||
for plugin in registrationList.packageClassList {
|
||||
if let pluginClass = NSClassFromString(plugin) {
|
||||
if pluginClass == CDVPlugin.self {
|
||||
injectCordovaFiles = true
|
||||
} else {
|
||||
pluginList.append(pluginClass)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
CAPLog.print("Error registering plugins: \(error)")
|
||||
}
|
||||
}
|
||||
|
||||
for plugin in pluginList {
|
||||
if plugin is CAPInstancePlugin.Type { continue }
|
||||
if let capPlugin = plugin as? CapacitorPlugin.Type {
|
||||
registerPlugin(capPlugin)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public func registerPluginType(_ pluginType: CAPPlugin.Type) {
|
||||
if autoRegisterPlugins { return }
|
||||
if pluginType is CAPInstancePlugin.Type {
|
||||
Swift.fatalError("""
|
||||
|
||||
⚡️ ❌ Cannot register class \(pluginType): CAPInstancePlugin through registerPluginType(_:).
|
||||
⚡️ ❌ Use `registerPluginInstance(_:)` to register subclasses of CAPInstancePlugin.
|
||||
""")
|
||||
}
|
||||
guard let bridgedType = pluginType as? CapacitorPlugin.Type else { return }
|
||||
registerPlugin(bridgedType)
|
||||
}
|
||||
|
||||
public func registerPluginInstance(_ pluginInstance: CAPPlugin) {
|
||||
guard let pluginInstance = pluginInstance as? CapacitorPlugin else {
|
||||
CAPLog.print("""
|
||||
|
||||
⚡️ Plugin \(pluginInstance.classForCoder) must conform to CAPBridgedPlugin.
|
||||
⚡️ Not loading plugin \(pluginInstance.classForCoder)
|
||||
""")
|
||||
return
|
||||
}
|
||||
|
||||
if plugins[pluginInstance.jsName] != nil {
|
||||
CAPLog.print("⚡️ Overriding existing registered plugin \(pluginInstance.classForCoder)")
|
||||
}
|
||||
plugins[pluginInstance.jsName] = pluginInstance
|
||||
pluginInstance.load(on: self)
|
||||
|
||||
JSExport.exportJS(for: pluginInstance, in: webViewDelegationHandler.contentController)
|
||||
}
|
||||
|
||||
/**
|
||||
Register a single plugin.
|
||||
*/
|
||||
func registerPlugin(_ pluginType: CapacitorPlugin.Type) {
|
||||
if let plugin = loadPlugin(type: pluginType) {
|
||||
JSExport.exportJS(for: plugin, in: webViewDelegationHandler.contentController)
|
||||
}
|
||||
}
|
||||
|
||||
func loadPlugin(type: CAPPlugin.Type) -> CapacitorPlugin? {
|
||||
guard let plugin = type.init() as? CapacitorPlugin else {
|
||||
CAPLog.print("⚡️ Unable to load plugin \(type.classForCoder()). No such module found.")
|
||||
return nil
|
||||
}
|
||||
plugin.load(on: self)
|
||||
plugins[plugin.jsName] = plugin
|
||||
return plugin
|
||||
}
|
||||
|
||||
// MARK: - CAPBridgeProtocol: Plugin Access
|
||||
|
||||
@objc public func plugin(withName: String) -> CAPPlugin? {
|
||||
return self.plugins[withName]
|
||||
}
|
||||
|
||||
// MARK: - CAPBridgeProtocol: Call Management
|
||||
|
||||
@objc public func saveCall(_ call: CAPPluginCall) {
|
||||
storedCalls[call.callbackId] = call
|
||||
}
|
||||
|
||||
@objc public func savedCall(withID: String) -> CAPPluginCall? {
|
||||
return storedCalls[withID]
|
||||
}
|
||||
|
||||
@objc public func releaseCall(_ call: CAPPluginCall) {
|
||||
releaseCall(withID: call.callbackId)
|
||||
}
|
||||
|
||||
@objc public func releaseCall(withID: String) {
|
||||
_ = storedCalls.withLock { $0.removeValue(forKey: withID) }
|
||||
}
|
||||
|
||||
// MARK: - Deprecated Versions
|
||||
|
||||
@objc public func getSavedCall(_ callbackId: String) -> CAPPluginCall? {
|
||||
return savedCall(withID: callbackId)
|
||||
}
|
||||
|
||||
@objc public func releaseCall(callbackId: String) {
|
||||
releaseCall(withID: callbackId)
|
||||
}
|
||||
|
||||
// MARK: - Internal
|
||||
|
||||
func getDispatchQueue() -> DispatchQueue {
|
||||
return self.dispatchQueue
|
||||
}
|
||||
|
||||
func registerCordovaPlugins() {
|
||||
guard let cordovaParser = cordovaParser else {
|
||||
return
|
||||
}
|
||||
cordovaPluginManager = CDVPluginManager.init(parser: cordovaParser, viewController: self.viewController, webView: self.getWebView())
|
||||
if cordovaParser.startupPluginNames.count > 0 {
|
||||
for pluginName in cordovaParser.startupPluginNames {
|
||||
_ = cordovaPluginManager?.getCommandInstance(pluginName as? String)
|
||||
}
|
||||
}
|
||||
do {
|
||||
try JSExport.exportCordovaPluginsJS(userContentController: webViewDelegationHandler.contentController)
|
||||
} catch {
|
||||
type(of: self).fatalError(error, error)
|
||||
}
|
||||
}
|
||||
|
||||
func reload() {
|
||||
self.getWebView()?.reload()
|
||||
}
|
||||
|
||||
func docLink(_ url: String) -> String {
|
||||
return "\(type(of: self).capacitorSite)docs/\(url)"
|
||||
}
|
||||
|
||||
private func setupWebDebugging(configuration: InstanceConfiguration) {
|
||||
let isWebDebuggable = configuration.isWebDebuggable
|
||||
if isWebDebuggable, #unavailable(iOS 16.4) {
|
||||
CAPLog.print("⚡️ Warning: isWebDebuggable only functions as intended on iOS 16.4 and above.")
|
||||
}
|
||||
|
||||
if #available(iOS 16.4, *) {
|
||||
self.webView?.isInspectable = isWebDebuggable
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Handle a call from JavaScript. First, find the corresponding plugin, construct a selector,
|
||||
and perform that selector on the plugin instance.
|
||||
|
||||
Quiet the length warning because we don't want to refactor the function at this time.
|
||||
*/
|
||||
// swiftlint:disable:next function_body_length
|
||||
func handleJSCall(call: JSCall) {
|
||||
let load = {
|
||||
NSClassFromString(call.pluginId)
|
||||
.flatMap { $0 as? CAPPlugin.Type }
|
||||
.flatMap(self.loadPlugin(type:))
|
||||
}
|
||||
|
||||
guard let plugin = plugins[call.pluginId] ?? load() else {
|
||||
CAPLog.print("⚡️ Error loading plugin \(call.pluginId) for call. Check that the pluginId is correct")
|
||||
return
|
||||
}
|
||||
|
||||
let selector: Selector
|
||||
if call.method == "addListener" || call.method == "removeListener" || call.method == "removeAllListeners" {
|
||||
selector = NSSelectorFromString(call.method + ":")
|
||||
} else {
|
||||
guard let method = plugin.getMethod(named: call.method) else {
|
||||
CAPLog.print("⚡️ Error calling method \(call.method) on plugin \(call.pluginId): No method found.")
|
||||
CAPLog.print("⚡️ Ensure plugin method exists and uses @objc in its declaration, and has been defined")
|
||||
return
|
||||
}
|
||||
|
||||
selector = method.selector
|
||||
}
|
||||
|
||||
if !plugin.responds(to: selector) {
|
||||
// we don't want to break up string literals
|
||||
// swiftlint:disable line_length
|
||||
CAPLog.print("⚡️ Error: Plugin \(plugin.getId()) does not respond to method call \"\(call.method)\" using selector \"\(selector)\".")
|
||||
CAPLog.print("⚡️ Ensure plugin method exists, uses @objc in its declaration, and arguments match selector without callbacks in CAP_PLUGIN_METHOD.")
|
||||
CAPLog.print("⚡️ Learn more: \(docLink(DocLinks.CAPPluginMethodSelector.rawValue))")
|
||||
// swiftlint:enable line_length
|
||||
return
|
||||
}
|
||||
|
||||
// Create a plugin call object and handle the success/error callbacks
|
||||
dispatchQueue.async { [weak self] in
|
||||
// let startTime = CFAbsoluteTimeGetCurrent()
|
||||
|
||||
let pluginCall = CAPPluginCall(callbackId: call.callbackId, methodName: call.method,
|
||||
options: JSTypes.coerceDictionaryToJSObject(call.options,
|
||||
formattingDatesAsStrings: plugin.shouldStringifyDatesInCalls) ?? [:],
|
||||
success: {(result: CAPPluginCallResult?, pluginCall: CAPPluginCall?) in
|
||||
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)
|
||||
}
|
||||
}, error: {(error: CAPPluginCallError?) in
|
||||
if let error = error {
|
||||
self?.toJsError(error: JSResultError(call: call, callError: error))
|
||||
} else {
|
||||
self?.toJsError(error: JSResultError(call: call,
|
||||
errorMessage: "",
|
||||
errorDescription: "",
|
||||
errorCode: nil,
|
||||
result: .dictionary([:])))
|
||||
}
|
||||
})
|
||||
|
||||
if let pluginCall = pluginCall {
|
||||
plugin.perform(selector, with: pluginCall)
|
||||
if pluginCall.keepAlive {
|
||||
self?.saveCall(pluginCall)
|
||||
}
|
||||
}
|
||||
|
||||
// let timeElapsed = CFAbsoluteTimeGetCurrent() - startTime
|
||||
// CAPLog.print("Native call took", timeElapsed)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Handle a Cordova call from JavaScript. First, find the corresponding plugin,
|
||||
construct a selector, and perform that selector on the plugin instance.
|
||||
*/
|
||||
func handleCordovaJSCall(call: JSCall) {
|
||||
// Create a selector to send to the plugin
|
||||
|
||||
if let plugin = self.cordovaPluginManager?.getCommandInstance(call.pluginId.lowercased()) {
|
||||
let selector = NSSelectorFromString("\(call.method):")
|
||||
if !plugin.responds(to: selector) {
|
||||
CAPLog.print("Error: Plugin \(plugin.className ?? "") does not respond to method call \(selector).")
|
||||
CAPLog.print("Ensure plugin method exists and uses @objc in its declaration")
|
||||
return
|
||||
}
|
||||
|
||||
let arguments: [Any] = call.options["options"] as? [Any] ?? []
|
||||
let pluginCall = CDVInvokedUrlCommand(arguments: arguments,
|
||||
callbackId: call.callbackId,
|
||||
className: plugin.className,
|
||||
methodName: call.method)
|
||||
plugin.perform(selector, with: pluginCall)
|
||||
|
||||
} else {
|
||||
CAPLog.print("Error: Cordova Plugin mapping not found")
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func removeAllPluginListeners() {
|
||||
for plugin in plugins.values {
|
||||
plugin.perform(#selector(CAPPlugin.removeAllListeners(_:)), with: nil)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Send a successful result to the JavaScript layer.
|
||||
*/
|
||||
func toJs(result: JSResultProtocol, save: Bool) {
|
||||
let resultJson = result.jsonPayload()
|
||||
CAPLog.print("⚡️ TO JS", resultJson.prefix(256))
|
||||
|
||||
DispatchQueue.main.async {
|
||||
self.webView?.evaluateJavaScript("""
|
||||
window.Capacitor.fromNative({
|
||||
callbackId: '\(result.callbackID)',
|
||||
pluginId: '\(result.pluginID)',
|
||||
methodName: '\(result.methodName)',
|
||||
save: \(save),
|
||||
success: true,
|
||||
data: \(resultJson)
|
||||
})
|
||||
""") { (_, error) in
|
||||
if let error = error {
|
||||
CAPLog.print(error)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Send an error result to the JavaScript layer.
|
||||
*/
|
||||
func toJsError(error: JSResultProtocol) {
|
||||
DispatchQueue.main.async {
|
||||
self.webView?.evaluateJavaScript("window.Capacitor.fromNative({ callbackId: '\(error.callbackID)', pluginId: '\(error.pluginID)', methodName: '\(error.methodName)', success: false, error: \(error.jsonPayload())})") { (_, error) in
|
||||
if let error = error {
|
||||
CAPLog.print(error)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - CAPBridgeProtocol: JavaScript Handling
|
||||
|
||||
/**
|
||||
Inject JavaScript from an external file before the WebView loads.
|
||||
|
||||
`path` is relative to the public folder
|
||||
*/
|
||||
public func injectScriptBeforeLoad(path: String) {
|
||||
if canInjectJS {
|
||||
injectMiscFiles.append(path)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Eval JS for a specific plugin.
|
||||
|
||||
`js` is a short name but needs to be preserved for backwards compatibility.
|
||||
*/
|
||||
// swiftlint:disable:next identifier_name
|
||||
@objc public func evalWithPlugin(_ plugin: CAPPlugin, js: String) {
|
||||
let wrappedJs = """
|
||||
window.Capacitor.withPlugin('\(plugin.getId())', function(plugin) {
|
||||
if(!plugin) { console.error('Unable to execute JS in plugin, no such plugin found for id \(plugin.getId())'); }
|
||||
\(js)
|
||||
});
|
||||
"""
|
||||
|
||||
DispatchQueue.main.async {
|
||||
self.getWebView()?.evaluateJavaScript(wrappedJs, completionHandler: { (_, error) in
|
||||
if let error = error {
|
||||
CAPLog.print("⚡️ JS Eval error", error.localizedDescription)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Eval JS in the web view
|
||||
|
||||
`js` is a short name but needs to be preserved for backwards compatibility.
|
||||
*/
|
||||
// swiftlint:disable:next identifier_name
|
||||
@objc public func eval(js: String) {
|
||||
DispatchQueue.main.async {
|
||||
self.getWebView()?.evaluateJavaScript(js, completionHandler: { (_, error) in
|
||||
if let error = error {
|
||||
CAPLog.print("⚡️ JS Eval error", error.localizedDescription)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@objc public func triggerJSEvent(eventName: String, target: String) {
|
||||
self.eval(js: "window.Capacitor.triggerEvent('\(eventName)', '\(target)')")
|
||||
}
|
||||
|
||||
@objc public func triggerJSEvent(eventName: String, target: String, data: String) {
|
||||
self.eval(js: "window.Capacitor.triggerEvent('\(eventName)', '\(target)', \(data))")
|
||||
}
|
||||
|
||||
@objc public func triggerWindowJSEvent(eventName: String) {
|
||||
self.triggerJSEvent(eventName: eventName, target: "window")
|
||||
}
|
||||
|
||||
@objc public func triggerWindowJSEvent(eventName: String, data: String) {
|
||||
self.triggerJSEvent(eventName: eventName, target: "window", data: data)
|
||||
}
|
||||
|
||||
@objc public func triggerDocumentJSEvent(eventName: String) {
|
||||
self.triggerJSEvent(eventName: eventName, target: "document")
|
||||
}
|
||||
|
||||
@objc public func triggerDocumentJSEvent(eventName: String, data: String) {
|
||||
self.triggerJSEvent(eventName: eventName, target: "document", data: data)
|
||||
}
|
||||
|
||||
public func logToJs(_ message: String, _ level: String = "log") {
|
||||
DispatchQueue.main.async {
|
||||
self.getWebView()?.evaluateJavaScript("window.Capacitor.logJs('\(message)', '\(level)')") { (result, error) in
|
||||
if error != nil, let result = result {
|
||||
CAPLog.print(result)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - CAPBridgeProtocol: Paths, Files, Assets
|
||||
|
||||
/**
|
||||
Translate a URL from the web view into a file URL for native iOS.
|
||||
|
||||
The web view may be handling several different types of URLs:
|
||||
- res:// (shortcut scheme to web assets)
|
||||
- file:// (fully qualified URL to file on the local device)
|
||||
- base64:// (to be implemented)
|
||||
- [web view scheme]:// (already converted once to load in the web view, to be implemented)
|
||||
*/
|
||||
public func localURL(fromWebURL webURL: URL?) -> URL? {
|
||||
guard let inputURL = webURL else {
|
||||
return nil
|
||||
}
|
||||
|
||||
let url: URL
|
||||
|
||||
switch inputURL.scheme {
|
||||
case "res":
|
||||
url = config.appLocation.appendingPathComponent(inputURL.path)
|
||||
case "file":
|
||||
url = inputURL
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
|
||||
return url
|
||||
}
|
||||
|
||||
/**
|
||||
Translate a file URL for native iOS into a URL to load in the web view.
|
||||
*/
|
||||
public func portablePath(fromLocalURL localURL: URL?) -> URL? {
|
||||
guard let inputURL = localURL else {
|
||||
return nil
|
||||
}
|
||||
|
||||
return self.config.localURL.appendingPathComponent(CapacitorBridge.fileStartIdentifier).appendingPathComponent(inputURL.path)
|
||||
}
|
||||
|
||||
// MARK: - CAPBridgeProtocol: View Presentation
|
||||
|
||||
@objc open func showAlertWith(title: String, message: String, buttonTitle: String) {
|
||||
let alert = UIAlertController(title: title, message: message, preferredStyle: UIAlertController.Style.alert)
|
||||
alert.addAction(UIAlertAction(title: buttonTitle, style: UIAlertAction.Style.default, handler: nil))
|
||||
self.viewController?.present(alert, animated: true, completion: nil)
|
||||
}
|
||||
|
||||
@objc open func presentVC(_ viewControllerToPresent: UIViewController, animated flag: Bool, completion: (() -> Void)? = nil) {
|
||||
if viewControllerToPresent.modalPresentationStyle == .popover {
|
||||
self.viewController?.present(viewControllerToPresent, animated: flag, completion: completion)
|
||||
} else {
|
||||
self.tmpWindow = UIWindow.init(frame: UIScreen.main.bounds)
|
||||
self.tmpWindow?.rootViewController = TmpViewController.init()
|
||||
self.tmpWindow?.makeKeyAndVisible()
|
||||
self.tmpWindow?.rootViewController?.present(viewControllerToPresent, animated: flag, completion: completion)
|
||||
}
|
||||
}
|
||||
|
||||
@objc open func dismissVC(animated flag: Bool, completion: (() -> Void)? = nil) {
|
||||
if self.tmpWindow == nil {
|
||||
self.viewController?.dismiss(animated: flag, completion: completion)
|
||||
} else {
|
||||
self.tmpWindow?.rootViewController?.dismiss(animated: flag, completion: completion)
|
||||
self.tmpWindow = nil
|
||||
}
|
||||
}
|
||||
}
|
||||
24
node_modules/@capacitor/ios/Capacitor/Capacitor/CapacitorExtension.swift
generated
vendored
Normal file
24
node_modules/@capacitor/ios/Capacitor/Capacitor/CapacitorExtension.swift
generated
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
import Foundation
|
||||
|
||||
public protocol CapacitorExtension {
|
||||
associatedtype CapacitorType
|
||||
var capacitor: CapacitorType { get }
|
||||
static var capacitor: CapacitorType.Type { get }
|
||||
}
|
||||
|
||||
public extension CapacitorExtension {
|
||||
var capacitor: CapacitorExtensionTypeWrapper<Self> {
|
||||
return CapacitorExtensionTypeWrapper(self)
|
||||
}
|
||||
|
||||
static var capacitor: CapacitorExtensionTypeWrapper<Self>.Type {
|
||||
return CapacitorExtensionTypeWrapper.self
|
||||
}
|
||||
}
|
||||
|
||||
public struct CapacitorExtensionTypeWrapper<T> {
|
||||
var baseType: T
|
||||
init(_ baseType: T) {
|
||||
self.baseType = baseType
|
||||
}
|
||||
}
|
||||
479
node_modules/@capacitor/ios/Capacitor/Capacitor/Codable/JSValueDecoder.swift
generated
vendored
Normal file
479
node_modules/@capacitor/ios/Capacitor/Capacitor/Codable/JSValueDecoder.swift
generated
vendored
Normal file
@@ -0,0 +1,479 @@
|
||||
//
|
||||
// JSValueDecoder.swift
|
||||
// Capacitor
|
||||
//
|
||||
// Created by Steven Sherry on 12/8/23.
|
||||
// Copyright © 2023 Drifty Co. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import Combine
|
||||
|
||||
/// A decoder that can decode ``JSValue`` objects into `Decodable` types.
|
||||
public final class JSValueDecoder: TopLevelDecoder {
|
||||
/// The strategies available for formatting dates when decoding from a ``JSValue``
|
||||
public typealias DateDecodingStrategy = JSONDecoder.DateDecodingStrategy
|
||||
/// The strategies available for decoding raw data.
|
||||
public typealias DataDecodingStrategy = JSONDecoder.DataDecodingStrategy
|
||||
|
||||
/// The strategies availble for decoding NaN, Infinity, and -Infinity
|
||||
public enum NonConformingFloatDecodingStrategy {
|
||||
/// Decodes directly into the floating point type as .infinity, -.infinity, or .nan
|
||||
case deferred
|
||||
/// Throw an error when a non-conforming float is encountered
|
||||
case `throw`
|
||||
/// Converts from the provided strings into .infinity, -.infinity, or .nan
|
||||
case convertFromString(positiveInfinity: String, negativeInfinity: String, nan: String)
|
||||
}
|
||||
|
||||
fileprivate struct Options {
|
||||
var dataStrategy: DataDecodingStrategy
|
||||
var dateStrategy: DateDecodingStrategy
|
||||
var nonConformingStrategy: NonConformingFloatDecodingStrategy
|
||||
}
|
||||
|
||||
private var options: Options
|
||||
|
||||
/// Creates a new JSValueDecoder with the provided decoding and formatting strategies
|
||||
/// - Parameters:
|
||||
/// - dateDecodingStrategy: Defaults to `DateDecodingStrategy.deferredToDate`
|
||||
/// - dataDecodingStrategy: Defaults to `DataDecodingStrategy.deferredToData`
|
||||
/// - nonConformingFloatDecodingStrategy: Defaults to ``NonConformingFloatDecodingStrategy/deferred``
|
||||
public init(
|
||||
dateDecodingStrategy: DateDecodingStrategy = .deferredToDate,
|
||||
dataDecodingStrategy: DataDecodingStrategy = .deferredToData,
|
||||
nonConformingFloatDecodingStrategy: NonConformingFloatDecodingStrategy = .deferred
|
||||
) {
|
||||
self.options = .init(dataStrategy: dataDecodingStrategy, dateStrategy: dateDecodingStrategy, nonConformingStrategy: nonConformingFloatDecodingStrategy)
|
||||
}
|
||||
|
||||
fileprivate init(options: Options) {
|
||||
self.options = options
|
||||
}
|
||||
|
||||
/// The strategy to use when decoding dates from a ``JSValue``
|
||||
public var dateDecodingStrategy: DateDecodingStrategy {
|
||||
get { options.dateStrategy }
|
||||
set { options.dateStrategy = newValue }
|
||||
}
|
||||
|
||||
/// The strategy to use when decoding raw data from a ``JSValue``
|
||||
public var dataDecodingStrategy: DataDecodingStrategy {
|
||||
get { options.dataStrategy }
|
||||
set { options.dataStrategy = newValue }
|
||||
}
|
||||
|
||||
/// The strategy used by a decoder when it encounters exceptional floating-point values
|
||||
public var nonConformingFloatDecodingStrategy: NonConformingFloatDecodingStrategy {
|
||||
get { options.nonConformingStrategy }
|
||||
set { options.nonConformingStrategy = newValue }
|
||||
}
|
||||
|
||||
/// Decodes a ``JSValue`` into the provided `Decodable` type
|
||||
/// - Parameters:
|
||||
/// - type: The type of the value to decode from the provided ``JSValue`` object
|
||||
/// - data: The ``JSValue`` to decode
|
||||
/// - Returns: A value of the specified type.
|
||||
///
|
||||
/// An error will be thrown from this method for two possible reasons:
|
||||
/// 1. A type mismatch was found.
|
||||
/// 2. A key was not found in the `data` field that is required in the `type` provided.
|
||||
public func decode<T>(_ type: T.Type, from data: JSValue) throws -> T where T: Decodable {
|
||||
let decoder = _JSValueDecoder(data: data, options: options)
|
||||
return try decoder.decodeData(as: T.self)
|
||||
}
|
||||
}
|
||||
|
||||
typealias CodingUserInfo = [CodingUserInfoKey: Any]
|
||||
private typealias Options = JSValueDecoder.Options
|
||||
|
||||
private final class _JSValueDecoder {
|
||||
var codingPath: [CodingKey] = []
|
||||
var userInfo: CodingUserInfo = [:]
|
||||
var options: Options
|
||||
fileprivate var data: JSValue
|
||||
|
||||
init(data: JSValue, options: Options) {
|
||||
self.data = data
|
||||
self.options = options
|
||||
}
|
||||
}
|
||||
|
||||
extension _JSValueDecoder: Decoder {
|
||||
func container<Key>(keyedBy type: Key.Type) throws -> KeyedDecodingContainer<Key> where Key: CodingKey {
|
||||
guard let data = data as? JSObject else {
|
||||
throw DecodingError.typeMismatch(JSObject.self, on: data, codingPath: codingPath)
|
||||
}
|
||||
|
||||
return KeyedDecodingContainer(
|
||||
KeyedContainer(
|
||||
data: data,
|
||||
codingPath: codingPath,
|
||||
userInfo: userInfo,
|
||||
options: options
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
func unkeyedContainer() throws -> UnkeyedDecodingContainer {
|
||||
guard let data = data as? JSArray else {
|
||||
throw DecodingError.typeMismatch(JSArray.self, on: data, codingPath: codingPath)
|
||||
}
|
||||
|
||||
return UnkeyedContainer(data: data, codingPath: codingPath, userInfo: userInfo, options: options)
|
||||
}
|
||||
|
||||
func singleValueContainer() throws -> SingleValueDecodingContainer {
|
||||
SingleValueContainer(data: data, codingPath: codingPath, userInfo: userInfo, options: options)
|
||||
}
|
||||
|
||||
// force casting is fine becasue we've already determined that T is the type in the case
|
||||
// the swift standard library also force casts in their similar functions
|
||||
// https://github.com/swiftlang/swift-foundation/blob/da80d51fa3e77f3e7ed57c4300a870689e755713/Sources/FoundationEssentials/JSON/JSONEncoder.swift#L1140
|
||||
// swiftlint:disable force_cast
|
||||
fileprivate func decodeData<T>(as type: T.Type) throws -> T where T: Decodable {
|
||||
switch type {
|
||||
case is Date.Type:
|
||||
return try decodeDate() as! T
|
||||
case is URL.Type:
|
||||
return try decodeUrl() as! T
|
||||
case is Data.Type:
|
||||
return try decodeData() as! T
|
||||
default:
|
||||
return try T(from: self)
|
||||
}
|
||||
}
|
||||
// swiftlint:enable force_cast
|
||||
|
||||
private func decodeDate() throws -> Date {
|
||||
switch options.dateStrategy {
|
||||
case .deferredToDate:
|
||||
return try Date(from: self)
|
||||
case .secondsSince1970:
|
||||
guard let value = data as? NSNumber else { throw DecodingError.dataCorrupted(data, target: Double.self, codingPath: codingPath) }
|
||||
return Date(timeIntervalSince1970: value.doubleValue)
|
||||
case .millisecondsSince1970:
|
||||
guard let value = data as? NSNumber else { throw DecodingError.dataCorrupted(data, target: Double.self, codingPath: codingPath) }
|
||||
return Date(timeIntervalSince1970: value.doubleValue / Double(MSEC_PER_SEC))
|
||||
case .iso8601:
|
||||
guard let value = data as? String else { throw DecodingError.dataCorrupted(data, target: String.self, codingPath: codingPath) }
|
||||
let formatter = ISO8601DateFormatter()
|
||||
guard let date = formatter.date(from: value) else { throw DecodingError.dataCorrupted(value, target: Date.self, codingPath: codingPath) }
|
||||
return date
|
||||
case .formatted(let formatter):
|
||||
guard let value = data as? String else { throw DecodingError.dataCorrupted(data, target: String.self, codingPath: codingPath) }
|
||||
guard let date = formatter.date(from: value) else { throw DecodingError.dataCorrupted(value, target: Date.self, codingPath: codingPath) }
|
||||
return date
|
||||
case .custom(let decode):
|
||||
return try decode(self)
|
||||
@unknown default:
|
||||
return try Date(from: self)
|
||||
}
|
||||
}
|
||||
|
||||
private func decodeUrl() throws -> URL {
|
||||
guard let str = data as? String,
|
||||
let url = URL(string: str)
|
||||
else { throw DecodingError.dataCorrupted(data, target: URL.self, codingPath: codingPath) }
|
||||
|
||||
return url
|
||||
}
|
||||
|
||||
private func decodeData() throws -> Data {
|
||||
switch options.dataStrategy {
|
||||
case .deferredToData:
|
||||
return try Data(from: self)
|
||||
case .base64:
|
||||
guard let value = data as? String else { throw DecodingError.dataCorrupted(data, target: String.self, codingPath: codingPath) }
|
||||
guard let data = Data(base64Encoded: value) else { throw DecodingError.dataCorrupted(value, target: Data.self, codingPath: codingPath) }
|
||||
return data
|
||||
case .custom(let decode):
|
||||
return try decode(self)
|
||||
@unknown default:
|
||||
return try Data(from: self)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private final class KeyedContainer<Key> where Key: CodingKey {
|
||||
var data: JSObject
|
||||
var codingPath: [CodingKey]
|
||||
var userInfo: CodingUserInfo
|
||||
var allKeys: [Key]
|
||||
var options: Options
|
||||
|
||||
init(data: JSObject, codingPath: [CodingKey], userInfo: CodingUserInfo, options: Options) {
|
||||
self.data = data
|
||||
self.codingPath = codingPath
|
||||
self.userInfo = userInfo
|
||||
self.allKeys = data.keys.compactMap(Key.init(stringValue:))
|
||||
self.options = options
|
||||
}
|
||||
}
|
||||
|
||||
extension KeyedContainer: KeyedDecodingContainerProtocol {
|
||||
func contains(_ key: Key) -> Bool {
|
||||
allKeys.contains { $0.stringValue == key.stringValue }
|
||||
}
|
||||
|
||||
func decodeNil(forKey key: Key) throws -> Bool {
|
||||
data[key.stringValue] == nil || data[key.stringValue] is NSNull
|
||||
}
|
||||
|
||||
func decode<T>(_ type: T.Type, forKey key: Key) throws -> T where T: Decodable {
|
||||
guard let rawValue = data[key.stringValue] else {
|
||||
throw DecodingError.keyNotFound(key, on: data, codingPath: codingPath)
|
||||
}
|
||||
|
||||
var newPath = codingPath
|
||||
newPath.append(key)
|
||||
let decoder = _JSValueDecoder(data: rawValue, options: options)
|
||||
return try decoder.decodeData(as: T.self)
|
||||
}
|
||||
|
||||
func nestedUnkeyedContainer(forKey key: Key) throws -> UnkeyedDecodingContainer {
|
||||
var newPath = codingPath
|
||||
newPath.append(key)
|
||||
guard let data = data[key.stringValue] as? JSArray else {
|
||||
throw DecodingError.typeMismatch(
|
||||
JSArray.self,
|
||||
on: data[key.stringValue] ?? "null value",
|
||||
codingPath: newPath
|
||||
)
|
||||
}
|
||||
|
||||
return UnkeyedContainer(data: data, codingPath: newPath, userInfo: userInfo, options: options)
|
||||
}
|
||||
|
||||
func nestedContainer<NestedKey>(keyedBy type: NestedKey.Type, forKey key: Key) throws -> KeyedDecodingContainer<NestedKey> where NestedKey: CodingKey {
|
||||
var newPath = codingPath
|
||||
newPath.append(key)
|
||||
guard let data = data[key.stringValue] as? JSObject else {
|
||||
throw DecodingError.typeMismatch(
|
||||
JSObject.self,
|
||||
on: data[key.stringValue] ?? "null value",
|
||||
codingPath: newPath
|
||||
)
|
||||
}
|
||||
|
||||
return KeyedDecodingContainer(KeyedContainer<NestedKey>(data: data, codingPath: newPath, userInfo: userInfo, options: options))
|
||||
}
|
||||
|
||||
enum SuperKey: String, CodingKey { case `super` }
|
||||
|
||||
func superDecoder() throws -> Decoder {
|
||||
var newPath = codingPath
|
||||
newPath.append(SuperKey.super)
|
||||
guard let data = data[SuperKey.super.stringValue] else {
|
||||
throw DecodingError.keyNotFound(SuperKey.super, on: data, codingPath: newPath)
|
||||
}
|
||||
|
||||
return _JSValueDecoder(data: data, options: options)
|
||||
}
|
||||
|
||||
func superDecoder(forKey key: Key) throws -> Decoder {
|
||||
var newPath = codingPath
|
||||
newPath.append(key)
|
||||
guard let data = data[key.stringValue] else {
|
||||
throw DecodingError.keyNotFound(key, on: data, codingPath: newPath)
|
||||
}
|
||||
|
||||
return _JSValueDecoder(data: data, options: options)
|
||||
}
|
||||
}
|
||||
|
||||
private final class UnkeyedContainer {
|
||||
var data: JSArray
|
||||
var codingPath: [CodingKey]
|
||||
var userInfo: CodingUserInfo
|
||||
private(set) var currentIndex = 0
|
||||
var options: Options
|
||||
|
||||
init(data: JSArray, codingPath: [CodingKey], userInfo: CodingUserInfo, options: Options) {
|
||||
self.data = data
|
||||
self.codingPath = codingPath
|
||||
self.userInfo = userInfo
|
||||
self.options = options
|
||||
}
|
||||
}
|
||||
|
||||
extension UnkeyedContainer: UnkeyedDecodingContainer {
|
||||
var count: Int? {
|
||||
data.count
|
||||
}
|
||||
|
||||
var isAtEnd: Bool {
|
||||
currentIndex == data.endIndex
|
||||
}
|
||||
|
||||
func decodeNil() throws -> Bool {
|
||||
defer { currentIndex += 1 }
|
||||
return data[currentIndex] is NSNull
|
||||
}
|
||||
|
||||
func decode<T>(_ type: T.Type) throws -> T where T: Decodable {
|
||||
defer { currentIndex += 1 }
|
||||
let decoder = _JSValueDecoder(data: data[currentIndex], options: options)
|
||||
return try decoder.decodeData(as: T.self)
|
||||
}
|
||||
|
||||
func nestedUnkeyedContainer() throws -> UnkeyedDecodingContainer {
|
||||
defer { currentIndex += 1 }
|
||||
guard let data = data[currentIndex] as? JSArray else {
|
||||
throw DecodingError.typeMismatch(JSArray.self, on: data[currentIndex], codingPath: codingPath)
|
||||
}
|
||||
|
||||
return UnkeyedContainer(data: data, codingPath: codingPath, userInfo: userInfo, options: options)
|
||||
}
|
||||
|
||||
func nestedContainer<NestedKey>(keyedBy type: NestedKey.Type) throws -> KeyedDecodingContainer<NestedKey> where NestedKey: CodingKey {
|
||||
defer { currentIndex += 1 }
|
||||
guard let data = data[currentIndex] as? JSObject else {
|
||||
throw DecodingError.typeMismatch(JSObject.self, on: data[currentIndex], codingPath: codingPath)
|
||||
}
|
||||
|
||||
return KeyedDecodingContainer(KeyedContainer(data: data, codingPath: codingPath, userInfo: userInfo, options: options))
|
||||
}
|
||||
|
||||
func superDecoder() throws -> Decoder {
|
||||
defer { currentIndex += 1 }
|
||||
let data = data[currentIndex]
|
||||
return _JSValueDecoder(data: data, options: options)
|
||||
}
|
||||
}
|
||||
|
||||
private final class SingleValueContainer {
|
||||
var data: JSValue
|
||||
var codingPath: [CodingKey]
|
||||
var userInfo: CodingUserInfo
|
||||
var options: Options
|
||||
|
||||
init(data: JSValue, codingPath: [CodingKey], userInfo: CodingUserInfo, options: Options) {
|
||||
self.data = data
|
||||
self.codingPath = codingPath
|
||||
self.userInfo = userInfo
|
||||
self.options = options
|
||||
}
|
||||
}
|
||||
|
||||
extension SingleValueContainer: SingleValueDecodingContainer {
|
||||
func decodeNil() -> Bool {
|
||||
return data is NSNull
|
||||
}
|
||||
|
||||
private func cast<T>(to type: T.Type) throws -> T {
|
||||
guard let data = data as? T else {
|
||||
throw DecodingError.typeMismatch(type, on: data, codingPath: codingPath)
|
||||
}
|
||||
|
||||
return data
|
||||
}
|
||||
|
||||
private func castFloat<N>(to type: N.Type) throws -> N where N: FloatingPoint {
|
||||
if let data = data as? String,
|
||||
case let .convertFromString(positiveInfinity: pos, negativeInfinity: neg, nan: nan) = options.nonConformingStrategy {
|
||||
switch data {
|
||||
case pos:
|
||||
return N.infinity
|
||||
case neg:
|
||||
return -N.infinity
|
||||
case nan:
|
||||
return N.nan
|
||||
default:
|
||||
throw DecodingError.typeMismatch(type, on: data, codingPath: codingPath)
|
||||
}
|
||||
}
|
||||
|
||||
let data = try cast(to: N.self)
|
||||
if !data.isFinite, case .throw = options.nonConformingStrategy {
|
||||
throw DecodingError.dataCorrupted(.init(codingPath: codingPath, debugDescription: "\(data) is a non-conforming floating point number"))
|
||||
}
|
||||
return data
|
||||
}
|
||||
|
||||
func decode(_ type: Bool.Type) throws -> Bool {
|
||||
try cast(to: type)
|
||||
}
|
||||
|
||||
func decode(_ type: String.Type) throws -> String {
|
||||
try cast(to: type)
|
||||
}
|
||||
|
||||
func decode(_ type: Double.Type) throws -> Double {
|
||||
try castFloat(to: type)
|
||||
}
|
||||
|
||||
func decode(_ type: Float.Type) throws -> Float {
|
||||
try castFloat(to: type)
|
||||
}
|
||||
|
||||
func decode(_ type: Int.Type) throws -> Int {
|
||||
try cast(to: type)
|
||||
}
|
||||
|
||||
func decode(_ type: Int8.Type) throws -> Int8 {
|
||||
try cast(to: type)
|
||||
}
|
||||
|
||||
func decode(_ type: Int16.Type) throws -> Int16 {
|
||||
try cast(to: type)
|
||||
}
|
||||
|
||||
func decode(_ type: Int32.Type) throws -> Int32 {
|
||||
try cast(to: type)
|
||||
}
|
||||
|
||||
func decode(_ type: Int64.Type) throws -> Int64 {
|
||||
try cast(to: type)
|
||||
}
|
||||
|
||||
func decode(_ type: UInt.Type) throws -> UInt {
|
||||
try cast(to: type)
|
||||
}
|
||||
|
||||
func decode(_ type: UInt8.Type) throws -> UInt8 {
|
||||
try cast(to: type)
|
||||
}
|
||||
|
||||
func decode(_ type: UInt16.Type) throws -> UInt16 {
|
||||
try cast(to: type)
|
||||
}
|
||||
|
||||
func decode(_ type: UInt32.Type) throws -> UInt32 {
|
||||
try cast(to: type)
|
||||
}
|
||||
|
||||
func decode(_ type: UInt64.Type) throws -> UInt64 {
|
||||
try cast(to: type)
|
||||
}
|
||||
|
||||
func decode<T>(_ type: T.Type) throws -> T where T: Decodable {
|
||||
let decoder = _JSValueDecoder(data: data, options: options)
|
||||
return try decoder.decodeData(as: T.self)
|
||||
}
|
||||
}
|
||||
|
||||
extension DecodingError {
|
||||
static func typeMismatch(_ type: Any.Type, on data: any JSValue, codingPath: [CodingKey]) -> DecodingError {
|
||||
return .typeMismatch(
|
||||
type,
|
||||
.init(
|
||||
codingPath: codingPath,
|
||||
debugDescription: "\(data) was unable to be cast to \(type)."
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
static func keyNotFound(_ key: any CodingKey, on data: any JSValue, codingPath: [CodingKey]) -> DecodingError {
|
||||
return .keyNotFound(
|
||||
key,
|
||||
.init(
|
||||
codingPath: codingPath,
|
||||
debugDescription: "Key \(key.stringValue) not found in \(data)")
|
||||
)
|
||||
}
|
||||
|
||||
static func dataCorrupted<T>(_ value: any JSValue, target type: T.Type, codingPath: [CodingKey]) -> DecodingError where T: Decodable {
|
||||
return .dataCorrupted(.init(codingPath: codingPath, debugDescription: "\(value) was not in the format expected for \(T.self)"))
|
||||
}
|
||||
}
|
||||
671
node_modules/@capacitor/ios/Capacitor/Capacitor/Codable/JSValueEncoder.swift
generated
vendored
Normal file
671
node_modules/@capacitor/ios/Capacitor/Capacitor/Codable/JSValueEncoder.swift
generated
vendored
Normal file
@@ -0,0 +1,671 @@
|
||||
//
|
||||
// JSValueEncoder.swift
|
||||
// Capacitor
|
||||
//
|
||||
// Created by Steven Sherry on 12/8/23.
|
||||
// Copyright © 2023 Drifty Co. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import Combine
|
||||
|
||||
/// An encoder than can encode ``JSValue`` objects from `Encodable` types
|
||||
public final class JSValueEncoder: TopLevelEncoder {
|
||||
/// The strategy to use when encoding `nil` values
|
||||
public enum OptionalEncodingStrategy {
|
||||
/// Encode `nil` values as `NSNull`
|
||||
case explicitNulls
|
||||
/// Excludes the value from the encoded object altogether
|
||||
case undefined
|
||||
}
|
||||
|
||||
/// The strategies available for encoding .nan, .infinity, and -.infinity
|
||||
public enum NonConformingFloatEncodingStrategy: Equatable {
|
||||
/// Throws an error when encountering an exceptional floating-point value
|
||||
case `throw`
|
||||
/// Converts to the provided strings
|
||||
case convertToString(positiveInfinity: String, negativeInfinity: String, nan: String)
|
||||
/// Encodes directly into an NSNumber
|
||||
case deferred
|
||||
}
|
||||
|
||||
/// The strategy to use when encoding `Date` values
|
||||
public typealias DateEncodingStrategy = JSONEncoder.DateEncodingStrategy
|
||||
|
||||
/// The strategy to use when encoding `Data` values
|
||||
public typealias DataEncodingStrategy = JSONEncoder.DataEncodingStrategy
|
||||
|
||||
fileprivate struct Options {
|
||||
var optionalStrategy: OptionalEncodingStrategy
|
||||
var dateStrategy: DateEncodingStrategy
|
||||
var dataStrategy: DataEncodingStrategy
|
||||
var nonConformingFloatStrategy: NonConformingFloatEncodingStrategy
|
||||
}
|
||||
|
||||
private var options: Options
|
||||
|
||||
/// The strategy to use when encoding `nil` values
|
||||
public var optionalEncodingStrategy: OptionalEncodingStrategy {
|
||||
get { options.optionalStrategy }
|
||||
set { options.optionalStrategy = newValue }
|
||||
}
|
||||
|
||||
/// The strategy to use when encoding dates
|
||||
public var dateEncodingStrategy: DateEncodingStrategy {
|
||||
get { options.dateStrategy }
|
||||
set { options.dateStrategy = newValue }
|
||||
}
|
||||
|
||||
/// The encoding strategy to use when encoding raw data
|
||||
public var dataEncodingStrategy: DataEncodingStrategy {
|
||||
get { options.dataStrategy }
|
||||
set { options.dataStrategy = newValue }
|
||||
}
|
||||
|
||||
/// The encoding strategy to use when the encoder encounters exceptional floating-point values
|
||||
public var nonConformingFloatEncodingStrategy: NonConformingFloatEncodingStrategy {
|
||||
get { options.nonConformingFloatStrategy }
|
||||
set { options.nonConformingFloatStrategy = newValue }
|
||||
}
|
||||
|
||||
/// Creates a new `JSValueEncoder`
|
||||
/// - Parameter optionalEncodingStrategy: The strategy to use when encoding `nil` values. Defaults to ``OptionalEncodingStrategy-swift.enum/undefined``
|
||||
/// - Parameter dateEncodingStrategy: Defaults to `DateEncodingStrategy.deferredToDate`
|
||||
/// - Parameter dataEncodingStrategy: Defaults to `DataEncodingStrategy.deferredToData`
|
||||
/// - Parameter nonConformingFloatEncodingStategy: Defaults to ``NonConformingFloatEncodingStrategy-swift.enum/deferred``
|
||||
public init(
|
||||
optionalEncodingStrategy: OptionalEncodingStrategy = .undefined,
|
||||
dateEncodingStrategy: DateEncodingStrategy = .deferredToDate,
|
||||
dataEncodingStrategy: DataEncodingStrategy = .deferredToData,
|
||||
nonConformingFloatEncodingStategy: NonConformingFloatEncodingStrategy = .deferred
|
||||
) {
|
||||
self.options = .init(
|
||||
optionalStrategy: optionalEncodingStrategy,
|
||||
dateStrategy: dateEncodingStrategy,
|
||||
dataStrategy: dataEncodingStrategy,
|
||||
nonConformingFloatStrategy: nonConformingFloatEncodingStategy
|
||||
)
|
||||
}
|
||||
|
||||
/// Encodes an `Encodable` value to a ``JSValue``
|
||||
/// - Parameter value: The value to encode to ``JSValue``
|
||||
/// - Returns: The encoded ``JSValue``
|
||||
/// - Throws: An error if the value could not be encoded as a ``JSValue``
|
||||
public func encode<T>(_ value: T) throws -> JSValue where T: Encodable {
|
||||
let encoder = _JSValueEncoder(options: options)
|
||||
try encoder.encodeGeneric(value)
|
||||
guard let value = encoder.data else {
|
||||
throw EncodingError.invalidValue(
|
||||
value,
|
||||
.init(
|
||||
codingPath: encoder.codingPath,
|
||||
debugDescription: "\(value) was unable to be encoded as a JSValue"
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
return value
|
||||
}
|
||||
|
||||
/// Encodes an `Encodable` value to a ``JSObject``
|
||||
/// - Parameter value: The value to encode to a ``JSObject``
|
||||
/// - Returns: The encoded ``JSObject``
|
||||
/// - Throws: An error if the value could not be encoded as a ``JSObject``
|
||||
///
|
||||
/// This method is a convenience method for encoding an `Encodable` value to a ``JSObject``.
|
||||
/// It is equivalent to calling ``encode(_:)`` and casting the result to a ``JSObject`` and
|
||||
/// throwing an error if the cast fails.
|
||||
public func encodeJSObject<T>(_ value: T) throws -> JSObject where T: Encodable {
|
||||
guard let object = try encode(value) as? JSObject else {
|
||||
throw EncodingError.invalidValue(
|
||||
value,
|
||||
.init(
|
||||
codingPath: [],
|
||||
debugDescription: "\(value) was unable to be encoded as a JSObject"
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
return object
|
||||
}
|
||||
}
|
||||
|
||||
private protocol JSValueEncodingContainer {
|
||||
var data: JSValue? { get }
|
||||
}
|
||||
|
||||
private enum EncodingContainer: JSValueEncodingContainer {
|
||||
case singleValue(SingleValueContainer)
|
||||
case unkeyed(UnkeyedContainer)
|
||||
case keyed(AnyKeyedContainer)
|
||||
|
||||
var data: JSValue? {
|
||||
switch self {
|
||||
case let .singleValue(container):
|
||||
return container.data
|
||||
case let .unkeyed(container):
|
||||
return container.data
|
||||
case let .keyed(container):
|
||||
return container.data
|
||||
}
|
||||
}
|
||||
|
||||
var type: String {
|
||||
switch self {
|
||||
case .singleValue:
|
||||
"SingleValueContainer"
|
||||
case .unkeyed:
|
||||
"UnkeyedContainer"
|
||||
case .keyed:
|
||||
"KeyedContainer"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private typealias Options = JSValueEncoder.Options
|
||||
|
||||
private final class _JSValueEncoder: JSValueEncodingContainer {
|
||||
var codingPath: [CodingKey] = []
|
||||
var data: JSValue? {
|
||||
containers.data
|
||||
}
|
||||
|
||||
var options: Options
|
||||
|
||||
var userInfo: CodingUserInfo = [:]
|
||||
fileprivate var containers: [EncodingContainer] = []
|
||||
|
||||
init(options: Options) {
|
||||
self.options = options
|
||||
}
|
||||
}
|
||||
|
||||
extension Array: JSValueEncodingContainer where Element == EncodingContainer {
|
||||
var data: JSValue? {
|
||||
guard count != 0 else { return nil }
|
||||
guard count != 1 else { return self[0].data }
|
||||
var data: (any JSValue)?
|
||||
|
||||
for container in self {
|
||||
if data == nil {
|
||||
data = container.data
|
||||
} else {
|
||||
// The top-level container is
|
||||
switch container {
|
||||
case let .keyed(container):
|
||||
guard let obj = data as? JSObject else { break }
|
||||
data = obj.merging(container.object() ?? [:]) { $1 }
|
||||
case let .unkeyed(container):
|
||||
guard var copy = data as? JSArray else { break }
|
||||
copy.append(contentsOf: container.array ?? [])
|
||||
data = copy
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return data
|
||||
}
|
||||
}
|
||||
|
||||
private enum EncodedValue {
|
||||
case value(any JSValue)
|
||||
case nestedContainer(any JSValueEncodingContainer)
|
||||
}
|
||||
|
||||
extension _JSValueEncoder: Encoder {
|
||||
func addContainer(_ container: EncodingContainer) {
|
||||
guard !containers.isEmpty else {
|
||||
containers.append(container)
|
||||
return
|
||||
}
|
||||
|
||||
for existingContainer in containers {
|
||||
switch (existingContainer, container) {
|
||||
case (.unkeyed, .unkeyed), (.keyed, .keyed):
|
||||
containers.append(container)
|
||||
default:
|
||||
preconditionFailure("Sibling top-level containers must be of the same type. Attempted to add a \(container)")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func container<Key>(keyedBy type: Key.Type) -> KeyedEncodingContainer<Key> where Key: CodingKey {
|
||||
let container = KeyedContainer<Key>(
|
||||
codingPath: codingPath,
|
||||
userInfo: userInfo,
|
||||
options: options
|
||||
)
|
||||
addContainer(.keyed(.init(container)))
|
||||
return KeyedEncodingContainer(container)
|
||||
}
|
||||
|
||||
func unkeyedContainer() -> UnkeyedEncodingContainer {
|
||||
let container = UnkeyedContainer(
|
||||
codingPath: codingPath,
|
||||
userInfo: userInfo,
|
||||
options: options
|
||||
)
|
||||
addContainer(.unkeyed(container))
|
||||
return container
|
||||
}
|
||||
|
||||
func singleValueContainer() -> SingleValueEncodingContainer {
|
||||
let container = SingleValueContainer(
|
||||
codingPath: codingPath,
|
||||
userInfo: userInfo,
|
||||
options: options
|
||||
)
|
||||
addContainer(.singleValue(container))
|
||||
return container
|
||||
}
|
||||
|
||||
fileprivate func encodeGeneric<T>(_ value: T) throws where T: Encodable {
|
||||
switch value {
|
||||
case let value as Date:
|
||||
switch options.dateStrategy {
|
||||
case .deferredToDate:
|
||||
try value.encode(to: self)
|
||||
case .millisecondsSince1970:
|
||||
try (value.timeIntervalSince1970 * Double(MSEC_PER_SEC)).encode(to: self)
|
||||
case .secondsSince1970:
|
||||
try value.timeIntervalSince1970.encode(to: self)
|
||||
case .iso8601:
|
||||
let formattedDate = ISO8601DateFormatter().string(from: value)
|
||||
try formattedDate.encode(to: self)
|
||||
case .formatted(let formatter):
|
||||
let formattedDate = formatter.string(from: value)
|
||||
try formattedDate.encode(to: self)
|
||||
case .custom(let encode):
|
||||
try encode(value, self)
|
||||
@unknown default:
|
||||
try value.encode(to: self)
|
||||
}
|
||||
case let value as URL:
|
||||
try value.absoluteString.encode(to: self)
|
||||
case let value as Data:
|
||||
switch options.dataStrategy {
|
||||
case .deferredToData:
|
||||
try value.encode(to: self)
|
||||
case .base64:
|
||||
try value.base64EncodedString().encode(to: self)
|
||||
case .custom(let encode):
|
||||
try encode(value, self)
|
||||
@unknown default:
|
||||
try value.encode(to: self)
|
||||
}
|
||||
default:
|
||||
try value.encode(to: self)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private final class KeyedContainer<Key> where Key: CodingKey {
|
||||
var object: JSObject? {
|
||||
encodedKeyedValue?.reduce(into: [:]) { obj, next in
|
||||
let (key, value) = next
|
||||
switch value {
|
||||
case .value(let value):
|
||||
obj[key] = value
|
||||
case .nestedContainer(let container):
|
||||
obj[key] = container.data
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var codingPath: [CodingKey]
|
||||
var userInfo: CodingUserInfo
|
||||
var options: Options
|
||||
private var encodedKeyedValue: [String: EncodedValue]?
|
||||
|
||||
init(codingPath: [CodingKey], userInfo: CodingUserInfo, options: Options) {
|
||||
self.codingPath = codingPath
|
||||
self.userInfo = userInfo
|
||||
self.options = options
|
||||
}
|
||||
}
|
||||
|
||||
extension KeyedContainer: KeyedEncodingContainerProtocol {
|
||||
func insert(_ value: JSValue, for key: Key) {
|
||||
insert(.value(value), for: key)
|
||||
}
|
||||
|
||||
func insert<K: CodingKey>(_ encodedValue: EncodedValue, for key: K) {
|
||||
if encodedKeyedValue == nil {
|
||||
encodedKeyedValue = [key.stringValue: encodedValue]
|
||||
} else {
|
||||
encodedKeyedValue![key.stringValue] = encodedValue
|
||||
}
|
||||
}
|
||||
|
||||
func encodeNil(forKey key: Key) throws {
|
||||
insert(NSNull(), for: key)
|
||||
}
|
||||
|
||||
func encode<T>(_ value: T, forKey key: Key) throws where T: Encodable {
|
||||
let encoder = _JSValueEncoder(options: options)
|
||||
try encoder.encodeGeneric(value)
|
||||
insert(.nestedContainer(encoder), for: key)
|
||||
}
|
||||
|
||||
// This is a perectly valid name for this method. The underscore is to avoid a conflict with the
|
||||
// protocol requirement.
|
||||
// swiftlint:disable:next identifier_name
|
||||
func _encodeIfPresent<T>(_ value: T?, forKey key: Key) throws where T: Encodable {
|
||||
switch options.optionalStrategy {
|
||||
case .explicitNulls:
|
||||
if let value = value {
|
||||
try encode(value, forKey: key)
|
||||
} else {
|
||||
try encodeNil(forKey: key)
|
||||
}
|
||||
case .undefined:
|
||||
guard let value = value else { return }
|
||||
try encode(value, forKey: key)
|
||||
}
|
||||
}
|
||||
|
||||
func encodeIfPresent<T>(_ value: T?, forKey key: Key) throws where T: Encodable {
|
||||
try _encodeIfPresent(value, forKey: key)
|
||||
}
|
||||
|
||||
func encodeIfPresent(_ value: Bool?, forKey key: Key) throws {
|
||||
try _encodeIfPresent(value, forKey: key)
|
||||
}
|
||||
|
||||
func encodeIfPresent(_ value: String?, forKey key: Key) throws {
|
||||
try _encodeIfPresent(value, forKey: key)
|
||||
}
|
||||
|
||||
func encodeIfPresent(_ value: Double?, forKey key: Key) throws {
|
||||
try _encodeIfPresent(value, forKey: key)
|
||||
}
|
||||
|
||||
func encodeIfPresent(_ value: Float?, forKey key: Key) throws {
|
||||
try _encodeIfPresent(value, forKey: key)
|
||||
}
|
||||
|
||||
func encodeIfPresent(_ value: Int?, forKey key: Key) throws {
|
||||
try _encodeIfPresent(value, forKey: key)
|
||||
}
|
||||
|
||||
func encodeIfPresent(_ value: Int8?, forKey key: Key) throws {
|
||||
try _encodeIfPresent(value, forKey: key)
|
||||
}
|
||||
|
||||
func encodeIfPresent(_ value: Int16?, forKey key: Key) throws {
|
||||
try _encodeIfPresent(value, forKey: key)
|
||||
}
|
||||
|
||||
func encodeIfPresent(_ value: Int32?, forKey key: Key) throws {
|
||||
try _encodeIfPresent(value, forKey: key)
|
||||
}
|
||||
|
||||
func encodeIfPresent(_ value: Int64?, forKey key: Key) throws {
|
||||
try _encodeIfPresent(value, forKey: key)
|
||||
}
|
||||
|
||||
func encodeIfPresent(_ value: UInt?, forKey key: Key) throws {
|
||||
try _encodeIfPresent(value, forKey: key)
|
||||
}
|
||||
|
||||
func encodeIfPresent(_ value: UInt8?, forKey key: Key) throws {
|
||||
try _encodeIfPresent(value, forKey: key)
|
||||
}
|
||||
|
||||
func encodeIfPresent(_ value: UInt16?, forKey key: Key) throws {
|
||||
try _encodeIfPresent(value, forKey: key)
|
||||
}
|
||||
|
||||
func encodeIfPresent(_ value: UInt32?, forKey key: Key) throws {
|
||||
try _encodeIfPresent(value, forKey: key)
|
||||
}
|
||||
|
||||
func encodeIfPresent(_ value: UInt64?, forKey key: Key) throws {
|
||||
try _encodeIfPresent(value, forKey: key)
|
||||
}
|
||||
|
||||
func nestedContainer<NestedKey>(keyedBy keyType: NestedKey.Type, forKey key: Key) -> KeyedEncodingContainer<NestedKey> where NestedKey: CodingKey {
|
||||
var newPath = codingPath
|
||||
newPath.append(key)
|
||||
|
||||
let nestedContainer = KeyedContainer<NestedKey>(
|
||||
codingPath: newPath,
|
||||
userInfo: userInfo,
|
||||
options: options
|
||||
)
|
||||
|
||||
insert(.nestedContainer(nestedContainer), for: key)
|
||||
return KeyedEncodingContainer(nestedContainer)
|
||||
}
|
||||
|
||||
func nestedUnkeyedContainer(forKey key: Key) -> UnkeyedEncodingContainer {
|
||||
var newPath = codingPath
|
||||
newPath.append(key)
|
||||
let nestedContainer = UnkeyedContainer(
|
||||
codingPath: codingPath,
|
||||
userInfo: userInfo,
|
||||
options: options
|
||||
)
|
||||
insert(.nestedContainer(nestedContainer), for: key)
|
||||
return nestedContainer
|
||||
}
|
||||
|
||||
enum SuperKey: String, CodingKey {
|
||||
case `super`
|
||||
}
|
||||
|
||||
func superEncoder() -> Encoder {
|
||||
let encoder = _JSValueEncoder(options: options)
|
||||
insert(.nestedContainer(encoder), for: SuperKey.super)
|
||||
return encoder
|
||||
}
|
||||
|
||||
func superEncoder(forKey key: Key) -> Encoder {
|
||||
let encoder = _JSValueEncoder(options: options)
|
||||
insert(.nestedContainer(encoder), for: key)
|
||||
return encoder
|
||||
}
|
||||
}
|
||||
|
||||
private class AnyKeyedContainer: JSValueEncodingContainer {
|
||||
var data: JSValue? { object() }
|
||||
var object: () -> JSObject?
|
||||
|
||||
init<Key>(_ keyedContainer: KeyedContainer<Key>) where Key: CodingKey {
|
||||
object = { keyedContainer.object }
|
||||
}
|
||||
}
|
||||
|
||||
extension KeyedContainer: JSValueEncodingContainer {
|
||||
var data: JSValue? { object }
|
||||
}
|
||||
|
||||
private final class UnkeyedContainer {
|
||||
var array: JSArray? {
|
||||
encodedUnkeyedValue?.reduce(into: []) { arr, next in
|
||||
switch next {
|
||||
case .value(let value):
|
||||
arr.append(value)
|
||||
case .nestedContainer(let container):
|
||||
guard let data = container.data else { return }
|
||||
arr.append(data)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var codingPath: [CodingKey]
|
||||
var userInfo: CodingUserInfo
|
||||
var options: Options
|
||||
private var encodedUnkeyedValue: [EncodedValue]?
|
||||
|
||||
init(codingPath: [CodingKey], userInfo: CodingUserInfo, options: Options) {
|
||||
self.codingPath = codingPath
|
||||
self.userInfo = userInfo
|
||||
self.options = options
|
||||
}
|
||||
}
|
||||
|
||||
extension UnkeyedContainer: UnkeyedEncodingContainer {
|
||||
private func append(_ value: any JSValue) {
|
||||
append(.value(value))
|
||||
}
|
||||
|
||||
private func append(_ value: EncodedValue) {
|
||||
if encodedUnkeyedValue == nil {
|
||||
encodedUnkeyedValue = [value]
|
||||
} else {
|
||||
encodedUnkeyedValue!.append(value)
|
||||
}
|
||||
}
|
||||
|
||||
var count: Int {
|
||||
array?.count ?? 0
|
||||
}
|
||||
|
||||
func encodeNil() throws {
|
||||
append(NSNull())
|
||||
}
|
||||
|
||||
func encode<T>(_ value: T) throws where T: Encodable {
|
||||
let encoder = _JSValueEncoder(options: options)
|
||||
try encoder.encodeGeneric(value)
|
||||
append(.nestedContainer(encoder))
|
||||
}
|
||||
|
||||
func nestedUnkeyedContainer() -> UnkeyedEncodingContainer {
|
||||
let nestedContainer = UnkeyedContainer(
|
||||
codingPath: codingPath,
|
||||
userInfo: userInfo,
|
||||
options: options
|
||||
)
|
||||
append(.nestedContainer(nestedContainer))
|
||||
return nestedContainer
|
||||
}
|
||||
|
||||
func nestedContainer<NestedKey>(keyedBy keyType: NestedKey.Type) -> KeyedEncodingContainer<NestedKey> where NestedKey: CodingKey {
|
||||
let nestedContainer = KeyedContainer<NestedKey>(
|
||||
codingPath: codingPath,
|
||||
userInfo: userInfo,
|
||||
options: options
|
||||
)
|
||||
append(.nestedContainer(nestedContainer))
|
||||
return KeyedEncodingContainer(nestedContainer)
|
||||
}
|
||||
|
||||
func superEncoder() -> Encoder {
|
||||
let encoder = _JSValueEncoder(options: options)
|
||||
append(.nestedContainer(encoder))
|
||||
return encoder
|
||||
}
|
||||
}
|
||||
|
||||
extension UnkeyedContainer: JSValueEncodingContainer {
|
||||
var data: JSValue? { array }
|
||||
}
|
||||
|
||||
private final class SingleValueContainer {
|
||||
var data: JSValue?
|
||||
var codingPath: [CodingKey]
|
||||
var userInfo: CodingUserInfo
|
||||
var options: Options
|
||||
|
||||
init(codingPath: [CodingKey], userInfo: CodingUserInfo, options: Options) {
|
||||
self.codingPath = codingPath
|
||||
self.userInfo = userInfo
|
||||
self.options = options
|
||||
}
|
||||
}
|
||||
|
||||
extension SingleValueContainer: SingleValueEncodingContainer {
|
||||
func encodeNil() throws {
|
||||
data = NSNull()
|
||||
}
|
||||
|
||||
func encode(_ value: Bool) throws {
|
||||
data = value
|
||||
}
|
||||
|
||||
func encode(_ value: String) throws {
|
||||
data = value
|
||||
}
|
||||
|
||||
func encode(_ value: Double) throws {
|
||||
try encodeFloat(value)
|
||||
}
|
||||
|
||||
// swiftlint:disable force_cast
|
||||
private func encodeFloat<N>(_ value: N) throws where N: FloatingPoint {
|
||||
if value.isFinite {
|
||||
data = value as! NSNumber
|
||||
} else {
|
||||
switch options.nonConformingFloatStrategy {
|
||||
case .deferred:
|
||||
data = value as! NSNumber
|
||||
case let .convertToString(positiveInfinity: pos, negativeInfinity: neg, nan: nan):
|
||||
if value == .infinity { data = pos }
|
||||
if value == -.infinity { data = neg }
|
||||
if value.isNaN { data = nan }
|
||||
case .throw:
|
||||
throw EncodingError.invalidValue(
|
||||
value,
|
||||
.init(codingPath: codingPath, debugDescription: "Unable to encode \(value) to JSValue")
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
// swiftlint:enable force_cast
|
||||
|
||||
func encode(_ value: Float) throws {
|
||||
try encodeFloat(value)
|
||||
}
|
||||
|
||||
func encode(_ value: Int) throws {
|
||||
data = value as NSNumber
|
||||
}
|
||||
|
||||
func encode(_ value: Int8) throws {
|
||||
data = value as NSNumber
|
||||
}
|
||||
|
||||
func encode(_ value: Int16) throws {
|
||||
data = value as NSNumber
|
||||
}
|
||||
|
||||
func encode(_ value: Int32) throws {
|
||||
data = value as NSNumber
|
||||
}
|
||||
|
||||
func encode(_ value: Int64) throws {
|
||||
data = value as NSNumber
|
||||
}
|
||||
|
||||
func encode(_ value: UInt) throws {
|
||||
data = value as NSNumber
|
||||
}
|
||||
|
||||
func encode(_ value: UInt8) throws {
|
||||
data = value as NSNumber
|
||||
}
|
||||
|
||||
func encode(_ value: UInt16) throws {
|
||||
data = value as NSNumber
|
||||
}
|
||||
|
||||
func encode(_ value: UInt32) throws {
|
||||
data = value as NSNumber
|
||||
}
|
||||
|
||||
func encode(_ value: UInt64) throws {
|
||||
data = value as NSNumber
|
||||
}
|
||||
|
||||
func encode<T>(_ value: T) throws where T: Encodable {
|
||||
let encoder = _JSValueEncoder(options: options)
|
||||
try encoder.encodeGeneric(value)
|
||||
data = encoder.data
|
||||
}
|
||||
}
|
||||
|
||||
extension SingleValueContainer: JSValueEncodingContainer {}
|
||||
22
node_modules/@capacitor/ios/Capacitor/Capacitor/Data+Capacitor.swift
generated
vendored
Normal file
22
node_modules/@capacitor/ios/Capacitor/Capacitor/Data+Capacitor.swift
generated
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
extension Data: CapacitorExtension {}
|
||||
public extension CapacitorExtensionTypeWrapper where T == Data {
|
||||
|
||||
static func data(base64EncodedOrDataUrl: String) -> Data? {
|
||||
if isBase64DataUrl(base64EncodedOrDataUrl) {
|
||||
if let url = URL(string: base64EncodedOrDataUrl) {
|
||||
do {
|
||||
return try T(contentsOf: url)
|
||||
} catch {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
return nil
|
||||
} else {
|
||||
return T(base64Encoded: base64EncodedOrDataUrl)
|
||||
}
|
||||
}
|
||||
|
||||
private static func isBase64DataUrl(_ base64EncodedOrDataUrl: String) -> Bool {
|
||||
return base64EncodedOrDataUrl.starts(with: "data:") && base64EncodedOrDataUrl.contains("base64,")
|
||||
}
|
||||
}
|
||||
8
node_modules/@capacitor/ios/Capacitor/Capacitor/DocLinks.swift
generated
vendored
Normal file
8
node_modules/@capacitor/ios/Capacitor/Capacitor/DocLinks.swift
generated
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
import Foundation
|
||||
|
||||
enum DocLinks: String {
|
||||
case CAPPluginMethodSelector = "plugins/ios/#defining-methods"
|
||||
case NSPhotoLibraryAddUsageDescription = "https://developer.apple.com/library/content/documentation/General/Reference/InfoPlistKeyReference/Articles/CocoaKeys.html#//apple_ref/doc/uid/TP40009251-SW73"
|
||||
case NSPhotoLibraryUsageDescription = "https://developer.apple.com/library/content/documentation/General/Reference/InfoPlistKeyReference/Articles/CocoaKeys.html#//apple_ref/doc/uid/TP40009251-SW17"
|
||||
case NSCameraUsageDescription = "https://developer.apple.com/library/content/documentation/General/Reference/InfoPlistKeyReference/Articles/CocoaKeys.html#//apple_ref/doc/uid/TP40009251-SW24"
|
||||
}
|
||||
24
node_modules/@capacitor/ios/Capacitor/Capacitor/Info.plist
generated
vendored
Normal file
24
node_modules/@capacitor/ios/Capacitor/Capacitor/Info.plist
generated
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>$(DEVELOPMENT_LANGUAGE)</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>$(EXECUTABLE_NAME)</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>$(PRODUCT_NAME)</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>FMWK</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.0</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>$(CURRENT_PROJECT_VERSION)</string>
|
||||
<key>NSPrincipalClass</key>
|
||||
<string></string>
|
||||
</dict>
|
||||
</plist>
|
||||
122
node_modules/@capacitor/ios/Capacitor/Capacitor/JS.swift
generated
vendored
Normal file
122
node_modules/@capacitor/ios/Capacitor/Capacitor/JS.swift
generated
vendored
Normal file
@@ -0,0 +1,122 @@
|
||||
import Foundation
|
||||
|
||||
public class JSDate {
|
||||
@available(*, deprecated, message: "No longer needed. Dates will be mapped to strings during serialization.")
|
||||
static func toString(_ date: Date) -> String {
|
||||
let formatter = ISO8601DateFormatter()
|
||||
return formatter.string(from: date)
|
||||
}
|
||||
}
|
||||
|
||||
@available(*, deprecated, renamed: "PluginCallResultData")
|
||||
public typealias JSResultBody = [String: Any]
|
||||
|
||||
/**
|
||||
* A call originating from JavaScript land
|
||||
*/
|
||||
internal struct JSCall {
|
||||
let options: [String: Any]
|
||||
let pluginId: String
|
||||
let method: String
|
||||
let callbackId: String
|
||||
}
|
||||
|
||||
internal protocol JSResultProtocol {
|
||||
var call: JSCall { get }
|
||||
var callbackID: String { get }
|
||||
var pluginID: String { get }
|
||||
var methodName: String { get }
|
||||
func jsonPayload() -> String
|
||||
}
|
||||
|
||||
internal extension JSResultProtocol {
|
||||
var callbackID: String {
|
||||
return call.callbackId
|
||||
}
|
||||
|
||||
var pluginID: String {
|
||||
return call.pluginId
|
||||
}
|
||||
|
||||
var methodName: String {
|
||||
return call.method
|
||||
}
|
||||
}
|
||||
|
||||
private enum SerializationResult: String {
|
||||
case undefined = "undefined"
|
||||
case empty = "{}"
|
||||
}
|
||||
|
||||
/**
|
||||
* A result of processing a JSCall, contains
|
||||
* a reference to the original call and the new result.
|
||||
*/
|
||||
|
||||
internal struct JSResult: JSResultProtocol {
|
||||
let call: JSCall
|
||||
let result: PluginCallResult?
|
||||
|
||||
func jsonPayload() -> String {
|
||||
guard let result = result else {
|
||||
return SerializationResult.undefined.rawValue
|
||||
}
|
||||
do {
|
||||
if let payload = try result.jsonRepresentation() {
|
||||
return payload
|
||||
}
|
||||
} catch PluginCallResult.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 {
|
||||
CAPLog.print("Unable to serialize plugin response as JSON: \(error.localizedDescription)")
|
||||
}
|
||||
return SerializationResult.empty.rawValue
|
||||
}
|
||||
}
|
||||
|
||||
internal extension JSResult {
|
||||
init(call: JSCall, callResult: CAPPluginCallResult) {
|
||||
self.call = call
|
||||
self.result = callResult.resultData
|
||||
}
|
||||
}
|
||||
|
||||
internal struct JSResultError: JSResultProtocol {
|
||||
let call: JSCall
|
||||
let errorMessage: String
|
||||
let errorDescription: String
|
||||
let errorCode: String?
|
||||
let result: PluginCallResult
|
||||
|
||||
func jsonPayload() -> String {
|
||||
var errorDictionary: [String: Any] = [
|
||||
"message": self.errorMessage,
|
||||
"errorMessage": self.errorMessage
|
||||
]
|
||||
errorDictionary["code"] = self.errorCode
|
||||
|
||||
do {
|
||||
if let payload = try result.jsonRepresentation(includingFields: errorDictionary) {
|
||||
CAPLog.print("ERROR MESSAGE: ", payload.prefix(512))
|
||||
return payload
|
||||
}
|
||||
} catch PluginCallResult.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 {
|
||||
CAPLog.print("Unable to serialize plugin response as JSON: \(error.localizedDescription)")
|
||||
}
|
||||
return SerializationResult.empty.rawValue
|
||||
}
|
||||
}
|
||||
|
||||
internal extension JSResultError {
|
||||
init(call: JSCall, callError: CAPPluginCallError) {
|
||||
self.call = call
|
||||
errorMessage = callError.message
|
||||
errorDescription = callError.error?.localizedDescription ?? ""
|
||||
errorCode = callError.code
|
||||
result = callError.resultData ?? .dictionary([:])
|
||||
}
|
||||
}
|
||||
218
node_modules/@capacitor/ios/Capacitor/Capacitor/JSExport.swift
generated
vendored
Normal file
218
node_modules/@capacitor/ios/Capacitor/Capacitor/JSExport.swift
generated
vendored
Normal file
@@ -0,0 +1,218 @@
|
||||
internal struct PluginHeaderMethod: Codable {
|
||||
let name: String
|
||||
let rtype: String?
|
||||
}
|
||||
|
||||
internal struct PluginHeader: Codable {
|
||||
let name: String
|
||||
let methods: [PluginHeaderMethod]
|
||||
}
|
||||
|
||||
/**
|
||||
JSExport handles defining JS APIs that map to registered plugins and are responsible for proxying calls to our bridge.
|
||||
*/
|
||||
internal class JSExport {
|
||||
static let catchallOptionsParameter = "_options"
|
||||
static let callbackParameter = "_callback"
|
||||
|
||||
static func exportCapacitorGlobalJS(userContentController: WKUserContentController, isDebug: Bool, loggingEnabled: Bool, localUrl: String) throws {
|
||||
let data = "window.Capacitor = { DEBUG: \(isDebug), isLoggingEnabled: \(loggingEnabled), Plugins: {} }; window.WEBVIEW_SERVER_URL = '\(localUrl)';"
|
||||
let userScript = WKUserScript(source: data, injectionTime: .atDocumentStart, forMainFrameOnly: true)
|
||||
userContentController.addUserScript(userScript)
|
||||
}
|
||||
|
||||
static func exportBridgeJS(userContentController: WKUserContentController) throws {
|
||||
let capBundle = Bundle(for: Self.self)
|
||||
guard let jsUrl = capBundle.url(forResource: "native-bridge", withExtension: "js") else {
|
||||
CAPLog.print("ERROR: Required native-bridge.js file in Capacitor not found. Bridge will not function!")
|
||||
throw CapacitorBridgeError.errorExportingCoreJS
|
||||
}
|
||||
do {
|
||||
try self.injectFile(fileURL: jsUrl, userContentController: userContentController)
|
||||
} catch {
|
||||
CAPLog.print("ERROR: Unable to read required native-bridge.js file from the Capacitor framework. Bridge will not function!")
|
||||
throw CapacitorBridgeError.errorExportingCoreJS
|
||||
}
|
||||
}
|
||||
|
||||
static func exportCordovaJS(userContentController: WKUserContentController) throws {
|
||||
guard let cordovaUrl = Bundle.main.url(forResource: "public/cordova", withExtension: "js") else {
|
||||
CAPLog.print("ERROR: Required cordova.js file not found. Cordova plugins will not function!")
|
||||
throw CapacitorBridgeError.errorExportingCoreJS
|
||||
}
|
||||
guard let cordovaPluginsUrl = Bundle.main.url(forResource: "public/cordova_plugins", withExtension: "js") else {
|
||||
CAPLog.print("ERROR: Required cordova_plugins.js file not found. Cordova plugins will not function!")
|
||||
throw CapacitorBridgeError.errorExportingCoreJS
|
||||
}
|
||||
do {
|
||||
try self.injectFile(fileURL: cordovaUrl, userContentController: userContentController)
|
||||
try self.injectFile(fileURL: cordovaPluginsUrl, userContentController: userContentController)
|
||||
} catch {
|
||||
CAPLog.print("ERROR: Unable to read required cordova files. Cordova plugins will not function!")
|
||||
throw CapacitorBridgeError.errorExportingCoreJS
|
||||
}
|
||||
}
|
||||
|
||||
static func exportMiscFileJS(paths: [String], userContentController: WKUserContentController) {
|
||||
for path in paths {
|
||||
if let miscJSFilePath = Bundle.main.url(forResource: "public/\(path.replacingOccurrences(of: ".js", with: ""))", withExtension: "js") {
|
||||
do {
|
||||
try self.injectFile(fileURL: miscJSFilePath, userContentController: userContentController)
|
||||
} catch {
|
||||
CAPLog.print("WARNING: Unable to inject js from path \(miscJSFilePath)")
|
||||
}
|
||||
} else {
|
||||
CAPLog.print("WARNING: Unable to inject js from path \(path)")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Export the JS required to implement the given plugin.
|
||||
*/
|
||||
static func exportJS(for plugin: CapacitorPlugin, in userContentController: WKUserContentController) {
|
||||
var lines = [String]()
|
||||
|
||||
lines.append("""
|
||||
(function(w) {
|
||||
var a = (w.Capacitor = w.Capacitor || {});
|
||||
var p = (a.Plugins = a.Plugins || {});
|
||||
var t = (p['\(plugin.jsName)'] = {});
|
||||
t.addListener = function(eventName, callback) {
|
||||
return w.Capacitor.addListener('\(plugin.jsName)', eventName, callback);
|
||||
}
|
||||
t.removeAllListeners = function() {
|
||||
return w.Capacitor.nativePromise('\(plugin.jsName)', 'removeAllListeners');
|
||||
}
|
||||
""")
|
||||
|
||||
for method in plugin.pluginMethods {
|
||||
lines.append(generateMethod(pluginClassName: plugin.jsName, method: method))
|
||||
}
|
||||
|
||||
lines.append("""
|
||||
})(window);
|
||||
""")
|
||||
if let data = try? JSONEncoder().encode(createPluginHeader(for: plugin)),
|
||||
let header = String(data: data, encoding: .utf8) {
|
||||
lines.append("""
|
||||
(function(w) {
|
||||
var a = (w.Capacitor = w.Capacitor || {});
|
||||
var h = (a.PluginHeaders = a.PluginHeaders || []);
|
||||
h.push(\(header));
|
||||
})(window);
|
||||
""")
|
||||
}
|
||||
let js = lines.joined(separator: "\n")
|
||||
let userScript = WKUserScript(source: js, injectionTime: .atDocumentStart, forMainFrameOnly: true)
|
||||
userContentController.addUserScript(userScript)
|
||||
}
|
||||
|
||||
private static func createPluginHeader(for plugin: CapacitorPlugin) -> PluginHeader? {
|
||||
let methods = [
|
||||
PluginHeaderMethod(name: "addListener", rtype: nil),
|
||||
PluginHeaderMethod(name: "removeListener", rtype: nil),
|
||||
PluginHeaderMethod(name: "removeAllListeners", rtype: "promise"),
|
||||
PluginHeaderMethod(name: "checkPermissions", rtype: "promise"),
|
||||
PluginHeaderMethod(name: "requestPermissions", rtype: "promise")
|
||||
]
|
||||
|
||||
return PluginHeader(
|
||||
name: plugin.jsName,
|
||||
methods: methods + plugin.pluginMethods.map(createPluginHeaderMethod)
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
private static func createPluginHeaderMethod(method: CAPPluginMethod) -> PluginHeaderMethod {
|
||||
var rtype = method.returnType
|
||||
if rtype == "none" {
|
||||
rtype = nil
|
||||
}
|
||||
return PluginHeaderMethod(name: method.name, rtype: rtype)
|
||||
}
|
||||
|
||||
private static func generateMethod(pluginClassName: String, method: CAPPluginMethod) -> String {
|
||||
let methodName = method.name!
|
||||
let returnType = method.returnType!
|
||||
var paramList = [String]()
|
||||
|
||||
// add the catch-all
|
||||
// options argument which takes a full object and converts each
|
||||
// key/value pair into an option for plugin call.
|
||||
paramList.append(catchallOptionsParameter)
|
||||
|
||||
// Automatically add the _callback param if returning data through a callback
|
||||
if returnType == CAPPluginReturnCallback {
|
||||
paramList.append(callbackParameter)
|
||||
}
|
||||
|
||||
// Create a param string of the form "param1, param2, param3"
|
||||
let paramString = paramList.joined(separator: ", ")
|
||||
|
||||
// Generate the argument object that will be sent on each call
|
||||
let argObjectString = catchallOptionsParameter
|
||||
|
||||
var lines = [String]()
|
||||
|
||||
// Create the function declaration
|
||||
lines.append("t['\(method.name!)'] = function(\(paramString)) {")
|
||||
|
||||
// Create the call to Capacitor ...
|
||||
if returnType == CAPPluginReturnNone {
|
||||
// ...using none
|
||||
lines.append("""
|
||||
return w.Capacitor.nativeCallback('\(pluginClassName)', '\(methodName)', \(argObjectString));
|
||||
""")
|
||||
} else if returnType == CAPPluginReturnPromise {
|
||||
|
||||
// ...using a promise
|
||||
lines.append("""
|
||||
return w.Capacitor.nativePromise('\(pluginClassName)', '\(methodName)', \(argObjectString));
|
||||
""")
|
||||
} else if returnType == CAPPluginReturnCallback {
|
||||
// ...using a callback
|
||||
lines.append("""
|
||||
return w.Capacitor.nativeCallback('\(pluginClassName)', '\(methodName)', \(argObjectString), \(callbackParameter));
|
||||
""")
|
||||
} else {
|
||||
CAPLog.print("Error: plugin method return type \(returnType) is not supported!")
|
||||
}
|
||||
|
||||
// Close the function
|
||||
lines.append("}")
|
||||
return lines.joined(separator: "\n")
|
||||
}
|
||||
|
||||
static func exportCordovaPluginsJS(userContentController: WKUserContentController) throws {
|
||||
if let pluginsJSFolder = Bundle.main.url(forResource: "public/plugins", withExtension: nil) {
|
||||
self.injectFilesForFolder(folder: pluginsJSFolder, userContentController: userContentController)
|
||||
}
|
||||
}
|
||||
|
||||
static func injectFilesForFolder(folder: URL, userContentController: WKUserContentController) {
|
||||
let fileManager = FileManager.default
|
||||
do {
|
||||
let fileURLs = try fileManager.contentsOfDirectory(at: folder, includingPropertiesForKeys: nil, options: [])
|
||||
for fileURL in fileURLs {
|
||||
if fileURL.hasDirectoryPath {
|
||||
injectFilesForFolder(folder: fileURL, userContentController: userContentController)
|
||||
} else {
|
||||
try self.injectFile(fileURL: fileURL, userContentController: userContentController)
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
CAPLog.print("Error while enumerating files")
|
||||
}
|
||||
}
|
||||
|
||||
static func injectFile(fileURL: URL, userContentController: WKUserContentController) throws {
|
||||
do {
|
||||
let data = try String(contentsOf: fileURL, encoding: .utf8)
|
||||
let userScript = WKUserScript(source: data, injectionTime: .atDocumentStart, forMainFrameOnly: true)
|
||||
userContentController.addUserScript(userScript)
|
||||
} catch {
|
||||
CAPLog.print("Unable to inject js file")
|
||||
}
|
||||
}
|
||||
}
|
||||
254
node_modules/@capacitor/ios/Capacitor/Capacitor/JSTypes.swift
generated
vendored
Normal file
254
node_modules/@capacitor/ios/Capacitor/Capacitor/JSTypes.swift
generated
vendored
Normal file
@@ -0,0 +1,254 @@
|
||||
import Foundation
|
||||
|
||||
// declare our empty protocol, and conformance, for typing
|
||||
public protocol JSValue {}
|
||||
extension String: JSValue {}
|
||||
extension Bool: JSValue {}
|
||||
extension Int: JSValue {}
|
||||
extension Float: JSValue {}
|
||||
extension Double: JSValue {}
|
||||
extension NSNumber: JSValue {}
|
||||
extension NSNull: JSValue {}
|
||||
extension Array: JSValue {}
|
||||
extension Date: JSValue {}
|
||||
extension Dictionary: JSValue where Key == String, Value == JSValue {}
|
||||
|
||||
// convenience aliases
|
||||
public typealias JSObject = [String: JSValue]
|
||||
public typealias JSArray = [JSValue]
|
||||
|
||||
// string types
|
||||
public protocol JSStringContainer {
|
||||
func getString(_ key: String, _ defaultValue: String) -> String
|
||||
func getString(_ key: String) -> String?
|
||||
}
|
||||
|
||||
extension JSStringContainer {
|
||||
public func getString(_ key: String, _ defaultValue: String) -> String {
|
||||
return getString(key) ?? defaultValue
|
||||
}
|
||||
}
|
||||
|
||||
// boolean types
|
||||
public protocol JSBoolContainer {
|
||||
func getBool(_ key: String, _ defaultValue: Bool) -> Bool
|
||||
func getBool(_ key: String) -> Bool?
|
||||
}
|
||||
|
||||
extension JSBoolContainer {
|
||||
public func getBool(_ key: String, _ defaultValue: Bool) -> Bool {
|
||||
return getBool(key) ?? defaultValue
|
||||
}
|
||||
}
|
||||
|
||||
// integer types
|
||||
public protocol JSIntContainer {
|
||||
func getInt(_ key: String, _ defaultValue: Int) -> Int
|
||||
func getInt(_ key: String) -> Int?
|
||||
}
|
||||
|
||||
extension JSIntContainer {
|
||||
public func getInt(_ key: String, _ defaultValue: Int) -> Int {
|
||||
return getInt(key) ?? defaultValue
|
||||
}
|
||||
}
|
||||
|
||||
// float types
|
||||
public protocol JSFloatContainer {
|
||||
func getFloat(_ key: String, _ defaultValue: Float) -> Float
|
||||
func getFloat(_ key: String) -> Float?
|
||||
}
|
||||
|
||||
extension JSFloatContainer {
|
||||
public func getFloat(_ key: String, _ defaultValue: Float) -> Float {
|
||||
return getFloat(key) ?? defaultValue
|
||||
}
|
||||
}
|
||||
|
||||
// double types
|
||||
public protocol JSDoubleContainer {
|
||||
func getDouble(_ key: String, _ defaultValue: Double) -> Double
|
||||
func getDouble(_ key: String) -> Double?
|
||||
}
|
||||
|
||||
extension JSDoubleContainer {
|
||||
public func getDouble(_ key: String, _ defaultValue: Double) -> Double {
|
||||
return getDouble(key) ?? defaultValue
|
||||
}
|
||||
}
|
||||
|
||||
// date types
|
||||
public protocol JSDateContainer {
|
||||
func getDate(_ key: String, _ defaultValue: Date) -> Date
|
||||
func getDate(_ key: String) -> Date?
|
||||
}
|
||||
|
||||
extension JSDateContainer {
|
||||
public func getDate(_ key: String, _ defaultValue: Date) -> Date {
|
||||
return getDate(key) ?? defaultValue
|
||||
}
|
||||
}
|
||||
|
||||
// array types
|
||||
public protocol JSArrayContainer {
|
||||
func getArray(_ key: String, _ defaultValue: JSArray) -> JSArray
|
||||
func getArray<T>(_ key: String, _ ofType: T.Type) -> [T]?
|
||||
func getArray(_ key: String) -> JSArray?
|
||||
}
|
||||
|
||||
extension JSArrayContainer {
|
||||
public func getArray(_ key: String, _ defaultValue: JSArray) -> JSArray {
|
||||
return getArray(key) ?? defaultValue
|
||||
}
|
||||
|
||||
public func getArray<T>(_ key: String, _ ofType: T.Type) -> [T]? {
|
||||
return getArray(key) as? [T]
|
||||
}
|
||||
}
|
||||
|
||||
// dictionary types
|
||||
public protocol JSObjectContainer {
|
||||
func getObject(_ key: String, _ defaultValue: JSObject) -> JSObject
|
||||
func getObject(_ key: String) -> JSObject?
|
||||
}
|
||||
|
||||
extension JSObjectContainer {
|
||||
public func getObject(_ key: String, _ defaultValue: JSObject) -> JSObject {
|
||||
return getObject(key) ?? defaultValue
|
||||
}
|
||||
}
|
||||
|
||||
public protocol JSValueContainer: JSStringContainer, JSBoolContainer, JSIntContainer, JSFloatContainer,
|
||||
JSDoubleContainer, JSDateContainer, JSArrayContainer, JSObjectContainer {
|
||||
static var jsDateFormatter: ISO8601DateFormatter { get }
|
||||
var jsObjectRepresentation: JSObject { get }
|
||||
}
|
||||
|
||||
extension JSValueContainer {
|
||||
public func getValue(_ key: String) -> JSValue? {
|
||||
return jsObjectRepresentation[key]
|
||||
}
|
||||
|
||||
@available(*, message: "All values returned conform to JSValue, use getValue(_:) instead.", renamed: "getValue(_:)")
|
||||
public func getAny(_ key: String) -> Any? {
|
||||
return getValue(key)
|
||||
}
|
||||
|
||||
public func getString(_ key: String) -> String? {
|
||||
return jsObjectRepresentation[key] as? String
|
||||
}
|
||||
|
||||
public func getBool(_ key: String) -> Bool? {
|
||||
return jsObjectRepresentation[key] as? Bool
|
||||
}
|
||||
|
||||
public func getInt(_ key: String) -> Int? {
|
||||
return jsObjectRepresentation[key] as? Int
|
||||
}
|
||||
|
||||
public func getFloat(_ key: String) -> Float? {
|
||||
if let floatValue = jsObjectRepresentation[key] as? Float {
|
||||
return floatValue
|
||||
} else if let doubleValue = jsObjectRepresentation[key] as? Double {
|
||||
return Float(doubleValue)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
public func getDouble(_ key: String) -> Double? {
|
||||
return jsObjectRepresentation[key] as? Double
|
||||
}
|
||||
|
||||
public func getDate(_ key: String) -> Date? {
|
||||
if let isoString = jsObjectRepresentation[key] as? String {
|
||||
return Self.jsDateFormatter.date(from: isoString)
|
||||
}
|
||||
return jsObjectRepresentation[key] as? Date
|
||||
}
|
||||
|
||||
public func getArray(_ key: String) -> JSArray? {
|
||||
return jsObjectRepresentation[key] as? JSArray
|
||||
}
|
||||
|
||||
public func getObject(_ key: String) -> JSObject? {
|
||||
return jsObjectRepresentation[key] as? JSObject
|
||||
}
|
||||
|
||||
/// Decodes a value of the given type for the given key.
|
||||
/// - Parameters:
|
||||
/// - type: The type of the value to decode.
|
||||
/// - key: The key that the decoded value is associated with.
|
||||
/// - decoder: The decoder to use to decode the value. Defaults to `JSValueDecoder()`.
|
||||
/// - Returns: A value of the requested type, if present for the given key and convertible to the requested type.
|
||||
/// - Throws: `DecodingError` if the encountered encoded value is corrupted.
|
||||
public func decode<T: Decodable>(_ type: T.Type, for key: String, with decoder: JSValueDecoder = JSValueDecoder()) throws -> T {
|
||||
try decoder.decode(type, from: jsObjectRepresentation[key] ?? [:])
|
||||
}
|
||||
}
|
||||
|
||||
@objc protocol BridgedJSValueContainer: NSObjectProtocol {
|
||||
static var jsDateFormatter: ISO8601DateFormatter { get }
|
||||
var dictionaryRepresentation: NSDictionary { get }
|
||||
}
|
||||
|
||||
/*
|
||||
Simply casting objects from foundation class clusters (such as __NSArrayM)
|
||||
doesn't work with the JSValue protocol and will always fail. So we need to
|
||||
recursively and explicitly convert each value in the dictionary.
|
||||
*/
|
||||
public enum JSTypes {}
|
||||
extension JSTypes {
|
||||
public static func coerceDictionaryToJSObject(_ dictionary: NSDictionary?, formattingDatesAsStrings: Bool = false) -> JSObject? {
|
||||
return coerceToJSValue(dictionary, formattingDates: formattingDatesAsStrings) as? JSObject
|
||||
}
|
||||
|
||||
public static func coerceDictionaryToJSObject(_ dictionary: [AnyHashable: Any]?, formattingDatesAsStrings: Bool = false) -> JSObject? {
|
||||
return coerceToJSValue(dictionary, formattingDates: formattingDatesAsStrings) as? JSObject
|
||||
}
|
||||
|
||||
public static func coerceArrayToJSArray(_ array: [Any]?, formattingDatesAsStrings: Bool = false) -> JSArray? {
|
||||
return array?.compactMap { coerceToJSValue($0, formattingDates: formattingDatesAsStrings) }
|
||||
}
|
||||
}
|
||||
|
||||
private let dateStringFormatter = ISO8601DateFormatter()
|
||||
|
||||
// We need a large switch statement because we have a lot of types.
|
||||
// swiftlint:disable:next cyclomatic_complexity
|
||||
private func coerceToJSValue(_ value: Any?, formattingDates: Bool) -> JSValue? {
|
||||
guard let value = value else {
|
||||
return nil
|
||||
}
|
||||
switch value {
|
||||
case let stringValue as String:
|
||||
return stringValue
|
||||
case let numberValue as NSNumber:
|
||||
return numberValue
|
||||
case let boolValue as Bool:
|
||||
return boolValue
|
||||
case let intValue as Int:
|
||||
return intValue
|
||||
case let floatValue as Float:
|
||||
return floatValue
|
||||
case let doubleValue as Double:
|
||||
return doubleValue
|
||||
case let dateValue as Date:
|
||||
if formattingDates {
|
||||
return dateStringFormatter.string(from: dateValue)
|
||||
}
|
||||
return dateValue
|
||||
case let nullValue as NSNull:
|
||||
return nullValue
|
||||
case let arrayValue as NSArray:
|
||||
return arrayValue.compactMap { coerceToJSValue($0, formattingDates: formattingDates) }
|
||||
case let dictionaryValue as NSDictionary:
|
||||
let keys = dictionaryValue.allKeys.compactMap { $0 as? String }
|
||||
var result: JSObject = [:]
|
||||
for key in keys {
|
||||
result[key] = coerceToJSValue(dictionaryValue[key], formattingDates: formattingDates)
|
||||
}
|
||||
return result
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
60
node_modules/@capacitor/ios/Capacitor/Capacitor/KeyPath.swift
generated
vendored
Normal file
60
node_modules/@capacitor/ios/Capacitor/Capacitor/KeyPath.swift
generated
vendored
Normal file
@@ -0,0 +1,60 @@
|
||||
import Foundation
|
||||
|
||||
public struct KeyPath {
|
||||
var segments: [String]
|
||||
var isEmpty: Bool { return segments.isEmpty }
|
||||
var path: String {
|
||||
return segments.joined(separator: ".")
|
||||
}
|
||||
|
||||
// initializers
|
||||
init(_ string: String) {
|
||||
self.segments = string.components(separatedBy: ".")
|
||||
}
|
||||
|
||||
init(segments: [String]) {
|
||||
self.segments = segments
|
||||
}
|
||||
|
||||
// returns a tuple of the first segment and the remaining key path. result is nil if the key path has no segments.
|
||||
func headAndRemainder() -> (head: String, remainder: KeyPath)? {
|
||||
guard !isEmpty else {
|
||||
return nil
|
||||
}
|
||||
var paths = segments
|
||||
let head = paths.removeFirst()
|
||||
return (head, KeyPath(segments: paths))
|
||||
}
|
||||
}
|
||||
|
||||
extension KeyPath: ExpressibleByStringLiteral {
|
||||
public init(stringLiteral value: String) {
|
||||
self.init(value)
|
||||
}
|
||||
|
||||
public init(unicodeScalarLiteral value: String) {
|
||||
self.init(value)
|
||||
}
|
||||
|
||||
public init(extendedGraphemeClusterLiteral value: String) {
|
||||
self.init(value)
|
||||
}
|
||||
}
|
||||
|
||||
extension JSObject {
|
||||
public subscript(keyPath keyPath: KeyPath) -> JSValue? {
|
||||
switch keyPath.headAndRemainder() {
|
||||
case nil: // path is empty
|
||||
return nil
|
||||
case let (head, remainder)? where remainder.isEmpty: // reached the end of the path
|
||||
return self[head]
|
||||
case let (head, remainder)?: // we have at least one level to traverse
|
||||
switch self[head] {
|
||||
case let childObject as JSObject: // iterate down the next level
|
||||
return childObject[keyPath: remainder]
|
||||
default: // not an object, can't go any deeper
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
303
node_modules/@capacitor/ios/Capacitor/Capacitor/KeyValueStore.swift
generated
vendored
Normal file
303
node_modules/@capacitor/ios/Capacitor/Capacitor/KeyValueStore.swift
generated
vendored
Normal file
@@ -0,0 +1,303 @@
|
||||
//
|
||||
// KeyValueStore.swift
|
||||
// Capacitor
|
||||
//
|
||||
// Created by Steven Sherry on 1/5/24.
|
||||
// Copyright © 2024 Drifty Co. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
/// A generic KeyValueStore that allows storing and retrieving values associated with string keys.
|
||||
/// The store supports both ephemeral (in-memory) storage and persistent (file-based) storage backends
|
||||
/// by default, however it can also take anything that conforms to ``KeyValueStoreBackend`` as
|
||||
/// a backend.
|
||||
///
|
||||
/// This class provides methods to get, set and delete key-value pairs for any type of value, provided the
|
||||
/// types conform to `Codable`. The default ``Backend/ephemeral`` and ``Backend/persistent(suiteName:)``
|
||||
/// backends are thread-safe.
|
||||
///
|
||||
/// ## Usage Examples
|
||||
///
|
||||
/// ### Non-throwing API
|
||||
/// ```swift
|
||||
/// let store = KeyValueStore.standard
|
||||
/// // Set
|
||||
/// store["key"] = "value"
|
||||
///
|
||||
/// // Get
|
||||
/// if let value = store["key", as: String.self] {
|
||||
/// // Do something with value
|
||||
/// }
|
||||
///
|
||||
/// // Delete
|
||||
/// // The type here is a required argument because
|
||||
/// // it is unable to be inferred
|
||||
/// store["key", as: String.self] = nil
|
||||
/// // or
|
||||
/// store["key"] = nil as String?
|
||||
/// ```
|
||||
///
|
||||
///
|
||||
/// ### Throwing API
|
||||
///
|
||||
/// ```swift
|
||||
/// let store = KeyValueStore.standard
|
||||
/// do {
|
||||
/// // Set
|
||||
/// try store.set("key", value: "value")
|
||||
///
|
||||
/// // Get
|
||||
/// if let value = try store.get("key", as: String.self) {
|
||||
/// // Do something with value
|
||||
/// }
|
||||
///
|
||||
/// // Delete
|
||||
/// try store.delete("key")
|
||||
/// } catch {
|
||||
/// print(error.localizedDescription)
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// ### Throwing vs Non-throwing
|
||||
///
|
||||
/// Of the built-in backends, both ``Backend/ephemeral`` and ``Backend/persistent(suiteName:)`` will throw in the following cases:
|
||||
/// * The data read from the file retrieved during ``get(_:as:)`` is unable to be decoded as the type provided.
|
||||
/// * The value provided to ``set(_:value:)`` encounters an error during encoding.
|
||||
/// * This is more likely to happen with types that have custom `Encodable` implementations
|
||||
///
|
||||
/// ``Backend/persistent(suiteName:)`` will throw for the following additional cases:
|
||||
/// * A file is unable to be read from disk during ``get(_:as:)``
|
||||
/// * The existence of the file on disk is checked before attempting to read the file, so out of the
|
||||
/// [possible file reading errors](https://developer.apple.com/documentation/foundation/1448136-nserror_codes#file-reading-errors),
|
||||
/// the only likely candidate would be
|
||||
/// [NSFileReadCorruptFileError](https://developer.apple.com/documentation/foundation/1448136-nserror_codes/nsfilereadcorruptfileerror).
|
||||
/// In practice, this should never happen since writes happen atomically.
|
||||
/// * The data from the value encoded in ``set(_:value:)`` is unable to be written to disk
|
||||
/// * Of the [possible file writing errors](https://developer.apple.com/documentation/foundation/1448136-nserror_codes#file-writing-errors),
|
||||
/// the only likely candidates are
|
||||
/// [NSFileWriteInvalidFileNameError](https://developer.apple.com/documentation/foundation/1448136-nserror_codes/nsfilewriteinvalidfilenameerror)
|
||||
/// if the key provided makes for an invalid file name and
|
||||
/// [NSFileWriteOutOfSpaceError](https://developer.apple.com/documentation/foundation/1448136-nserror_codes/nsfilewriteoutofspaceerror)
|
||||
/// if the user has no space left on disk
|
||||
///
|
||||
/// The throwing API should be used in cases where detailed error information is needed for logging or diagnostics. The non-throwing API should be used
|
||||
/// in cases where silent failure is preferred.
|
||||
public class KeyValueStore {
|
||||
|
||||
/// The built-in storage backends
|
||||
public enum Backend {
|
||||
/// An in-memory backing store
|
||||
case ephemeral
|
||||
/// A persistent file-based backing store using the
|
||||
/// `suiteName` as an identifier for the collection of files
|
||||
case persistent(suiteName: String)
|
||||
}
|
||||
|
||||
private let backend: any KeyValueStoreBackend
|
||||
|
||||
/// Creates an instance of ``KeyValueStore`` with a custom backend
|
||||
/// - Parameter backend: The custom backend implementation
|
||||
public init(backend: any KeyValueStoreBackend) {
|
||||
self.backend = backend
|
||||
}
|
||||
|
||||
/// Creates an instance of ``KeyValueStore`` with the provided built-in ``Backend``
|
||||
/// - Parameter type: The type of ``Backend`` to use
|
||||
public init(type: Backend) {
|
||||
switch type {
|
||||
case .ephemeral:
|
||||
backend = InMemoryStore()
|
||||
case .persistent(suiteName: let name):
|
||||
backend = FileStore.with(name: name)
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates an instance of ``KeyValueStore`` with ``Backend/persistent(suiteName:)``
|
||||
/// - Parameter suiteName: The suite name to provide ``Backend/persistent(suiteName:)``
|
||||
public convenience init(suiteName: String) {
|
||||
self.init(type: .persistent(suiteName: suiteName))
|
||||
}
|
||||
|
||||
/// Retrieves a value of the specified type and key
|
||||
/// - Parameters:
|
||||
/// - key: The unique identifier for the value
|
||||
/// - type: The expected type of the value being retried
|
||||
/// - Returns: A decoded value of the given type or `nil` if there is no such value
|
||||
public func `get`<T>(_ key: String, as type: T.Type = T.self) throws -> T? where T: Decodable {
|
||||
try backend.get(key, as: type)
|
||||
}
|
||||
|
||||
/// Stores the value under the specified key
|
||||
/// - Parameters:
|
||||
/// - key: The unique identifier
|
||||
/// - value: The value to be stored
|
||||
public func `set`<T>(_ key: String, value: T) throws where T: Encodable {
|
||||
try backend.set(key, value: value)
|
||||
}
|
||||
|
||||
/// Deletes the value for the specified key
|
||||
public func `delete`(_ key: String) throws {
|
||||
try backend.delete(key)
|
||||
}
|
||||
|
||||
/// Convenience for accessing and modifying values in the store without calling ``get(_:as:)``, ``set(_:value:)``, or ``delete(_:)``
|
||||
/// - Parameters:
|
||||
/// - key: The unique identifier for the value to access or modify
|
||||
/// - type: The type the value is stored as
|
||||
///
|
||||
/// This method is only really necessary when accessing a key and the type cannot be inferred from it's context.
|
||||
/// ```swift
|
||||
/// let store = KeyValueStore.standard
|
||||
///
|
||||
/// // Get
|
||||
/// let value = store["key", as: String.self]
|
||||
///
|
||||
/// // If the type can be inferred then it may be omitted
|
||||
/// let value: String? = store["key"]
|
||||
/// let value = store["key"] as String?
|
||||
/// let value = store["key"] ?? "default"
|
||||
///
|
||||
/// // Delete
|
||||
/// store["key", as: String.self] = nil
|
||||
/// store["key"] = nil as String?
|
||||
/// ```
|
||||
public subscript<T> (_ key: String, as type: T.Type = T.self) -> T? where T: Codable {
|
||||
get { try? self.get(key) }
|
||||
set {
|
||||
if let newValue {
|
||||
try? self.set(key, value: newValue)
|
||||
} else {
|
||||
try? self.delete(key)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A shared persistent instance of ``KeyValueStore``
|
||||
public static let standard = KeyValueStore(type: .persistent(suiteName: "standard"))
|
||||
}
|
||||
|
||||
public protocol KeyValueStoreBackend {
|
||||
func `get`<T>(_ key: String, as type: T.Type) throws -> T? where T: Decodable
|
||||
func `set`<T>(_ key: String, value: T) throws where T: Encodable
|
||||
func `delete`(_ key: String) throws
|
||||
}
|
||||
|
||||
private class FileStore: KeyValueStoreBackend {
|
||||
private let cache = ConcurrentDictionary<Data>()
|
||||
private let decoder = JSONDecoder()
|
||||
private let encoder = JSONEncoder()
|
||||
private let baseUrl: URL
|
||||
|
||||
private init(baseUrl: URL) {
|
||||
self.baseUrl = baseUrl
|
||||
}
|
||||
|
||||
func get<T>(_ key: String, as type: T.Type) throws -> T? where T: Decodable {
|
||||
if let cached = cache[key],
|
||||
let value = try? decoder.decode(type, from: cached) {
|
||||
return value
|
||||
}
|
||||
|
||||
let fileCacheLocation = baseUrl.appendingPathComponent(key)
|
||||
guard FileManager.default.fileExists(atPath: fileCacheLocation.path) else { return nil }
|
||||
|
||||
let data = try Data(contentsOf: fileCacheLocation)
|
||||
let decoded = try decoder.decode(type, from: data)
|
||||
|
||||
cache[key] = data
|
||||
return decoded
|
||||
}
|
||||
|
||||
func set<T>(_ key: String, value: T) throws where T: Encodable {
|
||||
let encoded = try encoder.encode(value)
|
||||
try encoded.write(to: url(for: key), options: .atomic)
|
||||
cache[key] = encoded
|
||||
}
|
||||
|
||||
func delete(_ key: String) throws {
|
||||
cache[key] = nil
|
||||
try FileManager.default.removeItem(at: url(for: key))
|
||||
}
|
||||
|
||||
private func url(for key: String) -> URL {
|
||||
baseUrl.appendingPathComponent(key)
|
||||
}
|
||||
|
||||
private static let instances = ConcurrentDictionary<FileStore>()
|
||||
|
||||
// This ensures we essentially have singletons for accessing file based resources
|
||||
// so we don't have a scenario where two separate instances may be writing to
|
||||
// the same files.
|
||||
static func with(name: String) -> FileStore {
|
||||
if let existing = instances[name] { return existing }
|
||||
guard let library = try? FileManager
|
||||
.default
|
||||
.url(
|
||||
for: .libraryDirectory,
|
||||
in: .userDomainMask,
|
||||
appropriateFor: nil,
|
||||
create: true
|
||||
)
|
||||
else { fatalError("⚡️ ❌ Library URL unable to be accessed or created by the current application. This is an impossible state.") }
|
||||
|
||||
let url = library.appendingPathComponent("kvstore").appendingPathComponent(name)
|
||||
|
||||
// Create the folder if it doesn't exist. This should never throw for the current base directory, so we ignore the exception.
|
||||
try? FileManager.default.createDirectory(at: url, withIntermediateDirectories: true, attributes: nil)
|
||||
|
||||
let new = FileStore(baseUrl: url)
|
||||
instances[name] = new
|
||||
return new
|
||||
}
|
||||
}
|
||||
|
||||
private class InMemoryStore: KeyValueStoreBackend {
|
||||
private let storage = ConcurrentDictionary<Data>()
|
||||
private let decoder = JSONDecoder()
|
||||
private let encoder = JSONEncoder()
|
||||
|
||||
func get<T>(_ key: String, as type: T.Type) throws -> T? where T: Decodable {
|
||||
guard let data = storage[key] else { return nil }
|
||||
return try decoder.decode(type, from: data)
|
||||
}
|
||||
|
||||
func set<T>(_ key: String, value: T) throws where T: Encodable {
|
||||
let data = try encoder.encode(value)
|
||||
storage[key] = data
|
||||
}
|
||||
|
||||
func delete(_ key: String) {
|
||||
storage[key] = nil
|
||||
}
|
||||
}
|
||||
|
||||
class ConcurrentDictionary<Value> {
|
||||
typealias StorageType = [String: Value]
|
||||
private var storage: StorageType
|
||||
private let lock = NSLock()
|
||||
|
||||
init(_ initial: StorageType = [:]) {
|
||||
storage = initial
|
||||
}
|
||||
|
||||
subscript (_ key: String) -> Value? {
|
||||
get {
|
||||
lock.withLock {
|
||||
storage[key]
|
||||
}
|
||||
}
|
||||
|
||||
set {
|
||||
lock.withLock {
|
||||
storage[key] = newValue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func withLock<T>(_ body: (_ storage: inout StorageType) -> T) -> T {
|
||||
lock.withLock {
|
||||
body(&storage)
|
||||
}
|
||||
}
|
||||
}
|
||||
6
node_modules/@capacitor/ios/Capacitor/Capacitor/NotificationHandlerProtocol.swift
generated
vendored
Normal file
6
node_modules/@capacitor/ios/Capacitor/Capacitor/NotificationHandlerProtocol.swift
generated
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
import Foundation
|
||||
|
||||
@objc(CAPNotificationHandlerProtocol) public protocol NotificationHandlerProtocol {
|
||||
func willPresent(notification: UNNotification) -> UNNotificationPresentationOptions
|
||||
func didReceive(response: UNNotificationResponse)
|
||||
}
|
||||
60
node_modules/@capacitor/ios/Capacitor/Capacitor/NotificationRouter.swift
generated
vendored
Normal file
60
node_modules/@capacitor/ios/Capacitor/Capacitor/NotificationRouter.swift
generated
vendored
Normal file
@@ -0,0 +1,60 @@
|
||||
import Foundation
|
||||
|
||||
@objc(CAPNotificationRouter) public class NotificationRouter: NSObject, UNUserNotificationCenterDelegate {
|
||||
var handleApplicationNotifications: Bool {
|
||||
get {
|
||||
return UNUserNotificationCenter.current().delegate === self
|
||||
}
|
||||
set {
|
||||
let center = UNUserNotificationCenter.current()
|
||||
|
||||
if newValue {
|
||||
center.delegate = self
|
||||
} else if center.delegate === self {
|
||||
center.delegate = nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public weak var pushNotificationHandler: NotificationHandlerProtocol? {
|
||||
didSet {
|
||||
if pushNotificationHandler != nil, oldValue != nil {
|
||||
CAPLog.print("Push notification handler overriding previous instance: \(String(describing: type(of: oldValue)))")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public weak var localNotificationHandler: NotificationHandlerProtocol? {
|
||||
didSet {
|
||||
if localNotificationHandler != nil, oldValue != nil {
|
||||
CAPLog.print("Local notification handler overriding previous instance: \(String(describing: type(of: oldValue)))")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public func userNotificationCenter(_ center: UNUserNotificationCenter,
|
||||
willPresent notification: UNNotification,
|
||||
withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
|
||||
let presentationOptions: UNNotificationPresentationOptions?
|
||||
|
||||
if notification.request.trigger?.isKind(of: UNPushNotificationTrigger.self) == true {
|
||||
presentationOptions = pushNotificationHandler?.willPresent(notification: notification)
|
||||
} else {
|
||||
presentationOptions = localNotificationHandler?.willPresent(notification: notification)
|
||||
}
|
||||
|
||||
completionHandler(presentationOptions ?? [])
|
||||
}
|
||||
|
||||
public func userNotificationCenter(_ center: UNUserNotificationCenter,
|
||||
didReceive response: UNNotificationResponse,
|
||||
withCompletionHandler completionHandler: @escaping () -> Void) {
|
||||
if response.notification.request.trigger?.isKind(of: UNPushNotificationTrigger.self) == true {
|
||||
pushNotificationHandler?.didReceive(response: response)
|
||||
} else {
|
||||
localNotificationHandler?.didReceive(response: response)
|
||||
}
|
||||
|
||||
completionHandler()
|
||||
}
|
||||
}
|
||||
106
node_modules/@capacitor/ios/Capacitor/Capacitor/PluginCallResult.swift
generated
vendored
Normal file
106
node_modules/@capacitor/ios/Capacitor/Capacitor/PluginCallResult.swift
generated
vendored
Normal file
@@ -0,0 +1,106 @@
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
56
node_modules/@capacitor/ios/Capacitor/Capacitor/PluginConfig.swift
generated
vendored
Normal file
56
node_modules/@capacitor/ios/Capacitor/Capacitor/PluginConfig.swift
generated
vendored
Normal file
@@ -0,0 +1,56 @@
|
||||
import Foundation
|
||||
|
||||
@objc public class PluginConfig: NSObject {
|
||||
|
||||
// The object containing the plugin config values
|
||||
private var config: JSObject
|
||||
|
||||
init(config: JSObject) {
|
||||
self.config = config
|
||||
}
|
||||
|
||||
@objc public func getString(_ configKey: String, _ defaultValue: String? = nil) -> String? {
|
||||
if let val = (self.config)[keyPath: KeyPath(configKey)] as? String {
|
||||
return val
|
||||
}
|
||||
return defaultValue
|
||||
}
|
||||
|
||||
@objc public func getBoolean(_ configKey: String, _ defaultValue: Bool) -> Bool {
|
||||
if let val = (self.config)[keyPath: KeyPath(configKey)] as? Bool {
|
||||
return val
|
||||
}
|
||||
return defaultValue
|
||||
}
|
||||
|
||||
@objc public func getInt(_ configKey: String, _ defaultValue: Int) -> Int {
|
||||
if let val = (self.config)[keyPath: KeyPath(configKey)] as? Int {
|
||||
return val
|
||||
}
|
||||
return defaultValue
|
||||
}
|
||||
|
||||
public func getArray(_ configKey: String, _ defaultValue: JSArray? = nil) -> JSArray? {
|
||||
if let val = (self.config)[keyPath: KeyPath(configKey)] as? JSArray {
|
||||
return val
|
||||
}
|
||||
return defaultValue
|
||||
}
|
||||
|
||||
public func getObject(_ configKey: String) -> JSObject? {
|
||||
return (self.config)[keyPath: KeyPath(configKey)] as? JSObject
|
||||
}
|
||||
|
||||
@objc public func isEmpty() -> Bool {
|
||||
return self.config.isEmpty
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the JSObject containing the config of the the provided plugin ID.
|
||||
*
|
||||
* @return The config for that plugin
|
||||
*/
|
||||
public func getConfigJSON() -> JSObject {
|
||||
return self.config
|
||||
}
|
||||
}
|
||||
141
node_modules/@capacitor/ios/Capacitor/Capacitor/Plugins/CapacitorCookieManager.swift
generated
vendored
Normal file
141
node_modules/@capacitor/ios/Capacitor/Capacitor/Plugins/CapacitorCookieManager.swift
generated
vendored
Normal file
@@ -0,0 +1,141 @@
|
||||
import Foundation
|
||||
|
||||
public class CapacitorWKCookieObserver: NSObject, WKHTTPCookieStoreObserver {
|
||||
// Sync WKWebView Cookies to HTTPCookieStorage
|
||||
public func cookiesDidChange(in cookieStore: WKHTTPCookieStore) {
|
||||
DispatchQueue.main.async {
|
||||
cookieStore.getAllCookies { cookies in
|
||||
cookies.forEach { cookie in
|
||||
HTTPCookieStorage.shared.setCookie(cookie)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class CapacitorCookieManager {
|
||||
var config: InstanceConfiguration?
|
||||
|
||||
init(_ capConfig: InstanceConfiguration?) {
|
||||
self.config = capConfig
|
||||
}
|
||||
|
||||
public func getServerUrl() -> URL? {
|
||||
return self.config?.serverURL ?? self.config?.localURL
|
||||
}
|
||||
|
||||
private func isUrlSanitized(_ urlString: String) -> Bool {
|
||||
return urlString.isEmpty || urlString == getServerUrl()?.absoluteString || urlString.hasPrefix("http://") || urlString.hasPrefix("https://")
|
||||
}
|
||||
|
||||
public func getServerUrl(_ urlString: String?) -> URL? {
|
||||
guard let urlString = urlString else {
|
||||
return getServerUrl()
|
||||
}
|
||||
|
||||
if urlString.isEmpty {
|
||||
return getServerUrl()
|
||||
}
|
||||
|
||||
let validUrlString = (isUrlSanitized(urlString)) ? urlString : "http://\(urlString)"
|
||||
|
||||
guard let url = URL(string: validUrlString) else {
|
||||
return getServerUrl()
|
||||
}
|
||||
|
||||
return url
|
||||
}
|
||||
|
||||
public func encode(_ value: String) -> String {
|
||||
return value.addingPercentEncoding(withAllowedCharacters: .urlPathAllowed)!
|
||||
}
|
||||
|
||||
public func decode(_ value: String) -> String {
|
||||
return value.removingPercentEncoding!
|
||||
}
|
||||
|
||||
public func setCookie(_ domain: String, _ action: String) {
|
||||
let url = getServerUrl(domain)!
|
||||
let jar = HTTPCookieStorage.shared
|
||||
let field = ["Set-Cookie": action]
|
||||
let cookies = HTTPCookie.cookies(withResponseHeaderFields: field, for: url)
|
||||
jar.setCookies(cookies, for: url, mainDocumentURL: nil)
|
||||
syncCookiesToWebView()
|
||||
}
|
||||
|
||||
public func setCookie(_ url: URL, _ key: String, _ value: String, _ expires: String?, _ path: String?) {
|
||||
let jar = HTTPCookieStorage.shared
|
||||
let field = ["Set-Cookie": "\(key)=\(value); expires=\(expires ?? ""); path=\(path ?? "/")"]
|
||||
let cookies = HTTPCookie.cookies(withResponseHeaderFields: field, for: url)
|
||||
jar.setCookies(cookies, for: url, mainDocumentURL: nil)
|
||||
syncCookiesToWebView()
|
||||
}
|
||||
|
||||
public func getCookiesAsMap(_ url: URL) -> [String: String] {
|
||||
syncCookiesToWebView()
|
||||
var cookiesMap: [String: String] = [:]
|
||||
let jar = HTTPCookieStorage.shared
|
||||
if let cookies = jar.cookies(for: url) {
|
||||
for cookie in cookies {
|
||||
if !cookie.isHTTPOnly {
|
||||
cookiesMap[cookie.name] = cookie.value
|
||||
}
|
||||
}
|
||||
}
|
||||
return cookiesMap
|
||||
}
|
||||
|
||||
public func getCookies() -> String {
|
||||
syncCookiesToWebView()
|
||||
let jar = HTTPCookieStorage.shared
|
||||
guard let url = self.getServerUrl() else { return "" }
|
||||
guard let cookies = jar.cookies(for: url) else { return "" }
|
||||
let filteredCookies = cookies.filter { !$0.isHTTPOnly }
|
||||
return filteredCookies.map({"\($0.name)=\($0.value)"}).joined(separator: "; ")
|
||||
}
|
||||
|
||||
public func deleteCookie(_ url: URL, _ key: String) {
|
||||
let jar = HTTPCookieStorage.shared
|
||||
if let cookie = jar.cookies(for: url)?.first(where: { (cookie) -> Bool in
|
||||
return cookie.name == key
|
||||
}) {
|
||||
jar.deleteCookie(cookie)
|
||||
DispatchQueue.main.async {
|
||||
WKWebsiteDataStore.default().httpCookieStore.delete(cookie)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public func clearCookies(_ url: URL) {
|
||||
let jar = HTTPCookieStorage.shared
|
||||
jar.cookies(for: url)?.forEach({ (cookie) in
|
||||
jar.deleteCookie(cookie)
|
||||
DispatchQueue.main.async {
|
||||
WKWebsiteDataStore.default().httpCookieStore.delete(cookie)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
public func clearAllCookies() {
|
||||
let jar = HTTPCookieStorage.shared
|
||||
jar.cookies?.forEach({ (cookie) in
|
||||
jar.deleteCookie(cookie)
|
||||
DispatchQueue.main.async {
|
||||
WKWebsiteDataStore.default().httpCookieStore.delete(cookie)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
public func syncCookiesToWebView() {
|
||||
if let cookies = HTTPCookieStorage.shared.cookies {
|
||||
for cookie in cookies {
|
||||
DispatchQueue.main.async {
|
||||
WKWebsiteDataStore.default()
|
||||
.httpCookieStore
|
||||
.setCookie(cookie, completionHandler: nil)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
57
node_modules/@capacitor/ios/Capacitor/Capacitor/Plugins/CapacitorCookies.swift
generated
vendored
Normal file
57
node_modules/@capacitor/ios/Capacitor/Capacitor/Plugins/CapacitorCookies.swift
generated
vendored
Normal file
@@ -0,0 +1,57 @@
|
||||
import Foundation
|
||||
|
||||
@objc(CAPCookiesPlugin)
|
||||
public class CAPCookiesPlugin: CAPPlugin, CAPBridgedPlugin {
|
||||
public let identifier = "CAPCookiesPlugin"
|
||||
public let jsName = "CapacitorCookies"
|
||||
public let pluginMethods: [CAPPluginMethod] = [
|
||||
CAPPluginMethod(name: "getCookies", returnType: CAPPluginReturnPromise),
|
||||
CAPPluginMethod(name: "setCookie", returnType: CAPPluginReturnPromise),
|
||||
CAPPluginMethod(name: "deleteCookie", returnType: CAPPluginReturnPromise),
|
||||
CAPPluginMethod(name: "clearCookies", returnType: CAPPluginReturnPromise),
|
||||
CAPPluginMethod(name: "clearAllCookies", returnType: CAPPluginReturnPromise)
|
||||
]
|
||||
|
||||
var cookieManager: CapacitorCookieManager?
|
||||
|
||||
@objc override public func load() {
|
||||
cookieManager = CapacitorCookieManager(bridge?.config)
|
||||
}
|
||||
|
||||
@objc func getCookies(_ call: CAPPluginCall) {
|
||||
guard let url = cookieManager!.getServerUrl(call.getString("url")) else { return call.reject("Invalid URL / Server URL")}
|
||||
call.resolve(cookieManager!.getCookiesAsMap(url))
|
||||
}
|
||||
|
||||
@objc func setCookie(_ call: CAPPluginCall) {
|
||||
guard let key = call.getString("key") else { return call.reject("Must provide key") }
|
||||
guard let value = call.getString("value") else { return call.reject("Must provide value") }
|
||||
|
||||
guard let url = cookieManager!.getServerUrl(call.getString("url")) else { return call.reject("Invalid domain") }
|
||||
|
||||
let expires = call.getString("expires", "")
|
||||
let path = call.getString("path", "")
|
||||
cookieManager!.setCookie(url, key, cookieManager!.encode(value), expires, path)
|
||||
call.resolve()
|
||||
}
|
||||
|
||||
@objc func deleteCookie(_ call: CAPPluginCall) {
|
||||
guard let key = call.getString("key") else { return call.reject("Must provide key") }
|
||||
guard let url = cookieManager!.getServerUrl(call.getString("url")) else { return call.reject("Invalid URL / Server URL")}
|
||||
cookieManager!.deleteCookie(url, key)
|
||||
call.resolve()
|
||||
}
|
||||
|
||||
@objc func clearCookies(_ call: CAPPluginCall) {
|
||||
let url = cookieManager!.getServerUrl(call.getString("url"))
|
||||
if url != nil {
|
||||
cookieManager!.clearCookies(url!)
|
||||
call.resolve()
|
||||
}
|
||||
}
|
||||
|
||||
@objc func clearAllCookies(_ call: CAPPluginCall) {
|
||||
cookieManager!.clearAllCookies()
|
||||
call.resolve()
|
||||
}
|
||||
}
|
||||
57
node_modules/@capacitor/ios/Capacitor/Capacitor/Plugins/CapacitorHttp.swift
generated
vendored
Normal file
57
node_modules/@capacitor/ios/Capacitor/Capacitor/Plugins/CapacitorHttp.swift
generated
vendored
Normal file
@@ -0,0 +1,57 @@
|
||||
import Foundation
|
||||
|
||||
@objc(CAPHttpPlugin)
|
||||
public class CAPHttpPlugin: CAPPlugin, CAPBridgedPlugin {
|
||||
public let identifier = "CAPHttpPlugin"
|
||||
public let jsName = "CapacitorHttp"
|
||||
public let pluginMethods: [CAPPluginMethod] = [
|
||||
CAPPluginMethod(name: "request", returnType: CAPPluginReturnPromise),
|
||||
CAPPluginMethod(name: "get", returnType: CAPPluginReturnPromise),
|
||||
CAPPluginMethod(name: "post", returnType: CAPPluginReturnPromise),
|
||||
CAPPluginMethod(name: "put", returnType: CAPPluginReturnPromise),
|
||||
CAPPluginMethod(name: "patch", returnType: CAPPluginReturnPromise),
|
||||
CAPPluginMethod(name: "delete", returnType: CAPPluginReturnPromise)
|
||||
]
|
||||
|
||||
@objc func http(_ call: CAPPluginCall, _ httpMethod: String?) {
|
||||
do {
|
||||
if let clazz = NSClassFromString("SSLPinningHttpRequestHandlerClass") {
|
||||
// swiftlint:disable force_cast
|
||||
(clazz as! NSObject.Type).perform(#selector(self.request(_:)), with: [
|
||||
"call": call,
|
||||
"httpMethod": httpMethod as Any,
|
||||
"config": self.bridge?.config as Any
|
||||
])
|
||||
// swiftlint:enable force_cast
|
||||
} else {
|
||||
try HttpRequestHandler.request(call, httpMethod, self.bridge?.config)
|
||||
}
|
||||
} catch let error {
|
||||
call.reject(error.localizedDescription)
|
||||
}
|
||||
}
|
||||
|
||||
@objc func request(_ call: CAPPluginCall) {
|
||||
http(call, nil)
|
||||
}
|
||||
|
||||
@objc func get(_ call: CAPPluginCall) {
|
||||
http(call, "GET")
|
||||
}
|
||||
|
||||
@objc func post(_ call: CAPPluginCall) {
|
||||
http(call, "POST")
|
||||
}
|
||||
|
||||
@objc func put(_ call: CAPPluginCall) {
|
||||
http(call, "PUT")
|
||||
}
|
||||
|
||||
@objc func patch(_ call: CAPPluginCall) {
|
||||
http(call, "PATCH")
|
||||
}
|
||||
|
||||
@objc func delete(_ call: CAPPluginCall) {
|
||||
http(call, "DELETE")
|
||||
}
|
||||
}
|
||||
225
node_modules/@capacitor/ios/Capacitor/Capacitor/Plugins/CapacitorUrlRequest.swift
generated
vendored
Normal file
225
node_modules/@capacitor/ios/Capacitor/Capacitor/Plugins/CapacitorUrlRequest.swift
generated
vendored
Normal file
@@ -0,0 +1,225 @@
|
||||
import Foundation
|
||||
|
||||
open class CapacitorUrlRequest: NSObject, URLSessionTaskDelegate {
|
||||
public var request: URLRequest
|
||||
public var headers: [String: String]
|
||||
|
||||
public enum CapacitorUrlRequestError: Error {
|
||||
case serializationError(String?)
|
||||
}
|
||||
|
||||
public init(_ url: URL, method: String) {
|
||||
request = URLRequest(url: url)
|
||||
request.httpMethod = method
|
||||
headers = [:]
|
||||
if let lang = Locale.autoupdatingCurrent.languageCode {
|
||||
if let country = Locale.autoupdatingCurrent.regionCode {
|
||||
headers["Accept-Language"] = "\(lang)-\(country),\(lang);q=0.5"
|
||||
} else {
|
||||
headers["Accept-Language"] = "\(lang);q=0.5"
|
||||
}
|
||||
request.addValue(headers["Accept-Language"]!, forHTTPHeaderField: "Accept-Language")
|
||||
}
|
||||
}
|
||||
|
||||
public func getRequestDataAsJson(_ data: JSValue) throws -> Data? {
|
||||
// We need to check if the JSON is valid before attempting to serialize, as JSONSerialization.data will not throw an exception that can be caught, and will cause the application to crash if it fails.
|
||||
if JSONSerialization.isValidJSONObject(data) {
|
||||
return try JSONSerialization.data(withJSONObject: data)
|
||||
} else {
|
||||
throw CapacitorUrlRequest.CapacitorUrlRequestError.serializationError("[ data ] argument for request of content-type [ application/json ] must be serializable to JSON")
|
||||
}
|
||||
}
|
||||
|
||||
public func getRequestDataAsFormUrlEncoded(_ data: JSValue) throws -> Data? {
|
||||
guard var components = URLComponents(url: request.url!, resolvingAgainstBaseURL: false) else { return nil }
|
||||
components.queryItems = []
|
||||
|
||||
guard let obj = data as? JSObject else {
|
||||
// Throw, other data types explicitly not supported
|
||||
throw CapacitorUrlRequestError.serializationError("[ data ] argument for request with content-type [ multipart/form-data ] may only be a plain javascript object")
|
||||
}
|
||||
|
||||
let allowed = CharacterSet(charactersIn: "-._*").union(.alphanumerics)
|
||||
|
||||
obj.keys.forEach { (key: String) in
|
||||
let value = obj[key] as? String ?? ""
|
||||
components.queryItems?.append(URLQueryItem(name: key.addingPercentEncoding(withAllowedCharacters: allowed)?.replacingOccurrences(of: "%20", with: "+") ?? key, value: value.addingPercentEncoding(withAllowedCharacters: allowed)?.replacingOccurrences(of: "%20", with: "+")))
|
||||
}
|
||||
|
||||
if components.query != nil {
|
||||
return Data(components.query!.utf8)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
public func getRequestDataAsMultipartFormData(_ data: JSValue, _ contentType: String) throws -> Data {
|
||||
guard let obj = data as? JSObject else {
|
||||
// Throw, other data types explicitly not supported.
|
||||
throw CapacitorUrlRequestError.serializationError("[ data ] argument for request with content-type [ application/x-www-form-urlencoded ] may only be a plain javascript object")
|
||||
}
|
||||
|
||||
let strings: [String: String] = obj.compactMapValues { any in
|
||||
any as? String
|
||||
}
|
||||
|
||||
var data = Data()
|
||||
var boundary = UUID().uuidString
|
||||
if contentType.contains("="), let contentBoundary = contentType.components(separatedBy: "=").last {
|
||||
boundary = contentBoundary
|
||||
} else {
|
||||
overrideContentType(boundary)
|
||||
}
|
||||
strings.forEach { key, value in
|
||||
data.append("\r\n--\(boundary)\r\n".data(using: .utf8)!)
|
||||
data.append("Content-Disposition: form-data; name=\"\(key)\"\r\n\r\n".data(using: .utf8)!)
|
||||
data.append(value.data(using: .utf8)!)
|
||||
}
|
||||
data.append("\r\n--\(boundary)--\r\n".data(using: .utf8)!)
|
||||
|
||||
return data
|
||||
}
|
||||
|
||||
private func overrideContentType(_ boundary: String) {
|
||||
let contentType = "multipart/form-data; boundary=\(boundary)"
|
||||
request.setValue(contentType, forHTTPHeaderField: "Content-Type")
|
||||
headers["Content-Type"] = contentType
|
||||
}
|
||||
|
||||
public func getRequestDataAsString(_ data: JSValue) throws -> Data {
|
||||
guard let stringData = data as? String else {
|
||||
throw CapacitorUrlRequestError.serializationError("[ data ] argument could not be parsed as string")
|
||||
}
|
||||
return Data(stringData.utf8)
|
||||
}
|
||||
|
||||
public func getRequestHeader(_ index: String) -> Any? {
|
||||
var normalized = [:] as [String: Any]
|
||||
self.headers.keys.forEach { (key: String) in
|
||||
normalized[key.lowercased()] = self.headers[key]
|
||||
}
|
||||
|
||||
return normalized[index.lowercased()]
|
||||
}
|
||||
|
||||
public func getRequestDataFromFormData(_ data: JSValue, _ contentType: String) throws -> Data? {
|
||||
guard let list = data as? JSArray else {
|
||||
// Throw, other data types explicitly not supported.
|
||||
throw CapacitorUrlRequestError.serializationError("Data must be an array for FormData")
|
||||
}
|
||||
var data = Data()
|
||||
var boundary = UUID().uuidString
|
||||
if contentType.contains("="), let contentBoundary = contentType.components(separatedBy: "=").last {
|
||||
boundary = contentBoundary
|
||||
} else {
|
||||
overrideContentType(boundary)
|
||||
}
|
||||
for entry in list {
|
||||
guard let item = entry as? [String: String] else {
|
||||
throw CapacitorUrlRequestError.serializationError("Data must be an array for FormData")
|
||||
}
|
||||
|
||||
let type = item["type"]
|
||||
let key = item["key"]
|
||||
let value = item["value"]!
|
||||
|
||||
if type == "base64File" {
|
||||
let fileName = item["fileName"]
|
||||
let fileContentType = item["contentType"]
|
||||
|
||||
data.append("--\(boundary)\r\n".data(using: .utf8)!)
|
||||
data.append("Content-Disposition: form-data; name=\"\(key!)\"; filename=\"\(fileName!)\"\r\n".data(using: .utf8)!)
|
||||
data.append("Content-Type: \(fileContentType!)\r\n".data(using: .utf8)!)
|
||||
data.append("Content-Transfer-Encoding: binary\r\n".data(using: .utf8)!)
|
||||
data.append("\r\n".data(using: .utf8)!)
|
||||
|
||||
data.append(Data(base64Encoded: value)!)
|
||||
|
||||
data.append("\r\n".data(using: .utf8)!)
|
||||
} else if type == "string" {
|
||||
data.append("--\(boundary)\r\n".data(using: .utf8)!)
|
||||
data.append("Content-Disposition: form-data; name=\"\(key!)\"\r\n".data(using: .utf8)!)
|
||||
data.append("\r\n".data(using: .utf8)!)
|
||||
data.append(value.data(using: .utf8)!)
|
||||
data.append("\r\n".data(using: .utf8)!)
|
||||
}
|
||||
}
|
||||
data.append("--\(boundary)--\r\n".data(using: .utf8)!)
|
||||
|
||||
return data
|
||||
}
|
||||
|
||||
public func getRequestData(_ body: JSValue, _ contentType: String, _ dataType: String? = nil) throws -> Data? {
|
||||
if dataType == "file" {
|
||||
guard let stringData = body as? String else {
|
||||
throw CapacitorUrlRequestError.serializationError("[ data ] argument could not be parsed as string")
|
||||
}
|
||||
return Data(base64Encoded: stringData)
|
||||
} else if dataType == "formData" {
|
||||
return try getRequestDataFromFormData(body, contentType)
|
||||
}
|
||||
|
||||
// If data can be parsed directly as a string, return that without processing.
|
||||
if let strVal = try? getRequestDataAsString(body) {
|
||||
return strVal
|
||||
} else if contentType.contains("application/json") {
|
||||
return try getRequestDataAsJson(body)
|
||||
} else if contentType.contains("application/x-www-form-urlencoded") {
|
||||
return try getRequestDataAsFormUrlEncoded(body)
|
||||
} else if contentType.contains("multipart/form-data") {
|
||||
return try getRequestDataAsMultipartFormData(body, contentType)
|
||||
} else {
|
||||
throw CapacitorUrlRequestError.serializationError("[ data ] argument could not be parsed for content type [ \(contentType) ]")
|
||||
}
|
||||
}
|
||||
|
||||
@available(*, deprecated, message: "Use newer function with passed headers of type [String: Any]")
|
||||
public func setRequestHeaders(_ headers: [String: String]) {
|
||||
headers.keys.forEach { (key: String) in
|
||||
let value = headers[key]
|
||||
request.addValue(value!, forHTTPHeaderField: key)
|
||||
self.headers[key] = value
|
||||
}
|
||||
}
|
||||
|
||||
public func setRequestHeaders(_ headers: [String: Any]) {
|
||||
headers.keys.forEach { (key: String) in
|
||||
let value = headers[key]
|
||||
request.setValue("\(value!)", forHTTPHeaderField: key)
|
||||
self.headers[key] = "\(value!)"
|
||||
}
|
||||
}
|
||||
|
||||
public func setRequestBody(_ body: JSValue, _ dataType: String? = nil) throws {
|
||||
let contentType = self.getRequestHeader("Content-Type") as? String
|
||||
|
||||
if contentType != nil {
|
||||
request.httpBody = try getRequestData(body, contentType!, dataType)
|
||||
}
|
||||
}
|
||||
|
||||
public func setContentType(_ data: String?) {
|
||||
request.setValue(data, forHTTPHeaderField: "Content-Type")
|
||||
}
|
||||
|
||||
public func setTimeout(_ timeout: TimeInterval) {
|
||||
request.timeoutInterval = timeout
|
||||
}
|
||||
|
||||
public func getUrlRequest() -> URLRequest {
|
||||
return request
|
||||
}
|
||||
|
||||
open func urlSession(_ session: URLSession, task: URLSessionTask, willPerformHTTPRedirection response: HTTPURLResponse, newRequest request: URLRequest, completionHandler: @escaping (URLRequest?) -> Void) {
|
||||
completionHandler(nil)
|
||||
}
|
||||
|
||||
open func getUrlSession(_ call: CAPPluginCall) -> URLSession {
|
||||
let disableRedirects = call.getBool("disableRedirects") ?? false
|
||||
if !disableRedirects {
|
||||
return URLSession.shared
|
||||
}
|
||||
return URLSession(configuration: URLSessionConfiguration.default, delegate: self, delegateQueue: nil)
|
||||
}
|
||||
}
|
||||
16
node_modules/@capacitor/ios/Capacitor/Capacitor/Plugins/Console.swift
generated
vendored
Normal file
16
node_modules/@capacitor/ios/Capacitor/Capacitor/Plugins/Console.swift
generated
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
import Foundation
|
||||
|
||||
@objc(CAPConsolePlugin)
|
||||
public class CAPConsolePlugin: CAPPlugin, CAPBridgedPlugin {
|
||||
public let identifier = "CAPConsolePlugin"
|
||||
public let jsName = "Console"
|
||||
public let pluginMethods: [CAPPluginMethod] = [
|
||||
CAPPluginMethod(name: "log", returnType: CAPPluginReturnNone)
|
||||
]
|
||||
|
||||
@objc public func log(_ call: CAPPluginCall) {
|
||||
let message = call.getString("message") ?? ""
|
||||
let level = call.getString("level") ?? "log"
|
||||
CAPLog.print("⚡️ [\(level)] - \(message)")
|
||||
}
|
||||
}
|
||||
236
node_modules/@capacitor/ios/Capacitor/Capacitor/Plugins/HttpRequestHandler.swift
generated
vendored
Normal file
236
node_modules/@capacitor/ios/Capacitor/Capacitor/Plugins/HttpRequestHandler.swift
generated
vendored
Normal file
@@ -0,0 +1,236 @@
|
||||
import Foundation
|
||||
|
||||
/// See https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/responseType
|
||||
public enum ResponseType: String {
|
||||
case arrayBuffer = "arraybuffer"
|
||||
case blob = "blob"
|
||||
case document = "document"
|
||||
case json = "json"
|
||||
case text = "text"
|
||||
|
||||
public static let `default`: ResponseType = .text
|
||||
|
||||
public init(string: String?) {
|
||||
guard let string = string else {
|
||||
self = .default
|
||||
return
|
||||
}
|
||||
|
||||
guard let responseType = ResponseType(rawValue: string.lowercased()) else {
|
||||
self = .default
|
||||
return
|
||||
}
|
||||
|
||||
self = responseType
|
||||
}
|
||||
}
|
||||
|
||||
/// Helper that safely parses JSON Data. Otherwise returns an error (without throwing)
|
||||
/// - Parameters:
|
||||
/// - data: The JSON Data to parse
|
||||
/// - Returns: The parsed value or an error
|
||||
func tryParseJson(_ data: Data) -> Any {
|
||||
do {
|
||||
return try JSONSerialization.jsonObject(with: data, options: [.mutableContainers, .fragmentsAllowed])
|
||||
} catch {
|
||||
return error.localizedDescription
|
||||
}
|
||||
}
|
||||
|
||||
/// Helper to convert the headers dictionary to lower case keys. This allows case-insensitive querying in the bridge javascript.
|
||||
/// - Parameters:
|
||||
/// - headers: The headers as dictionary. The type is unspecific because the incoming headers are coming from the
|
||||
/// allHeaderFields property of the HttpResponse.
|
||||
/// - Returns: The modified headers dictionary with lowercase keys
|
||||
private func lowerCaseHeaderDictionary(_ headers: [AnyHashable: Any]) -> [String: Any] {
|
||||
// Lowercases the key of the headers dictionary.
|
||||
return Dictionary(uniqueKeysWithValues: headers.map({ (key: AnyHashable, value: Any) in
|
||||
return (String(describing: key).lowercased(), value)
|
||||
}))
|
||||
}
|
||||
|
||||
open class HttpRequestHandler {
|
||||
open class CapacitorHttpRequestBuilder {
|
||||
public var url: URL?
|
||||
public var method: String?
|
||||
public var params: [String: String]?
|
||||
open var request: CapacitorUrlRequest?
|
||||
|
||||
public init() { }
|
||||
|
||||
/// Set the URL of the HttpRequest
|
||||
/// - Throws: an error of URLError if the urlString cannot be parsed
|
||||
/// - Parameters:
|
||||
/// - urlString: The URL value to parse
|
||||
/// - Returns: self to continue chaining functions
|
||||
public func setUrl(_ urlString: String) throws -> CapacitorHttpRequestBuilder {
|
||||
guard let url = URL(string: urlString) else {
|
||||
throw URLError(.badURL)
|
||||
}
|
||||
self.url = url
|
||||
return self
|
||||
}
|
||||
|
||||
public func setMethod(_ method: String) -> CapacitorHttpRequestBuilder {
|
||||
self.method = method
|
||||
return self
|
||||
}
|
||||
|
||||
public func setUrlParams(_ params: [String: Any], _ shouldEncodeUrlParams: Bool = true) -> CapacitorHttpRequestBuilder {
|
||||
if params.count != 0 {
|
||||
// swiftlint:disable force_cast
|
||||
var cmps = URLComponents(url: url!, resolvingAgainstBaseURL: true)
|
||||
if cmps?.queryItems == nil {
|
||||
cmps?.queryItems = []
|
||||
}
|
||||
|
||||
if shouldEncodeUrlParams {
|
||||
var urlSafeParams: [URLQueryItem] = []
|
||||
for (key, value) in params {
|
||||
if let arr = value as? [String] {
|
||||
arr.forEach { str in
|
||||
urlSafeParams.append(URLQueryItem(name: key, value: str))
|
||||
}
|
||||
} else {
|
||||
urlSafeParams.append(URLQueryItem(name: key, value: (value as! String)))
|
||||
}
|
||||
}
|
||||
cmps!.queryItems?.append(contentsOf: urlSafeParams)
|
||||
} else {
|
||||
cmps?.query = params.flatMap { key, value -> [String] in
|
||||
if let arrayValue = value as? [String] {
|
||||
return arrayValue.map { "\(key)=\($0)" }
|
||||
} else {
|
||||
return ["\(key)=\(value)"]
|
||||
}
|
||||
}.joined(separator: "&")
|
||||
}
|
||||
url = cmps!.url!
|
||||
}
|
||||
return self
|
||||
}
|
||||
|
||||
open func openConnection() -> CapacitorHttpRequestBuilder {
|
||||
request = CapacitorUrlRequest(url!, method: method!)
|
||||
return self
|
||||
}
|
||||
|
||||
public func build() -> CapacitorUrlRequest {
|
||||
return request!
|
||||
}
|
||||
}
|
||||
|
||||
public static func setCookiesFromResponse(_ response: HTTPURLResponse, _ config: InstanceConfiguration?) {
|
||||
let headers = response.allHeaderFields
|
||||
if let cookies = headers["Set-Cookie"] as? String {
|
||||
for cookie in cookies.components(separatedBy: ",") {
|
||||
let domainComponents = cookie.lowercased().components(separatedBy: "domain=")
|
||||
if domainComponents.count > 1 {
|
||||
CapacitorCookieManager(config).setCookie(
|
||||
domainComponents[1].components(separatedBy: ";")[0],
|
||||
cookie
|
||||
)
|
||||
} else {
|
||||
CapacitorCookieManager(config).setCookie("", cookie)
|
||||
}
|
||||
}
|
||||
}
|
||||
CapacitorCookieManager(config).syncCookiesToWebView()
|
||||
}
|
||||
|
||||
public static func buildResponse(_ data: Data?, _ response: HTTPURLResponse, responseType: ResponseType = .default) -> [String: Any] {
|
||||
var output = [:] as [String: Any]
|
||||
|
||||
output["status"] = response.statusCode
|
||||
|
||||
// HTTP Headers are case insensitive. The allHeaderFields dictionary returned by Apple Foundation Code has its keys capitalized.
|
||||
// According to the documentation at https://developer.apple.com/documentation/foundation/httpurlresponse/1417930-allheaderfields
|
||||
// "HTTP headers are case insensitive. To simplify your code, URL Loading System canonicalizes certain header field names into
|
||||
// their standard form. For example, if the server sends a content-length header, it’s automatically adjusted to be Content-Length."
|
||||
// To handle the case insevitivy, we are converting the header keys to lower case here. When querying for headers in the native bridge,
|
||||
// we are lowercasing the key as well.
|
||||
output["headers"] = lowerCaseHeaderDictionary(response.allHeaderFields)
|
||||
output["url"] = response.url?.absoluteString
|
||||
|
||||
guard let data = data else {
|
||||
output["data"] = ""
|
||||
return output
|
||||
}
|
||||
|
||||
let contentType = (response.allHeaderFields["Content-Type"] as? String ?? "application/default").lowercased()
|
||||
|
||||
if contentType.contains("application/json") || responseType == .json {
|
||||
output["data"] = tryParseJson(data)
|
||||
} else if responseType == .arrayBuffer || responseType == .blob {
|
||||
output["data"] = data.base64EncodedString()
|
||||
} else if responseType == .document || responseType == .text || responseType == .default {
|
||||
output["data"] = String(data: data, encoding: .utf8)
|
||||
}
|
||||
|
||||
return output
|
||||
}
|
||||
|
||||
public static func request(_ call: CAPPluginCall, _ httpMethod: String?, _ config: InstanceConfiguration?) throws {
|
||||
guard var urlString = call.getString("url") else { throw URLError(.badURL) }
|
||||
let method = httpMethod ?? call.getString("method", "GET")
|
||||
|
||||
var headers = (call.getObject("headers") ?? [:]) as [String: Any]
|
||||
let params = (call.getObject("params") ?? [:]) as [String: Any]
|
||||
let responseType = call.getString("responseType") ?? "text"
|
||||
let connectTimeout = call.getDouble("connectTimeout")
|
||||
let shouldEncodeUrlParams = call.getBool("shouldEncodeUrlParams", true)
|
||||
let readTimeout = call.getDouble("readTimeout")
|
||||
let dataType = call.getString("dataType") ?? "any"
|
||||
|
||||
if urlString == urlString.removingPercentEncoding {
|
||||
guard let encodedUrlString = urlString.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) else { throw URLError(.badURL) }
|
||||
urlString = encodedUrlString
|
||||
}
|
||||
|
||||
let request = try CapacitorHttpRequestBuilder()
|
||||
.setUrl(urlString)
|
||||
.setMethod(method)
|
||||
.setUrlParams(params, shouldEncodeUrlParams)
|
||||
.openConnection()
|
||||
.build()
|
||||
|
||||
if let userAgentString = config?.overridenUserAgentString, headers["User-Agent"] == nil, headers["user-agent"] == nil {
|
||||
headers["User-Agent"] = userAgentString
|
||||
}
|
||||
|
||||
request.setRequestHeaders(headers)
|
||||
|
||||
// Timeouts in iOS are in seconds. So read the value in millis and divide by 1000
|
||||
let timeout = (connectTimeout ?? readTimeout ?? 600000.0) / 1000.0
|
||||
request.setTimeout(timeout)
|
||||
|
||||
if let data = call.options["data"] as? JSValue {
|
||||
do {
|
||||
try request.setRequestBody(data, dataType)
|
||||
} catch {
|
||||
// Explicitly reject if the http request body was not set successfully,
|
||||
// so as to not send a known malformed request, and to provide the developer with additional context.
|
||||
call.reject(error.localizedDescription, (error as NSError).domain, error, nil)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
let urlRequest = request.getUrlRequest()
|
||||
let urlSession = request.getUrlSession(call)
|
||||
let task = urlSession.dataTask(with: urlRequest) { (data, response, error) in
|
||||
urlSession.invalidateAndCancel()
|
||||
|
||||
if let error = error {
|
||||
call.reject(error.localizedDescription, (error as NSError).domain, error, nil)
|
||||
return
|
||||
}
|
||||
|
||||
setCookiesFromResponse(response as! HTTPURLResponse, config)
|
||||
|
||||
let type = ResponseType(rawValue: responseType) ?? .default
|
||||
call.resolve(self.buildResponse(data, response as! HTTPURLResponse, responseType: type))
|
||||
}
|
||||
|
||||
task.resume()
|
||||
}
|
||||
}
|
||||
44
node_modules/@capacitor/ios/Capacitor/Capacitor/Plugins/WebView.swift
generated
vendored
Normal file
44
node_modules/@capacitor/ios/Capacitor/Capacitor/Plugins/WebView.swift
generated
vendored
Normal file
@@ -0,0 +1,44 @@
|
||||
import Foundation
|
||||
|
||||
@objc(CAPWebViewPlugin)
|
||||
public class CAPWebViewPlugin: CAPPlugin, CAPBridgedPlugin {
|
||||
public let identifier = "CAPWebViewPlugin"
|
||||
public let jsName = "WebView"
|
||||
public let pluginMethods: [CAPPluginMethod] = [
|
||||
CAPPluginMethod(name: "setServerAssetPath", returnType: CAPPluginReturnPromise),
|
||||
CAPPluginMethod(name: "setServerBasePath", returnType: CAPPluginReturnPromise),
|
||||
CAPPluginMethod(name: "getServerBasePath", returnType: CAPPluginReturnPromise),
|
||||
CAPPluginMethod(name: "persistServerBasePath", returnType: CAPPluginReturnPromise)
|
||||
]
|
||||
|
||||
@objc func setServerAssetPath(_ call: CAPPluginCall) {
|
||||
if let path = call.getString("path"), let viewController = bridge?.viewController as? CAPBridgeViewController {
|
||||
viewController.setServerBasePath(path: Bundle.main.url(forResource: path, withExtension: nil)?.path ?? path)
|
||||
call.resolve()
|
||||
}
|
||||
}
|
||||
|
||||
@objc func setServerBasePath(_ call: CAPPluginCall) {
|
||||
if let path = call.getString("path"), let viewController = bridge?.viewController as? CAPBridgeViewController {
|
||||
viewController.setServerBasePath(path: path)
|
||||
call.resolve()
|
||||
}
|
||||
}
|
||||
|
||||
@objc func getServerBasePath(_ call: CAPPluginCall) {
|
||||
if let viewController = bridge?.viewController as? CAPBridgeViewController {
|
||||
let path = viewController.getServerBasePath()
|
||||
call.resolve([
|
||||
"path": path
|
||||
])
|
||||
}
|
||||
}
|
||||
|
||||
@objc func persistServerBasePath(_ call: CAPPluginCall) {
|
||||
if let viewController = bridge?.viewController as? CAPBridgeViewController {
|
||||
let path = viewController.getServerBasePath()
|
||||
KeyValueStore.standard["serverBasePath"] = path
|
||||
call.resolve()
|
||||
}
|
||||
}
|
||||
}
|
||||
14
node_modules/@capacitor/ios/Capacitor/Capacitor/PrivacyInfo.xcprivacy
generated
vendored
Normal file
14
node_modules/@capacitor/ios/Capacitor/Capacitor/PrivacyInfo.xcprivacy
generated
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>NSPrivacyAccessedAPITypes</key>
|
||||
<array/>
|
||||
<key>NSPrivacyCollectedDataTypes</key>
|
||||
<array/>
|
||||
<key>NSPrivacyTrackingDomains</key>
|
||||
<array/>
|
||||
<key>NSPrivacyTracking</key>
|
||||
<false/>
|
||||
</dict>
|
||||
</plist>
|
||||
29
node_modules/@capacitor/ios/Capacitor/Capacitor/Router.swift
generated
vendored
Normal file
29
node_modules/@capacitor/ios/Capacitor/Capacitor/Router.swift
generated
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
//
|
||||
// Router.swift
|
||||
// Capacitor
|
||||
//
|
||||
// Created by Steven Sherry on 3/29/22.
|
||||
// Copyright © 2022 Drifty Co. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
public protocol Router {
|
||||
func route(for path: String) -> String
|
||||
var basePath: String { get set }
|
||||
}
|
||||
|
||||
public struct CapacitorRouter: Router {
|
||||
public init() {}
|
||||
public var basePath: String = ""
|
||||
public func route(for path: String) -> String {
|
||||
let pathUrl = URL(fileURLWithPath: path)
|
||||
|
||||
// If there's no path extension it also means the path is empty or a SPA route
|
||||
if pathUrl.pathExtension.isEmpty {
|
||||
return basePath + "/index.html"
|
||||
}
|
||||
|
||||
return basePath + path
|
||||
}
|
||||
}
|
||||
8
node_modules/@capacitor/ios/Capacitor/Capacitor/TmpViewController.swift
generated
vendored
Normal file
8
node_modules/@capacitor/ios/Capacitor/Capacitor/TmpViewController.swift
generated
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
import UIKit
|
||||
|
||||
internal class TmpViewController: UIViewController {
|
||||
override func viewDidAppear(_ animated: Bool) {
|
||||
super.viewDidAppear(animated)
|
||||
NotificationCenter.default.post(CapacitorBridge.tmpVCAppeared)
|
||||
}
|
||||
}
|
||||
55
node_modules/@capacitor/ios/Capacitor/Capacitor/UIColor.swift
generated
vendored
Normal file
55
node_modules/@capacitor/ios/Capacitor/Capacitor/UIColor.swift
generated
vendored
Normal file
@@ -0,0 +1,55 @@
|
||||
extension UIColor: CapacitorExtension {}
|
||||
public extension CapacitorExtensionTypeWrapper where T: UIColor {
|
||||
// disable linting for the short variable names, since that's the point of the method
|
||||
// swiftlint:disable:next identifier_name
|
||||
static func color(r: Int, g: Int, b: Int, a: Int = 0xFF) -> UIColor {
|
||||
return T(
|
||||
red: CGFloat(r) / 255.0,
|
||||
green: CGFloat(g) / 255.0,
|
||||
blue: CGFloat(b) / 255.0,
|
||||
alpha: CGFloat(a) / 255.0
|
||||
)
|
||||
}
|
||||
|
||||
static func color(argb: UInt32) -> UIColor {
|
||||
return T(
|
||||
red: CGFloat((argb >> 16) & 0xFF),
|
||||
green: CGFloat((argb >> 8) & 0xFF),
|
||||
blue: CGFloat(argb & 0xFF),
|
||||
alpha: CGFloat((argb >> 24) & 0xFF)
|
||||
)
|
||||
}
|
||||
|
||||
static func color(fromHex: String) -> UIColor? {
|
||||
let hexString = fromHex.trimmingCharacters(in: .whitespacesAndNewlines).replacingOccurrences(
|
||||
of: "#",
|
||||
with: ""
|
||||
)
|
||||
|
||||
var argb: UInt64 = 0
|
||||
|
||||
var red: CGFloat = 0.0
|
||||
var green: CGFloat = 0.0
|
||||
var blue: CGFloat = 0.0
|
||||
var alpha: CGFloat = 1.0
|
||||
|
||||
guard Scanner(string: hexString).scanHexInt64(&argb) else { return nil }
|
||||
|
||||
if hexString.count == 6 {
|
||||
red = CGFloat((argb & 0xFF0000) >> 16) / 255.0
|
||||
green = CGFloat((argb & 0x00FF00) >> 8) / 255.0
|
||||
blue = CGFloat(argb & 0x0000FF) / 255.0
|
||||
|
||||
} else if hexString.count == 8 {
|
||||
red = CGFloat((argb & 0xFF00_0000) >> 24) / 255.0
|
||||
green = CGFloat((argb & 0x00FF0000) >> 16) / 255.0
|
||||
blue = CGFloat((argb & 0x0000FF00) >> 8) / 255.0
|
||||
alpha = CGFloat(argb & 0x000000FF) / 255.0
|
||||
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
|
||||
return T(red: red, green: green, blue: blue, alpha: alpha)
|
||||
}
|
||||
}
|
||||
37
node_modules/@capacitor/ios/Capacitor/Capacitor/UIStatusBarManager+CAPHandleTapAction.m
generated
vendored
Normal file
37
node_modules/@capacitor/ios/Capacitor/Capacitor/UIStatusBarManager+CAPHandleTapAction.m
generated
vendored
Normal file
@@ -0,0 +1,37 @@
|
||||
#import <Capacitor/Capacitor-Swift.h>
|
||||
#import <objc/message.h>
|
||||
#import <objc/runtime.h>
|
||||
|
||||
@implementation UIStatusBarManager (CAPHandleTapAction)
|
||||
|
||||
+ (void)load {
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
Class class = [self class];
|
||||
SEL originalSelector = NSSelectorFromString(@"handleTapAction:");
|
||||
SEL swizzledSelector = @selector(nofity_handleTapAction:);
|
||||
|
||||
Method originalMethod = class_getInstanceMethod(class, originalSelector);
|
||||
Method swizzledMethod = class_getInstanceMethod(class, swizzledSelector);
|
||||
|
||||
BOOL didAddMethod = class_addMethod(class,
|
||||
originalSelector,
|
||||
method_getImplementation(swizzledMethod),
|
||||
method_getTypeEncoding(swizzledMethod));
|
||||
if (didAddMethod) {
|
||||
class_replaceMethod(class,
|
||||
swizzledSelector,
|
||||
method_getImplementation(originalMethod),
|
||||
method_getTypeEncoding(originalMethod));
|
||||
} else {
|
||||
method_exchangeImplementations(originalMethod, swizzledMethod);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
-(void)nofity_handleTapAction:(id)arg1 {
|
||||
[[NSNotificationCenter defaultCenter] postNotification:[NSNotification notificationWithName:NSNotification.capacitorStatusBarTapped object:nil]];
|
||||
[self nofity_handleTapAction:arg1];
|
||||
}
|
||||
|
||||
@end
|
||||
15
node_modules/@capacitor/ios/Capacitor/Capacitor/WKWebView+Capacitor.m
generated
vendored
Normal file
15
node_modules/@capacitor/ios/Capacitor/Capacitor/WKWebView+Capacitor.m
generated
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
#import <objc/runtime.h>
|
||||
#import <Capacitor/Capacitor-Swift.h>
|
||||
|
||||
// Swift extensions marked as @objc and internal are available to the runtime but won't be found at compile time
|
||||
// so we need this declaration to avoid compiler complaints.
|
||||
@interface WKWebView (InternalSwiftExtension)
|
||||
+ (void)_swizzleKeyboardMethods;
|
||||
@end
|
||||
|
||||
// +load is the safest place to swizzle methods but that won't work from a swift extension so we need this wrapper.
|
||||
@implementation WKWebView (CapacitorAutoFocus)
|
||||
+ (void)load {
|
||||
[self _swizzleKeyboardMethods];
|
||||
}
|
||||
@end
|
||||
81
node_modules/@capacitor/ios/Capacitor/Capacitor/WKWebView+Capacitor.swift
generated
vendored
Normal file
81
node_modules/@capacitor/ios/Capacitor/Capacitor/WKWebView+Capacitor.swift
generated
vendored
Normal file
@@ -0,0 +1,81 @@
|
||||
import Foundation
|
||||
import WebKit
|
||||
|
||||
extension WKWebView: CapacitorExtension {}
|
||||
public extension CapacitorExtensionTypeWrapper where T == WKWebView {
|
||||
var keyboardShouldRequireUserInteraction: Bool? {
|
||||
return (self.baseType.associatedKeyboardFlagValue as? NSNumber)?.boolValue
|
||||
}
|
||||
|
||||
// the readonly nature of the wrapper extension means we can't use a computed property with a setter
|
||||
func setKeyboardShouldRequireUserInteraction(_ flag: Bool? = nil) {
|
||||
if let flag = flag {
|
||||
self.baseType.associatedKeyboardFlagValue = NSNumber(value: flag)
|
||||
} else {
|
||||
self.baseType.associatedKeyboardFlagValue = nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private var associatedKeyboardFlagHandle: UInt8 = 0
|
||||
|
||||
internal extension WKWebView {
|
||||
// Our lazy property can't be represented in Obj-C so we need this simple wrapper.
|
||||
// swiftlint:disable identifier_name
|
||||
@objc static func _swizzleKeyboardMethods() {
|
||||
_ = oneTimeOnlySwizzle
|
||||
}
|
||||
|
||||
typealias FiveArgClosureType = @convention(c) (Any, Selector, UnsafeRawPointer, Bool, Bool, Bool, Any?) -> Void
|
||||
|
||||
// dispatch_once isn't available in Swift, but lazy properties use the same mechanism under the hood so
|
||||
// we can safely assume that this block of code will only execute once.
|
||||
static let oneTimeOnlySwizzle: () = {
|
||||
let frameworkName = "WK"
|
||||
let className = "ContentView"
|
||||
guard let targetClass = NSClassFromString(frameworkName + className) else {
|
||||
return
|
||||
}
|
||||
|
||||
let containingWebView = { (object: Any?) -> WKWebView? in
|
||||
var view = object as? UIView
|
||||
while view != nil {
|
||||
if let webview = view as? WKWebView {
|
||||
return webview
|
||||
}
|
||||
view = view?.superview
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
let swizzleFiveArgClosure = { (method: Method, selector: Selector) in
|
||||
let originalImp: IMP = method_getImplementation(method)
|
||||
let original: FiveArgClosureType = unsafeBitCast(originalImp, to: FiveArgClosureType.self)
|
||||
let block: @convention(block) (Any, UnsafeRawPointer, Bool, Bool, Bool, Any?) -> Void = { (me, arg0, arg1, arg2, arg3, arg4) in
|
||||
if let webview = containingWebView(me), let flag = webview.capacitor.keyboardShouldRequireUserInteraction {
|
||||
original(me, selector, arg0, !flag, arg2, arg3, arg4)
|
||||
} else {
|
||||
original(me, selector, arg0, arg1, arg2, arg3, arg4)
|
||||
}
|
||||
}
|
||||
let imp: IMP = imp_implementationWithBlock(block)
|
||||
method_setImplementation(method, imp)
|
||||
}
|
||||
|
||||
// iOS 13+
|
||||
let selectorMkIV: Selector = sel_getUid("_elementDidFocus:userIsInteracting:blurPreviousNode:activityStateChanges:userObject:")
|
||||
|
||||
if let method = class_getInstanceMethod(targetClass, selectorMkIV) {
|
||||
swizzleFiveArgClosure(method, selectorMkIV)
|
||||
}
|
||||
}()
|
||||
|
||||
var associatedKeyboardFlagValue: Any? {
|
||||
get {
|
||||
return objc_getAssociatedObject(self, &associatedKeyboardFlagHandle)
|
||||
}
|
||||
set {
|
||||
objc_setAssociatedObject(self, &associatedKeyboardFlagHandle, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
|
||||
}
|
||||
}
|
||||
}
|
||||
550
node_modules/@capacitor/ios/Capacitor/Capacitor/WebViewAssetHandler.swift
generated
vendored
Normal file
550
node_modules/@capacitor/ios/Capacitor/Capacitor/WebViewAssetHandler.swift
generated
vendored
Normal file
@@ -0,0 +1,550 @@
|
||||
import Foundation
|
||||
import MobileCoreServices
|
||||
|
||||
@objc(CAPWebViewAssetHandler)
|
||||
// swiftlint:disable type_body_length
|
||||
open class WebViewAssetHandler: NSObject, WKURLSchemeHandler {
|
||||
private var router: Router
|
||||
private var serverUrl: URL?
|
||||
|
||||
public init(router: Router) {
|
||||
self.router = router
|
||||
super.init()
|
||||
}
|
||||
|
||||
open func setAssetPath(_ assetPath: String) {
|
||||
router.basePath = assetPath
|
||||
}
|
||||
|
||||
open func setServerUrl(_ serverUrl: URL?) {
|
||||
self.serverUrl = serverUrl
|
||||
}
|
||||
|
||||
private func isUsingLiveReload(_ localUrl: URL) -> Bool {
|
||||
return self.serverUrl != nil && self.serverUrl?.scheme != localUrl.scheme
|
||||
}
|
||||
|
||||
open func webView(_ webView: WKWebView, start urlSchemeTask: WKURLSchemeTask) {
|
||||
let startPath: String
|
||||
let url = urlSchemeTask.request.url!
|
||||
let stringToLoad = url.path
|
||||
let localUrl = URL.init(string: url.absoluteString)!
|
||||
|
||||
if url.path.starts(with: CapacitorBridge.httpInterceptorStartIdentifier) {
|
||||
handleCapacitorHttpRequest(urlSchemeTask, localUrl, false)
|
||||
return
|
||||
}
|
||||
|
||||
if stringToLoad.starts(with: CapacitorBridge.fileStartIdentifier) {
|
||||
startPath = stringToLoad.replacingOccurrences(of: CapacitorBridge.fileStartIdentifier, with: "")
|
||||
} else {
|
||||
startPath = router.route(for: stringToLoad)
|
||||
}
|
||||
|
||||
let fileUrl = URL.init(fileURLWithPath: startPath)
|
||||
|
||||
do {
|
||||
var data = Data()
|
||||
let mimeType = mimeTypeForExtension(pathExtension: url.pathExtension)
|
||||
var headers = [
|
||||
"Content-Type": mimeType,
|
||||
"Cache-Control": "no-cache"
|
||||
]
|
||||
|
||||
// if using live reload, then set CORS headers
|
||||
if isUsingLiveReload(localUrl) {
|
||||
headers["Access-Control-Allow-Origin"] = self.serverUrl?.absoluteString
|
||||
headers["Access-Control-Allow-Methods"] = "GET, HEAD, OPTIONS, TRACE"
|
||||
}
|
||||
|
||||
if let rangeString = urlSchemeTask.request.value(forHTTPHeaderField: "Range"),
|
||||
let totalSize = try fileUrl.resourceValues(forKeys: [.fileSizeKey]).fileSize {
|
||||
let fileHandle = try FileHandle(forReadingFrom: fileUrl)
|
||||
let parts = rangeString.components(separatedBy: "=")
|
||||
let streamParts = parts[1].components(separatedBy: "-")
|
||||
let fromRange = Int(streamParts[0]) ?? 0
|
||||
var toRange = totalSize - 1
|
||||
if streamParts.count > 1 {
|
||||
toRange = Int(streamParts[1]) ?? toRange
|
||||
}
|
||||
let rangeLength = toRange - fromRange + 1
|
||||
try fileHandle.seek(toOffset: UInt64(fromRange))
|
||||
data = fileHandle.readData(ofLength: rangeLength)
|
||||
headers["Accept-Ranges"] = "bytes"
|
||||
headers["Content-Range"] = "bytes \(fromRange)-\(toRange)/\(totalSize)"
|
||||
headers["Content-Length"] = String(data.count)
|
||||
let response = HTTPURLResponse(url: localUrl, statusCode: 206, httpVersion: nil, headerFields: headers)
|
||||
urlSchemeTask.didReceive(response!)
|
||||
try fileHandle.close()
|
||||
} else {
|
||||
if !stringToLoad.contains("cordova.js") {
|
||||
if isMediaExtension(pathExtension: url.pathExtension) {
|
||||
data = try Data(contentsOf: fileUrl, options: Data.ReadingOptions.mappedIfSafe)
|
||||
} else {
|
||||
data = try Data(contentsOf: fileUrl)
|
||||
}
|
||||
}
|
||||
let urlResponse = URLResponse(url: localUrl, mimeType: mimeType, expectedContentLength: data.count, textEncodingName: nil)
|
||||
let httpResponse = HTTPURLResponse(url: localUrl, statusCode: 200, httpVersion: nil, headerFields: headers)
|
||||
if isMediaExtension(pathExtension: url.pathExtension) {
|
||||
urlSchemeTask.didReceive(urlResponse)
|
||||
} else {
|
||||
urlSchemeTask.didReceive(httpResponse!)
|
||||
}
|
||||
}
|
||||
urlSchemeTask.didReceive(data)
|
||||
} catch let error as NSError {
|
||||
urlSchemeTask.didFailWithError(error)
|
||||
return
|
||||
}
|
||||
urlSchemeTask.didFinish()
|
||||
}
|
||||
|
||||
open func webView(_ webView: WKWebView, stop urlSchemeTask: WKURLSchemeTask) {
|
||||
urlSchemeTask.stopped = true
|
||||
}
|
||||
|
||||
open func mimeTypeForExtension(pathExtension: String) -> String {
|
||||
if !pathExtension.isEmpty {
|
||||
if let uti = UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, pathExtension as NSString, nil)?.takeRetainedValue() {
|
||||
if let mimetype = UTTypeCopyPreferredTagWithClass(uti, kUTTagClassMIMEType)?.takeRetainedValue() {
|
||||
return mimetype as String
|
||||
}
|
||||
}
|
||||
// TODO: Remove in the future if Apple fixes the issue
|
||||
if let mimeType = mimeTypes[pathExtension] {
|
||||
return mimeType
|
||||
}
|
||||
return "application/octet-stream"
|
||||
}
|
||||
return "text/html"
|
||||
}
|
||||
|
||||
open func isMediaExtension(pathExtension: String) -> Bool {
|
||||
let mediaExtensions = ["m4v", "mov", "mp4",
|
||||
"aac", "ac3", "aiff", "au", "flac", "m4a", "mp3", "wav"]
|
||||
if mediaExtensions.contains(pathExtension.lowercased()) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func handleCapacitorHttpRequest(_ urlSchemeTask: WKURLSchemeTask, _ localUrl: URL, _ isHttpsRequest: Bool) {
|
||||
var urlRequest = urlSchemeTask.request
|
||||
guard let url = urlRequest.url else { return }
|
||||
|
||||
let urlComponents = URLComponents(url: url, resolvingAgainstBaseURL: false)
|
||||
if let targetUrl = urlComponents?.queryItems?.first(where: { $0.name == CapacitorBridge.httpInterceptorUrlParam })?.value,
|
||||
!targetUrl.isEmpty {
|
||||
urlRequest.url = URL(string: targetUrl)
|
||||
}
|
||||
|
||||
let urlSession = URLSession.shared
|
||||
let task = urlSession.dataTask(with: urlRequest) { (data, response, error) in
|
||||
DispatchQueue.main.async {
|
||||
guard !urlSchemeTask.stopped else { return }
|
||||
if let error = error {
|
||||
urlSchemeTask.didFailWithError(error)
|
||||
return
|
||||
}
|
||||
|
||||
if let response = response as? HTTPURLResponse {
|
||||
let existingHeaders = response.allHeaderFields
|
||||
var newHeaders: [AnyHashable: Any] = [:]
|
||||
|
||||
// if using live reload, then set CORS headers
|
||||
if self.isUsingLiveReload(url) {
|
||||
newHeaders = [
|
||||
"Access-Control-Allow-Origin": self.serverUrl?.absoluteString ?? "",
|
||||
"Access-Control-Allow-Methods": "GET, HEAD, OPTIONS, TRACE"
|
||||
]
|
||||
}
|
||||
|
||||
if let mergedHeaders = existingHeaders.merging(newHeaders, uniquingKeysWith: { (_, newHeaders) in newHeaders }) as? [String: String] {
|
||||
|
||||
if let responseUrl = response.url {
|
||||
if let modifiedResponse = HTTPURLResponse(
|
||||
url: responseUrl,
|
||||
statusCode: response.statusCode,
|
||||
httpVersion: nil,
|
||||
headerFields: mergedHeaders
|
||||
) {
|
||||
urlSchemeTask.didReceive(modifiedResponse)
|
||||
}
|
||||
}
|
||||
|
||||
if let data = data {
|
||||
urlSchemeTask.didReceive(data)
|
||||
}
|
||||
}
|
||||
}
|
||||
urlSchemeTask.didFinish()
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
task.resume()
|
||||
}
|
||||
|
||||
public let mimeTypes = [
|
||||
"aaf": "application/octet-stream",
|
||||
"aca": "application/octet-stream",
|
||||
"accdb": "application/msaccess",
|
||||
"accde": "application/msaccess",
|
||||
"accdt": "application/msaccess",
|
||||
"acx": "application/internet-property-stream",
|
||||
"afm": "application/octet-stream",
|
||||
"ai": "application/postscript",
|
||||
"aif": "audio/x-aiff",
|
||||
"aifc": "audio/aiff",
|
||||
"aiff": "audio/aiff",
|
||||
"application": "application/x-ms-application",
|
||||
"art": "image/x-jg",
|
||||
"asd": "application/octet-stream",
|
||||
"asf": "video/x-ms-asf",
|
||||
"asi": "application/octet-stream",
|
||||
"asm": "text/plain",
|
||||
"asr": "video/x-ms-asf",
|
||||
"asx": "video/x-ms-asf",
|
||||
"atom": "application/atom+xml",
|
||||
"au": "audio/basic",
|
||||
"avi": "video/x-msvideo",
|
||||
"axs": "application/olescript",
|
||||
"bas": "text/plain",
|
||||
"bcpio": "application/x-bcpio",
|
||||
"bin": "application/octet-stream",
|
||||
"bmp": "image/bmp",
|
||||
"c": "text/plain",
|
||||
"cab": "application/octet-stream",
|
||||
"calx": "application/vnd.ms-office.calx",
|
||||
"cat": "application/vnd.ms-pki.seccat",
|
||||
"cdf": "application/x-cdf",
|
||||
"chm": "application/octet-stream",
|
||||
"class": "application/x-java-applet",
|
||||
"clp": "application/x-msclip",
|
||||
"cmx": "image/x-cmx",
|
||||
"cnf": "text/plain",
|
||||
"cod": "image/cis-cod",
|
||||
"cpio": "application/x-cpio",
|
||||
"cpp": "text/plain",
|
||||
"crd": "application/x-mscardfile",
|
||||
"crl": "application/pkix-crl",
|
||||
"crt": "application/x-x509-ca-cert",
|
||||
"csh": "application/x-csh",
|
||||
"css": "text/css",
|
||||
"csv": "application/octet-stream",
|
||||
"cur": "application/octet-stream",
|
||||
"dcr": "application/x-director",
|
||||
"deploy": "application/octet-stream",
|
||||
"der": "application/x-x509-ca-cert",
|
||||
"dib": "image/bmp",
|
||||
"dir": "application/x-director",
|
||||
"disco": "text/xml",
|
||||
"dll": "application/x-msdownload",
|
||||
"dll.config": "text/xml",
|
||||
"dlm": "text/dlm",
|
||||
"doc": "application/msword",
|
||||
"docm": "application/vnd.ms-word.document.macroEnabled.12",
|
||||
"docx": "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
|
||||
"dot": "application/msword",
|
||||
"dotm": "application/vnd.ms-word.template.macroEnabled.12",
|
||||
"dotx": "application/vnd.openxmlformats-officedocument.wordprocessingml.template",
|
||||
"dsp": "application/octet-stream",
|
||||
"dtd": "text/xml",
|
||||
"dvi": "application/x-dvi",
|
||||
"dwf": "drawing/x-dwf",
|
||||
"dwp": "application/octet-stream",
|
||||
"dxr": "application/x-director",
|
||||
"eml": "message/rfc822",
|
||||
"emz": "application/octet-stream",
|
||||
"eot": "application/octet-stream",
|
||||
"eps": "application/postscript",
|
||||
"etx": "text/x-setext",
|
||||
"evy": "application/envoy",
|
||||
"exe": "application/octet-stream",
|
||||
"exe.config": "text/xml",
|
||||
"fdf": "application/vnd.fdf",
|
||||
"fif": "application/fractals",
|
||||
"fla": "application/octet-stream",
|
||||
"flr": "x-world/x-vrml",
|
||||
"flv": "video/x-flv",
|
||||
"gif": "image/gif",
|
||||
"gtar": "application/x-gtar",
|
||||
"gz": "application/x-gzip",
|
||||
"h": "text/plain",
|
||||
"hdf": "application/x-hdf",
|
||||
"hdml": "text/x-hdml",
|
||||
"hhc": "application/x-oleobject",
|
||||
"hhk": "application/octet-stream",
|
||||
"hhp": "application/octet-stream",
|
||||
"hlp": "application/winhlp",
|
||||
"hqx": "application/mac-binhex40",
|
||||
"hta": "application/hta",
|
||||
"htc": "text/x-component",
|
||||
"htm": "text/html",
|
||||
"html": "text/html",
|
||||
"htt": "text/webviewhtml",
|
||||
"hxt": "text/html",
|
||||
"ico": "image/x-icon",
|
||||
"ics": "application/octet-stream",
|
||||
"ief": "image/ief",
|
||||
"iii": "application/x-iphone",
|
||||
"inf": "application/octet-stream",
|
||||
"ins": "application/x-internet-signup",
|
||||
"isp": "application/x-internet-signup",
|
||||
"IVF": "video/x-ivf",
|
||||
"jar": "application/java-archive",
|
||||
"java": "application/octet-stream",
|
||||
"jck": "application/liquidmotion",
|
||||
"jcz": "application/liquidmotion",
|
||||
"jfif": "image/pjpeg",
|
||||
"jpb": "application/octet-stream",
|
||||
"jpe": "image/jpeg",
|
||||
"jpeg": "image/jpeg",
|
||||
"jpg": "image/jpeg",
|
||||
"js": "application/x-javascript",
|
||||
"jsx": "text/jscript",
|
||||
"latex": "application/x-latex",
|
||||
"lit": "application/x-ms-reader",
|
||||
"lpk": "application/octet-stream",
|
||||
"lsf": "video/x-la-asf",
|
||||
"lsx": "video/x-la-asf",
|
||||
"lzh": "application/octet-stream",
|
||||
"m13": "application/x-msmediaview",
|
||||
"m14": "application/x-msmediaview",
|
||||
"m1v": "video/mpeg",
|
||||
"m3u": "audio/x-mpegurl",
|
||||
"man": "application/x-troff-man",
|
||||
"manifest": "application/x-ms-manifest",
|
||||
"map": "text/plain",
|
||||
"mdb": "application/x-msaccess",
|
||||
"mdp": "application/octet-stream",
|
||||
"me": "application/x-troff-me",
|
||||
"mht": "message/rfc822",
|
||||
"mhtml": "message/rfc822",
|
||||
"mid": "audio/mid",
|
||||
"midi": "audio/mid",
|
||||
"mix": "application/octet-stream",
|
||||
"mmf": "application/x-smaf",
|
||||
"mno": "text/xml",
|
||||
"mny": "application/x-msmoney",
|
||||
"mov": "video/quicktime",
|
||||
"movie": "video/x-sgi-movie",
|
||||
"mp2": "video/mpeg",
|
||||
"mp3": "audio/mpeg",
|
||||
"mpa": "video/mpeg",
|
||||
"mpe": "video/mpeg",
|
||||
"mpeg": "video/mpeg",
|
||||
"mpg": "video/mpeg",
|
||||
"mpp": "application/vnd.ms-project",
|
||||
"mpv2": "video/mpeg",
|
||||
"ms": "application/x-troff-ms",
|
||||
"msi": "application/octet-stream",
|
||||
"mso": "application/octet-stream",
|
||||
"mvb": "application/x-msmediaview",
|
||||
"mvc": "application/x-miva-compiled",
|
||||
"nc": "application/x-netcdf",
|
||||
"nsc": "video/x-ms-asf",
|
||||
"nws": "message/rfc822",
|
||||
"ocx": "application/octet-stream",
|
||||
"oda": "application/oda",
|
||||
"odc": "text/x-ms-odc",
|
||||
"ods": "application/oleobject",
|
||||
"one": "application/onenote",
|
||||
"onea": "application/onenote",
|
||||
"onetoc": "application/onenote",
|
||||
"onetoc2": "application/onenote",
|
||||
"onetmp": "application/onenote",
|
||||
"onepkg": "application/onenote",
|
||||
"osdx": "application/opensearchdescription+xml",
|
||||
"p10": "application/pkcs10",
|
||||
"p12": "application/x-pkcs12",
|
||||
"p7b": "application/x-pkcs7-certificates",
|
||||
"p7c": "application/pkcs7-mime",
|
||||
"p7m": "application/pkcs7-mime",
|
||||
"p7r": "application/x-pkcs7-certreqresp",
|
||||
"p7s": "application/pkcs7-signature",
|
||||
"pbm": "image/x-portable-bitmap",
|
||||
"pcx": "application/octet-stream",
|
||||
"pcz": "application/octet-stream",
|
||||
"pdf": "application/pdf",
|
||||
"pfb": "application/octet-stream",
|
||||
"pfm": "application/octet-stream",
|
||||
"pfx": "application/x-pkcs12",
|
||||
"pgm": "image/x-portable-graymap",
|
||||
"pko": "application/vnd.ms-pki.pko",
|
||||
"pma": "application/x-perfmon",
|
||||
"pmc": "application/x-perfmon",
|
||||
"pml": "application/x-perfmon",
|
||||
"pmr": "application/x-perfmon",
|
||||
"pmw": "application/x-perfmon",
|
||||
"png": "image/png",
|
||||
"pnm": "image/x-portable-anymap",
|
||||
"pnz": "image/png",
|
||||
"pot": "application/vnd.ms-powerpoint",
|
||||
"potm": "application/vnd.ms-powerpoint.template.macroEnabled.12",
|
||||
"potx": "application/vnd.openxmlformats-officedocument.presentationml.template",
|
||||
"ppam": "application/vnd.ms-powerpoint.addin.macroEnabled.12",
|
||||
"ppm": "image/x-portable-pixmap",
|
||||
"pps": "application/vnd.ms-powerpoint",
|
||||
"ppsm": "application/vnd.ms-powerpoint.slideshow.macroEnabled.12",
|
||||
"ppsx": "application/vnd.openxmlformats-officedocument.presentationml.slideshow",
|
||||
"ppt": "application/vnd.ms-powerpoint",
|
||||
"pptm": "application/vnd.ms-powerpoint.presentation.macroEnabled.12",
|
||||
"pptx": "application/vnd.openxmlformats-officedocument.presentationml.presentation",
|
||||
"prf": "application/pics-rules",
|
||||
"prm": "application/octet-stream",
|
||||
"prx": "application/octet-stream",
|
||||
"ps": "application/postscript",
|
||||
"psd": "application/octet-stream",
|
||||
"psm": "application/octet-stream",
|
||||
"psp": "application/octet-stream",
|
||||
"pub": "application/x-mspublisher",
|
||||
"qt": "video/quicktime",
|
||||
"qtl": "application/x-quicktimeplayer",
|
||||
"qxd": "application/octet-stream",
|
||||
"ra": "audio/x-pn-realaudio",
|
||||
"ram": "audio/x-pn-realaudio",
|
||||
"rar": "application/octet-stream",
|
||||
"ras": "image/x-cmu-raster",
|
||||
"rf": "image/vnd.rn-realflash",
|
||||
"rgb": "image/x-rgb",
|
||||
"rm": "application/vnd.rn-realmedia",
|
||||
"rmi": "audio/mid",
|
||||
"roff": "application/x-troff",
|
||||
"rpm": "audio/x-pn-realaudio-plugin",
|
||||
"rtf": "application/rtf",
|
||||
"rtx": "text/richtext",
|
||||
"scd": "application/x-msschedule",
|
||||
"sct": "text/scriptlet",
|
||||
"sea": "application/octet-stream",
|
||||
"setpay": "application/set-payment-initiation",
|
||||
"setreg": "application/set-registration-initiation",
|
||||
"sgml": "text/sgml",
|
||||
"sh": "application/x-sh",
|
||||
"shar": "application/x-shar",
|
||||
"sit": "application/x-stuffit",
|
||||
"sldm": "application/vnd.ms-powerpoint.slide.macroEnabled.12",
|
||||
"sldx": "application/vnd.openxmlformats-officedocument.presentationml.slide",
|
||||
"smd": "audio/x-smd",
|
||||
"smi": "application/octet-stream",
|
||||
"smx": "audio/x-smd",
|
||||
"smz": "audio/x-smd",
|
||||
"snd": "audio/basic",
|
||||
"snp": "application/octet-stream",
|
||||
"spc": "application/x-pkcs7-certificates",
|
||||
"spl": "application/futuresplash",
|
||||
"src": "application/x-wais-source",
|
||||
"ssm": "application/streamingmedia",
|
||||
"sst": "application/vnd.ms-pki.certstore",
|
||||
"stl": "application/vnd.ms-pki.stl",
|
||||
"sv4cpio": "application/x-sv4cpio",
|
||||
"sv4crc": "application/x-sv4crc",
|
||||
"svg": "image/svg+xml",
|
||||
"swf": "application/x-shockwave-flash",
|
||||
"t": "application/x-troff",
|
||||
"tar": "application/x-tar",
|
||||
"tcl": "application/x-tcl",
|
||||
"tex": "application/x-tex",
|
||||
"texi": "application/x-texinfo",
|
||||
"texinfo": "application/x-texinfo",
|
||||
"tgz": "application/x-compressed",
|
||||
"thmx": "application/vnd.ms-officetheme",
|
||||
"thn": "application/octet-stream",
|
||||
"tif": "image/tiff",
|
||||
"tiff": "image/tiff",
|
||||
"toc": "application/octet-stream",
|
||||
"tr": "application/x-troff",
|
||||
"trm": "application/x-msterminal",
|
||||
"tsv": "text/tab-separated-values",
|
||||
"ttf": "application/octet-stream",
|
||||
"txt": "text/plain",
|
||||
"u32": "application/octet-stream",
|
||||
"uls": "text/iuls",
|
||||
"ustar": "application/x-ustar",
|
||||
"vbs": "text/vbscript",
|
||||
"vcf": "text/x-vcard",
|
||||
"vcs": "text/plain",
|
||||
"vdx": "application/vnd.ms-visio.viewer",
|
||||
"vml": "text/xml",
|
||||
"vsd": "application/vnd.visio",
|
||||
"vss": "application/vnd.visio",
|
||||
"vst": "application/vnd.visio",
|
||||
"vsto": "application/x-ms-vsto",
|
||||
"vsw": "application/vnd.visio",
|
||||
"vsx": "application/vnd.visio",
|
||||
"vtx": "application/vnd.visio",
|
||||
"wasm": "application/wasm",
|
||||
"wav": "audio/wav",
|
||||
"wax": "audio/x-ms-wax",
|
||||
"wbmp": "image/vnd.wap.wbmp",
|
||||
"wcm": "application/vnd.ms-works",
|
||||
"wdb": "application/vnd.ms-works",
|
||||
"wks": "application/vnd.ms-works",
|
||||
"wm": "video/x-ms-wm",
|
||||
"wma": "audio/x-ms-wma",
|
||||
"wmd": "application/x-ms-wmd",
|
||||
"wmf": "application/x-msmetafile",
|
||||
"wml": "text/vnd.wap.wml",
|
||||
"wmlc": "application/vnd.wap.wmlc",
|
||||
"wmls": "text/vnd.wap.wmlscript",
|
||||
"wmlsc": "application/vnd.wap.wmlscriptc",
|
||||
"wmp": "video/x-ms-wmp",
|
||||
"wmv": "video/x-ms-wmv",
|
||||
"wmx": "video/x-ms-wmx",
|
||||
"wmz": "application/x-ms-wmz",
|
||||
"wps": "application/vnd.ms-works",
|
||||
"wri": "application/x-mswrite",
|
||||
"wrl": "x-world/x-vrml",
|
||||
"wrz": "x-world/x-vrml",
|
||||
"wsdl": "text/xml",
|
||||
"wvx": "video/x-ms-wvx",
|
||||
"x": "application/directx",
|
||||
"xaf": "x-world/x-vrml",
|
||||
"xaml": "application/xaml+xml",
|
||||
"xap": "application/x-silverlight-app",
|
||||
"xbap": "application/x-ms-xbap",
|
||||
"xbm": "image/x-xbitmap",
|
||||
"xdr": "text/plain",
|
||||
"xht": "application/xhtml+xml",
|
||||
"xhtml": "application/xhtml+xml",
|
||||
"xla": "application/vnd.ms-excel",
|
||||
"xlam": "application/vnd.ms-excel.addin.macroEnabled.12",
|
||||
"xlc": "application/vnd.ms-excel",
|
||||
"xlm": "application/vnd.ms-excel",
|
||||
"xls": "application/vnd.ms-excel",
|
||||
"xlsb": "application/vnd.ms-excel.sheet.binary.macroEnabled.12",
|
||||
"xlsm": "application/vnd.ms-excel.sheet.macroEnabled.12",
|
||||
"xlsx": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
|
||||
"xlt": "application/vnd.ms-excel",
|
||||
"xltm": "application/vnd.ms-excel.template.macroEnabled.12",
|
||||
"xltx": "application/vnd.openxmlformats-officedocument.spreadsheetml.template",
|
||||
"xlw": "application/vnd.ms-excel",
|
||||
"xml": "text/xml",
|
||||
"xof": "x-world/x-vrml",
|
||||
"xpm": "image/x-xpixmap",
|
||||
"xps": "application/vnd.ms-xpsdocument",
|
||||
"xsd": "text/xml",
|
||||
"xsf": "text/xml",
|
||||
"xsl": "text/xml",
|
||||
"xslt": "text/xml",
|
||||
"xsn": "application/octet-stream",
|
||||
"xtp": "application/octet-stream",
|
||||
"xwd": "image/x-xwindowdump",
|
||||
"z": "application/x-compress",
|
||||
"zip": "application/x-zip-compressed"
|
||||
]
|
||||
}
|
||||
|
||||
private var stoppedKey = malloc(1)
|
||||
|
||||
private extension WKURLSchemeTask {
|
||||
var stopped: Bool {
|
||||
get {
|
||||
return objc_getAssociatedObject(self, &stoppedKey) as? Bool ?? false
|
||||
}
|
||||
set {
|
||||
objc_setAssociatedObject(self, &stoppedKey, newValue, .OBJC_ASSOCIATION_ASSIGN)
|
||||
}
|
||||
}
|
||||
}
|
||||
343
node_modules/@capacitor/ios/Capacitor/Capacitor/WebViewDelegationHandler.swift
generated
vendored
Normal file
343
node_modules/@capacitor/ios/Capacitor/Capacitor/WebViewDelegationHandler.swift
generated
vendored
Normal file
@@ -0,0 +1,343 @@
|
||||
import Foundation
|
||||
import WebKit
|
||||
|
||||
// adopting a public protocol in an internal class is by design
|
||||
// swiftlint:disable lower_acl_than_parent
|
||||
@objc(CAPWebViewDelegationHandler)
|
||||
open class WebViewDelegationHandler: NSObject, WKNavigationDelegate, WKUIDelegate, WKScriptMessageHandler, UIScrollViewDelegate {
|
||||
public internal(set) weak var bridge: CapacitorBridge?
|
||||
open fileprivate(set) var contentController = WKUserContentController()
|
||||
enum WebViewLoadingState {
|
||||
case unloaded
|
||||
case initialLoad(isOpaque: Bool)
|
||||
case subsequentLoad
|
||||
}
|
||||
|
||||
fileprivate(set) var webViewLoadingState = WebViewLoadingState.unloaded
|
||||
|
||||
private let handlerName = "bridge"
|
||||
|
||||
override public init() {
|
||||
super.init()
|
||||
contentController.add(self, name: handlerName)
|
||||
}
|
||||
|
||||
open func cleanUp() {
|
||||
contentController.removeScriptMessageHandler(forName: handlerName)
|
||||
}
|
||||
|
||||
open func willLoadWebview(_ webView: WKWebView?) {
|
||||
// Set the webview to be not opaque on the inital load. This prevents
|
||||
// the webview from showing a white background, which is its default
|
||||
// loading display, as that can appear as a screen flash. The opacity
|
||||
// might have been set by something else, like a plugin, so we want
|
||||
// to save the current value so it can be reset on success or failure.
|
||||
if let webView = webView, case .unloaded = webViewLoadingState {
|
||||
webViewLoadingState = .initialLoad(isOpaque: webView.isOpaque)
|
||||
webView.isOpaque = false
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - WKNavigationDelegate
|
||||
|
||||
// The force unwrap is part of the protocol declaration, so we should keep it.
|
||||
// swiftlint:disable:next implicitly_unwrapped_optional
|
||||
open func webView(_ webView: WKWebView, didStartProvisionalNavigation navigation: WKNavigation!) {
|
||||
// Reset the bridge on each navigation
|
||||
bridge?.reset()
|
||||
}
|
||||
|
||||
@available(iOS 15, *)
|
||||
open func webView(
|
||||
_ webView: WKWebView,
|
||||
requestMediaCapturePermissionFor origin: WKSecurityOrigin,
|
||||
initiatedByFrame frame: WKFrameInfo,
|
||||
type: WKMediaCaptureType,
|
||||
decisionHandler: @escaping (WKPermissionDecision) -> Void
|
||||
) {
|
||||
decisionHandler(.grant)
|
||||
}
|
||||
|
||||
@available(iOS 15, *)
|
||||
open func webView(_ webView: WKWebView,
|
||||
requestDeviceOrientationAndMotionPermissionFor origin: WKSecurityOrigin,
|
||||
initiatedByFrame frame: WKFrameInfo,
|
||||
decisionHandler: @escaping (WKPermissionDecision) -> Void) {
|
||||
decisionHandler(.grant)
|
||||
}
|
||||
|
||||
open func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
|
||||
// post a notification for any listeners
|
||||
NotificationCenter.default.post(name: .capacitorDecidePolicyForNavigationAction, object: navigationAction)
|
||||
|
||||
// sanity check, these shouldn't ever be nil in practice
|
||||
guard let bridge = bridge, let navURL = navigationAction.request.url else {
|
||||
decisionHandler(.allow)
|
||||
return
|
||||
}
|
||||
|
||||
// first, give plugins the chance to handle the decision
|
||||
for pluginObject in bridge.plugins {
|
||||
let plugin = pluginObject.value
|
||||
let selector = NSSelectorFromString("shouldOverrideLoad:")
|
||||
if plugin.responds(to: selector) {
|
||||
let shouldOverrideLoad = plugin.shouldOverrideLoad(navigationAction)
|
||||
if shouldOverrideLoad != nil {
|
||||
if shouldOverrideLoad == true {
|
||||
decisionHandler(.cancel)
|
||||
return
|
||||
} else if shouldOverrideLoad == false {
|
||||
decisionHandler(.allow)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// next, check if this is covered by the allowedNavigation configuration
|
||||
if let host = navURL.host, bridge.config.shouldAllowNavigation(to: host) {
|
||||
decisionHandler(.allow)
|
||||
return
|
||||
}
|
||||
|
||||
// otherwise, is this a new window or a main frame navigation but to an outside source
|
||||
let toplevelNavigation = (navigationAction.targetFrame == nil || navigationAction.targetFrame?.isMainFrame == true)
|
||||
|
||||
// Check if the url being navigated to is configured as an application url (whether local or remote)
|
||||
let isApplicationNavigation = navURL.absoluteString.starts(with: bridge.config.serverURL.absoluteString) ||
|
||||
navURL.absoluteString.starts(with: bridge.config.localURL.absoluteString)
|
||||
|
||||
if !isApplicationNavigation, toplevelNavigation {
|
||||
// disallow and let the system handle it
|
||||
if UIApplication.shared.applicationState == .active {
|
||||
UIApplication.shared.open(navURL, options: [:], completionHandler: nil)
|
||||
}
|
||||
decisionHandler(.cancel)
|
||||
return
|
||||
}
|
||||
|
||||
// fallthrough to allowing it
|
||||
decisionHandler(.allow)
|
||||
}
|
||||
|
||||
// The force unwrap is part of the protocol declaration, so we should keep it.
|
||||
// swiftlint:disable:next implicitly_unwrapped_optional
|
||||
open func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
|
||||
if case .initialLoad(let isOpaque) = webViewLoadingState {
|
||||
webView.isOpaque = isOpaque
|
||||
webViewLoadingState = .subsequentLoad
|
||||
}
|
||||
CAPLog.print("⚡️ WebView loaded")
|
||||
}
|
||||
|
||||
// The force unwrap is part of the protocol declaration, so we should keep it.
|
||||
// swiftlint:disable:next implicitly_unwrapped_optional
|
||||
open func webView(_ webView: WKWebView, didFail navigation: WKNavigation!, withError error: Error) {
|
||||
if case .initialLoad(let isOpaque) = webViewLoadingState {
|
||||
webView.isOpaque = isOpaque
|
||||
webViewLoadingState = .subsequentLoad
|
||||
}
|
||||
|
||||
if let errorURL = bridge?.config.errorPathURL {
|
||||
webView.load(URLRequest(url: errorURL))
|
||||
}
|
||||
|
||||
CAPLog.print("⚡️ WebView failed to load")
|
||||
CAPLog.print("⚡️ Error: " + error.localizedDescription)
|
||||
}
|
||||
|
||||
// The force unwrap is part of the protocol declaration, so we should keep it.
|
||||
// swiftlint:disable:next implicitly_unwrapped_optional
|
||||
open func webView(_ webView: WKWebView, didFailProvisionalNavigation navigation: WKNavigation!, withError error: Error) {
|
||||
if let errorURL = bridge?.config.errorPathURL {
|
||||
webView.load(URLRequest(url: errorURL))
|
||||
}
|
||||
|
||||
CAPLog.print("⚡️ WebView failed provisional navigation")
|
||||
CAPLog.print("⚡️ Error: " + error.localizedDescription)
|
||||
}
|
||||
|
||||
open func webViewWebContentProcessDidTerminate(_ webView: WKWebView) {
|
||||
CAPLog.print("⚡️ WebView process terminated")
|
||||
bridge?.reset()
|
||||
webView.reload()
|
||||
}
|
||||
|
||||
// MARK: - WKScriptMessageHandler
|
||||
|
||||
open func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
|
||||
guard let bridge = bridge else {
|
||||
return
|
||||
}
|
||||
|
||||
let body = message.body
|
||||
if let dict = body as? [String: Any] {
|
||||
let type = dict["type"] as? String ?? ""
|
||||
|
||||
if type == "js.error" {
|
||||
if let error = dict["error"] as? [String: Any] {
|
||||
logJSError(error)
|
||||
}
|
||||
} else if type == "message" {
|
||||
let pluginId = dict["pluginId"] as? String ?? ""
|
||||
let method = dict["methodName"] as? String ?? ""
|
||||
let callbackId = dict["callbackId"] as? String ?? ""
|
||||
|
||||
let options = dict["options"] as? [String: Any] ?? [:]
|
||||
|
||||
if pluginId != "Console" {
|
||||
CAPLog.print("⚡️ To Native -> ", pluginId, method, callbackId)
|
||||
}
|
||||
|
||||
bridge.handleJSCall(call: JSCall(options: options, pluginId: pluginId, method: method, callbackId: callbackId))
|
||||
} else if type == "cordova" {
|
||||
let pluginId = dict["service"] as? String ?? ""
|
||||
let method = dict["action"] as? String ?? ""
|
||||
let callbackId = dict["callbackId"] as? String ?? ""
|
||||
|
||||
let args = dict["actionArgs"] as? Array ?? []
|
||||
let options = ["options": args]
|
||||
|
||||
CAPLog.print("To Native Cordova -> ", pluginId, method, callbackId, options)
|
||||
|
||||
bridge.handleCordovaJSCall(call: JSCall(options: options, pluginId: pluginId, method: method, callbackId: callbackId))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - WKUIDelegate
|
||||
|
||||
open func webView(_ webView: WKWebView, runJavaScriptAlertPanelWithMessage message: String, initiatedByFrame frame: WKFrameInfo, completionHandler: @escaping () -> Void) {
|
||||
guard var viewController = bridge?.viewController else {
|
||||
completionHandler()
|
||||
return
|
||||
}
|
||||
|
||||
if let presentedVC = viewController.presentedViewController, !presentedVC.isBeingDismissed {
|
||||
viewController = presentedVC
|
||||
}
|
||||
|
||||
let alertController = UIAlertController(title: nil, message: message, preferredStyle: .alert)
|
||||
|
||||
alertController.addAction(UIAlertAction(title: "Ok", style: .default, handler: { (_) in
|
||||
completionHandler()
|
||||
}))
|
||||
|
||||
viewController.present(alertController, animated: true, completion: nil)
|
||||
}
|
||||
|
||||
open func webView(_ webView: WKWebView, runJavaScriptConfirmPanelWithMessage message: String, initiatedByFrame frame: WKFrameInfo, completionHandler: @escaping (Bool) -> Void) {
|
||||
guard let viewController = bridge?.viewController else {
|
||||
return
|
||||
}
|
||||
|
||||
let alertController = UIAlertController(title: nil, message: message, preferredStyle: .alert)
|
||||
|
||||
alertController.addAction(UIAlertAction(title: "Cancel", style: .default, handler: { (_) in
|
||||
completionHandler(false)
|
||||
}))
|
||||
|
||||
alertController.addAction(UIAlertAction(title: "Ok", style: .default, handler: { (_) in
|
||||
completionHandler(true)
|
||||
}))
|
||||
|
||||
viewController.present(alertController, animated: true, completion: nil)
|
||||
}
|
||||
|
||||
open func webView(_ webView: WKWebView, runJavaScriptTextInputPanelWithPrompt prompt: String, defaultText: String?, initiatedByFrame frame: WKFrameInfo, completionHandler: @escaping (String?) -> Void) {
|
||||
|
||||
// Check if this is synchronous cookie or http call
|
||||
do {
|
||||
if let dataFromString = prompt.data(using: .utf8, allowLossyConversion: false) {
|
||||
if let payload = try JSONSerialization.jsonObject(with: dataFromString, options: .fragmentsAllowed) as? [String: AnyObject] {
|
||||
let type = payload["type"] as? String
|
||||
|
||||
if type == "CapacitorCookies.get" {
|
||||
completionHandler(CapacitorCookieManager(bridge!.config).getCookies())
|
||||
// Don't present prompt
|
||||
return
|
||||
} else if type == "CapacitorCookies.set" {
|
||||
// swiftlint:disable force_cast
|
||||
let action = payload["action"] as! String
|
||||
let domain = payload["domain"] as! String
|
||||
CapacitorCookieManager(bridge!.config).setCookie(domain, action)
|
||||
completionHandler("")
|
||||
// swiftlint:enable force_cast
|
||||
// Don't present prompt
|
||||
return
|
||||
} else if type == "CapacitorCookies.isEnabled" {
|
||||
let pluginConfig = bridge!.config.getPluginConfig("CapacitorCookies")
|
||||
completionHandler(String(pluginConfig.getBoolean("enabled", false)))
|
||||
// Don't present prompt
|
||||
return
|
||||
} else if type == "CapacitorHttp" {
|
||||
let pluginConfig = bridge!.config.getPluginConfig("CapacitorHttp")
|
||||
completionHandler(String(pluginConfig.getBoolean("enabled", false)))
|
||||
// Don't present prompt
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
// Continue with regular prompt
|
||||
}
|
||||
|
||||
guard let viewController = bridge?.viewController else {
|
||||
return
|
||||
}
|
||||
|
||||
let alertController = UIAlertController(title: nil, message: prompt, preferredStyle: .alert)
|
||||
|
||||
alertController.addTextField { (textField) in
|
||||
textField.text = defaultText
|
||||
}
|
||||
|
||||
alertController.addAction(UIAlertAction(title: "Cancel", style: .default, handler: { (_) in
|
||||
completionHandler(nil)
|
||||
}))
|
||||
|
||||
alertController.addAction(UIAlertAction(title: "Ok", style: .default, handler: { (_) in
|
||||
if let text = alertController.textFields?.first?.text {
|
||||
completionHandler(text)
|
||||
} else {
|
||||
completionHandler(defaultText)
|
||||
}
|
||||
}))
|
||||
|
||||
viewController.present(alertController, animated: true, completion: nil)
|
||||
}
|
||||
|
||||
open func webView(_ webView: WKWebView, createWebViewWith configuration: WKWebViewConfiguration, for navigationAction: WKNavigationAction, windowFeatures: WKWindowFeatures) -> WKWebView? {
|
||||
if let url = navigationAction.request.url {
|
||||
UIApplication.shared.open(url, options: [:], completionHandler: nil)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// MARK: - UIScrollViewDelegate
|
||||
|
||||
// disable zooming in WKWebView ScrollView
|
||||
open func scrollViewWillBeginZooming(_ scrollView: UIScrollView, with view: UIView?) {
|
||||
scrollView.pinchGestureRecognizer?.isEnabled = false
|
||||
}
|
||||
|
||||
// MARK: - Private
|
||||
|
||||
private func logJSError(_ error: [String: Any]) {
|
||||
let message = error["message"] ?? "No message"
|
||||
let url = error["url"] as? String ?? ""
|
||||
let line = error["line"] ?? ""
|
||||
let col = error["col"] ?? ""
|
||||
var filename = ""
|
||||
if let filenameIndex = url.range(of: "/", options: .backwards)?.lowerBound {
|
||||
let index = url.index(after: filenameIndex)
|
||||
filename = String(url[index...])
|
||||
}
|
||||
|
||||
CAPLog.print("\n⚡️ ------ STARTUP JS ERROR ------\n")
|
||||
CAPLog.print("⚡️ \(message)")
|
||||
CAPLog.print("⚡️ URL: \(url)")
|
||||
CAPLog.print("⚡️ \(filename):\(line):\(col)")
|
||||
CAPLog.print("\n⚡️ See above for help with debugging blank-screen issues")
|
||||
}
|
||||
}
|
||||
1029
node_modules/@capacitor/ios/Capacitor/Capacitor/assets/native-bridge.js
generated
vendored
Normal file
1029
node_modules/@capacitor/ios/Capacitor/Capacitor/assets/native-bridge.js
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
26
node_modules/@capacitor/ios/CapacitorCordova.podspec
generated
vendored
Normal file
26
node_modules/@capacitor/ios/CapacitorCordova.podspec
generated
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
require 'json'
|
||||
package = JSON.parse(File.read(File.join(__dir__, 'package.json')))
|
||||
prefix = if ENV['NATIVE_PUBLISH'] == 'true'
|
||||
'ios/'
|
||||
else
|
||||
''
|
||||
end
|
||||
|
||||
Pod::Spec.new do |s|
|
||||
s.name = 'CapacitorCordova'
|
||||
s.module_name = 'Cordova'
|
||||
s.version = package['version']
|
||||
s.summary = 'Capacitor Cordova Compatibility Layer'
|
||||
s.homepage = 'https://capacitorjs.com'
|
||||
s.license = 'MIT'
|
||||
s.authors = { 'Ionic Team' => 'hi@ionicframework.com' }
|
||||
s.source = { git: 'https://github.com/ionic-team/capacitor', tag: s.version.to_s }
|
||||
s.platform = :ios, 14.0
|
||||
s.source_files = "#{prefix}CapacitorCordova/CapacitorCordova/**/*.{h,m}"
|
||||
s.public_header_files = "#{prefix}CapacitorCordova/CapacitorCordova/Classes/Public/*.h",
|
||||
"#{prefix}CapacitorCordova/CapacitorCordova/CapacitorCordova.h"
|
||||
s.module_map = "#{prefix}CapacitorCordova/CapacitorCordova/CapacitorCordova.modulemap"
|
||||
s.resources = ["#{prefix}CapacitorCordova/CapacitorCordova/PrivacyInfo.xcprivacy"]
|
||||
s.requires_arc = true
|
||||
s.framework = 'WebKit'
|
||||
end
|
||||
24
node_modules/@capacitor/ios/CapacitorCordova/CapacitorCordova/CapacitorCordova.h
generated
vendored
Normal file
24
node_modules/@capacitor/ios/CapacitorCordova/CapacitorCordova/CapacitorCordova.h
generated
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
//! Project version number for CapacitorCordova.
|
||||
FOUNDATION_EXPORT double CapacitorCordovaVersionNumber;
|
||||
|
||||
//! Project version string for CapacitorCordova.
|
||||
FOUNDATION_EXPORT const unsigned char CapacitorCordovaVersionString[];
|
||||
|
||||
#import <Cordova/AppDelegate.h>
|
||||
#import <Cordova/CDV.h>
|
||||
#import <Cordova/CDVAvailability.h>
|
||||
#import <Cordova/CDVCommandDelegate.h>
|
||||
#import <Cordova/CDVCommandDelegateImpl.h>
|
||||
#import <Cordova/CDVConfigParser.h>
|
||||
#import <Cordova/CDVInvokedUrlCommand.h>
|
||||
#import <Cordova/CDVPlugin+Resources.h>
|
||||
#import <Cordova/CDVPlugin.h>
|
||||
#import <Cordova/CDVPluginManager.h>
|
||||
#import <Cordova/CDVPluginResult.h>
|
||||
#import <Cordova/CDVScreenOrientationDelegate.h>
|
||||
#import <Cordova/CDVURLProtocol.h>
|
||||
#import <Cordova/CDVViewController.h>
|
||||
#import <Cordova/CDVWebViewProcessPoolFactory.h>
|
||||
#import <Cordova/NSDictionary+CordovaPreferences.h>
|
||||
6
node_modules/@capacitor/ios/CapacitorCordova/CapacitorCordova/CapacitorCordova.modulemap
generated
vendored
Normal file
6
node_modules/@capacitor/ios/CapacitorCordova/CapacitorCordova/CapacitorCordova.modulemap
generated
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
framework module Cordova {
|
||||
umbrella header "CapacitorCordova.h"
|
||||
|
||||
export *
|
||||
module * { export * }
|
||||
}
|
||||
8
node_modules/@capacitor/ios/CapacitorCordova/CapacitorCordova/Classes/Public/AppDelegate.h
generated
vendored
Normal file
8
node_modules/@capacitor/ios/CapacitorCordova/CapacitorCordova/Classes/Public/AppDelegate.h
generated
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "CDVViewController.h"
|
||||
|
||||
@interface AppDelegate : NSObject
|
||||
|
||||
@property (nonatomic, strong) CDVViewController* viewController;
|
||||
|
||||
@end
|
||||
5
node_modules/@capacitor/ios/CapacitorCordova/CapacitorCordova/Classes/Public/AppDelegate.m
generated
vendored
Normal file
5
node_modules/@capacitor/ios/CapacitorCordova/CapacitorCordova/Classes/Public/AppDelegate.m
generated
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
#import "AppDelegate.h"
|
||||
|
||||
@implementation AppDelegate
|
||||
|
||||
@end
|
||||
28
node_modules/@capacitor/ios/CapacitorCordova/CapacitorCordova/Classes/Public/CDV.h
generated
vendored
Normal file
28
node_modules/@capacitor/ios/CapacitorCordova/CapacitorCordova/Classes/Public/CDV.h
generated
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you under the Apache License, Version 2.0 (the
|
||||
"License"); you may not use this file except in compliance
|
||||
with the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing,
|
||||
software distributed under the License is distributed on an
|
||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
KIND, either express or implied. See the License for the
|
||||
specific language governing permissions and limitations
|
||||
under the License.
|
||||
*/
|
||||
|
||||
#import "CDVAvailability.h"
|
||||
#import "CDVPlugin.h"
|
||||
#import "CDVPluginResult.h"
|
||||
#import "CDVCommandDelegate.h"
|
||||
#import "CDVInvokedUrlCommand.h"
|
||||
#import "CDVViewController.h"
|
||||
#import "CDVURLProtocol.h"
|
||||
#import "CDVScreenOrientationDelegate.h"
|
||||
#import "CDVWebViewProcessPoolFactory.h"
|
||||
109
node_modules/@capacitor/ios/CapacitorCordova/CapacitorCordova/Classes/Public/CDVAvailability.h
generated
vendored
Normal file
109
node_modules/@capacitor/ios/CapacitorCordova/CapacitorCordova/Classes/Public/CDVAvailability.h
generated
vendored
Normal file
@@ -0,0 +1,109 @@
|
||||
/*
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you under the Apache License, Version 2.0 (the
|
||||
"License"); you may not use this file except in compliance
|
||||
with the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing,
|
||||
software distributed under the License is distributed on an
|
||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
KIND, either express or implied. See the License for the
|
||||
specific language governing permissions and limitations
|
||||
under the License.
|
||||
*/
|
||||
|
||||
#define __CORDOVA_IOS__
|
||||
|
||||
#define __CORDOVA_0_9_6 906
|
||||
#define __CORDOVA_1_0_0 10000
|
||||
#define __CORDOVA_1_1_0 10100
|
||||
#define __CORDOVA_1_2_0 10200
|
||||
#define __CORDOVA_1_3_0 10300
|
||||
#define __CORDOVA_1_4_0 10400
|
||||
#define __CORDOVA_1_4_1 10401
|
||||
#define __CORDOVA_1_5_0 10500
|
||||
#define __CORDOVA_1_6_0 10600
|
||||
#define __CORDOVA_1_6_1 10601
|
||||
#define __CORDOVA_1_7_0 10700
|
||||
#define __CORDOVA_1_8_0 10800
|
||||
#define __CORDOVA_1_8_1 10801
|
||||
#define __CORDOVA_1_9_0 10900
|
||||
#define __CORDOVA_2_0_0 20000
|
||||
#define __CORDOVA_2_1_0 20100
|
||||
#define __CORDOVA_2_2_0 20200
|
||||
#define __CORDOVA_2_3_0 20300
|
||||
#define __CORDOVA_2_4_0 20400
|
||||
#define __CORDOVA_2_5_0 20500
|
||||
#define __CORDOVA_2_6_0 20600
|
||||
#define __CORDOVA_2_7_0 20700
|
||||
#define __CORDOVA_2_8_0 20800
|
||||
#define __CORDOVA_2_9_0 20900
|
||||
#define __CORDOVA_3_0_0 30000
|
||||
#define __CORDOVA_3_1_0 30100
|
||||
#define __CORDOVA_3_2_0 30200
|
||||
#define __CORDOVA_3_3_0 30300
|
||||
#define __CORDOVA_3_4_0 30400
|
||||
#define __CORDOVA_3_4_1 30401
|
||||
#define __CORDOVA_3_5_0 30500
|
||||
#define __CORDOVA_3_6_0 30600
|
||||
#define __CORDOVA_3_7_0 30700
|
||||
#define __CORDOVA_3_8_0 30800
|
||||
#define __CORDOVA_3_9_0 30900
|
||||
#define __CORDOVA_3_9_1 30901
|
||||
#define __CORDOVA_3_9_2 30902
|
||||
#define __CORDOVA_4_0_0 40000
|
||||
#define __CORDOVA_4_0_1 40001
|
||||
#define __CORDOVA_4_1_0 40100
|
||||
#define __CORDOVA_4_1_1 40101
|
||||
#define __CORDOVA_4_2_0 40200
|
||||
#define __CORDOVA_4_2_1 40201
|
||||
#define __CORDOVA_4_3_0 40300
|
||||
#define __CORDOVA_4_3_1 40301
|
||||
#define __CORDOVA_4_4_0 40400
|
||||
#define __CORDOVA_4_5_0 40500
|
||||
#define __CORDOVA_4_5_1 40501
|
||||
#define __CORDOVA_4_5_2 40502
|
||||
#define __CORDOVA_4_5_4 40504
|
||||
/* coho:next-version,insert-before */
|
||||
#define __CORDOVA_NA 99999 /* not available */
|
||||
|
||||
/*
|
||||
#if CORDOVA_VERSION_MIN_REQUIRED >= __CORDOVA_4_0_0
|
||||
// do something when its at least 4.0.0
|
||||
#else
|
||||
// do something else (non 4.0.0)
|
||||
#endif
|
||||
*/
|
||||
#ifndef CORDOVA_VERSION_MIN_REQUIRED
|
||||
/* coho:next-version-min-required,replace-after */
|
||||
#define CORDOVA_VERSION_MIN_REQUIRED __CORDOVA_4_5_4
|
||||
#endif
|
||||
|
||||
/*
|
||||
Returns YES if it is at least version specified as NSString(X)
|
||||
Usage:
|
||||
if (IsAtLeastiOSVersion(@"5.1")) {
|
||||
// do something for iOS 5.1 or greater
|
||||
}
|
||||
*/
|
||||
#define IsAtLeastiOSVersion(X) ([[[UIDevice currentDevice] systemVersion] compare:X options:NSNumericSearch] != NSOrderedAscending)
|
||||
|
||||
/* Return the string version of the decimal version */
|
||||
#define CDV_VERSION [NSString stringWithFormat:@"%d.%d.%d", \
|
||||
(CORDOVA_VERSION_MIN_REQUIRED / 10000), \
|
||||
(CORDOVA_VERSION_MIN_REQUIRED % 10000) / 100, \
|
||||
(CORDOVA_VERSION_MIN_REQUIRED % 10000) % 100]
|
||||
|
||||
// Enable this to log all exec() calls.
|
||||
#define CDV_ENABLE_EXEC_LOGGING 0
|
||||
#if CDV_ENABLE_EXEC_LOGGING
|
||||
#define CDV_EXEC_LOG NSLog
|
||||
#else
|
||||
#define CDV_EXEC_LOG(...) do { \
|
||||
} while (NO)
|
||||
#endif
|
||||
49
node_modules/@capacitor/ios/CapacitorCordova/CapacitorCordova/Classes/Public/CDVCommandDelegate.h
generated
vendored
Normal file
49
node_modules/@capacitor/ios/CapacitorCordova/CapacitorCordova/Classes/Public/CDVCommandDelegate.h
generated
vendored
Normal file
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you under the Apache License, Version 2.0 (the
|
||||
"License"); you may not use this file except in compliance
|
||||
with the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing,
|
||||
software distributed under the License is distributed on an
|
||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
KIND, either express or implied. See the License for the
|
||||
specific language governing permissions and limitations
|
||||
under the License.
|
||||
*/
|
||||
|
||||
#import "CDVInvokedUrlCommand.h"
|
||||
|
||||
@class CDVPlugin;
|
||||
@class CDVPluginResult;
|
||||
|
||||
typedef NSURL* (^ UrlTransformerBlock)(NSURL*);
|
||||
|
||||
@protocol CDVCommandDelegate <NSObject>
|
||||
|
||||
@property (nonatomic, readonly) NSDictionary* settings;
|
||||
@property (nonatomic, copy) UrlTransformerBlock urlTransformer;
|
||||
|
||||
- (NSString*)pathForResource:(NSString*)resourcepath;
|
||||
- (id)getCommandInstance:(NSString*)pluginName;
|
||||
|
||||
// Sends a plugin result to the JS. This is thread-safe.
|
||||
- (void)sendPluginResult:(CDVPluginResult*)result callbackId:(NSString*)callbackId;
|
||||
// Evaluates the given JS. This is thread-safe.
|
||||
- (void)evalJs:(NSString*)js;
|
||||
// Can be used to evaluate JS right away instead of scheduling it on the run-loop.
|
||||
// This is required for dispatch resign and pause events, but should not be used
|
||||
// without reason. Without the run-loop delay, alerts used in JS callbacks may result
|
||||
// in dead-lock. This method must be called from the UI thread.
|
||||
- (void)evalJs:(NSString*)js scheduledOnRunLoop:(BOOL)scheduledOnRunLoop;
|
||||
// Run the javascript
|
||||
- (void)evalJsHelper2:(NSString*)js;
|
||||
// Runs the given block on a background thread using a shared thread-pool.
|
||||
- (void)runInBackground:(void (^)(void))block;
|
||||
|
||||
@end
|
||||
39
node_modules/@capacitor/ios/CapacitorCordova/CapacitorCordova/Classes/Public/CDVCommandDelegateImpl.h
generated
vendored
Normal file
39
node_modules/@capacitor/ios/CapacitorCordova/CapacitorCordova/Classes/Public/CDVCommandDelegateImpl.h
generated
vendored
Normal file
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you under the Apache License, Version 2.0 (the
|
||||
"License"); you may not use this file except in compliance
|
||||
with the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing,
|
||||
software distributed under the License is distributed on an
|
||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
KIND, either express or implied. See the License for the
|
||||
specific language governing permissions and limitations
|
||||
under the License.
|
||||
*/
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
#import "CDVCommandDelegate.h"
|
||||
#import <WebKit/WebKit.h>
|
||||
#import "CDVPluginManager.h"
|
||||
|
||||
@class CDVViewController;
|
||||
@class CDVCommandQueue;
|
||||
|
||||
@interface CDVCommandDelegateImpl : NSObject <CDVCommandDelegate>{
|
||||
@private
|
||||
__weak WKWebView* _webView;
|
||||
__weak CDVPluginManager* _manager;
|
||||
NSRegularExpression* _callbackIdPattern;
|
||||
@protected
|
||||
__weak CDVCommandQueue* _commandQueue;
|
||||
BOOL _delayResponses;
|
||||
}
|
||||
- (id)initWithWebView:(WKWebView*)webView pluginManager:(CDVPluginManager *)manager;
|
||||
- (void)flushCommandQueueWithDelayedJs;
|
||||
@end
|
||||
149
node_modules/@capacitor/ios/CapacitorCordova/CapacitorCordova/Classes/Public/CDVCommandDelegateImpl.m
generated
vendored
Normal file
149
node_modules/@capacitor/ios/CapacitorCordova/CapacitorCordova/Classes/Public/CDVCommandDelegateImpl.m
generated
vendored
Normal file
@@ -0,0 +1,149 @@
|
||||
/*
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you under the Apache License, Version 2.0 (the
|
||||
"License"); you may not use this file except in compliance
|
||||
with the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing,
|
||||
software distributed under the License is distributed on an
|
||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
KIND, either express or implied. See the License for the
|
||||
specific language governing permissions and limitations
|
||||
under the License.
|
||||
*/
|
||||
|
||||
#import "CDVCommandDelegateImpl.h"
|
||||
#import "CDVPluginResult.h"
|
||||
#import <WebKit/WebKit.h>
|
||||
|
||||
@implementation CDVCommandDelegateImpl
|
||||
|
||||
@synthesize urlTransformer;
|
||||
|
||||
- (id)initWithWebView:(WKWebView*)webView pluginManager:(CDVPluginManager *)manager
|
||||
{
|
||||
self = [super init];
|
||||
if (self != nil) {
|
||||
_webView = webView;
|
||||
_manager = manager;
|
||||
NSError* err = nil;
|
||||
_callbackIdPattern = [NSRegularExpression regularExpressionWithPattern:@"[^A-Za-z0-9._-]" options:0 error:&err];
|
||||
if (err != nil) {
|
||||
// Couldn't initialize Regex
|
||||
NSLog(@"Error: Couldn't initialize regex");
|
||||
_callbackIdPattern = nil;
|
||||
}
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (NSString*)pathForResource:(NSString*)resourcepath
|
||||
{
|
||||
NSBundle* mainBundle = [NSBundle mainBundle];
|
||||
NSMutableArray* directoryParts = [NSMutableArray arrayWithArray:[resourcepath componentsSeparatedByString:@"/"]];
|
||||
NSString* filename = [directoryParts lastObject];
|
||||
|
||||
[directoryParts removeLastObject];
|
||||
|
||||
NSString* directoryPartsJoined = [directoryParts componentsJoinedByString:@"/"];
|
||||
NSString* baseFolder = @"public";
|
||||
NSString* directoryStr = baseFolder;
|
||||
|
||||
if ([directoryPartsJoined length] > 0) {
|
||||
directoryStr = [NSString stringWithFormat:@"%@/%@", baseFolder, [directoryParts componentsJoinedByString:@"/"]];
|
||||
}
|
||||
|
||||
return [mainBundle pathForResource:filename ofType:@"" inDirectory:directoryStr];
|
||||
}
|
||||
|
||||
- (void)flushCommandQueueWithDelayedJs
|
||||
{
|
||||
_delayResponses = YES;
|
||||
_delayResponses = NO;
|
||||
}
|
||||
|
||||
- (void)evalJsHelper2:(NSString*)js
|
||||
{
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
[self->_webView evaluateJavaScript:js completionHandler:^(id obj, NSError* error) {
|
||||
// TODO: obj can be something other than string
|
||||
if ([obj isKindOfClass:[NSString class]]) {
|
||||
NSString* commandsJSON = (NSString*)obj;
|
||||
if ([commandsJSON length] > 0) {
|
||||
NSLog(@"Exec: Retrieved new exec messages by chaining.");
|
||||
}
|
||||
}
|
||||
}];
|
||||
});
|
||||
}
|
||||
|
||||
- (BOOL)isValidCallbackId:(NSString*)callbackId
|
||||
{
|
||||
if ((callbackId == nil) || (_callbackIdPattern == nil)) {
|
||||
return NO;
|
||||
}
|
||||
|
||||
// Disallow if too long or if any invalid characters were found.
|
||||
if (([callbackId length] > 100) || [_callbackIdPattern firstMatchInString:callbackId options:0 range:NSMakeRange(0, [callbackId length])]) {
|
||||
return NO;
|
||||
}
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (void)sendPluginResult:(CDVPluginResult*)result callbackId:(NSString*)callbackId
|
||||
{
|
||||
// This occurs when there is are no win/fail callbacks for the call.
|
||||
if ([@"INVALID" isEqualToString:callbackId]) {
|
||||
return;
|
||||
}
|
||||
// This occurs when the callback id is malformed.
|
||||
if (![self isValidCallbackId:callbackId]) {
|
||||
NSLog(@"Invalid callback id received by sendPluginResult");
|
||||
return;
|
||||
}
|
||||
int status = [result.status intValue];
|
||||
BOOL keepCallback = [result.keepCallback boolValue];
|
||||
NSString* argumentsAsJSON = [result argumentsAsJSON];
|
||||
BOOL debug = NO;
|
||||
|
||||
#ifdef DEBUG
|
||||
debug = YES;
|
||||
#endif
|
||||
|
||||
NSString* js = [NSString stringWithFormat:@"cordova.require('cordova/exec').nativeCallback('%@',%d,%@,%d, %d)", callbackId, status, argumentsAsJSON, keepCallback, debug];
|
||||
|
||||
[self evalJsHelper2:js];
|
||||
}
|
||||
|
||||
- (void)evalJs:(NSString*)js
|
||||
{
|
||||
[self evalJs:js scheduledOnRunLoop:YES];
|
||||
}
|
||||
|
||||
- (void)evalJs:(NSString*)js scheduledOnRunLoop:(BOOL)scheduledOnRunLoop
|
||||
{
|
||||
js = [NSString stringWithFormat:@"try{cordova.require('cordova/exec').nativeEvalAndFetch(function(){%@})}catch(e){console.log('exception nativeEvalAndFetch : '+e);};", js];
|
||||
[self evalJsHelper2:js];
|
||||
}
|
||||
|
||||
- (id)getCommandInstance:(NSString*)pluginName
|
||||
{
|
||||
return [_manager getCommandInstance:pluginName];
|
||||
}
|
||||
|
||||
- (void)runInBackground:(void (^)(void))block
|
||||
{
|
||||
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), block);
|
||||
}
|
||||
|
||||
- (NSDictionary*)settings
|
||||
{
|
||||
return _manager.settings;
|
||||
}
|
||||
|
||||
@end
|
||||
31
node_modules/@capacitor/ios/CapacitorCordova/CapacitorCordova/Classes/Public/CDVConfigParser.h
generated
vendored
Normal file
31
node_modules/@capacitor/ios/CapacitorCordova/CapacitorCordova/Classes/Public/CDVConfigParser.h
generated
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you under the Apache License, Version 2.0 (the
|
||||
"License"); you may not use this file except in compliance
|
||||
with the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing,
|
||||
software distributed under the License is distributed on an
|
||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
KIND, either express or implied. See the License for the
|
||||
specific language governing permissions and limitations
|
||||
under the License.
|
||||
*/
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@interface CDVConfigParser : NSObject <NSXMLParserDelegate>
|
||||
{
|
||||
NSString* featureName;
|
||||
}
|
||||
|
||||
@property (nonatomic, readonly, strong) NSMutableDictionary* pluginsDict;
|
||||
@property (nonatomic, readonly, strong) NSMutableDictionary* settings;
|
||||
@property (nonatomic, readonly, strong) NSMutableArray* startupPluginNames;
|
||||
@property (nonatomic, readonly, strong) NSString* startPage;
|
||||
|
||||
@end
|
||||
81
node_modules/@capacitor/ios/CapacitorCordova/CapacitorCordova/Classes/Public/CDVConfigParser.m
generated
vendored
Normal file
81
node_modules/@capacitor/ios/CapacitorCordova/CapacitorCordova/Classes/Public/CDVConfigParser.m
generated
vendored
Normal file
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you under the Apache License, Version 2.0 (the
|
||||
"License"); you may not use this file except in compliance
|
||||
with the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing,
|
||||
software distributed under the License is distributed on an
|
||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
KIND, either express or implied. See the License for the
|
||||
specific language governing permissions and limitations
|
||||
under the License.
|
||||
*/
|
||||
|
||||
#import "CDVConfigParser.h"
|
||||
|
||||
@interface CDVConfigParser ()
|
||||
|
||||
@property (nonatomic, readwrite, strong) NSMutableDictionary* pluginsDict;
|
||||
@property (nonatomic, readwrite, strong) NSMutableDictionary* settings;
|
||||
@property (nonatomic, readwrite, strong) NSMutableArray* startupPluginNames;
|
||||
@property (nonatomic, readwrite, strong) NSString* startPage;
|
||||
|
||||
@end
|
||||
|
||||
@implementation CDVConfigParser
|
||||
|
||||
@synthesize pluginsDict, settings, startPage, startupPluginNames;
|
||||
|
||||
- (id)init
|
||||
{
|
||||
self = [super init];
|
||||
if (self != nil) {
|
||||
self.pluginsDict = [[NSMutableDictionary alloc] initWithCapacity:30];
|
||||
self.settings = [[NSMutableDictionary alloc] initWithCapacity:30];
|
||||
self.startupPluginNames = [[NSMutableArray alloc] initWithCapacity:8];
|
||||
featureName = nil;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)parser:(NSXMLParser*)parser didStartElement:(NSString*)elementName namespaceURI:(NSString*)namespaceURI qualifiedName:(NSString*)qualifiedName attributes:(NSDictionary*)attributeDict
|
||||
{
|
||||
if ([elementName isEqualToString:@"preference"]) {
|
||||
settings[[attributeDict[@"name"] lowercaseString]] = attributeDict[@"value"];
|
||||
} else if ([elementName isEqualToString:@"feature"]) { // store feature name to use with correct parameter set
|
||||
featureName = [attributeDict[@"name"] lowercaseString];
|
||||
} else if ((featureName != nil) && [elementName isEqualToString:@"param"]) {
|
||||
NSString* paramName = [attributeDict[@"name"] lowercaseString];
|
||||
id value = attributeDict[@"value"];
|
||||
if ([paramName isEqualToString:@"ios-package"]) {
|
||||
pluginsDict[featureName] = value;
|
||||
}
|
||||
BOOL paramIsOnload = ([paramName isEqualToString:@"onload"] && [@"true" isEqualToString : value]);
|
||||
BOOL attribIsOnload = [@"true" isEqualToString :[attributeDict[@"onload"] lowercaseString]];
|
||||
if (paramIsOnload || attribIsOnload) {
|
||||
[self.startupPluginNames addObject:featureName];
|
||||
}
|
||||
} else if ([elementName isEqualToString:@"content"]) {
|
||||
self.startPage = attributeDict[@"src"];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)parser:(NSXMLParser*)parser didEndElement:(NSString*)elementName namespaceURI:(NSString*)namespaceURI qualifiedName:(NSString*)qualifiedName
|
||||
{
|
||||
if ([elementName isEqualToString:@"feature"]) { // no longer handling a feature so release
|
||||
featureName = nil;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)parser:(NSXMLParser*)parser parseErrorOccurred:(NSError*)parseError
|
||||
{
|
||||
NSAssert(NO, @"config.xml parse error line %ld col %ld", (long)[parser lineNumber], (long)[parser columnNumber]);
|
||||
}
|
||||
|
||||
@end
|
||||
52
node_modules/@capacitor/ios/CapacitorCordova/CapacitorCordova/Classes/Public/CDVInvokedUrlCommand.h
generated
vendored
Normal file
52
node_modules/@capacitor/ios/CapacitorCordova/CapacitorCordova/Classes/Public/CDVInvokedUrlCommand.h
generated
vendored
Normal file
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you under the Apache License, Version 2.0 (the
|
||||
"License"); you may not use this file except in compliance
|
||||
with the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing,
|
||||
software distributed under the License is distributed on an
|
||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
KIND, either express or implied. See the License for the
|
||||
specific language governing permissions and limitations
|
||||
under the License.
|
||||
*/
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@interface CDVInvokedUrlCommand : NSObject {
|
||||
NSString* _callbackId;
|
||||
NSString* _className;
|
||||
NSString* _methodName;
|
||||
NSArray* _arguments;
|
||||
}
|
||||
|
||||
@property (nonatomic, readonly) NSArray* arguments;
|
||||
@property (nonatomic, readonly) NSString* callbackId;
|
||||
@property (nonatomic, readonly) NSString* className;
|
||||
@property (nonatomic, readonly) NSString* methodName;
|
||||
|
||||
+ (CDVInvokedUrlCommand*)commandFromJson:(NSArray*)jsonEntry;
|
||||
|
||||
- (id)initWithArguments:(NSArray*)arguments
|
||||
callbackId:(NSString*)callbackId
|
||||
className:(NSString*)className
|
||||
methodName:(NSString*)methodName;
|
||||
|
||||
- (id)initFromJson:(NSArray*)jsonEntry;
|
||||
|
||||
// Returns the argument at the given index.
|
||||
// If index >= the number of arguments, returns nil.
|
||||
// If the argument at the given index is NSNull, returns nil.
|
||||
- (id)argumentAtIndex:(NSUInteger)index;
|
||||
// Same as above, but returns defaultValue instead of nil.
|
||||
- (id)argumentAtIndex:(NSUInteger)index withDefault:(id)defaultValue;
|
||||
// Same as above, but returns defaultValue instead of nil, and if the argument is not of the expected class, returns defaultValue
|
||||
- (id)argumentAtIndex:(NSUInteger)index withDefault:(id)defaultValue andClass:(Class)aClass;
|
||||
|
||||
@end
|
||||
116
node_modules/@capacitor/ios/CapacitorCordova/CapacitorCordova/Classes/Public/CDVInvokedUrlCommand.m
generated
vendored
Normal file
116
node_modules/@capacitor/ios/CapacitorCordova/CapacitorCordova/Classes/Public/CDVInvokedUrlCommand.m
generated
vendored
Normal file
@@ -0,0 +1,116 @@
|
||||
/*
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you under the Apache License, Version 2.0 (the
|
||||
"License"); you may not use this file except in compliance
|
||||
with the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing,
|
||||
software distributed under the License is distributed on an
|
||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
KIND, either express or implied. See the License for the
|
||||
specific language governing permissions and limitations
|
||||
under the License.
|
||||
*/
|
||||
|
||||
#import "CDVInvokedUrlCommand.h"
|
||||
|
||||
|
||||
@implementation CDVInvokedUrlCommand
|
||||
|
||||
@synthesize arguments = _arguments;
|
||||
@synthesize callbackId = _callbackId;
|
||||
@synthesize className = _className;
|
||||
@synthesize methodName = _methodName;
|
||||
|
||||
+ (CDVInvokedUrlCommand*)commandFromJson:(NSArray*)jsonEntry
|
||||
{
|
||||
return [[CDVInvokedUrlCommand alloc] initFromJson:jsonEntry];
|
||||
}
|
||||
|
||||
- (id)initFromJson:(NSArray*)jsonEntry
|
||||
{
|
||||
id tmp = [jsonEntry objectAtIndex:0];
|
||||
NSString* callbackId = tmp == [NSNull null] ? nil : tmp;
|
||||
NSString* className = [jsonEntry objectAtIndex:1];
|
||||
NSString* methodName = [jsonEntry objectAtIndex:2];
|
||||
NSMutableArray* arguments = [jsonEntry objectAtIndex:3];
|
||||
|
||||
return [self initWithArguments:arguments
|
||||
callbackId:callbackId
|
||||
className:className
|
||||
methodName:methodName];
|
||||
}
|
||||
|
||||
- (id)initWithArguments:(NSArray*)arguments
|
||||
callbackId:(NSString*)callbackId
|
||||
className:(NSString*)className
|
||||
methodName:(NSString*)methodName
|
||||
{
|
||||
self = [super init];
|
||||
if (self != nil) {
|
||||
_arguments = arguments;
|
||||
_callbackId = callbackId;
|
||||
_className = className;
|
||||
_methodName = methodName;
|
||||
}
|
||||
[self massageArguments];
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)massageArguments
|
||||
{
|
||||
NSMutableArray* newArgs = nil;
|
||||
|
||||
for (NSUInteger i = 0, count = [_arguments count]; i < count; ++i) {
|
||||
id arg = [_arguments objectAtIndex:i];
|
||||
if (![arg isKindOfClass:[NSDictionary class]]) {
|
||||
continue;
|
||||
}
|
||||
NSDictionary* dict = arg;
|
||||
NSString* type = [dict objectForKey:@"CDVType"];
|
||||
if (!type || ![type isEqualToString:@"ArrayBuffer"]) {
|
||||
continue;
|
||||
}
|
||||
NSString* data = [dict objectForKey:@"data"];
|
||||
if (!data) {
|
||||
continue;
|
||||
}
|
||||
if (newArgs == nil) {
|
||||
newArgs = [NSMutableArray arrayWithArray:_arguments];
|
||||
_arguments = newArgs;
|
||||
}
|
||||
[newArgs replaceObjectAtIndex:i withObject:[[NSData alloc] initWithBase64EncodedString:data options:0]];
|
||||
}
|
||||
}
|
||||
|
||||
- (id)argumentAtIndex:(NSUInteger)index
|
||||
{
|
||||
return [self argumentAtIndex:index withDefault:nil];
|
||||
}
|
||||
|
||||
- (id)argumentAtIndex:(NSUInteger)index withDefault:(id)defaultValue
|
||||
{
|
||||
return [self argumentAtIndex:index withDefault:defaultValue andClass:nil];
|
||||
}
|
||||
|
||||
- (id)argumentAtIndex:(NSUInteger)index withDefault:(id)defaultValue andClass:(Class)aClass
|
||||
{
|
||||
if (index >= [_arguments count]) {
|
||||
return defaultValue;
|
||||
}
|
||||
id ret = [_arguments objectAtIndex:index];
|
||||
if (ret == [NSNull null]) {
|
||||
ret = defaultValue;
|
||||
}
|
||||
if ((aClass != nil) && ![ret isKindOfClass:aClass]) {
|
||||
ret = defaultValue;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
@end
|
||||
39
node_modules/@capacitor/ios/CapacitorCordova/CapacitorCordova/Classes/Public/CDVPlugin+Resources.h
generated
vendored
Normal file
39
node_modules/@capacitor/ios/CapacitorCordova/CapacitorCordova/Classes/Public/CDVPlugin+Resources.h
generated
vendored
Normal file
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you under the Apache License, Version 2.0 (the
|
||||
"License"); you may not use this file except in compliance
|
||||
with the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing,
|
||||
software distributed under the License is distributed on an
|
||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
KIND, either express or implied. See the License for the
|
||||
specific language governing permissions and limitations
|
||||
under the License.
|
||||
*/
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
#import "CDVPlugin.h"
|
||||
|
||||
@interface CDVPlugin (CDVPluginResources)
|
||||
|
||||
/*
|
||||
This will return the localized string for a key in a .bundle that is named the same as your class
|
||||
For example, if your plugin class was called Foo, and you have a Spanish localized strings file, it will
|
||||
try to load the desired key from Foo.bundle/es.lproj/Localizable.strings
|
||||
*/
|
||||
- (NSString*)pluginLocalizedString:(NSString*)key;
|
||||
|
||||
/*
|
||||
This will return the image for a name in a .bundle that is named the same as your class
|
||||
For example, if your plugin class was called Foo, and you have an image called "bar",
|
||||
it will try to load the image from Foo.bundle/bar.png (and appropriately named retina versions)
|
||||
*/
|
||||
- (UIImage*)pluginImageResource:(NSString*)name;
|
||||
|
||||
@end
|
||||
38
node_modules/@capacitor/ios/CapacitorCordova/CapacitorCordova/Classes/Public/CDVPlugin+Resources.m
generated
vendored
Normal file
38
node_modules/@capacitor/ios/CapacitorCordova/CapacitorCordova/Classes/Public/CDVPlugin+Resources.m
generated
vendored
Normal file
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you under the Apache License, Version 2.0 (the
|
||||
"License"); you may not use this file except in compliance
|
||||
with the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing,
|
||||
software distributed under the License is distributed on an
|
||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
KIND, either express or implied. See the License for the
|
||||
specific language governing permissions and limitations
|
||||
under the License.
|
||||
*/
|
||||
|
||||
#import "CDVPlugin+Resources.h"
|
||||
|
||||
@implementation CDVPlugin (CDVPluginResources)
|
||||
|
||||
- (NSString*)pluginLocalizedString:(NSString*)key
|
||||
{
|
||||
NSBundle* bundle = [NSBundle bundleWithPath:[[NSBundle mainBundle] pathForResource:NSStringFromClass([self class]) ofType:@"bundle"]];
|
||||
|
||||
return [bundle localizedStringForKey:(key) value:nil table:nil];
|
||||
}
|
||||
|
||||
- (UIImage*)pluginImageResource:(NSString*)name
|
||||
{
|
||||
NSString* resourceIdentifier = [NSString stringWithFormat:@"%@.bundle/%@", NSStringFromClass([self class]), name];
|
||||
|
||||
return [UIImage imageNamed:resourceIdentifier];
|
||||
}
|
||||
|
||||
@end
|
||||
82
node_modules/@capacitor/ios/CapacitorCordova/CapacitorCordova/Classes/Public/CDVPlugin.h
generated
vendored
Normal file
82
node_modules/@capacitor/ios/CapacitorCordova/CapacitorCordova/Classes/Public/CDVPlugin.h
generated
vendored
Normal file
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you under the Apache License, Version 2.0 (the
|
||||
"License"); you may not use this file except in compliance
|
||||
with the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing,
|
||||
software distributed under the License is distributed on an
|
||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
KIND, either express or implied. See the License for the
|
||||
specific language governing permissions and limitations
|
||||
under the License.
|
||||
*/
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <UIKit/UIKit.h>
|
||||
#import "CDVPluginResult.h"
|
||||
#import "CDVCommandDelegate.h"
|
||||
#import "CDVAvailability.h"
|
||||
#import <WebKit/WebKit.h>
|
||||
|
||||
@interface UIView (org_apache_cordova_UIView_Extension)
|
||||
|
||||
@property (nonatomic, weak) UIScrollView* scrollView;
|
||||
|
||||
@end
|
||||
|
||||
extern NSString* const CDVPageDidLoadNotification;
|
||||
extern NSString* const CDVPluginHandleOpenURLNotification;
|
||||
extern NSString* const CDVPluginHandleOpenURLWithAppSourceAndAnnotationNotification;
|
||||
extern NSString* const CDVPluginResetNotification;
|
||||
extern NSString* const CDVViewWillAppearNotification;
|
||||
extern NSString* const CDVViewDidAppearNotification;
|
||||
extern NSString* const CDVViewWillDisappearNotification;
|
||||
extern NSString* const CDVViewDidDisappearNotification;
|
||||
extern NSString* const CDVViewWillLayoutSubviewsNotification;
|
||||
extern NSString* const CDVViewDidLayoutSubviewsNotification;
|
||||
extern NSString* const CDVViewWillTransitionToSizeNotification;
|
||||
|
||||
/*
|
||||
* The local and remote push notification functionality has been removed from the core in cordova-ios 4.x,
|
||||
* but these constants have unfortunately have not been removed, but will be removed in 5.x.
|
||||
*
|
||||
* To have the same functionality as 3.x, use a third-party plugin or the experimental
|
||||
* https://github.com/apache/cordova-plugins/tree/master/notification-rebroadcast
|
||||
*/
|
||||
|
||||
|
||||
@interface CDVPlugin : NSObject {}
|
||||
|
||||
- (instancetype)initWithWebViewEngine:(WKWebView *)theWebViewEngine;
|
||||
@property (nonatomic, weak) UIView* webView;
|
||||
@property (nonatomic, weak) WKWebView * webViewEngine;
|
||||
@property (nonatomic, strong) NSString * className;
|
||||
|
||||
@property (nonatomic, weak) UIViewController* viewController;
|
||||
@property (nonatomic, weak) id <CDVCommandDelegate> commandDelegate;
|
||||
|
||||
- (void)pluginInitialize;
|
||||
|
||||
- (void)handleOpenURL:(NSNotification*)notification;
|
||||
- (void)onAppTerminate;
|
||||
- (void)onMemoryWarning;
|
||||
- (void)onReset;
|
||||
- (void)dispose;
|
||||
|
||||
/*
|
||||
// see initWithWebView implementation
|
||||
- (void) onPause {}
|
||||
- (void) onResume {}
|
||||
- (void) onOrientationWillChange {}
|
||||
- (void) onOrientationDidChange {}
|
||||
*/
|
||||
|
||||
- (id)appDelegate;
|
||||
|
||||
@end
|
||||
154
node_modules/@capacitor/ios/CapacitorCordova/CapacitorCordova/Classes/Public/CDVPlugin.m
generated
vendored
Normal file
154
node_modules/@capacitor/ios/CapacitorCordova/CapacitorCordova/Classes/Public/CDVPlugin.m
generated
vendored
Normal file
@@ -0,0 +1,154 @@
|
||||
/*
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you under the Apache License, Version 2.0 (the
|
||||
"License"); you may not use this file except in compliance
|
||||
with the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing,
|
||||
software distributed under the License is distributed on an
|
||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
KIND, either express or implied. See the License for the
|
||||
specific language governing permissions and limitations
|
||||
under the License.
|
||||
*/
|
||||
|
||||
#import "CDVPlugin.h"
|
||||
#include <objc/message.h>
|
||||
|
||||
@implementation UIView (org_apache_cordova_UIView_Extension)
|
||||
|
||||
@dynamic scrollView;
|
||||
|
||||
- (UIScrollView*)scrollView
|
||||
{
|
||||
SEL scrollViewSelector = NSSelectorFromString(@"scrollView");
|
||||
|
||||
if ([self respondsToSelector:scrollViewSelector]) {
|
||||
return ((id (*)(id, SEL))objc_msgSend)(self, scrollViewSelector);
|
||||
}
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
NSString* const CDVPageDidLoadNotification = @"CDVPageDidLoadNotification";
|
||||
NSString* const CDVPluginHandleOpenURLNotification = @"CDVPluginHandleOpenURLNotification";
|
||||
NSString* const CDVPluginHandleOpenURLWithAppSourceAndAnnotationNotification = @"CDVPluginHandleOpenURLWithAppSourceAndAnnotationNotification";
|
||||
NSString* const CDVPluginResetNotification = @"CDVPluginResetNotification";
|
||||
NSString* const CDVLocalNotification = @"CDVLocalNotification";
|
||||
NSString* const CDVRemoteNotification = @"CDVRemoteNotification";
|
||||
NSString* const CDVRemoteNotificationError = @"CDVRemoteNotificationError";
|
||||
NSString* const CDVViewWillAppearNotification = @"CDVViewWillAppearNotification";
|
||||
NSString* const CDVViewDidAppearNotification = @"CDVViewDidAppearNotification";
|
||||
NSString* const CDVViewWillDisappearNotification = @"CDVViewWillDisappearNotification";
|
||||
NSString* const CDVViewDidDisappearNotification = @"CDVViewDidDisappearNotification";
|
||||
NSString* const CDVViewWillLayoutSubviewsNotification = @"CDVViewWillLayoutSubviewsNotification";
|
||||
NSString* const CDVViewDidLayoutSubviewsNotification = @"CDVViewDidLayoutSubviewsNotification";
|
||||
NSString* const CDVViewWillTransitionToSizeNotification = @"CDVViewWillTransitionToSizeNotification";
|
||||
|
||||
@interface CDVPlugin ()
|
||||
|
||||
@property (readwrite, assign) BOOL hasPendingOperation;
|
||||
|
||||
@end
|
||||
|
||||
@implementation CDVPlugin
|
||||
@synthesize webViewEngine, viewController, commandDelegate, hasPendingOperation, webView;
|
||||
|
||||
// Do not override these methods. Use pluginInitialize instead.
|
||||
- (instancetype)initWithWebViewEngine:(WKWebView *)theWebViewEngine
|
||||
{
|
||||
self = [super init];
|
||||
if (self) {
|
||||
self.webViewEngine = theWebViewEngine;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)pluginInitialize
|
||||
{
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onAppTerminate) name:UIApplicationWillTerminateNotification object:nil];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onMemoryWarning) name:UIApplicationDidReceiveMemoryWarningNotification object:nil];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleOpenURL:) name:CDVPluginHandleOpenURLNotification object:nil];
|
||||
// You can listen to more app notifications, see:
|
||||
// http://developer.apple.com/library/ios/#DOCUMENTATION/UIKit/Reference/UIApplication_Class/Reference/Reference.html#//apple_ref/doc/uid/TP40006728-CH3-DontLinkElementID_4
|
||||
|
||||
// NOTE: if you want to use these, make sure you uncomment the corresponding notification handler
|
||||
|
||||
// [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onPause) name:UIApplicationDidEnterBackgroundNotification object:nil];
|
||||
// [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onResume) name:UIApplicationWillEnterForegroundNotification object:nil];
|
||||
// [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onOrientationWillChange) name:UIApplicationWillChangeStatusBarOrientationNotification object:nil];
|
||||
// [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onOrientationDidChange) name:UIApplicationDidChangeStatusBarOrientationNotification object:nil];
|
||||
|
||||
// Added in 2.5.0
|
||||
// [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(pageDidLoad:) name:CDVPageDidLoadNotification object:self.webView];
|
||||
//Added in 4.3.0
|
||||
// [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(viewWillAppear:) name:CDVViewWillAppearNotification object:nil];
|
||||
// [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(viewDidAppear:) name:CDVViewDidAppearNotification object:nil];
|
||||
// [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(viewWillDisappear:) name:CDVViewWillDisappearNotification object:nil];
|
||||
// [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(viewDidDisappear:) name:CDVViewDidDisappearNotification object:nil];
|
||||
// [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(viewWillLayoutSubviews:) name:CDVViewWillLayoutSubviewsNotification object:nil];
|
||||
// [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(viewDidLayoutSubviews:) name:CDVViewDidLayoutSubviewsNotification object:nil];
|
||||
// [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(viewWillTransitionToSize:) name:CDVViewWillTransitionToSizeNotification object:nil];
|
||||
}
|
||||
|
||||
- (void)dispose
|
||||
{
|
||||
viewController = nil;
|
||||
commandDelegate = nil;
|
||||
}
|
||||
|
||||
/*
|
||||
// NOTE: for onPause and onResume, calls into JavaScript must not call or trigger any blocking UI, like alerts
|
||||
- (void) onPause {}
|
||||
- (void) onResume {}
|
||||
- (void) onOrientationWillChange {}
|
||||
- (void) onOrientationDidChange {}
|
||||
*/
|
||||
|
||||
/* NOTE: calls into JavaScript must not call or trigger any blocking UI, like alerts */
|
||||
- (void)handleOpenURL:(NSNotification*)notification
|
||||
{
|
||||
// override to handle urls sent to your app
|
||||
// register your url schemes in your App-Info.plist
|
||||
|
||||
NSURL* url = [notification object];
|
||||
|
||||
if ([url isKindOfClass:[NSURL class]]) {
|
||||
/* Do your thing! */
|
||||
}
|
||||
}
|
||||
|
||||
/* NOTE: calls into JavaScript must not call or trigger any blocking UI, like alerts */
|
||||
- (void)onAppTerminate
|
||||
{
|
||||
// override this if you need to do any cleanup on app exit
|
||||
}
|
||||
|
||||
- (void)onMemoryWarning
|
||||
{
|
||||
// override to remove caches, etc
|
||||
}
|
||||
|
||||
- (void)onReset
|
||||
{
|
||||
// Override to cancel any long-running requests when the WebView navigates or refreshes.
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self]; // this will remove all notifications unless added using addObserverForName:object:queue:usingBlock:
|
||||
}
|
||||
|
||||
- (id)appDelegate
|
||||
{
|
||||
return [[UIApplication sharedApplication] delegate];
|
||||
}
|
||||
|
||||
@end
|
||||
25
node_modules/@capacitor/ios/CapacitorCordova/CapacitorCordova/Classes/Public/CDVPluginManager.h
generated
vendored
Normal file
25
node_modules/@capacitor/ios/CapacitorCordova/CapacitorCordova/Classes/Public/CDVPluginManager.h
generated
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
//
|
||||
// CDVPluginManager.h
|
||||
// CapacitorCordova
|
||||
//
|
||||
// Created by Julio Cesar Sanchez Hernandez on 26/2/18.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "CDVPlugin.h"
|
||||
#import "CDVConfigParser.h"
|
||||
#import "CDVCommandDelegate.h"
|
||||
|
||||
@interface CDVPluginManager : NSObject
|
||||
|
||||
@property (nonatomic, strong) NSMutableDictionary * pluginsMap;
|
||||
@property (nonatomic, strong) NSMutableDictionary * pluginObjects;
|
||||
@property (nonatomic, strong) NSMutableDictionary * settings;
|
||||
@property (nonatomic, weak) UIViewController * viewController;
|
||||
@property (nonatomic, weak) WKWebView * webView;
|
||||
@property (nonatomic, strong) id <CDVCommandDelegate> commandDelegate;
|
||||
|
||||
- (id)initWithParser:(CDVConfigParser*)parser viewController:(UIViewController*)viewController webView:(WKWebView *)webview;
|
||||
- (CDVPlugin *)getCommandInstance:(NSString*)pluginName;
|
||||
|
||||
@end
|
||||
77
node_modules/@capacitor/ios/CapacitorCordova/CapacitorCordova/Classes/Public/CDVPluginManager.m
generated
vendored
Normal file
77
node_modules/@capacitor/ios/CapacitorCordova/CapacitorCordova/Classes/Public/CDVPluginManager.m
generated
vendored
Normal file
@@ -0,0 +1,77 @@
|
||||
#import "CDVPluginManager.h"
|
||||
#import "CDVPlugin.h"
|
||||
#import "CDVCommandDelegateImpl.h"
|
||||
|
||||
@implementation CDVPluginManager
|
||||
|
||||
- (id)initWithParser:(CDVConfigParser*)parser viewController:(UIViewController*)viewController webView:(WKWebView *)webview
|
||||
{
|
||||
self = [super init];
|
||||
if (self != nil) {
|
||||
_pluginsMap = parser.pluginsDict;
|
||||
_settings = parser.settings;
|
||||
_viewController = viewController;
|
||||
_webView = webview;
|
||||
_pluginObjects = [[NSMutableDictionary alloc] init];
|
||||
_commandDelegate = [[CDVCommandDelegateImpl alloc] initWithWebView:_webView pluginManager:self];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onAppDidEnterBackground:)
|
||||
name:UIApplicationDidEnterBackgroundNotification object:nil];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onAppWillEnterForeground:)
|
||||
name:UIApplicationWillEnterForegroundNotification object:nil];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
/**
|
||||
Returns an instance of a CordovaCommand object, based on its name. If one exists already, it is returned.
|
||||
*/
|
||||
- (CDVPlugin *)getCommandInstance:(NSString*)pluginName
|
||||
{
|
||||
NSString* className = [self.pluginsMap objectForKey:[pluginName lowercaseString]];
|
||||
|
||||
if (className == nil) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
id obj = [self.pluginObjects objectForKey:className];
|
||||
if (!obj) {
|
||||
obj = [[NSClassFromString(className)alloc] initWithWebViewEngine: self.webView];
|
||||
if (!obj) {
|
||||
NSString* fullClassName = [NSString stringWithFormat:@"%@.%@",
|
||||
NSBundle.mainBundle.infoDictionary[@"CFBundleExecutable"],
|
||||
className];
|
||||
obj = [[NSClassFromString(fullClassName)alloc] initWithWebViewEngine: self.webView];
|
||||
}
|
||||
|
||||
if (obj != nil) {
|
||||
[self registerPlugin:obj withClassName:className];
|
||||
} else {
|
||||
NSLog(@"CDVPlugin class %@ (pluginName: %@) does not exist.", className, pluginName);
|
||||
}
|
||||
}
|
||||
[obj setClassName:className];
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
|
||||
- (void)registerPlugin:(CDVPlugin*)plugin withClassName:(NSString*)className
|
||||
{
|
||||
[self.pluginObjects setObject:plugin forKey:className];
|
||||
plugin.viewController = self.viewController;
|
||||
plugin.webView = self.webView;
|
||||
plugin.commandDelegate = self.commandDelegate;
|
||||
[plugin pluginInitialize];
|
||||
}
|
||||
|
||||
- (void)onAppDidEnterBackground:(NSNotification*)notification
|
||||
{
|
||||
[self.commandDelegate evalJsHelper2:@"window.Capacitor.triggerEvent('pause', 'document');"];
|
||||
}
|
||||
|
||||
- (void)onAppWillEnterForeground:(NSNotification*)notification
|
||||
{
|
||||
[self.commandDelegate evalJsHelper2:@"window.Capacitor.triggerEvent('resume', 'document');"];
|
||||
}
|
||||
|
||||
@end
|
||||
82
node_modules/@capacitor/ios/CapacitorCordova/CapacitorCordova/Classes/Public/CDVPluginResult.h
generated
vendored
Normal file
82
node_modules/@capacitor/ios/CapacitorCordova/CapacitorCordova/Classes/Public/CDVPluginResult.h
generated
vendored
Normal file
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you under the Apache License, Version 2.0 (the
|
||||
"License"); you may not use this file except in compliance
|
||||
with the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing,
|
||||
software distributed under the License is distributed on an
|
||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
KIND, either express or implied. See the License for the
|
||||
specific language governing permissions and limitations
|
||||
under the License.
|
||||
*/
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
typedef NS_ENUM(NSUInteger, CDVCommandStatus) {
|
||||
CDVCommandStatus_NO_RESULT NS_SWIFT_NAME(noResult) = 0,
|
||||
CDVCommandStatus_OK NS_SWIFT_NAME(ok),
|
||||
CDVCommandStatus_CLASS_NOT_FOUND_EXCEPTION NS_SWIFT_NAME(classNotFoundException),
|
||||
CDVCommandStatus_ILLEGAL_ACCESS_EXCEPTION NS_SWIFT_NAME(illegalAccessException),
|
||||
CDVCommandStatus_INSTANTIATION_EXCEPTION NS_SWIFT_NAME(instantiationException),
|
||||
CDVCommandStatus_MALFORMED_URL_EXCEPTION NS_SWIFT_NAME(malformedUrlException),
|
||||
CDVCommandStatus_IO_EXCEPTION NS_SWIFT_NAME(ioException),
|
||||
CDVCommandStatus_INVALID_ACTION NS_SWIFT_NAME(invalidAction),
|
||||
CDVCommandStatus_JSON_EXCEPTION NS_SWIFT_NAME(jsonException),
|
||||
CDVCommandStatus_ERROR NS_SWIFT_NAME(error)
|
||||
};
|
||||
|
||||
// This exists to preserve compatibility with early Swift plugins, who are
|
||||
// using CDVCommandStatus as ObjC-style constants rather than as Swift enum
|
||||
// values.
|
||||
// This declares extern'ed constants (implemented in CDVPluginResult.m)
|
||||
#define SWIFT_ENUM_COMPAT_HACK(enumVal) extern const CDVCommandStatus SWIFT_##enumVal NS_SWIFT_NAME(enumVal)
|
||||
SWIFT_ENUM_COMPAT_HACK(CDVCommandStatus_NO_RESULT);
|
||||
SWIFT_ENUM_COMPAT_HACK(CDVCommandStatus_OK);
|
||||
SWIFT_ENUM_COMPAT_HACK(CDVCommandStatus_CLASS_NOT_FOUND_EXCEPTION);
|
||||
SWIFT_ENUM_COMPAT_HACK(CDVCommandStatus_ILLEGAL_ACCESS_EXCEPTION);
|
||||
SWIFT_ENUM_COMPAT_HACK(CDVCommandStatus_INSTANTIATION_EXCEPTION);
|
||||
SWIFT_ENUM_COMPAT_HACK(CDVCommandStatus_MALFORMED_URL_EXCEPTION);
|
||||
SWIFT_ENUM_COMPAT_HACK(CDVCommandStatus_IO_EXCEPTION);
|
||||
SWIFT_ENUM_COMPAT_HACK(CDVCommandStatus_INVALID_ACTION);
|
||||
SWIFT_ENUM_COMPAT_HACK(CDVCommandStatus_JSON_EXCEPTION);
|
||||
SWIFT_ENUM_COMPAT_HACK(CDVCommandStatus_ERROR);
|
||||
#undef SWIFT_ENUM_COMPAT_HACK
|
||||
|
||||
@interface CDVPluginResult : NSObject {}
|
||||
|
||||
@property (nonatomic, strong, readonly) NSNumber* status;
|
||||
@property (nonatomic, strong, readonly) id message;
|
||||
@property (nonatomic, strong) NSNumber* keepCallback;
|
||||
// This property can be used to scope the lifetime of another object. For example,
|
||||
// Use it to store the associated NSData when `message` is created using initWithBytesNoCopy.
|
||||
@property (nonatomic, strong) id associatedObject;
|
||||
|
||||
- (CDVPluginResult*)init;
|
||||
+ (CDVPluginResult*)resultWithStatus:(CDVCommandStatus)statusOrdinal;
|
||||
+ (CDVPluginResult*)resultWithStatus:(CDVCommandStatus)statusOrdinal messageAsString:(NSString*)theMessage;
|
||||
+ (CDVPluginResult*)resultWithStatus:(CDVCommandStatus)statusOrdinal messageAsArray:(NSArray*)theMessage;
|
||||
+ (CDVPluginResult*)resultWithStatus:(CDVCommandStatus)statusOrdinal messageAsInt:(int)theMessage;
|
||||
+ (CDVPluginResult*)resultWithStatus:(CDVCommandStatus)statusOrdinal messageAsNSInteger:(NSInteger)theMessage;
|
||||
+ (CDVPluginResult*)resultWithStatus:(CDVCommandStatus)statusOrdinal messageAsNSUInteger:(NSUInteger)theMessage;
|
||||
+ (CDVPluginResult*)resultWithStatus:(CDVCommandStatus)statusOrdinal messageAsDouble:(double)theMessage;
|
||||
+ (CDVPluginResult*)resultWithStatus:(CDVCommandStatus)statusOrdinal messageAsBool:(BOOL)theMessage;
|
||||
+ (CDVPluginResult*)resultWithStatus:(CDVCommandStatus)statusOrdinal messageAsDictionary:(NSDictionary*)theMessage;
|
||||
+ (CDVPluginResult*)resultWithStatus:(CDVCommandStatus)statusOrdinal messageAsArrayBuffer:(NSData*)theMessage;
|
||||
+ (CDVPluginResult*)resultWithStatus:(CDVCommandStatus)statusOrdinal messageAsMultipart:(NSArray*)theMessages;
|
||||
+ (CDVPluginResult*)resultWithStatus:(CDVCommandStatus)statusOrdinal messageToErrorObject:(int)errorCode;
|
||||
|
||||
+ (void)setVerbose:(BOOL)verbose;
|
||||
+ (BOOL)isVerbose;
|
||||
|
||||
- (void)setKeepCallbackAsBool:(BOOL)bKeepCallback;
|
||||
|
||||
- (NSString*)argumentsAsJSON;
|
||||
|
||||
@end
|
||||
216
node_modules/@capacitor/ios/CapacitorCordova/CapacitorCordova/Classes/Public/CDVPluginResult.m
generated
vendored
Normal file
216
node_modules/@capacitor/ios/CapacitorCordova/CapacitorCordova/Classes/Public/CDVPluginResult.m
generated
vendored
Normal file
@@ -0,0 +1,216 @@
|
||||
/*
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you under the Apache License, Version 2.0 (the
|
||||
"License"); you may not use this file except in compliance
|
||||
with the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing,
|
||||
software distributed under the License is distributed on an
|
||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
KIND, either express or implied. See the License for the
|
||||
specific language governing permissions and limitations
|
||||
under the License.
|
||||
*/
|
||||
|
||||
#import "CDVPluginResult.h"
|
||||
|
||||
// This exists to preserve compatibility with early Swift plugins, who are
|
||||
// using CDVCommandStatus as ObjC-style constants rather than as Swift enum
|
||||
// values.
|
||||
// These constants alias the enum values back to their previous names.
|
||||
#define SWIFT_ENUM_COMPAT_HACK(enumVal) const CDVCommandStatus SWIFT_##enumVal NS_SWIFT_NAME(enumVal) = enumVal
|
||||
SWIFT_ENUM_COMPAT_HACK(CDVCommandStatus_NO_RESULT);
|
||||
SWIFT_ENUM_COMPAT_HACK(CDVCommandStatus_OK);
|
||||
SWIFT_ENUM_COMPAT_HACK(CDVCommandStatus_CLASS_NOT_FOUND_EXCEPTION);
|
||||
SWIFT_ENUM_COMPAT_HACK(CDVCommandStatus_ILLEGAL_ACCESS_EXCEPTION);
|
||||
SWIFT_ENUM_COMPAT_HACK(CDVCommandStatus_INSTANTIATION_EXCEPTION);
|
||||
SWIFT_ENUM_COMPAT_HACK(CDVCommandStatus_MALFORMED_URL_EXCEPTION);
|
||||
SWIFT_ENUM_COMPAT_HACK(CDVCommandStatus_IO_EXCEPTION);
|
||||
SWIFT_ENUM_COMPAT_HACK(CDVCommandStatus_INVALID_ACTION);
|
||||
SWIFT_ENUM_COMPAT_HACK(CDVCommandStatus_JSON_EXCEPTION);
|
||||
SWIFT_ENUM_COMPAT_HACK(CDVCommandStatus_ERROR);
|
||||
#undef SWIFT_ENUM_COMPAT_HACK
|
||||
|
||||
@interface CDVPluginResult ()
|
||||
|
||||
- (CDVPluginResult*)initWithStatus:(CDVCommandStatus)statusOrdinal message:(id)theMessage;
|
||||
|
||||
@end
|
||||
|
||||
@implementation CDVPluginResult
|
||||
@synthesize status, message, keepCallback, associatedObject;
|
||||
|
||||
static NSArray* org_apache_cordova_CommandStatusMsgs;
|
||||
|
||||
id messageFromArrayBuffer(NSData* data)
|
||||
{
|
||||
return @{
|
||||
@"CDVType" : @"ArrayBuffer",
|
||||
@"data" :[data base64EncodedStringWithOptions:0]
|
||||
};
|
||||
}
|
||||
|
||||
id massageMessage(id message)
|
||||
{
|
||||
if ([message isKindOfClass:[NSData class]]) {
|
||||
return messageFromArrayBuffer(message);
|
||||
}
|
||||
return message;
|
||||
}
|
||||
|
||||
id messageFromMultipart(NSArray* theMessages)
|
||||
{
|
||||
NSMutableArray* messages = [NSMutableArray arrayWithArray:theMessages];
|
||||
|
||||
for (NSUInteger i = 0; i < messages.count; ++i) {
|
||||
[messages replaceObjectAtIndex:i withObject:massageMessage([messages objectAtIndex:i])];
|
||||
}
|
||||
|
||||
return @{
|
||||
@"CDVType" : @"MultiPart",
|
||||
@"messages" : messages
|
||||
};
|
||||
}
|
||||
|
||||
+ (void)initialize
|
||||
{
|
||||
org_apache_cordova_CommandStatusMsgs = [[NSArray alloc] initWithObjects:@"No result",
|
||||
@"OK",
|
||||
@"Class not found",
|
||||
@"Illegal access",
|
||||
@"Instantiation error",
|
||||
@"Malformed url",
|
||||
@"IO error",
|
||||
@"Invalid action",
|
||||
@"JSON error",
|
||||
@"Error",
|
||||
nil];
|
||||
}
|
||||
|
||||
- (CDVPluginResult*)init
|
||||
{
|
||||
return [self initWithStatus:CDVCommandStatus_NO_RESULT message:nil];
|
||||
}
|
||||
|
||||
- (CDVPluginResult*)initWithStatus:(CDVCommandStatus)statusOrdinal message:(id)theMessage
|
||||
{
|
||||
self = [super init];
|
||||
if (self) {
|
||||
status = [NSNumber numberWithUnsignedLong:statusOrdinal];
|
||||
message = theMessage;
|
||||
keepCallback = [NSNumber numberWithBool:NO];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
+ (CDVPluginResult*)resultWithStatus:(CDVCommandStatus)statusOrdinal
|
||||
{
|
||||
return [[self alloc] initWithStatus:statusOrdinal message:nil];
|
||||
}
|
||||
|
||||
+ (CDVPluginResult*)resultWithStatus:(CDVCommandStatus)statusOrdinal messageAsString:(NSString*)theMessage
|
||||
{
|
||||
return [[self alloc] initWithStatus:statusOrdinal message:theMessage];
|
||||
}
|
||||
|
||||
+ (CDVPluginResult*)resultWithStatus:(CDVCommandStatus)statusOrdinal messageAsArray:(NSArray*)theMessage
|
||||
{
|
||||
return [[self alloc] initWithStatus:statusOrdinal message:theMessage];
|
||||
}
|
||||
|
||||
+ (CDVPluginResult*)resultWithStatus:(CDVCommandStatus)statusOrdinal messageAsInt:(int)theMessage
|
||||
{
|
||||
return [[self alloc] initWithStatus:statusOrdinal message:[NSNumber numberWithInt:theMessage]];
|
||||
}
|
||||
|
||||
+ (CDVPluginResult*)resultWithStatus:(CDVCommandStatus)statusOrdinal messageAsNSInteger:(NSInteger)theMessage
|
||||
{
|
||||
return [[self alloc] initWithStatus:statusOrdinal message:[NSNumber numberWithInteger:theMessage]];
|
||||
}
|
||||
|
||||
+ (CDVPluginResult*)resultWithStatus:(CDVCommandStatus)statusOrdinal messageAsNSUInteger:(NSUInteger)theMessage
|
||||
{
|
||||
return [[self alloc] initWithStatus:statusOrdinal message:[NSNumber numberWithUnsignedInteger:theMessage]];
|
||||
}
|
||||
|
||||
+ (CDVPluginResult*)resultWithStatus:(CDVCommandStatus)statusOrdinal messageAsDouble:(double)theMessage
|
||||
{
|
||||
return [[self alloc] initWithStatus:statusOrdinal message:[NSNumber numberWithDouble:theMessage]];
|
||||
}
|
||||
|
||||
+ (CDVPluginResult*)resultWithStatus:(CDVCommandStatus)statusOrdinal messageAsBool:(BOOL)theMessage
|
||||
{
|
||||
return [[self alloc] initWithStatus:statusOrdinal message:[NSNumber numberWithBool:theMessage]];
|
||||
}
|
||||
|
||||
+ (CDVPluginResult*)resultWithStatus:(CDVCommandStatus)statusOrdinal messageAsDictionary:(NSDictionary*)theMessage
|
||||
{
|
||||
return [[self alloc] initWithStatus:statusOrdinal message:theMessage];
|
||||
}
|
||||
|
||||
+ (CDVPluginResult*)resultWithStatus:(CDVCommandStatus)statusOrdinal messageAsArrayBuffer:(NSData*)theMessage
|
||||
{
|
||||
return [[self alloc] initWithStatus:statusOrdinal message:messageFromArrayBuffer(theMessage)];
|
||||
}
|
||||
|
||||
+ (CDVPluginResult*)resultWithStatus:(CDVCommandStatus)statusOrdinal messageAsMultipart:(NSArray*)theMessages
|
||||
{
|
||||
return [[self alloc] initWithStatus:statusOrdinal message:messageFromMultipart(theMessages)];
|
||||
}
|
||||
|
||||
+ (CDVPluginResult*)resultWithStatus:(CDVCommandStatus)statusOrdinal messageToErrorObject:(int)errorCode
|
||||
{
|
||||
NSDictionary* errDict = @{@"code" :[NSNumber numberWithInt:errorCode]};
|
||||
|
||||
return [[self alloc] initWithStatus:statusOrdinal message:errDict];
|
||||
}
|
||||
|
||||
- (void)setKeepCallbackAsBool:(BOOL)bKeepCallback
|
||||
{
|
||||
[self setKeepCallback:[NSNumber numberWithBool:bKeepCallback]];
|
||||
}
|
||||
|
||||
- (NSString*)argumentsAsJSON
|
||||
{
|
||||
id arguments = (self.message == nil ? [NSNull null] : self.message);
|
||||
NSArray* argumentsWrappedInArray = [NSArray arrayWithObject:arguments];
|
||||
|
||||
NSString* argumentsJSON = [self JSONStringFromArray:argumentsWrappedInArray];
|
||||
|
||||
argumentsJSON = [argumentsJSON substringWithRange:NSMakeRange(1, [argumentsJSON length] - 2)];
|
||||
|
||||
return argumentsJSON;
|
||||
}
|
||||
|
||||
static BOOL gIsVerbose = NO;
|
||||
+ (void)setVerbose:(BOOL)verbose
|
||||
{
|
||||
gIsVerbose = verbose;
|
||||
}
|
||||
|
||||
+ (BOOL)isVerbose
|
||||
{
|
||||
return gIsVerbose;
|
||||
}
|
||||
|
||||
- (NSString*)JSONStringFromArray:(NSArray *) array
|
||||
{
|
||||
NSError* error = nil;
|
||||
NSData* jsonData = [NSJSONSerialization dataWithJSONObject:array
|
||||
options:0
|
||||
error:&error];
|
||||
|
||||
if (error != nil) {
|
||||
NSLog(@"NSArray JSONString error: %@", [error localizedDescription]);
|
||||
return nil;
|
||||
} else {
|
||||
return [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
33
node_modules/@capacitor/ios/CapacitorCordova/CapacitorCordova/Classes/Public/CDVScreenOrientationDelegate.h
generated
vendored
Normal file
33
node_modules/@capacitor/ios/CapacitorCordova/CapacitorCordova/Classes/Public/CDVScreenOrientationDelegate.h
generated
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you under the Apache License, Version 2.0 (the
|
||||
"License"); you may not use this file except in compliance
|
||||
with the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing,
|
||||
software distributed under the License is distributed on an
|
||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
KIND, either express or implied. See the License for the
|
||||
specific language governing permissions and limitations
|
||||
under the License.
|
||||
*/
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@protocol CDVScreenOrientationDelegate <NSObject>
|
||||
|
||||
#if __IPHONE_OS_VERSION_MAX_ALLOWED < 90000
|
||||
- (NSUInteger)supportedInterfaceOrientations;
|
||||
#else
|
||||
- (UIInterfaceOrientationMask)supportedInterfaceOrientations;
|
||||
#endif
|
||||
|
||||
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation;
|
||||
- (BOOL)shouldAutorotate;
|
||||
|
||||
@end
|
||||
27
node_modules/@capacitor/ios/CapacitorCordova/CapacitorCordova/Classes/Public/CDVURLProtocol.h
generated
vendored
Normal file
27
node_modules/@capacitor/ios/CapacitorCordova/CapacitorCordova/Classes/Public/CDVURLProtocol.h
generated
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you under the Apache License, Version 2.0 (the
|
||||
"License"); you may not use this file except in compliance
|
||||
with the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing,
|
||||
software distributed under the License is distributed on an
|
||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
KIND, either express or implied. See the License for the
|
||||
specific language governing permissions and limitations
|
||||
under the License.
|
||||
*/
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "CDVAvailability.h"
|
||||
|
||||
@class CDVViewController;
|
||||
|
||||
@interface CDVURLProtocol : NSURLProtocol {}
|
||||
|
||||
@end
|
||||
74
node_modules/@capacitor/ios/CapacitorCordova/CapacitorCordova/Classes/Public/CDVURLProtocol.m
generated
vendored
Normal file
74
node_modules/@capacitor/ios/CapacitorCordova/CapacitorCordova/Classes/Public/CDVURLProtocol.m
generated
vendored
Normal file
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you under the Apache License, Version 2.0 (the
|
||||
"License"); you may not use this file except in compliance
|
||||
with the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing,
|
||||
software distributed under the License is distributed on an
|
||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
KIND, either express or implied. See the License for the
|
||||
specific language governing permissions and limitations
|
||||
under the License.
|
||||
*/
|
||||
|
||||
#import <MobileCoreServices/MobileCoreServices.h>
|
||||
#import "CDVURLProtocol.h"
|
||||
#import "CDVViewController.h"
|
||||
|
||||
// Contains a set of NSNumbers of addresses of controllers. It doesn't store
|
||||
// the actual pointer to avoid retaining.
|
||||
static NSMutableSet* gRegisteredControllers = nil;
|
||||
|
||||
NSString* const kCDVAssetsLibraryPrefixes = @"assets-library://";
|
||||
|
||||
@implementation CDVURLProtocol
|
||||
|
||||
|
||||
+ (BOOL)canInitWithRequest:(NSURLRequest*)theRequest
|
||||
{
|
||||
return NO;
|
||||
}
|
||||
|
||||
+ (NSURLRequest*)canonicalRequestForRequest:(NSURLRequest*)request
|
||||
{
|
||||
// NSLog(@"%@ received %@", self, NSStringFromSelector(_cmd));
|
||||
return request;
|
||||
}
|
||||
|
||||
- (void)startLoading
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
- (void)stopLoading
|
||||
{
|
||||
// do any cleanup here
|
||||
}
|
||||
|
||||
+ (BOOL)requestIsCacheEquivalent:(NSURLRequest*)requestA toRequest:(NSURLRequest*)requestB
|
||||
{
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (void)sendResponseWithResponseCode:(NSInteger)statusCode data:(NSData*)data mimeType:(NSString*)mimeType
|
||||
{
|
||||
if (mimeType == nil) {
|
||||
mimeType = @"text/plain";
|
||||
}
|
||||
|
||||
NSHTTPURLResponse* response = [[NSHTTPURLResponse alloc] initWithURL:[[self request] URL] statusCode:statusCode HTTPVersion:@"HTTP/1.1" headerFields:@{@"Content-Type" : mimeType}];
|
||||
|
||||
[[self client] URLProtocol:self didReceiveResponse:response cacheStoragePolicy:NSURLCacheStorageNotAllowed];
|
||||
if (data != nil) {
|
||||
[[self client] URLProtocol:self didLoadData:data];
|
||||
}
|
||||
[[self client] URLProtocolDidFinishLoading:self];
|
||||
}
|
||||
|
||||
@end
|
||||
30
node_modules/@capacitor/ios/CapacitorCordova/CapacitorCordova/Classes/Public/CDVViewController.h
generated
vendored
Normal file
30
node_modules/@capacitor/ios/CapacitorCordova/CapacitorCordova/Classes/Public/CDVViewController.h
generated
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you under the Apache License, Version 2.0 (the
|
||||
"License"); you may not use this file except in compliance
|
||||
with the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing,
|
||||
software distributed under the License is distributed on an
|
||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
KIND, either express or implied. See the License for the
|
||||
specific language governing permissions and limitations
|
||||
under the License.
|
||||
*/
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
@interface CDVViewController : UIViewController
|
||||
|
||||
@property (nonatomic, readonly, strong) NSMutableDictionary* pluginObjects;
|
||||
@property (nonatomic, readonly, strong) NSMutableDictionary* settings;
|
||||
@property (nonatomic, readonly, weak) UIView* webView;
|
||||
|
||||
- (id) getCommandInstance:(NSString*)className;
|
||||
|
||||
@end
|
||||
37
node_modules/@capacitor/ios/CapacitorCordova/CapacitorCordova/Classes/Public/CDVViewController.m
generated
vendored
Normal file
37
node_modules/@capacitor/ios/CapacitorCordova/CapacitorCordova/Classes/Public/CDVViewController.m
generated
vendored
Normal file
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you under the Apache License, Version 2.0 (the
|
||||
"License"); you may not use this file except in compliance
|
||||
with the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing,
|
||||
software distributed under the License is distributed on an
|
||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
KIND, either express or implied. See the License for the
|
||||
specific language governing permissions and limitations
|
||||
under the License.
|
||||
*/
|
||||
|
||||
|
||||
#import "CDVViewController.h"
|
||||
|
||||
@interface CDVViewController () {
|
||||
|
||||
}
|
||||
|
||||
|
||||
@property (nonatomic, readwrite, strong) NSMutableDictionary* pluginObjects;
|
||||
|
||||
@end
|
||||
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wincomplete-implementation"
|
||||
@implementation CDVViewController
|
||||
|
||||
@end
|
||||
#pragma clang diagnostic pop
|
||||
27
node_modules/@capacitor/ios/CapacitorCordova/CapacitorCordova/Classes/Public/CDVWebViewProcessPoolFactory.h
generated
vendored
Normal file
27
node_modules/@capacitor/ios/CapacitorCordova/CapacitorCordova/Classes/Public/CDVWebViewProcessPoolFactory.h
generated
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you under the Apache License, Version 2.0 (the
|
||||
"License"); you may not use this file except in compliance
|
||||
with the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing,
|
||||
software distributed under the License is distributed on an
|
||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
KIND, either express or implied. See the License for the
|
||||
specific language governing permissions and limitations
|
||||
under the License.
|
||||
*/
|
||||
|
||||
#import <WebKit/WebKit.h>
|
||||
|
||||
@interface CDVWebViewProcessPoolFactory : NSObject
|
||||
@property (nonatomic, retain) WKProcessPool* sharedPool;
|
||||
|
||||
+(instancetype) sharedFactory;
|
||||
-(WKProcessPool*) sharedProcessPool;
|
||||
@end
|
||||
49
node_modules/@capacitor/ios/CapacitorCordova/CapacitorCordova/Classes/Public/CDVWebViewProcessPoolFactory.m
generated
vendored
Normal file
49
node_modules/@capacitor/ios/CapacitorCordova/CapacitorCordova/Classes/Public/CDVWebViewProcessPoolFactory.m
generated
vendored
Normal file
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you under the Apache License, Version 2.0 (the
|
||||
"License"); you may not use this file except in compliance
|
||||
with the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing,
|
||||
software distributed under the License is distributed on an
|
||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
KIND, either express or implied. See the License for the
|
||||
specific language governing permissions and limitations
|
||||
under the License.
|
||||
*/
|
||||
|
||||
@import Foundation;
|
||||
@import WebKit;
|
||||
#import <Cordova/CDVWebViewProcessPoolFactory.h>
|
||||
|
||||
static CDVWebViewProcessPoolFactory *factory = nil;
|
||||
|
||||
@implementation CDVWebViewProcessPoolFactory
|
||||
|
||||
+ (instancetype)sharedFactory
|
||||
{
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
factory = [[CDVWebViewProcessPoolFactory alloc] init];
|
||||
});
|
||||
|
||||
return factory;
|
||||
}
|
||||
|
||||
- (instancetype)init
|
||||
{
|
||||
if (self = [super init]) {
|
||||
_sharedPool = [[WKProcessPool alloc] init];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (WKProcessPool*) sharedProcessPool {
|
||||
return _sharedPool;
|
||||
}
|
||||
@end
|
||||
35
node_modules/@capacitor/ios/CapacitorCordova/CapacitorCordova/Classes/Public/NSDictionary+CordovaPreferences.h
generated
vendored
Normal file
35
node_modules/@capacitor/ios/CapacitorCordova/CapacitorCordova/Classes/Public/NSDictionary+CordovaPreferences.h
generated
vendored
Normal file
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you under the Apache License, Version 2.0 (the
|
||||
"License"); you may not use this file except in compliance
|
||||
with the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing,
|
||||
software distributed under the License is distributed on an
|
||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
KIND, either express or implied. See the License for the
|
||||
specific language governing permissions and limitations
|
||||
under the License.
|
||||
*/
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
@interface NSDictionary (CordovaPreferences)
|
||||
|
||||
- (id)cordovaSettingForKey:(NSString*)key;
|
||||
- (BOOL)cordovaBoolSettingForKey:(NSString*)key defaultValue:(BOOL)defaultValue;
|
||||
- (CGFloat)cordovaFloatSettingForKey:(NSString*)key defaultValue:(CGFloat)defaultValue;
|
||||
|
||||
@end
|
||||
|
||||
@interface NSMutableDictionary (CordovaPreferences)
|
||||
|
||||
- (void)setCordovaSetting:(id)value forKey:(NSString*)key;
|
||||
|
||||
@end
|
||||
63
node_modules/@capacitor/ios/CapacitorCordova/CapacitorCordova/Classes/Public/NSDictionary+CordovaPreferences.m
generated
vendored
Normal file
63
node_modules/@capacitor/ios/CapacitorCordova/CapacitorCordova/Classes/Public/NSDictionary+CordovaPreferences.m
generated
vendored
Normal file
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you under the Apache License, Version 2.0 (the
|
||||
"License"); you may not use this file except in compliance
|
||||
with the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing,
|
||||
software distributed under the License is distributed on an
|
||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
KIND, either express or implied. See the License for the
|
||||
specific language governing permissions and limitations
|
||||
under the License.
|
||||
*/
|
||||
|
||||
#import "NSDictionary+CordovaPreferences.h"
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@implementation NSDictionary (CordovaPreferences)
|
||||
|
||||
- (id)cordovaSettingForKey:(NSString*)key
|
||||
{
|
||||
return [self objectForKey:[key lowercaseString]];
|
||||
}
|
||||
|
||||
- (BOOL)cordovaBoolSettingForKey:(NSString*)key defaultValue:(BOOL)defaultValue
|
||||
{
|
||||
BOOL value = defaultValue;
|
||||
id prefObj = [self cordovaSettingForKey:key];
|
||||
|
||||
if (prefObj != nil) {
|
||||
value = [(NSNumber*)prefObj boolValue];
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
- (CGFloat)cordovaFloatSettingForKey:(NSString*)key defaultValue:(CGFloat)defaultValue
|
||||
{
|
||||
CGFloat value = defaultValue;
|
||||
id prefObj = [self cordovaSettingForKey:key];
|
||||
|
||||
if (prefObj != nil) {
|
||||
value = [prefObj floatValue];
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation NSMutableDictionary (CordovaPreferences)
|
||||
|
||||
- (void)setCordovaSetting:(id)value forKey:(NSString*)key
|
||||
{
|
||||
[self setObject:value forKey:[key lowercaseString]];
|
||||
}
|
||||
|
||||
@end
|
||||
26
node_modules/@capacitor/ios/CapacitorCordova/CapacitorCordova/Info.plist
generated
vendored
Normal file
26
node_modules/@capacitor/ios/CapacitorCordova/CapacitorCordova/Info.plist
generated
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>$(DEVELOPMENT_LANGUAGE)</string>
|
||||
<key>CFBundleDisplayName</key>
|
||||
<string>Cordova</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>$(EXECUTABLE_NAME)</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>$(PRODUCT_NAME)</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>FMWK</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.0</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>$(CURRENT_PROJECT_VERSION)</string>
|
||||
<key>NSPrincipalClass</key>
|
||||
<string></string>
|
||||
</dict>
|
||||
</plist>
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user