@capacitor/ios 8.1.0 → 8.1.1-dev-20260305T152829.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Capacitor/Capacitor/CAPApplicationDelegateProxy.swift +0 -1
- package/Capacitor/Capacitor/CAPBridgeProtocol.swift +5 -0
- package/Capacitor/Capacitor/CAPBridgeViewController.swift +12 -6
- package/Capacitor/Capacitor/CAPInstanceDescriptor.h +2 -2
- package/Capacitor/Capacitor/CAPInstanceDescriptor.m +0 -1
- package/Capacitor/Capacitor/CAPInstanceDescriptor.swift +1 -18
- package/Capacitor/Capacitor/CapacitorBridge.swift +43 -105
- package/Capacitor/Capacitor/JS.swift +5 -5
- package/Capacitor/Capacitor/JSExport.swift +0 -40
- package/Capacitor/Capacitor/WebViewDelegationHandler.swift +2 -11
- package/Capacitor.podspec +0 -1
- package/CapacitorCordova/CapacitorCordova/Classes/Public/Plugin.swift +126 -0
- package/CapacitorCordova.podspec +2 -1
- package/package.json +2 -2
- package/Capacitor/Capacitor/CAPBridgeViewController+CDVScreenOrientationDelegate.h +0 -6
- package/Capacitor/Capacitor/CAPBridgeViewController+CDVScreenOrientationDelegate.m +0 -5
- package/Capacitor/Capacitor/TmpViewController.swift +0 -8
|
@@ -79,9 +79,14 @@ import WebKit
|
|
|
79
79
|
func registerPluginType(_ pluginType: CAPPlugin.Type)
|
|
80
80
|
func registerPluginInstance(_ pluginInstance: CAPPlugin)
|
|
81
81
|
|
|
82
|
+
// MARK: - Interceptors
|
|
83
|
+
func registerCallInterceptor(_ name: String, handler: @escaping ([String: Any]) -> Void)
|
|
84
|
+
|
|
82
85
|
// MARK: - View Presentation
|
|
83
86
|
func showAlertWith(title: String, message: String, buttonTitle: String)
|
|
87
|
+
@available(*, deprecated, message: "Use self?.bridge?.viewController?.present")
|
|
84
88
|
func presentVC(_ viewControllerToPresent: UIViewController, animated flag: Bool, completion: (() -> Void)?)
|
|
89
|
+
@available(*, deprecated, message: "Use self?.bridge?.viewController?.dismiss")
|
|
85
90
|
func dismissVC(animated flag: Bool, completion: (() -> Void)?)
|
|
86
91
|
}
|
|
87
92
|
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import UIKit
|
|
2
2
|
import WebKit
|
|
3
|
-
import Cordova
|
|
4
3
|
|
|
5
4
|
@objc open class CAPBridgeViewController: UIViewController {
|
|
6
5
|
private var capacitorBridge: CapacitorBridge?
|
|
@@ -47,10 +46,10 @@ import Cordova
|
|
|
47
46
|
// create the bridge
|
|
48
47
|
capacitorBridge = CapacitorBridge(with: configuration,
|
|
49
48
|
delegate: self,
|
|
50
|
-
cordovaConfiguration: configDescriptor.cordovaConfiguration,
|
|
51
49
|
assetHandler: assetHandler,
|
|
52
50
|
delegationHandler: delegationHandler)
|
|
53
51
|
capacitorDidLoad()
|
|
52
|
+
updateAppLocationIfNeeded()
|
|
54
53
|
|
|
55
54
|
if configDescriptor.instanceType == .fixed {
|
|
56
55
|
updateBinaryVersion()
|
|
@@ -89,18 +88,25 @@ import Cordova
|
|
|
89
88
|
- Note: This is called early in the View Controller's lifecycle. Not all properties will be set at invocation.
|
|
90
89
|
*/
|
|
91
90
|
open func instanceDescriptor() -> InstanceDescriptor {
|
|
92
|
-
|
|
93
|
-
|
|
91
|
+
return InstanceDescriptor()
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/// This function must be called after plugins are loaded or it will have no effect.
|
|
95
|
+
open func updateAppLocationIfNeeded() {
|
|
96
|
+
let cordovaPlugin = bridge?.plugin(withName: "__CordovaPlugin")
|
|
97
|
+
let cordovaDeployDisabled = cordovaPlugin?.perform(Selector(("cordovaDeployDisabled"))).takeUnretainedValue() as? Bool ?? false
|
|
98
|
+
|
|
99
|
+
if !isNewBinary && !cordovaDeployDisabled {
|
|
94
100
|
if let persistedPath = KeyValueStore.standard["serverBasePath", as: String.self], !persistedPath.isEmpty {
|
|
95
101
|
if let libPath = NSSearchPathForDirectoriesInDomains(.libraryDirectory, .userDomainMask, true).first {
|
|
96
|
-
|
|
102
|
+
let serverBasePath = URL(fileURLWithPath: libPath, isDirectory: true)
|
|
97
103
|
.appendingPathComponent("NoCloud")
|
|
98
104
|
.appendingPathComponent("ionic_built_snapshots")
|
|
99
105
|
.appendingPathComponent(URL(fileURLWithPath: persistedPath, isDirectory: true).lastPathComponent)
|
|
106
|
+
setServerBasePath(path: serverBasePath.path)
|
|
100
107
|
}
|
|
101
108
|
}
|
|
102
109
|
}
|
|
103
|
-
return descriptor
|
|
104
110
|
}
|
|
105
111
|
|
|
106
112
|
open func router() -> Router {
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
#define CAPInstanceDescriptor_h
|
|
3
3
|
|
|
4
4
|
@import UIKit;
|
|
5
|
-
|
|
5
|
+
|
|
6
6
|
|
|
7
7
|
typedef NS_ENUM(NSInteger, CAPInstanceType) {
|
|
8
8
|
CAPInstanceTypeFixed NS_SWIFT_NAME(fixed),
|
|
@@ -137,7 +137,7 @@ NS_SWIFT_NAME(InstanceDescriptor)
|
|
|
137
137
|
/**
|
|
138
138
|
@brief The parser used to load the cofiguration for Cordova plugins.
|
|
139
139
|
*/
|
|
140
|
-
@property (nonatomic, copy, nonnull)
|
|
140
|
+
@property (nonatomic, copy, nonnull) NSObject *cordovaConfiguration;
|
|
141
141
|
/**
|
|
142
142
|
@brief Warnings generated during initialization.
|
|
143
143
|
*/
|
|
@@ -45,7 +45,6 @@ NSString* const CAPInstanceDescriptorDefaultHostname = @"localhost";
|
|
|
45
45
|
_contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;
|
|
46
46
|
_appLocation = location;
|
|
47
47
|
_limitsNavigationsToAppBoundDomains = FALSE;
|
|
48
|
-
_cordovaConfiguration = [[CDVConfigParser alloc] init];
|
|
49
48
|
_warnings = 0;
|
|
50
49
|
if (location == nil) {
|
|
51
50
|
_warnings |= CAPInstanceWarningMissingAppDir;
|
|
@@ -52,23 +52,6 @@ internal extension InstanceDescriptor {
|
|
|
52
52
|
warnings.update(with: .missingFile)
|
|
53
53
|
}
|
|
54
54
|
|
|
55
|
-
// parse the cordova configuration
|
|
56
|
-
var configParser: XMLParser?
|
|
57
|
-
if let cordovaURL = cordovaURL,
|
|
58
|
-
FileManager.default.fileExists(atPath: cordovaURL.path, isDirectory: &isDirectory),
|
|
59
|
-
isDirectory.boolValue == false {
|
|
60
|
-
configParser = XMLParser(contentsOf: cordovaURL)
|
|
61
|
-
} else {
|
|
62
|
-
warnings.update(with: .missingCordovaFile)
|
|
63
|
-
// we don't want to break up string literals
|
|
64
|
-
// swiftlint:disable:next line_length
|
|
65
|
-
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) {
|
|
66
|
-
configParser = XMLParser(data: cordovaXML)
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
configParser?.delegate = cordovaConfiguration
|
|
70
|
-
configParser?.parse()
|
|
71
|
-
|
|
72
55
|
// extract our configuration values
|
|
73
56
|
if let config = config {
|
|
74
57
|
// to be removed
|
|
@@ -160,7 +143,7 @@ internal extension InstanceDescriptor {
|
|
|
160
143
|
|
|
161
144
|
extension InstanceDescriptor {
|
|
162
145
|
@objc public var cordovaDeployDisabled: Bool {
|
|
163
|
-
return
|
|
146
|
+
return false
|
|
164
147
|
}
|
|
165
148
|
|
|
166
149
|
@objc public func normalize() {
|
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
import Foundation
|
|
2
2
|
import Dispatch
|
|
3
3
|
import WebKit
|
|
4
|
-
import Cordova
|
|
5
4
|
|
|
6
5
|
internal typealias CapacitorPlugin = CAPPlugin & CAPBridgedPlugin
|
|
7
6
|
|
|
8
7
|
struct RegistrationList: Codable {
|
|
9
|
-
|
|
8
|
+
var packageClassList: Set<String>
|
|
10
9
|
}
|
|
11
10
|
|
|
12
11
|
/**
|
|
@@ -93,9 +92,6 @@ open class CapacitorBridge: NSObject, CAPBridgeProtocol {
|
|
|
93
92
|
}
|
|
94
93
|
}
|
|
95
94
|
}
|
|
96
|
-
|
|
97
|
-
var tmpWindow: UIWindow?
|
|
98
|
-
static let tmpVCAppeared = Notification(name: Notification.Name(rawValue: "tmpViewControllerAppeared"))
|
|
99
95
|
public static let capacitorSite = "https://capacitorjs.com/"
|
|
100
96
|
public static let fileStartIdentifier = "/_capacitor_file_"
|
|
101
97
|
public static let httpInterceptorStartIdentifier = "/_capacitor_http_interceptor_"
|
|
@@ -116,18 +112,16 @@ open class CapacitorBridge: NSObject, CAPBridgeProtocol {
|
|
|
116
112
|
@objc public var config: InstanceConfiguration
|
|
117
113
|
// Map of all loaded and instantiated plugins by pluginId -> instance
|
|
118
114
|
var plugins = [String: CapacitorPlugin]()
|
|
119
|
-
// Manager for getting Cordova plugins
|
|
120
|
-
var cordovaPluginManager: CDVPluginManager?
|
|
121
115
|
// Calls we are storing to resolve later
|
|
122
116
|
var storedCalls = ConcurrentDictionary<CAPPluginCall>()
|
|
123
117
|
// Whether to inject the Cordova files
|
|
124
|
-
private var
|
|
125
|
-
private var cordovaParser: CDVConfigParser?
|
|
118
|
+
private var cordovaIsPresent = false
|
|
126
119
|
private var injectMiscFiles: [String] = []
|
|
127
120
|
private var canInjectJS: Bool = true
|
|
128
121
|
|
|
129
122
|
// Background dispatch queue for plugin calls
|
|
130
123
|
open private(set) var dispatchQueue = DispatchQueue(label: "bridge")
|
|
124
|
+
internal private(set) var callInterceptors: [String: ([String: Any]) -> Void] = [:]
|
|
131
125
|
// Array of block based observers
|
|
132
126
|
var observers: [NSObjectProtocol] = []
|
|
133
127
|
|
|
@@ -204,12 +198,17 @@ open class CapacitorBridge: NSObject, CAPBridgeProtocol {
|
|
|
204
198
|
|
|
205
199
|
// MARK: - Initialization
|
|
206
200
|
|
|
207
|
-
|
|
201
|
+
@available(*, deprecated, renamed: "init", message: "Use different init")
|
|
202
|
+
public convenience init(with configuration: InstanceConfiguration, delegate bridgeDelegate: CAPBridgeDelegate, cordovaConfiguration: Any, assetHandler: WebViewAssetHandler, delegationHandler: WebViewDelegationHandler, autoRegisterPlugins: Bool = true) {
|
|
203
|
+
self.init(with: configuration, delegate: bridgeDelegate, assetHandler: assetHandler, delegationHandler: delegationHandler, autoRegisterPlugins: autoRegisterPlugins)
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
public init(with configuration: InstanceConfiguration, delegate bridgeDelegate: CAPBridgeDelegate, assetHandler: WebViewAssetHandler, delegationHandler: WebViewDelegationHandler, autoRegisterPlugins: Bool = true) {
|
|
207
|
+
|
|
208
208
|
self.bridgeDelegate = bridgeDelegate
|
|
209
209
|
self.webViewAssetHandler = assetHandler
|
|
210
210
|
self.webViewDelegationHandler = delegationHandler
|
|
211
211
|
self.config = configuration
|
|
212
|
-
self.cordovaParser = cordovaConfiguration
|
|
213
212
|
self.notificationRouter = NotificationRouter()
|
|
214
213
|
self.notificationRouter.handleApplicationNotifications = configuration.handleApplicationNotifications
|
|
215
214
|
self.autoRegisterPlugins = autoRegisterPlugins
|
|
@@ -219,12 +218,9 @@ open class CapacitorBridge: NSObject, CAPBridgeProtocol {
|
|
|
219
218
|
|
|
220
219
|
exportCoreJS(localUrl: configuration.localURL.absoluteString)
|
|
221
220
|
registerPlugins()
|
|
222
|
-
|
|
221
|
+
setupListeners()
|
|
223
222
|
exportMiscJS()
|
|
224
223
|
canInjectJS = false
|
|
225
|
-
observers.append(NotificationCenter.default.addObserver(forName: type(of: self).tmpVCAppeared.name, object: .none, queue: .none) { [weak self] _ in
|
|
226
|
-
self?.tmpWindow = nil
|
|
227
|
-
})
|
|
228
224
|
|
|
229
225
|
self.setupWebDebugging(configuration: configuration)
|
|
230
226
|
}
|
|
@@ -261,31 +257,27 @@ open class CapacitorBridge: NSObject, CAPBridgeProtocol {
|
|
|
261
257
|
injectMiscFiles.removeAll()
|
|
262
258
|
}
|
|
263
259
|
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
do {
|
|
286
|
-
try JSExport.exportCordovaJS(userContentController: webViewDelegationHandler.contentController)
|
|
287
|
-
} catch {
|
|
288
|
-
type(of: self).fatalError(error, error)
|
|
260
|
+
func setupListeners() {
|
|
261
|
+
if !cordovaIsPresent {
|
|
262
|
+
observers.append(
|
|
263
|
+
NotificationCenter.default.addObserver(
|
|
264
|
+
forName: UIApplication.willEnterForegroundNotification,
|
|
265
|
+
object: nil,
|
|
266
|
+
queue: .main
|
|
267
|
+
) { [weak self] _ in
|
|
268
|
+
self?.triggerDocumentJSEvent(eventName: "resume")
|
|
269
|
+
}
|
|
270
|
+
)
|
|
271
|
+
|
|
272
|
+
observers.append(
|
|
273
|
+
NotificationCenter.default.addObserver(
|
|
274
|
+
forName: UIApplication.didEnterBackgroundNotification,
|
|
275
|
+
object: nil,
|
|
276
|
+
queue: .main
|
|
277
|
+
) { [weak self] _ in
|
|
278
|
+
self?.triggerDocumentJSEvent(eventName: "pause")
|
|
279
|
+
}
|
|
280
|
+
)
|
|
289
281
|
}
|
|
290
282
|
}
|
|
291
283
|
|
|
@@ -308,14 +300,13 @@ open class CapacitorBridge: NSObject, CAPBridgeProtocol {
|
|
|
308
300
|
do {
|
|
309
301
|
if let pluginJSON = Bundle.main.url(forResource: "capacitor.config", withExtension: "json") {
|
|
310
302
|
let pluginData = try Data(contentsOf: pluginJSON)
|
|
311
|
-
|
|
303
|
+
var registrationList = try JSONDecoder().decode(RegistrationList.self, from: pluginData)
|
|
312
304
|
|
|
313
305
|
for plugin in registrationList.packageClassList {
|
|
314
|
-
if let pluginClass = NSClassFromString(plugin) {
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
pluginList.append(pluginClass)
|
|
306
|
+
if let pluginClass = NSClassFromString(plugin), pluginClass is CAPPlugin.Type {
|
|
307
|
+
pluginList.append(pluginClass)
|
|
308
|
+
if plugin == "CordovaPlugin" {
|
|
309
|
+
cordovaIsPresent = true
|
|
319
310
|
}
|
|
320
311
|
}
|
|
321
312
|
}
|
|
@@ -392,6 +383,10 @@ open class CapacitorBridge: NSObject, CAPBridgeProtocol {
|
|
|
392
383
|
|
|
393
384
|
// MARK: - CAPBridgeProtocol: Call Management
|
|
394
385
|
|
|
386
|
+
public func registerCallInterceptor(_ name: String, handler: @escaping ([String: Any]) -> Void) {
|
|
387
|
+
callInterceptors[name] = handler
|
|
388
|
+
}
|
|
389
|
+
|
|
395
390
|
@objc public func saveCall(_ call: CAPPluginCall) {
|
|
396
391
|
storedCalls[call.callbackId] = call
|
|
397
392
|
}
|
|
@@ -424,23 +419,6 @@ open class CapacitorBridge: NSObject, CAPBridgeProtocol {
|
|
|
424
419
|
return self.dispatchQueue
|
|
425
420
|
}
|
|
426
421
|
|
|
427
|
-
func registerCordovaPlugins() {
|
|
428
|
-
guard let cordovaParser = cordovaParser else {
|
|
429
|
-
return
|
|
430
|
-
}
|
|
431
|
-
cordovaPluginManager = CDVPluginManager.init(parser: cordovaParser, viewController: self.viewController, webView: self.getWebView())
|
|
432
|
-
if cordovaParser.startupPluginNames.count > 0 {
|
|
433
|
-
for pluginName in cordovaParser.startupPluginNames {
|
|
434
|
-
_ = cordovaPluginManager?.getCommandInstance(pluginName as? String)
|
|
435
|
-
}
|
|
436
|
-
}
|
|
437
|
-
do {
|
|
438
|
-
try JSExport.exportCordovaPluginsJS(userContentController: webViewDelegationHandler.contentController)
|
|
439
|
-
} catch {
|
|
440
|
-
type(of: self).fatalError(error, error)
|
|
441
|
-
}
|
|
442
|
-
}
|
|
443
|
-
|
|
444
422
|
func reload() {
|
|
445
423
|
self.getWebView()?.reload()
|
|
446
424
|
}
|
|
@@ -539,34 +517,6 @@ open class CapacitorBridge: NSObject, CAPBridgeProtocol {
|
|
|
539
517
|
}
|
|
540
518
|
}
|
|
541
519
|
|
|
542
|
-
/**
|
|
543
|
-
Handle a Cordova call from JavaScript. First, find the corresponding plugin,
|
|
544
|
-
construct a selector, and perform that selector on the plugin instance.
|
|
545
|
-
*/
|
|
546
|
-
func handleCordovaJSCall(call: JSCall) {
|
|
547
|
-
// Create a selector to send to the plugin
|
|
548
|
-
|
|
549
|
-
if let plugin = self.cordovaPluginManager?.getCommandInstance(call.pluginId.lowercased()) {
|
|
550
|
-
let selector = NSSelectorFromString("\(call.method):")
|
|
551
|
-
if !plugin.responds(to: selector) {
|
|
552
|
-
CAPLog.print("Error: Plugin \(plugin.className ?? "") does not respond to method call \(selector).")
|
|
553
|
-
CAPLog.print("Ensure plugin method exists and uses @objc in its declaration")
|
|
554
|
-
return
|
|
555
|
-
}
|
|
556
|
-
|
|
557
|
-
let arguments: [Any] = call.options["options"] as? [Any] ?? []
|
|
558
|
-
let pluginCall = CDVInvokedUrlCommand(arguments: arguments,
|
|
559
|
-
callbackId: call.callbackId,
|
|
560
|
-
className: plugin.className,
|
|
561
|
-
methodName: call.method)
|
|
562
|
-
plugin.perform(selector, with: pluginCall)
|
|
563
|
-
|
|
564
|
-
} else {
|
|
565
|
-
CAPLog.print("Error: Cordova Plugin mapping not found")
|
|
566
|
-
return
|
|
567
|
-
}
|
|
568
|
-
}
|
|
569
|
-
|
|
570
520
|
func removeAllPluginListeners() {
|
|
571
521
|
for plugin in plugins.values {
|
|
572
522
|
plugin.perform(#selector(CAPPlugin.removeAllListeners(_:)), with: nil)
|
|
@@ -747,22 +697,10 @@ open class CapacitorBridge: NSObject, CAPBridgeProtocol {
|
|
|
747
697
|
}
|
|
748
698
|
|
|
749
699
|
@objc open func presentVC(_ viewControllerToPresent: UIViewController, animated flag: Bool, completion: (() -> Void)? = nil) {
|
|
750
|
-
|
|
751
|
-
self.viewController?.present(viewControllerToPresent, animated: flag, completion: completion)
|
|
752
|
-
} else {
|
|
753
|
-
self.tmpWindow = UIWindow.init(frame: UIScreen.main.bounds)
|
|
754
|
-
self.tmpWindow?.rootViewController = TmpViewController.init()
|
|
755
|
-
self.tmpWindow?.makeKeyAndVisible()
|
|
756
|
-
self.tmpWindow?.rootViewController?.present(viewControllerToPresent, animated: flag, completion: completion)
|
|
757
|
-
}
|
|
700
|
+
self.viewController?.present(viewControllerToPresent, animated: flag, completion: completion)
|
|
758
701
|
}
|
|
759
702
|
|
|
760
703
|
@objc open func dismissVC(animated flag: Bool, completion: (() -> Void)? = nil) {
|
|
761
|
-
|
|
762
|
-
self.viewController?.dismiss(animated: flag, completion: completion)
|
|
763
|
-
} else {
|
|
764
|
-
self.tmpWindow?.rootViewController?.dismiss(animated: flag, completion: completion)
|
|
765
|
-
self.tmpWindow = nil
|
|
766
|
-
}
|
|
704
|
+
self.viewController?.dismiss(animated: flag, completion: completion)
|
|
767
705
|
}
|
|
768
706
|
}
|
|
@@ -14,11 +14,11 @@ public typealias JSResultBody = [String: Any]
|
|
|
14
14
|
/**
|
|
15
15
|
* A call originating from JavaScript land
|
|
16
16
|
*/
|
|
17
|
-
|
|
18
|
-
let options: [String: Any]
|
|
19
|
-
let pluginId: String
|
|
20
|
-
let method: String
|
|
21
|
-
let callbackId: String
|
|
17
|
+
public struct JSCall {
|
|
18
|
+
public let options: [String: Any]
|
|
19
|
+
public let pluginId: String
|
|
20
|
+
public let method: String
|
|
21
|
+
public let callbackId: String
|
|
22
22
|
}
|
|
23
23
|
|
|
24
24
|
internal protocol JSResultProtocol {
|
|
@@ -35,24 +35,6 @@ internal class JSExport {
|
|
|
35
35
|
}
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
-
static func exportCordovaJS(userContentController: WKUserContentController) throws {
|
|
39
|
-
guard let cordovaUrl = Bundle.main.url(forResource: "public/cordova", withExtension: "js") else {
|
|
40
|
-
CAPLog.print("ERROR: Required cordova.js file not found. Cordova plugins will not function!")
|
|
41
|
-
throw CapacitorBridgeError.errorExportingCoreJS
|
|
42
|
-
}
|
|
43
|
-
guard let cordovaPluginsUrl = Bundle.main.url(forResource: "public/cordova_plugins", withExtension: "js") else {
|
|
44
|
-
CAPLog.print("ERROR: Required cordova_plugins.js file not found. Cordova plugins will not function!")
|
|
45
|
-
throw CapacitorBridgeError.errorExportingCoreJS
|
|
46
|
-
}
|
|
47
|
-
do {
|
|
48
|
-
try self.injectFile(fileURL: cordovaUrl, userContentController: userContentController)
|
|
49
|
-
try self.injectFile(fileURL: cordovaPluginsUrl, userContentController: userContentController)
|
|
50
|
-
} catch {
|
|
51
|
-
CAPLog.print("ERROR: Unable to read required cordova files. Cordova plugins will not function!")
|
|
52
|
-
throw CapacitorBridgeError.errorExportingCoreJS
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
|
|
56
38
|
static func exportMiscFileJS(paths: [String], userContentController: WKUserContentController) {
|
|
57
39
|
for path in paths {
|
|
58
40
|
if let miscJSFilePath = Bundle.main.url(forResource: "public/\(path.replacingOccurrences(of: ".js", with: ""))", withExtension: "js") {
|
|
@@ -184,28 +166,6 @@ internal class JSExport {
|
|
|
184
166
|
return lines.joined(separator: "\n")
|
|
185
167
|
}
|
|
186
168
|
|
|
187
|
-
static func exportCordovaPluginsJS(userContentController: WKUserContentController) throws {
|
|
188
|
-
if let pluginsJSFolder = Bundle.main.url(forResource: "public/plugins", withExtension: nil) {
|
|
189
|
-
self.injectFilesForFolder(folder: pluginsJSFolder, userContentController: userContentController)
|
|
190
|
-
}
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
static func injectFilesForFolder(folder: URL, userContentController: WKUserContentController) {
|
|
194
|
-
let fileManager = FileManager.default
|
|
195
|
-
do {
|
|
196
|
-
let fileURLs = try fileManager.contentsOfDirectory(at: folder, includingPropertiesForKeys: nil, options: [])
|
|
197
|
-
for fileURL in fileURLs {
|
|
198
|
-
if fileURL.hasDirectoryPath {
|
|
199
|
-
injectFilesForFolder(folder: fileURL, userContentController: userContentController)
|
|
200
|
-
} else {
|
|
201
|
-
try self.injectFile(fileURL: fileURL, userContentController: userContentController)
|
|
202
|
-
}
|
|
203
|
-
}
|
|
204
|
-
} catch {
|
|
205
|
-
CAPLog.print("Error while enumerating files")
|
|
206
|
-
}
|
|
207
|
-
}
|
|
208
|
-
|
|
209
169
|
static func injectFile(fileURL: URL, userContentController: WKUserContentController) throws {
|
|
210
170
|
do {
|
|
211
171
|
let data = try String(contentsOf: fileURL, encoding: .utf8)
|
|
@@ -208,17 +208,8 @@ open class WebViewDelegationHandler: NSObject, WKNavigationDelegate, WKUIDelegat
|
|
|
208
208
|
}
|
|
209
209
|
|
|
210
210
|
bridge.handleJSCall(call: JSCall(options: options, pluginId: pluginId, method: method, callbackId: callbackId))
|
|
211
|
-
} else if
|
|
212
|
-
|
|
213
|
-
let method = dict["action"] as? String ?? ""
|
|
214
|
-
let callbackId = dict["callbackId"] as? String ?? ""
|
|
215
|
-
|
|
216
|
-
let args = dict["actionArgs"] as? Array ?? []
|
|
217
|
-
let options = ["options": args]
|
|
218
|
-
|
|
219
|
-
CAPLog.print("To Native Cordova -> ", pluginId, method, callbackId, options)
|
|
220
|
-
|
|
221
|
-
bridge.handleCordovaJSCall(call: JSCall(options: options, pluginId: pluginId, method: method, callbackId: callbackId))
|
|
211
|
+
} else if let handler = bridge.callInterceptors[type] {
|
|
212
|
+
handler(dict)
|
|
222
213
|
}
|
|
223
214
|
}
|
|
224
215
|
}
|
package/Capacitor.podspec
CHANGED
|
@@ -19,6 +19,5 @@ Pod::Spec.new do |s|
|
|
|
19
19
|
s.module_map = "#{prefix}Capacitor/Capacitor/Capacitor.modulemap"
|
|
20
20
|
s.resources = ["#{prefix}Capacitor/Capacitor/assets/native-bridge.js"]
|
|
21
21
|
s.resource_bundles = { 'Capacitor' => ["#{prefix}Capacitor/Capacitor/PrivacyInfo.xcprivacy"] }
|
|
22
|
-
s.dependency 'CapacitorCordova'
|
|
23
22
|
s.swift_version = '5.1'
|
|
24
23
|
end
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import Capacitor
|
|
2
|
+
|
|
3
|
+
@objc(CordovaPlugin)
|
|
4
|
+
public class CordovaPlugin: CAPPlugin, CAPBridgedPlugin {
|
|
5
|
+
public let jsName = "__CordovaPlugin"
|
|
6
|
+
public let pluginMethods: [CAPPluginMethod] = []
|
|
7
|
+
public var identifier: String { jsName }
|
|
8
|
+
|
|
9
|
+
private var _cordovaDeployDisabled = false
|
|
10
|
+
|
|
11
|
+
override public func load() {
|
|
12
|
+
injectJavascript()
|
|
13
|
+
configureRuntime()
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
func configureRuntime() {
|
|
17
|
+
guard let configURL = Bundle.main.url(forResource: "config", withExtension: "xml") else { fatalError() }
|
|
18
|
+
guard let bridge, let webView = bridge.webView else { return }
|
|
19
|
+
|
|
20
|
+
let cordovaConfigParser = CDVConfigParser()
|
|
21
|
+
|
|
22
|
+
let xmlParser = XMLParser(contentsOf: configURL)
|
|
23
|
+
xmlParser?.delegate = cordovaConfigParser
|
|
24
|
+
xmlParser?.parse()
|
|
25
|
+
|
|
26
|
+
guard let pluginManager = CDVPluginManager(
|
|
27
|
+
parser: cordovaConfigParser,
|
|
28
|
+
viewController: bridge.viewController,
|
|
29
|
+
webView: bridge.webView
|
|
30
|
+
) else { return }
|
|
31
|
+
|
|
32
|
+
for plugin in cordovaConfigParser.startupPluginNames.compactMap({ $0 as? String }) {
|
|
33
|
+
_ = pluginManager.getCommandInstance(plugin)
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
exportCordovaPluginsJS(userContentController: webView.configuration.userContentController)
|
|
37
|
+
|
|
38
|
+
bridge.registerCallInterceptor("cordova") { [pluginManager] dict in
|
|
39
|
+
let pluginId = dict["service"] as? String ?? ""
|
|
40
|
+
let method = dict["action"] as? String ?? ""
|
|
41
|
+
let callbackId = dict["callbackId"] as? String ?? ""
|
|
42
|
+
|
|
43
|
+
let args = dict["actionArgs"] as? Array ?? []
|
|
44
|
+
let options = ["options": args]
|
|
45
|
+
|
|
46
|
+
CAPLog.print("To Native Cordova -> ", pluginId, method, callbackId, options)
|
|
47
|
+
|
|
48
|
+
if let plugin = pluginManager.getCommandInstance(pluginId.lowercased()) {
|
|
49
|
+
let selector = NSSelectorFromString("\(method):")
|
|
50
|
+
if !plugin.responds(to: selector) {
|
|
51
|
+
CAPLog.print("Error: Plugin \(plugin.className ?? "") does not respond to method call \(selector).")
|
|
52
|
+
CAPLog.print("Ensure plugin method exists and uses @objc in its declaration")
|
|
53
|
+
return
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
let arguments = options["options"] ?? []
|
|
57
|
+
let pluginCall = CDVInvokedUrlCommand(
|
|
58
|
+
arguments: arguments,
|
|
59
|
+
callbackId: callbackId,
|
|
60
|
+
className: plugin.className,
|
|
61
|
+
methodName: method
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
plugin.perform(selector, with: pluginCall)
|
|
65
|
+
|
|
66
|
+
} else {
|
|
67
|
+
CAPLog.print("Error: Cordova Plugin mapping not found")
|
|
68
|
+
return
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
_cordovaDeployDisabled = (cordovaConfigParser.settings?["DisableDeploy".lowercased()] as? NSString)?.boolValue ?? false
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
@objc
|
|
76
|
+
func cordovaDeployDisabled() -> NSNumber {
|
|
77
|
+
return _cordovaDeployDisabled as NSNumber
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
func injectJavascript() {
|
|
81
|
+
guard let cordovaUrl = Bundle.main.url(forResource: "public/cordova", withExtension: "js") else {
|
|
82
|
+
fatalError("ERROR: Required cordova.js file not found. Cordova plugins will not function!")
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
guard let cordovaPluginsUrl = Bundle.main.url(forResource: "public/cordova_plugins", withExtension: "js") else {
|
|
86
|
+
fatalError("ERROR: Required cordova_plugins.js file not found. Cordova plugins will not function!")
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
guard let webView = bridge?.webView else { return }
|
|
90
|
+
|
|
91
|
+
injectFile(fileURL: cordovaUrl, userContentController: webView.configuration.userContentController)
|
|
92
|
+
injectFile(fileURL: cordovaPluginsUrl, userContentController: webView.configuration.userContentController)
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
func exportCordovaPluginsJS(userContentController: WKUserContentController) {
|
|
96
|
+
if let pluginsJSFolder = Bundle.main.url(forResource: "public/plugins", withExtension: nil) {
|
|
97
|
+
injectFilesForFolder(folder: pluginsJSFolder, userContentController: userContentController)
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
func injectFile(fileURL: URL, userContentController: WKUserContentController) {
|
|
102
|
+
do {
|
|
103
|
+
let data = try String(contentsOf: fileURL, encoding: .utf8)
|
|
104
|
+
let userScript = WKUserScript(source: data, injectionTime: .atDocumentStart, forMainFrameOnly: true)
|
|
105
|
+
userContentController.addUserScript(userScript)
|
|
106
|
+
} catch {
|
|
107
|
+
fatalError("Unable to inject js file")
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
func injectFilesForFolder(folder: URL, userContentController: WKUserContentController) {
|
|
112
|
+
let fileManager = FileManager.default
|
|
113
|
+
do {
|
|
114
|
+
let fileURLs = try fileManager.contentsOfDirectory(at: folder, includingPropertiesForKeys: nil, options: [])
|
|
115
|
+
for fileURL in fileURLs {
|
|
116
|
+
if fileURL.hasDirectoryPath {
|
|
117
|
+
injectFilesForFolder(folder: fileURL, userContentController: userContentController)
|
|
118
|
+
} else {
|
|
119
|
+
injectFile(fileURL: fileURL, userContentController: userContentController)
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
} catch {
|
|
123
|
+
CAPLog.print("Error while enumerating files")
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
package/CapacitorCordova.podspec
CHANGED
|
@@ -16,11 +16,12 @@ Pod::Spec.new do |s|
|
|
|
16
16
|
s.authors = { 'Ionic Team' => 'hi@ionicframework.com' }
|
|
17
17
|
s.source = { git: 'https://github.com/ionic-team/capacitor', tag: s.version.to_s }
|
|
18
18
|
s.platform = :ios, 15.0
|
|
19
|
-
s.source_files = "#{prefix}CapacitorCordova/CapacitorCordova/**/*.{h,m}"
|
|
19
|
+
s.source_files = "#{prefix}CapacitorCordova/CapacitorCordova/**/*.{h,m,swift}"
|
|
20
20
|
s.public_header_files = "#{prefix}CapacitorCordova/CapacitorCordova/Classes/Public/*.h",
|
|
21
21
|
"#{prefix}CapacitorCordova/CapacitorCordova/CapacitorCordova.h"
|
|
22
22
|
s.module_map = "#{prefix}CapacitorCordova/CapacitorCordova/CapacitorCordova.modulemap"
|
|
23
23
|
s.resource_bundles = { 'CapacitorCordova' => ["#{prefix}CapacitorCordova/CapacitorCordova/PrivacyInfo.xcprivacy"] }
|
|
24
24
|
s.requires_arc = true
|
|
25
|
+
s.dependency 'Capacitor', s.version.to_s
|
|
25
26
|
s.framework = 'WebKit'
|
|
26
27
|
end
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@capacitor/ios",
|
|
3
|
-
"version": "8.1.0",
|
|
3
|
+
"version": "8.1.1-dev-20260305T152829.0",
|
|
4
4
|
"description": "Capacitor: Cross-platform apps with JavaScript and the web",
|
|
5
5
|
"homepage": "https://capacitorjs.com",
|
|
6
6
|
"author": "Ionic Team <hi@ionic.io> (https://ionic.io)",
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
"xc:build:CapacitorCordova": "cd CapacitorCordova && xcodebuild && cd .."
|
|
26
26
|
},
|
|
27
27
|
"peerDependencies": {
|
|
28
|
-
"@capacitor/core": "^8.1.0"
|
|
28
|
+
"@capacitor/core": "^8.1.0-dev-20260305T152829.0"
|
|
29
29
|
},
|
|
30
30
|
"publishConfig": {
|
|
31
31
|
"access": "public"
|