From e006fc0be80f16f577750c1e06936ad4f97f3d8c Mon Sep 17 00:00:00 2001 From: Steven Sherry Date: Fri, 11 Nov 2022 11:54:00 -0600 Subject: [PATCH 1/3] feat(ios): Adds support for manual registration for plugins and the ability to register instances of plugins so that plugins can be instantiated by the user instead of relying on the bridge. --- .../Capacitor.xcodeproj/project.pbxproj | 4 + .../Capacitor/CAPBridgeProtocol.swift | 5 ++ .../Capacitor/CAPPlugin+LoadInstance.swift | 23 +++++ ios/Capacitor/Capacitor/CAPWebView.swift | 8 +- ios/Capacitor/Capacitor/CapacitorBridge.swift | 83 ++++++++++++++----- 5 files changed, 101 insertions(+), 22 deletions(-) create mode 100644 ios/Capacitor/Capacitor/CAPPlugin+LoadInstance.swift diff --git a/ios/Capacitor/Capacitor.xcodeproj/project.pbxproj b/ios/Capacitor/Capacitor.xcodeproj/project.pbxproj index 825395624..0dd269e7a 100644 --- a/ios/Capacitor/Capacitor.xcodeproj/project.pbxproj +++ b/ios/Capacitor/Capacitor.xcodeproj/project.pbxproj @@ -89,6 +89,7 @@ A38C3D7B2848BE6F004B3680 /* CapacitorCookieManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = A38C3D7A2848BE6F004B3680 /* CapacitorCookieManager.swift */; }; A71289E627F380A500DADDF3 /* Router.swift in Sources */ = {isa = PBXBuildFile; fileRef = A71289E527F380A500DADDF3 /* Router.swift */; }; A71289EB27F380FD00DADDF3 /* RouterTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A71289EA27F380FD00DADDF3 /* RouterTests.swift */; }; + A7F7EDC8291CB7E30015B73B /* CAPBridge+LoadInstance.swift in Sources */ = {isa = PBXBuildFile; fileRef = A7F7EDC7291CB7E30015B73B /* CAPBridge+LoadInstance.swift */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -225,6 +226,7 @@ A38C3D7A2848BE6F004B3680 /* CapacitorCookieManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CapacitorCookieManager.swift; sourceTree = ""; }; A71289E527F380A500DADDF3 /* Router.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Router.swift; sourceTree = ""; }; A71289EA27F380FD00DADDF3 /* RouterTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RouterTests.swift; sourceTree = ""; }; + A7F7EDC7291CB7E30015B73B /* CAPBridge+LoadInstance.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "CAPBridge+LoadInstance.swift"; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -327,6 +329,7 @@ 62959AE32524DA7700A3D7F1 /* JSExport.swift */, 621ECCD4254205BD00D3D615 /* CAPBridgeProtocol.swift */, 621ECCD9254205C400D3D615 /* CapacitorBridge.swift */, + A7F7EDC7291CB7E30015B73B /* CAPBridge+LoadInstance.swift */, 62959B142524DA7700A3D7F1 /* CAPBridge.swift */, 62959B042524DA7700A3D7F1 /* CAPBridgeViewController.swift */, 621ECCE2254206A600D3D615 /* CAPApplicationDelegateProxy.swift */, @@ -641,6 +644,7 @@ 623D691E254C7462002D01D1 /* CAPInstanceConfiguration.m in Sources */, 623D68FA254C5037002D01D1 /* KeyPath.swift in Sources */, 62959B222524DA7800A3D7F1 /* Console.swift in Sources */, + A7F7EDC8291CB7E30015B73B /* CAPBridge+LoadInstance.swift in Sources */, 62959B3A2524DA7800A3D7F1 /* CAPLog.swift in Sources */, 6214934725509C3F006C36F9 /* CAPInstanceConfiguration.swift in Sources */, 623D6914254C7030002D01D1 /* CAPInstanceDescriptor.swift in Sources */, diff --git a/ios/Capacitor/Capacitor/CAPBridgeProtocol.swift b/ios/Capacitor/Capacitor/CAPBridgeProtocol.swift index 82bb626dc..c4df14ff2 100644 --- a/ios/Capacitor/Capacitor/CAPBridgeProtocol.swift +++ b/ios/Capacitor/Capacitor/CAPBridgeProtocol.swift @@ -10,6 +10,7 @@ import WebKit var isSimEnvironment: Bool { get } var isDevEnvironment: Bool { get } var userInterfaceStyle: UIUserInterfaceStyle { get } + var autoRegisterPlugins: Bool { get set } var statusBarVisible: Bool { get set } var statusBarStyle: UIStatusBarStyle { get set } var statusBarAnimation: UIStatusBarAnimation { get set } @@ -72,6 +73,10 @@ import WebKit 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)?) diff --git a/ios/Capacitor/Capacitor/CAPPlugin+LoadInstance.swift b/ios/Capacitor/Capacitor/CAPPlugin+LoadInstance.swift new file mode 100644 index 000000000..e0b5b72fb --- /dev/null +++ b/ios/Capacitor/Capacitor/CAPPlugin+LoadInstance.swift @@ -0,0 +1,23 @@ +// +// CAPPlugin+LoadInstance.swift +// Capacitor +// +// Created by Steven Sherry on 11/9/22. +// Copyright © 2022 Drifty Co. All rights reserved. +// + +import Foundation + +open class CAPInstancePlugin: CAPPlugin {} + +extension CAPPlugin { + func load(as bridgedType: CAPBridgedPlugin.Type, on bridge: CAPBridgeProtocol) { + self.bridge = bridge + webView = bridge.webView + pluginId = bridgedType.pluginId() + pluginName = bridgedType.jsName() + shouldStringifyDatesInCalls = true + retainedEventArguments = [:] + load() + } +} diff --git a/ios/Capacitor/Capacitor/CAPWebView.swift b/ios/Capacitor/Capacitor/CAPWebView.swift index a7cac0bf1..d8e56c95b 100644 --- a/ios/Capacitor/Capacitor/CAPWebView.swift +++ b/ios/Capacitor/Capacitor/CAPWebView.swift @@ -14,7 +14,8 @@ open class CAPWebView: UIView { delegate: self, cordovaConfiguration: configDescriptor.cordovaConfiguration, assetHandler: assetHandler, - delegationHandler: delegationHandler + delegationHandler: delegationHandler, + autoRegisterPlugins: autoRegisterPlugins ) public final var bridge: CAPBridgeProtocol { @@ -31,15 +32,18 @@ open class CAPWebView: UIView { }() private lazy var delegationHandler = WebViewDelegationHandler() + private var autoRegisterPlugins: Bool open var router: Router { _Router() } public required init?(coder: NSCoder) { + autoRegisterPlugins = true super.init(coder: coder) setup() } - public init() { + public init(autoRegisterPlugins: Bool = true) { + self.autoRegisterPlugins = autoRegisterPlugins super.init(frame: .zero) setup() } diff --git a/ios/Capacitor/Capacitor/CapacitorBridge.swift b/ios/Capacitor/Capacitor/CapacitorBridge.swift index 78bbd6a8a..1cda6a960 100644 --- a/ios/Capacitor/Capacitor/CapacitorBridge.swift +++ b/ios/Capacitor/Capacitor/CapacitorBridge.swift @@ -31,6 +31,8 @@ internal class CapacitorBridge: NSObject, CAPBridgeProtocol { return bridgeDelegate?.bridgedWebView } + public var autoRegisterPlugins: Bool + public var notificationRouter: NotificationRouter public var isSimEnvironment: Bool { @@ -188,7 +190,7 @@ internal class CapacitorBridge: NSObject, CAPBridgeProtocol { // MARK: - Initialization - init(with configuration: InstanceConfiguration, delegate bridgeDelegate: CAPBridgeDelegate, cordovaConfiguration: CDVConfigParser, assetHandler: WebViewAssetHandler, delegationHandler: WebViewDelegationHandler) { + 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 @@ -196,7 +198,7 @@ internal class CapacitorBridge: NSObject, CAPBridgeProtocol { self.cordovaParser = cordovaConfiguration self.notificationRouter = NotificationRouter() self.notificationRouter.handleApplicationNotifications = configuration.handleApplicationNotifications - + self.autoRegisterPlugins = autoRegisterPlugins super.init() self.webViewDelegationHandler.bridge = self @@ -273,32 +275,73 @@ internal class CapacitorBridge: NSObject, CAPBridgeProtocol { Register all plugins that have been declared */ func registerPlugins() { - let classCount = objc_getClassList(nil, 0) - let classes = UnsafeMutablePointer.allocate(capacity: Int(classCount)) - - let releasingClasses = AutoreleasingUnsafeMutablePointer(classes) - let numClasses: Int32 = objc_getClassList(releasingClasses, classCount) - - for classIndex in 0...allocate(capacity: Int(classCount)) + + let releasingClasses = AutoreleasingUnsafeMutablePointer(classes) + let numClasses: Int32 = objc_getClassList(releasingClasses, classCount) + + for classIndex in 0.. Date: Fri, 11 Nov 2022 12:12:28 -0600 Subject: [PATCH 2/3] fix(ios): Add CAPPlugin+LoadInstance to xcodeproj to fix build errors --- ios/Capacitor/Capacitor.xcodeproj/project.pbxproj | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ios/Capacitor/Capacitor.xcodeproj/project.pbxproj b/ios/Capacitor/Capacitor.xcodeproj/project.pbxproj index 0dd269e7a..5d1c0bfda 100644 --- a/ios/Capacitor/Capacitor.xcodeproj/project.pbxproj +++ b/ios/Capacitor/Capacitor.xcodeproj/project.pbxproj @@ -89,7 +89,7 @@ A38C3D7B2848BE6F004B3680 /* CapacitorCookieManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = A38C3D7A2848BE6F004B3680 /* CapacitorCookieManager.swift */; }; A71289E627F380A500DADDF3 /* Router.swift in Sources */ = {isa = PBXBuildFile; fileRef = A71289E527F380A500DADDF3 /* Router.swift */; }; A71289EB27F380FD00DADDF3 /* RouterTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A71289EA27F380FD00DADDF3 /* RouterTests.swift */; }; - A7F7EDC8291CB7E30015B73B /* CAPBridge+LoadInstance.swift in Sources */ = {isa = PBXBuildFile; fileRef = A7F7EDC7291CB7E30015B73B /* CAPBridge+LoadInstance.swift */; }; + A7F7EDCD291EC75C0015B73B /* CAPPlugin+LoadInstance.swift in Sources */ = {isa = PBXBuildFile; fileRef = A7F7EDCC291EC75C0015B73B /* CAPPlugin+LoadInstance.swift */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -226,7 +226,7 @@ A38C3D7A2848BE6F004B3680 /* CapacitorCookieManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CapacitorCookieManager.swift; sourceTree = ""; }; A71289E527F380A500DADDF3 /* Router.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Router.swift; sourceTree = ""; }; A71289EA27F380FD00DADDF3 /* RouterTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RouterTests.swift; sourceTree = ""; }; - A7F7EDC7291CB7E30015B73B /* CAPBridge+LoadInstance.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "CAPBridge+LoadInstance.swift"; sourceTree = ""; }; + A7F7EDCC291EC75C0015B73B /* CAPPlugin+LoadInstance.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "CAPPlugin+LoadInstance.swift"; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -314,6 +314,7 @@ 62959B0F2524DA7700A3D7F1 /* Capacitor.h */, 62959B132524DA7700A3D7F1 /* CAPPlugin.h */, 62959B012524DA7700A3D7F1 /* CAPPlugin.m */, + A7F7EDCC291EC75C0015B73B /* CAPPlugin+LoadInstance.swift */, 62959AE52524DA7700A3D7F1 /* CAPBridgedPlugin.h */, 62959B092524DA7700A3D7F1 /* CAPPluginMethod.h */, 62959AE82524DA7700A3D7F1 /* CAPPluginMethod.m */, @@ -329,7 +330,6 @@ 62959AE32524DA7700A3D7F1 /* JSExport.swift */, 621ECCD4254205BD00D3D615 /* CAPBridgeProtocol.swift */, 621ECCD9254205C400D3D615 /* CapacitorBridge.swift */, - A7F7EDC7291CB7E30015B73B /* CAPBridge+LoadInstance.swift */, 62959B142524DA7700A3D7F1 /* CAPBridge.swift */, 62959B042524DA7700A3D7F1 /* CAPBridgeViewController.swift */, 621ECCE2254206A600D3D615 /* CAPApplicationDelegateProxy.swift */, @@ -644,11 +644,11 @@ 623D691E254C7462002D01D1 /* CAPInstanceConfiguration.m in Sources */, 623D68FA254C5037002D01D1 /* KeyPath.swift in Sources */, 62959B222524DA7800A3D7F1 /* Console.swift in Sources */, - A7F7EDC8291CB7E30015B73B /* CAPBridge+LoadInstance.swift in Sources */, 62959B3A2524DA7800A3D7F1 /* CAPLog.swift in Sources */, 6214934725509C3F006C36F9 /* CAPInstanceConfiguration.swift in Sources */, 623D6914254C7030002D01D1 /* CAPInstanceDescriptor.swift in Sources */, 621ECCE3254206A600D3D615 /* CAPApplicationDelegateProxy.swift in Sources */, + A7F7EDCD291EC75C0015B73B /* CAPPlugin+LoadInstance.swift in Sources */, 62959B262524DA7800A3D7F1 /* WebView.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; From 299cb996851313ebce0b23061c2162d2736233f5 Mon Sep 17 00:00:00 2001 From: Steven Sherry Date: Mon, 21 Nov 2022 11:33:32 -0600 Subject: [PATCH 3/3] chore(ios): Add @objc annotation to CAPInstancePlugin and move its definition to its own file. Make `autoRegisterPlugins` a get-only property since the bridge decides whether or not to auto-register on initialization and setting it at any time after init would do nothing. --- ios/Capacitor/Capacitor.xcodeproj/project.pbxproj | 4 ++++ ios/Capacitor/Capacitor/CAPBridgeProtocol.swift | 2 +- ios/Capacitor/Capacitor/CAPInstancePlugin.swift | 10 ++++++++++ ios/Capacitor/Capacitor/CAPPlugin+LoadInstance.swift | 4 ---- ios/Capacitor/Capacitor/CAPWebView.swift | 2 +- ios/Capacitor/Capacitor/CapacitorBridge.swift | 2 +- 6 files changed, 17 insertions(+), 7 deletions(-) create mode 100644 ios/Capacitor/Capacitor/CAPInstancePlugin.swift diff --git a/ios/Capacitor/Capacitor.xcodeproj/project.pbxproj b/ios/Capacitor/Capacitor.xcodeproj/project.pbxproj index 5d1c0bfda..e7f21d6bf 100644 --- a/ios/Capacitor/Capacitor.xcodeproj/project.pbxproj +++ b/ios/Capacitor/Capacitor.xcodeproj/project.pbxproj @@ -90,6 +90,7 @@ A71289E627F380A500DADDF3 /* Router.swift in Sources */ = {isa = PBXBuildFile; fileRef = A71289E527F380A500DADDF3 /* Router.swift */; }; A71289EB27F380FD00DADDF3 /* RouterTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A71289EA27F380FD00DADDF3 /* RouterTests.swift */; }; A7F7EDCD291EC75C0015B73B /* CAPPlugin+LoadInstance.swift in Sources */ = {isa = PBXBuildFile; fileRef = A7F7EDCC291EC75C0015B73B /* CAPPlugin+LoadInstance.swift */; }; + A7F7EDD5292BE8520015B73B /* CAPInstancePlugin.swift in Sources */ = {isa = PBXBuildFile; fileRef = A7F7EDD4292BE8520015B73B /* CAPInstancePlugin.swift */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -227,6 +228,7 @@ A71289E527F380A500DADDF3 /* Router.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Router.swift; sourceTree = ""; }; A71289EA27F380FD00DADDF3 /* RouterTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RouterTests.swift; sourceTree = ""; }; A7F7EDCC291EC75C0015B73B /* CAPPlugin+LoadInstance.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "CAPPlugin+LoadInstance.swift"; sourceTree = ""; }; + A7F7EDD4292BE8520015B73B /* CAPInstancePlugin.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CAPInstancePlugin.swift; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -321,6 +323,7 @@ 62959AE22524DA7700A3D7F1 /* CAPPluginCall.h */, 62959B062524DA7700A3D7F1 /* CAPPluginCall.m */, 62959AE62524DA7700A3D7F1 /* CAPPluginCall.swift */, + A7F7EDD4292BE8520015B73B /* CAPInstancePlugin.swift */, 62ADC0C925CB678000E914DE /* PluginCallResult.swift */, 621ECCBB2542046400D3D615 /* JSTypes.swift */, 621ECCB62542045900D3D615 /* CAPBridgedJSTypes.h */, @@ -615,6 +618,7 @@ 621ECCDA254205C400D3D615 /* CapacitorBridge.swift in Sources */, 62959B382524DA7800A3D7F1 /* CAPPluginCall.m in Sources */, 623D690A254C6FDF002D01D1 /* CAPInstanceDescriptor.m in Sources */, + A7F7EDD5292BE8520015B73B /* CAPInstancePlugin.swift in Sources */, A38C3D7B2848BE6F004B3680 /* CapacitorCookieManager.swift in Sources */, 62959B1B2524DA7800A3D7F1 /* CAPFile.swift in Sources */, 62959B462524DA7800A3D7F1 /* CAPBridge.swift in Sources */, diff --git a/ios/Capacitor/Capacitor/CAPBridgeProtocol.swift b/ios/Capacitor/Capacitor/CAPBridgeProtocol.swift index c4df14ff2..306756e2b 100644 --- a/ios/Capacitor/Capacitor/CAPBridgeProtocol.swift +++ b/ios/Capacitor/Capacitor/CAPBridgeProtocol.swift @@ -10,7 +10,7 @@ import WebKit var isSimEnvironment: Bool { get } var isDevEnvironment: Bool { get } var userInterfaceStyle: UIUserInterfaceStyle { get } - var autoRegisterPlugins: Bool { get set } + var autoRegisterPlugins: Bool { get } var statusBarVisible: Bool { get set } var statusBarStyle: UIStatusBarStyle { get set } var statusBarAnimation: UIStatusBarAnimation { get set } diff --git a/ios/Capacitor/Capacitor/CAPInstancePlugin.swift b/ios/Capacitor/Capacitor/CAPInstancePlugin.swift new file mode 100644 index 000000000..0a73e434f --- /dev/null +++ b/ios/Capacitor/Capacitor/CAPInstancePlugin.swift @@ -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 {} diff --git a/ios/Capacitor/Capacitor/CAPPlugin+LoadInstance.swift b/ios/Capacitor/Capacitor/CAPPlugin+LoadInstance.swift index e0b5b72fb..05af9ff27 100644 --- a/ios/Capacitor/Capacitor/CAPPlugin+LoadInstance.swift +++ b/ios/Capacitor/Capacitor/CAPPlugin+LoadInstance.swift @@ -6,10 +6,6 @@ // Copyright © 2022 Drifty Co. All rights reserved. // -import Foundation - -open class CAPInstancePlugin: CAPPlugin {} - extension CAPPlugin { func load(as bridgedType: CAPBridgedPlugin.Type, on bridge: CAPBridgeProtocol) { self.bridge = bridge diff --git a/ios/Capacitor/Capacitor/CAPWebView.swift b/ios/Capacitor/Capacitor/CAPWebView.swift index d4c10434c..4e9e90fb1 100644 --- a/ios/Capacitor/Capacitor/CAPWebView.swift +++ b/ios/Capacitor/Capacitor/CAPWebView.swift @@ -32,7 +32,7 @@ open class CAPWebView: UIView { }() private lazy var delegationHandler = WebViewDelegationHandler() - private var autoRegisterPlugins: Bool + private let autoRegisterPlugins: Bool open var router: Router { _Router() } diff --git a/ios/Capacitor/Capacitor/CapacitorBridge.swift b/ios/Capacitor/Capacitor/CapacitorBridge.swift index 1cda6a960..c46383c81 100644 --- a/ios/Capacitor/Capacitor/CapacitorBridge.swift +++ b/ios/Capacitor/Capacitor/CapacitorBridge.swift @@ -31,7 +31,7 @@ internal class CapacitorBridge: NSObject, CAPBridgeProtocol { return bridgeDelegate?.bridgedWebView } - public var autoRegisterPlugins: Bool + public let autoRegisterPlugins: Bool public var notificationRouter: NotificationRouter