From 4f3f53c5b9640cbde44e772cedea97b8fa64a415 Mon Sep 17 00:00:00 2001 From: Felix Kirchengast Date: Sat, 20 Mar 2021 13:09:45 +0100 Subject: [PATCH 01/34] Motivation and implementation plan --- README.md | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/README.md b/README.md index e76f0dfd..c0967813 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,28 @@ +# Embedded Capacitor + +This project enables an "embedded usage" of https://capacitorjs.com/ within existing native apps. +It exists because of the following frustrating situation: + +- Capacitor 2.X provides only bad support for "embedded usage", but promised to deliver with Capacitor 3.X [https://github.com/ionic-team/capacitor/pull/3405]. +- Capacitor 3.X deliberately destroyed "embedded usage", but promised to deliver an embedded closed-source-solution [https://github.com/ionic-team/capacitor/issues/4343]. + +For the time being, I consider Capacitor 2.X as more stable for embedded usage. +Therefore, this project only works with Capacitor 2.X. + +## Improvements over Ionic's Capacitor + +With only minimal changes, this project provides the following improvements over Ionic's Capacitor 2.X: + +- Configure custom URL-paths for Android's `BridgeFragment`: https://github.com/ionic-team/capacitor/pull/3405 +- Configure custom URL-paths for iOS `CAPBridgeViewController`: https://github.com/ionic-team/capacitor/issues/4370, https://github.com/ionic-team/capacitor/issues/3106 +- Make iOS `CAPBridgeViewController` extensible to better support embedded usage: https://github.com/ionic-team/capacitor/pull/1972 +- Speedup Android launch time: https://github.com/ionic-team/capacitor/issues/2992 +- Fix Android crashes triggered by unneeded plugins: + +## Installation + +--- +


From 0b4178fb76c6e84bf7b3f8451ff8a5ad00be2e5b Mon Sep 17 00:00:00 2001 From: Felix Kirchengast Date: Sat, 20 Mar 2021 13:40:03 +0100 Subject: [PATCH 02/34] Android: Pass urlPath to BridgeFragment --- .../capacitor/src/main/java/com/getcapacitor/Bridge.java | 9 ++++++--- .../src/main/java/com/getcapacitor/BridgeActivity.java | 2 +- .../src/main/java/com/getcapacitor/BridgeFragment.java | 9 +++++++-- 3 files changed, 14 insertions(+), 6 deletions(-) diff --git a/android/capacitor/src/main/java/com/getcapacitor/Bridge.java b/android/capacitor/src/main/java/com/getcapacitor/Bridge.java index f6c257de..c2c1ffce 100644 --- a/android/capacitor/src/main/java/com/getcapacitor/Bridge.java +++ b/android/capacitor/src/main/java/com/getcapacitor/Bridge.java @@ -136,7 +136,7 @@ public class Bridge { * @param context * @param webView */ - public Bridge(Activity context, WebView webView, List> initialPlugins, CordovaInterfaceImpl cordovaInterface, PluginManager pluginManager, CordovaPreferences preferences, JSONObject config) { + public Bridge(Activity context, WebView webView, List> initialPlugins, CordovaInterfaceImpl cordovaInterface, PluginManager pluginManager, CordovaPreferences preferences, JSONObject config, String urlPath) { this.context = context; this.webView = webView; this.webViewClient = new BridgeWebViewClient(this); @@ -169,10 +169,10 @@ public Bridge(Activity context, WebView webView, List> i // Register our core plugins this.registerAllPlugins(); - this.loadWebView(); + this.loadWebView(urlPath); } - private void loadWebView() { + private void loadWebView(String urlPath) { appUrlConfig = this.getServerUrl(); String[] appAllowNavigationConfig = this.config.getArray("server.allowNavigation"); @@ -207,6 +207,9 @@ private void loadWebView() { appUrl += "/"; } } + if (urlPath != null) { + appUrl += urlPath; + } final boolean html5mode = this.config.getBoolean("server.html5mode", true); diff --git a/android/capacitor/src/main/java/com/getcapacitor/BridgeActivity.java b/android/capacitor/src/main/java/com/getcapacitor/BridgeActivity.java index dad3dfb7..196fc81e 100644 --- a/android/capacitor/src/main/java/com/getcapacitor/BridgeActivity.java +++ b/android/capacitor/src/main/java/com/getcapacitor/BridgeActivity.java @@ -80,7 +80,7 @@ protected void load(Bundle savedInstanceState) { pluginManager = mockWebView.getPluginManager(); cordovaInterface.onCordovaInit(pluginManager); - bridge = new Bridge(this, webView, initialPlugins, cordovaInterface, pluginManager, preferences, this.config); + bridge = new Bridge(this, webView, initialPlugins, cordovaInterface, pluginManager, preferences, this.config, null); if (savedInstanceState != null) { bridge.restoreInstanceState(savedInstanceState); diff --git a/android/capacitor/src/main/java/com/getcapacitor/BridgeFragment.java b/android/capacitor/src/main/java/com/getcapacitor/BridgeFragment.java index a527a7a5..70bff3c1 100644 --- a/android/capacitor/src/main/java/com/getcapacitor/BridgeFragment.java +++ b/android/capacitor/src/main/java/com/getcapacitor/BridgeFragment.java @@ -45,6 +45,11 @@ public BridgeFragment() { // Required empty public constructor } + private String urlPath; + public void setUrlPath(String urlPath) { + this.urlPath = urlPath; + } + /** * Use this factory method to create a new instance of * this fragment using the provided parameters. @@ -72,7 +77,7 @@ public void addPlugin(Class plugin) { * Load the WebView and create the Bridge */ protected void load(Bundle savedInstanceState) { - Logger.debug("Starting BridgeActivity"); + Logger.debug("Starting BridgeFragment"); Bundle args = getArguments(); String startDir = null; @@ -97,7 +102,7 @@ protected void load(Bundle savedInstanceState) { preferences = new CordovaPreferences(); } - bridge = new Bridge(this.getActivity(), webView, initialPlugins, cordovaInterface, pluginManager, preferences, config); + bridge = new Bridge(this.getActivity(), webView, initialPlugins, cordovaInterface, pluginManager, preferences, config, urlPath); if (startDir != null) { bridge.setServerAssetPath(startDir); From f98ee4db26f79dbe83f3ebea212119e21517fd44 Mon Sep 17 00:00:00 2001 From: Felix Kirchengast Date: Sat, 20 Mar 2021 14:02:38 +0100 Subject: [PATCH 03/34] Android: Skip registration of unneeded plugins to improve performance and stability --- .../capacitor/src/main/java/com/getcapacitor/Bridge.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/android/capacitor/src/main/java/com/getcapacitor/Bridge.java b/android/capacitor/src/main/java/com/getcapacitor/Bridge.java index c2c1ffce..7f68d68e 100644 --- a/android/capacitor/src/main/java/com/getcapacitor/Bridge.java +++ b/android/capacitor/src/main/java/com/getcapacitor/Bridge.java @@ -415,7 +415,11 @@ private void initWebView() { * Register our core Plugin APIs */ private void registerAllPlugins() { - this.registerPlugin(App.class); + /** + * For performance and stability reasons, it is better to only register the plugins that + * your app is actually using. + */ + /*this.registerPlugin(App.class); this.registerPlugin(Accessibility.class); this.registerPlugin(BackgroundTask.class); this.registerPlugin(Browser.class); @@ -437,7 +441,7 @@ private void registerAllPlugins() { this.registerPlugin(StatusBar.class); this.registerPlugin(Storage.class); this.registerPlugin(com.getcapacitor.plugin.Toast.class); - this.registerPlugin(com.getcapacitor.plugin.WebView.class); + this.registerPlugin(com.getcapacitor.plugin.WebView.class);*/ for (Class pluginClass : this.initialPlugins) { this.registerPlugin(pluginClass); From 6691148fe52612e94a3bb77a8a7cd014277f7946 Mon Sep 17 00:00:00 2001 From: Felix Kirchengast Date: Sat, 20 Mar 2021 14:08:08 +0100 Subject: [PATCH 04/34] Fix Android-crashes related to LocalNotificationRestoreReceiver intent-filter --- android/capacitor/src/main/AndroidManifest.xml | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/android/capacitor/src/main/AndroidManifest.xml b/android/capacitor/src/main/AndroidManifest.xml index cf142882..f1cc6ace 100644 --- a/android/capacitor/src/main/AndroidManifest.xml +++ b/android/capacitor/src/main/AndroidManifest.xml @@ -14,12 +14,7 @@ - - - - - - + From c01388a80493ce7b27c475c18ecf0a0e7cd12948 Mon Sep 17 00:00:00 2001 From: Felix Kirchengast Date: Sat, 20 Mar 2021 14:14:25 +0100 Subject: [PATCH 05/34] Reduce AndroidManifest.xml to a minimum; removing unnecessary permissions --- .../capacitor/src/main/AndroidManifest.xml | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/android/capacitor/src/main/AndroidManifest.xml b/android/capacitor/src/main/AndroidManifest.xml index f1cc6ace..94585f59 100644 --- a/android/capacitor/src/main/AndroidManifest.xml +++ b/android/capacitor/src/main/AndroidManifest.xml @@ -1,23 +1,4 @@ - - - - - - - - - - - - - - - - - - \ No newline at end of file From 1e5b45d1fc9447a0fca7d94eff11ad0414f337ff Mon Sep 17 00:00:00 2001 From: Felix Kirchengast Date: Sat, 20 Mar 2021 14:52:54 +0100 Subject: [PATCH 06/34] Document Android usage --- README.md | 40 ++++++++++++++++++++++++++++++++++++---- android/package.json | 2 +- 2 files changed, 37 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index c0967813..edabe528 100644 --- a/README.md +++ b/README.md @@ -3,8 +3,8 @@ This project enables an "embedded usage" of https://capacitorjs.com/ within existing native apps. It exists because of the following frustrating situation: -- Capacitor 2.X provides only bad support for "embedded usage", but promised to deliver with Capacitor 3.X [https://github.com/ionic-team/capacitor/pull/3405]. -- Capacitor 3.X deliberately destroyed "embedded usage", but promised to deliver an embedded closed-source-solution [https://github.com/ionic-team/capacitor/issues/4343]. +- Capacitor 2.X provides only bad support for "embedded usage", but promised to deliver with Capacitor 3.X: https://github.com/ionic-team/capacitor/pull/3405 +- Capacitor 3.X deliberately destroyed "embedded usage", but promised to deliver an embedded closed-source-solution: https://github.com/ionic-team/capacitor/issues/4343 For the time being, I consider Capacitor 2.X as more stable for embedded usage. Therefore, this project only works with Capacitor 2.X. @@ -16,11 +16,43 @@ With only minimal changes, this project provides the following improvements over - Configure custom URL-paths for Android's `BridgeFragment`: https://github.com/ionic-team/capacitor/pull/3405 - Configure custom URL-paths for iOS `CAPBridgeViewController`: https://github.com/ionic-team/capacitor/issues/4370, https://github.com/ionic-team/capacitor/issues/3106 - Make iOS `CAPBridgeViewController` extensible to better support embedded usage: https://github.com/ionic-team/capacitor/pull/1972 -- Speedup Android launch time: https://github.com/ionic-team/capacitor/issues/2992 -- Fix Android crashes triggered by unneeded plugins: +- Remove implicit plugin-registration to speedup Android launch time: https://github.com/ionic-team/capacitor/issues/2992 +- Fix Android-crashes related to unneeded plugins: ## Installation +To use this project, replace your dependencies to `@capacitor/android` or `@capacitor/ios` as follows: + +`npm uninstall @capacitor/android` +`npm install capacitor-embedded-android` + +Afterwards, follow the Android/iOS-specific instructions below. + +### Embedded Android + +Firstly, change your `capacitor.settings.gradle` as follows: + +``` +include ':capacitor-android' +project(':capacitor-android').projectDir = new File('../node_modules/capacitor-embedded-android/capacitor') +``` + +Once this is working, I recommend to subclass `BridgeFragment` for embedded usage: + +``` +import android.os.Bundle +import com.getcapacitor.BridgeFragment +import com.getcapacitor.plugin.Device + +class MyBridgeFragment : BridgeFragment() { + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + super.addPlugin(Device::class.java) // Add default-plugins because they are no longer registered implicitly! + super.setUrlPath("/#embedded_feature_1") // Set an URL-path for your embedded usage + } +} +``` + ---
diff --git a/android/package.json b/android/package.json index 15167fab..d0f8d1c0 100644 --- a/android/package.json +++ b/android/package.json @@ -1,5 +1,5 @@ { - "name": "@capacitor/android", + "name": "capacitor-embedded-android", "version": "2.4.7", "description": "Capacitor: cross-platform mobile apps with the web", "homepage": "https://capacitor.ionicframework.com/", From fd59b5dae3e3644d2c32b2a03cd54932bac3173e Mon Sep 17 00:00:00 2001 From: Felix Kirchengast Date: Sat, 20 Mar 2021 15:02:58 +0100 Subject: [PATCH 07/34] Cleanup --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index edabe528..c48870d7 100644 --- a/README.md +++ b/README.md @@ -23,8 +23,8 @@ With only minimal changes, this project provides the following improvements over To use this project, replace your dependencies to `@capacitor/android` or `@capacitor/ios` as follows: -`npm uninstall @capacitor/android` -`npm install capacitor-embedded-android` +`npm uninstall @capacitor/android` +`npm install capacitor-embedded-android` Afterwards, follow the Android/iOS-specific instructions below. @@ -39,7 +39,7 @@ project(':capacitor-android').projectDir = new File('../node_modules/capacitor-e Once this is working, I recommend to subclass `BridgeFragment` for embedded usage: -``` +```Kotlin import android.os.Bundle import com.getcapacitor.BridgeFragment import com.getcapacitor.plugin.Device From 9528e4cc34fc269ea72111630901442e045072de Mon Sep 17 00:00:00 2001 From: Felix Kirchengast Date: Sat, 20 Mar 2021 15:22:49 +0100 Subject: [PATCH 08/34] iOS: Open CAPBridgeViewController for subclassing --- .../Capacitor/CAPBridgeViewController.swift | 104 +++++++++--------- 1 file changed, 52 insertions(+), 52 deletions(-) diff --git a/ios/Capacitor/Capacitor/CAPBridgeViewController.swift b/ios/Capacitor/Capacitor/CAPBridgeViewController.swift index 95abcb00..af65aedb 100644 --- a/ios/Capacitor/Capacitor/CAPBridgeViewController.swift +++ b/ios/Capacitor/Capacitor/CAPBridgeViewController.swift @@ -7,14 +7,14 @@ import UIKit import WebKit import Cordova -public class CAPBridgeViewController: UIViewController, CAPBridgeDelegate, WKScriptMessageHandler, WKUIDelegate, WKNavigationDelegate { - +open class CAPBridgeViewController: UIViewController, CAPBridgeDelegate, WKScriptMessageHandler, WKUIDelegate, WKNavigationDelegate { + private var webView: WKWebView? - + public var bridgedWebView: WKWebView? { return webView } - + public var bridgedViewController: UIViewController? { return self } @@ -23,27 +23,27 @@ public class CAPBridgeViewController: UIViewController, CAPBridgeDelegate, WKScr private var allowNavigationConfig: [String]? private var basePath: String = "" private let assetsFolder = "public" - + private enum WebViewLoadingState { case unloaded case initialLoad(isOpaque: Bool) case subsequentLoad } private var webViewLoadingState = WebViewLoadingState.unloaded - + private var isStatusBarVisible = true private var statusBarStyle: UIStatusBarStyle = .default private var statusBarAnimation: UIStatusBarAnimation = .slide @objc public var supportedOrientations: Array = [] - + @objc public var startDir = "" @objc public var config: String? // Construct the Capacitor runtime public var bridge: CAPBridge? private var handler: CAPAssetHandler? - - override public func loadView() { + + override open func loadView() { let configUrl = Bundle.main.url(forResource: "config", withExtension: "xml") let configParser = XMLParser(contentsOf: configUrl!)!; configParser.delegate = cordovaParser @@ -51,7 +51,7 @@ public class CAPBridgeViewController: UIViewController, CAPBridgeDelegate, WKScr guard let startPath = self.getStartPath() else { return } - + setStatusBarDefaults() setScreenOrientationDefaults() let capConfig = CAPConfig(self.config) @@ -72,7 +72,7 @@ public class CAPBridgeViewController: UIViewController, CAPBridgeDelegate, WKScr o.add(self, name: "bridge") webViewConfiguration.userContentController = o - + configureWebView(configuration: webViewConfiguration) if let appendUserAgent = (capConfig.getValue("ios.appendUserAgent") as? String) ?? (capConfig.getValue("appendUserAgent") as? String) { @@ -96,9 +96,9 @@ public class CAPBridgeViewController: UIViewController, CAPBridgeDelegate, WKScr } webView?.configuration.preferences.setValue(true, forKey: "allowFileAccessFromFileURLs") view = webView - + setKeyboardRequiresUserInteraction(false) - + bridge = CAPBridge(self, o, capConfig, specifiedScheme) if let backgroundColor = (bridge!.config.getValue("ios.backgroundColor") as? String) ?? (bridge!.config.getValue("backgroundColor") as? String) { @@ -109,7 +109,7 @@ public class CAPBridgeViewController: UIViewController, CAPBridgeDelegate, WKScr webView?.backgroundColor = UIColor.systemBackground webView?.scrollView.backgroundColor = UIColor.systemBackground } - + if let overrideUserAgent = (bridge!.config.getValue("ios.overrideUserAgent") as? String) ?? (bridge!.config.getValue("overrideUserAgent") as? String) { webView?.customUserAgent = overrideUserAgent } @@ -164,7 +164,7 @@ public class CAPBridgeViewController: UIViewController, CAPBridgeDelegate, WKScr return false } - override public func viewDidLoad() { + override open func viewDidLoad() { super.viewDidLoad() self.becomeFirstResponder() loadWebView() @@ -172,13 +172,13 @@ public class CAPBridgeViewController: UIViewController, CAPBridgeDelegate, WKScr func printLoadError() { let fullStartPath = URL(fileURLWithPath: assetsFolder).appendingPathComponent(startDir) - + CAPLog.print("⚡️ ERROR: Unable to load \(fullStartPath.relativePath)/index.html") 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.") } - + func fatalLoadError() -> Never { printLoadError() exit(1) @@ -194,7 +194,7 @@ public class CAPBridgeViewController: UIViewController, CAPBridgeDelegate, WKScr webViewLoadingState = .initialLoad(isOpaque: webView.isOpaque) webView.isOpaque = false } - + let fullStartPath = URL(fileURLWithPath: assetsFolder).appendingPathComponent(startDir).appendingPathComponent("index") if Bundle.main.path(forResource: fullStartPath.relativePath, ofType: "html") == nil { fatalLoadError() @@ -218,7 +218,7 @@ public class CAPBridgeViewController: UIViewController, CAPBridgeDelegate, WKScr self.handler?.setAssetPath(path) } - public func setStatusBarDefaults() { + open func setStatusBarDefaults() { if let plist = Bundle.main.infoDictionary { if let statusBarHidden = plist["UIStatusBarHidden"] as? Bool { if (statusBarHidden) { @@ -239,7 +239,7 @@ public class CAPBridgeViewController: UIViewController, CAPBridgeDelegate, WKScr } } - public func setScreenOrientationDefaults() { + open func setScreenOrientationDefaults() { if let plist = Bundle.main.infoDictionary { if let orientations = plist["UISupportedInterfaceOrientations"] as? Array { for orientation in orientations { @@ -263,22 +263,22 @@ public class CAPBridgeViewController: UIViewController, CAPBridgeDelegate, WKScr } } - public func configureWebView(configuration: WKWebViewConfiguration) { + open func configureWebView(configuration: WKWebViewConfiguration) { configuration.allowsInlineMediaPlayback = true configuration.suppressesIncrementalRendering = false configuration.allowsAirPlayForMediaPlayback = true configuration.mediaTypesRequiringUserActionForPlayback = [] } - public func webView(_ webView: WKWebView, didStartProvisionalNavigation navigation: WKNavigation!) { + open func webView(_ webView: WKWebView, didStartProvisionalNavigation navigation: WKNavigation!) { // Reset the bridge on each navigation bridge!.reset() } - public func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) { + open func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) { NotificationCenter.default.post(name: Notification.Name(CAPNotifications.DecidePolicyForNavigationAction.name()), object: navigationAction) let navUrl = navigationAction.request.url! - + /* * Give plugins the chance to handle the url */ @@ -300,7 +300,7 @@ public class CAPBridgeViewController: UIViewController, CAPBridgeDelegate, WKScr } } } - + if let allowNavigation = allowNavigationConfig, let requestHost = navUrl.host { for pattern in allowNavigation { if matchHost(host: requestHost, pattern: pattern.lowercased()) { @@ -321,7 +321,7 @@ public class CAPBridgeViewController: UIViewController, CAPBridgeDelegate, WKScr decisionHandler(.allow) } - public func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) { + open func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) { if case .initialLoad(let isOpaque) = webViewLoadingState { webView.isOpaque = isOpaque webViewLoadingState = .subsequentLoad @@ -329,7 +329,7 @@ public class CAPBridgeViewController: UIViewController, CAPBridgeDelegate, WKScr CAPLog.print("⚡️ WebView loaded") } - public func webView(_ webView: WKWebView, didFail navigation: WKNavigation!, withError error: Error) { + open func webView(_ webView: WKWebView, didFail navigation: WKNavigation!, withError error: Error) { if case .initialLoad(let isOpaque) = webViewLoadingState { webView.isOpaque = isOpaque webViewLoadingState = .subsequentLoad @@ -338,20 +338,20 @@ public class CAPBridgeViewController: UIViewController, CAPBridgeDelegate, WKScr CAPLog.print("⚡️ Error: " + error.localizedDescription) } - public func webView(_ webView: WKWebView, didFailProvisionalNavigation navigation: WKNavigation!, withError error: Error) { + open func webView(_ webView: WKWebView, didFailProvisionalNavigation navigation: WKNavigation!, withError error: Error) { CAPLog.print("⚡️ WebView failed provisional navigation") CAPLog.print("⚡️ Error: " + error.localizedDescription) } - public func webViewWebContentProcessDidTerminate(_ webView: WKWebView) { + open func webViewWebContentProcessDidTerminate(_ webView: WKWebView) { webView.reload() } - public override func canPerformUnwindSegueAction(_ action: Selector, from fromViewController: UIViewController, withSender sender: Any) -> Bool { + open override func canPerformUnwindSegueAction(_ action: Selector, from fromViewController: UIViewController, withSender sender: Any) -> Bool { return false } - public func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) { + open func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) { guard let bridge = bridge else { return } @@ -448,48 +448,48 @@ public class CAPBridgeViewController: UIViewController, CAPBridgeDelegate, WKScr return host == pattern } - override public func didReceiveMemoryWarning() { + override open func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() // Dispose of any resources that can be recreated. } - override public var prefersStatusBarHidden: Bool { + override open var prefersStatusBarHidden: Bool { get { return !isStatusBarVisible } } - override public var preferredStatusBarStyle: UIStatusBarStyle { + override open var preferredStatusBarStyle: UIStatusBarStyle { get { return statusBarStyle } } - override public var preferredStatusBarUpdateAnimation: UIStatusBarAnimation { + override open var preferredStatusBarUpdateAnimation: UIStatusBarAnimation { get { return statusBarAnimation } } - public func setStatusBarVisible(_ isStatusBarVisible: Bool) { + open func setStatusBarVisible(_ isStatusBarVisible: Bool) { self.isStatusBarVisible = isStatusBarVisible UIView.animate(withDuration: 0.2, animations: { self.setNeedsStatusBarAppearanceUpdate() }) } - public func setStatusBarStyle(_ statusBarStyle: UIStatusBarStyle) { + open func setStatusBarStyle(_ statusBarStyle: UIStatusBarStyle) { self.statusBarStyle = statusBarStyle UIView.animate(withDuration: 0.2, animations: { self.setNeedsStatusBarAppearanceUpdate() }) } - public func setStatusBarAnimation(_ statusBarAnimation: UIStatusBarAnimation) { + open func setStatusBarAnimation(_ statusBarAnimation: UIStatusBarAnimation) { self.statusBarAnimation = statusBarAnimation } - public func webView(_ webView: WKWebView, runJavaScriptAlertPanelWithMessage message: String, initiatedByFrame frame: WKFrameInfo, completionHandler: @escaping () -> Void) { + open func webView(_ webView: WKWebView, runJavaScriptAlertPanelWithMessage message: String, initiatedByFrame frame: WKFrameInfo, completionHandler: @escaping () -> Void) { let alertController = UIAlertController(title: nil, message: message, preferredStyle: .alert) @@ -500,7 +500,7 @@ public class CAPBridgeViewController: UIViewController, CAPBridgeDelegate, WKScr self.present(alertController, animated: true, completion: nil) } - public func webView(_ webView: WKWebView, runJavaScriptConfirmPanelWithMessage message: String, initiatedByFrame frame: WKFrameInfo, completionHandler: @escaping (Bool) -> Void) { + open func webView(_ webView: WKWebView, runJavaScriptConfirmPanelWithMessage message: String, initiatedByFrame frame: WKFrameInfo, completionHandler: @escaping (Bool) -> Void) { let alertController = UIAlertController(title: nil, message: message, preferredStyle: .alert) @@ -515,10 +515,10 @@ public class CAPBridgeViewController: UIViewController, CAPBridgeDelegate, WKScr self.present(alertController, animated: true, completion: nil) } - public func webView(_ webView: WKWebView, runJavaScriptTextInputPanelWithPrompt prompt: String, defaultText: String?, initiatedByFrame frame: WKFrameInfo, completionHandler: @escaping (String?) -> Void) { - + open func webView(_ webView: WKWebView, runJavaScriptTextInputPanelWithPrompt prompt: String, defaultText: String?, initiatedByFrame frame: WKFrameInfo, completionHandler: @escaping (String?) -> Void) { + let alertController = UIAlertController(title: nil, message: prompt, preferredStyle: .alert) - + alertController.addTextField { (textField) in textField.text = defaultText } @@ -533,30 +533,30 @@ public class CAPBridgeViewController: UIViewController, CAPBridgeDelegate, WKScr })) alertController.addAction(UIAlertAction(title: "Cancel", style: .default, handler: { (action) in - + completionHandler(nil) - + })) self.present(alertController, animated: true, completion: nil) } - public func webView(_ webView: WKWebView, createWebViewWith configuration: WKWebViewConfiguration, for navigationAction: WKNavigationAction, windowFeatures: WKWindowFeatures) -> WKWebView? { + open func webView(_ webView: WKWebView, createWebViewWith configuration: WKWebViewConfiguration, for navigationAction: WKNavigationAction, windowFeatures: WKWindowFeatures) -> WKWebView? { if (navigationAction.request.url != nil) { UIApplication.shared.open(navigationAction.request.url!, options: [:], completionHandler: nil) } return nil } - public func getWebView() -> WKWebView { + open func getWebView() -> WKWebView { return self.webView! } - public func getServerBasePath() -> String { + open func getServerBasePath() -> String { return self.basePath } - public func setServerBasePath(path: String) { + open func setServerBasePath(path: String) { setServerPath(path: path) let request = URLRequest(url: URL(string: hostname!)!) DispatchQueue.main.async { @@ -564,7 +564,7 @@ public class CAPBridgeViewController: UIViewController, CAPBridgeDelegate, WKScr } } - override public var supportedInterfaceOrientations: UIInterfaceOrientationMask { + override open var supportedInterfaceOrientations: UIInterfaceOrientationMask { var ret = 0 if self.supportedOrientations.contains(UIInterfaceOrientation.portrait.rawValue) { ret = ret | (1 << UIInterfaceOrientation.portrait.rawValue) @@ -583,7 +583,7 @@ public class CAPBridgeViewController: UIViewController, CAPBridgeDelegate, WKScr /** * Add hooks to detect failed HTTP requests - + func webView(webView: WKWebView, didFailProvisionalNavigation navigation: WKNavigation!, withError error: NSError) { @@ -596,5 +596,5 @@ public class CAPBridgeViewController: UIViewController, CAPBridgeDelegate, WKScr } } */ - + } From 95210f0b5dae2c7c3211fbb17f19eb8464b55a10 Mon Sep 17 00:00:00 2001 From: Felix Kirchengast Date: Sat, 20 Mar 2021 15:29:59 +0100 Subject: [PATCH 09/34] Fix GitHub refs --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index c48870d7..4cbd48f8 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ This project enables an "embedded usage" of https://capacitorjs.com/ within exis It exists because of the following frustrating situation: - Capacitor 2.X provides only bad support for "embedded usage", but promised to deliver with Capacitor 3.X: https://github.com/ionic-team/capacitor/pull/3405 -- Capacitor 3.X deliberately destroyed "embedded usage", but promised to deliver an embedded closed-source-solution: https://github.com/ionic-team/capacitor/issues/4343 +- Capacitor 3.X deliberately destroyed "embedded usage", but promised to deliver an embedded closed-source-solution: https://github.com/ionic-team/capacitor/issues/4343, https://github.com/ionic-team/capacitor/issues/4370 For the time being, I consider Capacitor 2.X as more stable for embedded usage. Therefore, this project only works with Capacitor 2.X. @@ -14,7 +14,7 @@ Therefore, this project only works with Capacitor 2.X. With only minimal changes, this project provides the following improvements over Ionic's Capacitor 2.X: - Configure custom URL-paths for Android's `BridgeFragment`: https://github.com/ionic-team/capacitor/pull/3405 -- Configure custom URL-paths for iOS `CAPBridgeViewController`: https://github.com/ionic-team/capacitor/issues/4370, https://github.com/ionic-team/capacitor/issues/3106 +- Configure custom URL-paths for iOS `CAPBridgeViewController`: https://github.com/ionic-team/capacitor/issues/3106 - Make iOS `CAPBridgeViewController` extensible to better support embedded usage: https://github.com/ionic-team/capacitor/pull/1972 - Remove implicit plugin-registration to speedup Android launch time: https://github.com/ionic-team/capacitor/issues/2992 - Fix Android-crashes related to unneeded plugins: From b1614abfada9f60ba72ee183ec5559405e2d3cc3 Mon Sep 17 00:00:00 2001 From: Felix Kirchengast Date: Sat, 20 Mar 2021 16:35:39 +0100 Subject: [PATCH 10/34] iOS: Add setUrlPath function to CAPBridgeViewController.swift --- ios/Capacitor/Capacitor/CAPBridgeViewController.swift | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/ios/Capacitor/Capacitor/CAPBridgeViewController.swift b/ios/Capacitor/Capacitor/CAPBridgeViewController.swift index af65aedb..28e68618 100644 --- a/ios/Capacitor/Capacitor/CAPBridgeViewController.swift +++ b/ios/Capacitor/Capacitor/CAPBridgeViewController.swift @@ -42,6 +42,11 @@ open class CAPBridgeViewController: UIViewController, CAPBridgeDelegate, WKScrip // Construct the Capacitor runtime public var bridge: CAPBridge? private var handler: CAPAssetHandler? + + private var urlPath: String? + open func setUrlPath(path: String) { + self.urlPath = path + } override open func loadView() { let configUrl = Bundle.main.url(forResource: "config", withExtension: "xml") @@ -202,6 +207,9 @@ open class CAPBridgeViewController: UIViewController, CAPBridgeDelegate, WKScrip hostname = bridge!.config.getString("server.url") ?? "\(bridge!.getLocalUrl())" allowNavigationConfig = bridge!.config.getValue("server.allowNavigation") as? Array + if let urlPath = self.urlPath { + hostname! += urlPath + } if bridge!.isDevMode() && bridge!.config.getString("server.url") != nil { let toastPlugin = bridge!.getOrLoadPlugin(pluginName: "Toast") as? CAPToastPlugin From c5af029caa24d5b11c5fec7eb8713848f9e97ed3 Mon Sep 17 00:00:00 2001 From: Felix Kirchengast Date: Sat, 20 Mar 2021 17:57:06 +0100 Subject: [PATCH 11/34] publish iOS --- README.md | 45 +++++++++++++++++++++++++++++++++++++-------- ios/package.json | 2 +- 2 files changed, 38 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 4cbd48f8..5e97ba6e 100644 --- a/README.md +++ b/README.md @@ -3,8 +3,8 @@ This project enables an "embedded usage" of https://capacitorjs.com/ within existing native apps. It exists because of the following frustrating situation: -- Capacitor 2.X provides only bad support for "embedded usage", but promised to deliver with Capacitor 3.X: https://github.com/ionic-team/capacitor/pull/3405 -- Capacitor 3.X deliberately destroyed "embedded usage", but promised to deliver an embedded closed-source-solution: https://github.com/ionic-team/capacitor/issues/4343, https://github.com/ionic-team/capacitor/issues/4370 +- Capacitor 2.X provides only bad support for "embedded usage", but promised to deliver with Capacitor 3.X [[3405](https://github.com/ionic-team/capacitor/pull/3405)] +- Capacitor 3.X deliberately destroyed "embedded usage", but promised to deliver an embedded closed-source-solution [[4343](https://github.com/ionic-team/capacitor/issues/4343), [4370](https://github.com/ionic-team/capacitor/issues/4370)] For the time being, I consider Capacitor 2.X as more stable for embedded usage. Therefore, this project only works with Capacitor 2.X. @@ -13,24 +13,28 @@ Therefore, this project only works with Capacitor 2.X. With only minimal changes, this project provides the following improvements over Ionic's Capacitor 2.X: -- Configure custom URL-paths for Android's `BridgeFragment`: https://github.com/ionic-team/capacitor/pull/3405 -- Configure custom URL-paths for iOS `CAPBridgeViewController`: https://github.com/ionic-team/capacitor/issues/3106 -- Make iOS `CAPBridgeViewController` extensible to better support embedded usage: https://github.com/ionic-team/capacitor/pull/1972 -- Remove implicit plugin-registration to speedup Android launch time: https://github.com/ionic-team/capacitor/issues/2992 +- Configure custom URL-paths for Android's `BridgeFragment`: [3405](https://github.com/ionic-team/capacitor/pull/3405) +- Configure custom URL-paths for iOS `CAPBridgeViewController`: [3106](https://github.com/ionic-team/capacitor/issues/3106) +- Make iOS `CAPBridgeViewController` extensible to better support embedded usage: [1972](https://github.com/ionic-team/capacitor/pull/1972) +- Remove implicit plugin-registrations to speedup Android launch time: [2992](https://github.com/ionic-team/capacitor/issues/2992) - Fix Android-crashes related to unneeded plugins: ## Installation -To use this project, replace your dependencies to `@capacitor/android` or `@capacitor/ios` as follows: +Before you install this project, ensure that regular Capacitor 2.X is working with your project (e.g. it should work in "fullscreen-mode"). +Once you finished a regular Capacitor 2.X setup, replace your dependencies to `@capacitor/android` or `@capacitor/ios` as follows: `npm uninstall @capacitor/android` `npm install capacitor-embedded-android` +`npm uninstall @capacitor/ios` +`npm install capacitor-embedded-ios` + Afterwards, follow the Android/iOS-specific instructions below. ### Embedded Android -Firstly, change your `capacitor.settings.gradle` as follows: +Firstly, change your `capacitor.settings.gradle` to point to the replaced package: ``` include ':capacitor-android' @@ -53,6 +57,31 @@ class MyBridgeFragment : BridgeFragment() { } ``` +### Embedded iOS + +Firstly, change your `Podfile` to point to the replaced package: + +```` + pod 'Capacitor', :path => '../../node_modules/capacitor-embedded-ios' + pod 'CapacitorCordova', :path => '../../node_modules/capacitor-embedded-ios' +```` + +Once this is working, I recommend to subclass `CAPBridgeViewController` for embedded usage: + +````Swift +public class MyCAPBridgeViewController: CAPBridgeViewController { + public override func loadView() { + super.setUrlPath(path: "/#embedded_feature_1") + super.loadView() + } +} +```` + +## Limitations + +Currently, `cap sync/cap update` does not work with this package, but `cap copy` still works. +This might be fixed in the future, but I don't expect that this is a huge deal for experienced mobile developers. + ---
diff --git a/ios/package.json b/ios/package.json index 1f30986b..a348f0e5 100644 --- a/ios/package.json +++ b/ios/package.json @@ -1,5 +1,5 @@ { - "name": "@capacitor/ios", + "name": "capacitor-embedded-ios", "version": "2.4.7", "description": "Capacitor: cross-platform mobile apps with the web", "homepage": "https://capacitor.ionicframework.com/", From 0f674c97daeb477b4e794ae56221172f686a517c Mon Sep 17 00:00:00 2001 From: Felix Kirchengast Date: Sat, 20 Mar 2021 18:36:27 +0100 Subject: [PATCH 12/34] Remove iOS splashscreen by default --- ios/Capacitor/Capacitor/Plugins/DefaultPlugins.m | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ios/Capacitor/Capacitor/Plugins/DefaultPlugins.m b/ios/Capacitor/Capacitor/Plugins/DefaultPlugins.m index b6d36d6f..31c32184 100644 --- a/ios/Capacitor/Capacitor/Plugins/DefaultPlugins.m +++ b/ios/Capacitor/Capacitor/Plugins/DefaultPlugins.m @@ -139,10 +139,10 @@ CAP_PLUGIN_METHOD(share, CAPPluginReturnPromise); ) -CAP_PLUGIN(CAPSplashScreenPlugin, "SplashScreen", +/*CAP_PLUGIN(CAPSplashScreenPlugin, "SplashScreen", CAP_PLUGIN_METHOD(show, CAPPluginReturnPromise); CAP_PLUGIN_METHOD(hide, CAPPluginReturnPromise); -) +)*/ CAP_PLUGIN(CAPStatusBarPlugin, "StatusBar", CAP_PLUGIN_METHOD(setStyle, CAPPluginReturnPromise); From 7eeb05c9f1356f7fba1770a476884bd8ec1f00e8 Mon Sep 17 00:00:00 2001 From: Felix Kirchengast Date: Sat, 20 Mar 2021 18:41:55 +0100 Subject: [PATCH 13/34] Android: Only disable splash screen plugin by default --- .../src/main/java/com/getcapacitor/Bridge.java | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/android/capacitor/src/main/java/com/getcapacitor/Bridge.java b/android/capacitor/src/main/java/com/getcapacitor/Bridge.java index 7f68d68e..8888aaea 100644 --- a/android/capacitor/src/main/java/com/getcapacitor/Bridge.java +++ b/android/capacitor/src/main/java/com/getcapacitor/Bridge.java @@ -415,11 +415,7 @@ private void initWebView() { * Register our core Plugin APIs */ private void registerAllPlugins() { - /** - * For performance and stability reasons, it is better to only register the plugins that - * your app is actually using. - */ - /*this.registerPlugin(App.class); + this.registerPlugin(App.class); this.registerPlugin(Accessibility.class); this.registerPlugin(BackgroundTask.class); this.registerPlugin(Browser.class); @@ -437,11 +433,11 @@ private void registerAllPlugins() { this.registerPlugin(Photos.class); this.registerPlugin(PushNotifications.class); this.registerPlugin(Share.class); - this.registerPlugin(SplashScreen.class); + //this.registerPlugin(SplashScreen.class); this.registerPlugin(StatusBar.class); this.registerPlugin(Storage.class); this.registerPlugin(com.getcapacitor.plugin.Toast.class); - this.registerPlugin(com.getcapacitor.plugin.WebView.class);*/ + this.registerPlugin(com.getcapacitor.plugin.WebView.class); for (Class pluginClass : this.initialPlugins) { this.registerPlugin(pluginClass); From 60ed7531070c180b15706b55cbae95c9daf2c2aa Mon Sep 17 00:00:00 2001 From: Felix Kirchengast Date: Sat, 20 Mar 2021 18:46:23 +0100 Subject: [PATCH 14/34] Update docs --- README.md | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 5e97ba6e..39f26ace 100644 --- a/README.md +++ b/README.md @@ -13,11 +13,10 @@ Therefore, this project only works with Capacitor 2.X. With only minimal changes, this project provides the following improvements over Ionic's Capacitor 2.X: -- Configure custom URL-paths for Android's `BridgeFragment`: [3405](https://github.com/ionic-team/capacitor/pull/3405) -- Configure custom URL-paths for iOS `CAPBridgeViewController`: [3106](https://github.com/ionic-team/capacitor/issues/3106) +- Configure custom URL-paths for Android/iOS: [3405](https://github.com/ionic-team/capacitor/pull/3405), [3106](https://github.com/ionic-team/capacitor/issues/3106) - Make iOS `CAPBridgeViewController` extensible to better support embedded usage: [1972](https://github.com/ionic-team/capacitor/pull/1972) -- Remove implicit plugin-registrations to speedup Android launch time: [2992](https://github.com/ionic-team/capacitor/issues/2992) - Fix Android-crashes related to unneeded plugins: +- Disable splashscreen-plugin by default to speedup launches (you can still enable it). ## Installation @@ -51,7 +50,6 @@ import com.getcapacitor.plugin.Device class MyBridgeFragment : BridgeFragment() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - super.addPlugin(Device::class.java) // Add default-plugins because they are no longer registered implicitly! super.setUrlPath("/#embedded_feature_1") // Set an URL-path for your embedded usage } } From 738cf015995a5a912c45ad609f1034f8d0951779 Mon Sep 17 00:00:00 2001 From: Felix Kirchengast Date: Sat, 20 Mar 2021 18:51:43 +0100 Subject: [PATCH 15/34] Show diff --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 39f26ace..e221b2af 100644 --- a/README.md +++ b/README.md @@ -18,6 +18,8 @@ With only minimal changes, this project provides the following improvements over - Fix Android-crashes related to unneeded plugins: - Disable splashscreen-plugin by default to speedup launches (you can still enable it). +To convince yourself, here are the differences between this project and Ionic's Capacitor: https://github.com/fkirc/embedded-capacitor/pull/1/files + ## Installation Before you install this project, ensure that regular Capacitor 2.X is working with your project (e.g. it should work in "fullscreen-mode"). From 95e763b2388fdccd21cc58bc29c4c0c9aeb89a0d Mon Sep 17 00:00:00 2001 From: Felix Kirchengast Date: Sat, 20 Mar 2021 18:57:55 +0100 Subject: [PATCH 16/34] Doc cleanup --- README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index e221b2af..dfda0db2 100644 --- a/README.md +++ b/README.md @@ -37,14 +37,14 @@ Afterwards, follow the Android/iOS-specific instructions below. Firstly, change your `capacitor.settings.gradle` to point to the replaced package: -``` +````Groovy include ':capacitor-android' project(':capacitor-android').projectDir = new File('../node_modules/capacitor-embedded-android/capacitor') -``` +```` Once this is working, I recommend to subclass `BridgeFragment` for embedded usage: -```Kotlin +````Kotlin import android.os.Bundle import com.getcapacitor.BridgeFragment import com.getcapacitor.plugin.Device @@ -55,7 +55,7 @@ class MyBridgeFragment : BridgeFragment() { super.setUrlPath("/#embedded_feature_1") // Set an URL-path for your embedded usage } } -``` +```` ### Embedded iOS @@ -71,7 +71,7 @@ Once this is working, I recommend to subclass `CAPBridgeViewController` for embe ````Swift public class MyCAPBridgeViewController: CAPBridgeViewController { public override func loadView() { - super.setUrlPath(path: "/#embedded_feature_1") + super.setUrlPath(path: "/#embedded_feature_1") // Set an URL-path for your embedded usage super.loadView() } } From 33a75415cd337d1a4f7fb73870aee76fa528f1d7 Mon Sep 17 00:00:00 2001 From: Felix Kirchengast Date: Sat, 20 Mar 2021 19:03:44 +0100 Subject: [PATCH 17/34] Simplify README --- README.md | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index dfda0db2..4d956318 100644 --- a/README.md +++ b/README.md @@ -23,26 +23,24 @@ To convince yourself, here are the differences between this project and Ionic's ## Installation Before you install this project, ensure that regular Capacitor 2.X is working with your project (e.g. it should work in "fullscreen-mode"). -Once you finished a regular Capacitor 2.X setup, replace your dependencies to `@capacitor/android` or `@capacitor/ios` as follows: +See https://capacitorjs.com/ for regular Capacitor instructions. +Once you finished a regular Capacitor 2.X setup, follow the Android/iOS-specific instructions below. -`npm uninstall @capacitor/android` -`npm install capacitor-embedded-android` - -`npm uninstall @capacitor/ios` -`npm install capacitor-embedded-ios` +### Embedded Android -Afterwards, follow the Android/iOS-specific instructions below. +Replace your `@capacitor/android` package as follows: -### Embedded Android +`npm uninstall @capacitor/android` +`npm install capacitor-embedded-android` -Firstly, change your `capacitor.settings.gradle` to point to the replaced package: +Next, change your `capacitor.settings.gradle` to point to the replaced package: ````Groovy include ':capacitor-android' project(':capacitor-android').projectDir = new File('../node_modules/capacitor-embedded-android/capacitor') ```` -Once this is working, I recommend to subclass `BridgeFragment` for embedded usage: +Finally, I recommend to subclass `BridgeFragment` for embedded usage: ````Kotlin import android.os.Bundle @@ -59,14 +57,19 @@ class MyBridgeFragment : BridgeFragment() { ### Embedded iOS -Firstly, change your `Podfile` to point to the replaced package: +Replace your `@capacitor/ios` package as follows: + +`npm uninstall @capacitor/ios` +`npm install capacitor-embedded-ios` + +Next, change your `Podfile` to point to the replaced package: ```` pod 'Capacitor', :path => '../../node_modules/capacitor-embedded-ios' pod 'CapacitorCordova', :path => '../../node_modules/capacitor-embedded-ios' ```` -Once this is working, I recommend to subclass `CAPBridgeViewController` for embedded usage: +Finally, I recommend to subclass `CAPBridgeViewController` for embedded usage: ````Swift public class MyCAPBridgeViewController: CAPBridgeViewController { From 10b9a62aa3cac66687cafd32265061e002bf16a5 Mon Sep 17 00:00:00 2001 From: Felix Kirchengast Date: Sat, 20 Mar 2021 19:08:35 +0100 Subject: [PATCH 18/34] diff cleanup --- ios/Capacitor/Capacitor/CAPBridgeViewController.swift | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ios/Capacitor/Capacitor/CAPBridgeViewController.swift b/ios/Capacitor/Capacitor/CAPBridgeViewController.swift index 28e68618..b1df3e21 100644 --- a/ios/Capacitor/Capacitor/CAPBridgeViewController.swift +++ b/ios/Capacitor/Capacitor/CAPBridgeViewController.swift @@ -8,13 +8,13 @@ import WebKit import Cordova open class CAPBridgeViewController: UIViewController, CAPBridgeDelegate, WKScriptMessageHandler, WKUIDelegate, WKNavigationDelegate { - + private var webView: WKWebView? - + public var bridgedWebView: WKWebView? { return webView } - + public var bridgedViewController: UIViewController? { return self } @@ -23,7 +23,7 @@ open class CAPBridgeViewController: UIViewController, CAPBridgeDelegate, WKScrip private var allowNavigationConfig: [String]? private var basePath: String = "" private let assetsFolder = "public" - + private enum WebViewLoadingState { case unloaded case initialLoad(isOpaque: Bool) From a10ce52488b94784be87396807538a30abda0290 Mon Sep 17 00:00:00 2001 From: Felix Kirchengast Date: Sat, 20 Mar 2021 19:12:33 +0100 Subject: [PATCH 19/34] Reduce diff --- .../Capacitor/CAPBridgeViewController.swift | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/ios/Capacitor/Capacitor/CAPBridgeViewController.swift b/ios/Capacitor/Capacitor/CAPBridgeViewController.swift index b1df3e21..a9132bc1 100644 --- a/ios/Capacitor/Capacitor/CAPBridgeViewController.swift +++ b/ios/Capacitor/Capacitor/CAPBridgeViewController.swift @@ -30,12 +30,12 @@ open class CAPBridgeViewController: UIViewController, CAPBridgeDelegate, WKScrip case subsequentLoad } private var webViewLoadingState = WebViewLoadingState.unloaded - + private var isStatusBarVisible = true private var statusBarStyle: UIStatusBarStyle = .default private var statusBarAnimation: UIStatusBarAnimation = .slide @objc public var supportedOrientations: Array = [] - + @objc public var startDir = "" @objc public var config: String? @@ -56,7 +56,7 @@ open class CAPBridgeViewController: UIViewController, CAPBridgeDelegate, WKScrip guard let startPath = self.getStartPath() else { return } - + setStatusBarDefaults() setScreenOrientationDefaults() let capConfig = CAPConfig(self.config) @@ -77,7 +77,7 @@ open class CAPBridgeViewController: UIViewController, CAPBridgeDelegate, WKScrip o.add(self, name: "bridge") webViewConfiguration.userContentController = o - + configureWebView(configuration: webViewConfiguration) if let appendUserAgent = (capConfig.getValue("ios.appendUserAgent") as? String) ?? (capConfig.getValue("appendUserAgent") as? String) { @@ -101,9 +101,9 @@ open class CAPBridgeViewController: UIViewController, CAPBridgeDelegate, WKScrip } webView?.configuration.preferences.setValue(true, forKey: "allowFileAccessFromFileURLs") view = webView - + setKeyboardRequiresUserInteraction(false) - + bridge = CAPBridge(self, o, capConfig, specifiedScheme) if let backgroundColor = (bridge!.config.getValue("ios.backgroundColor") as? String) ?? (bridge!.config.getValue("backgroundColor") as? String) { @@ -114,7 +114,7 @@ open class CAPBridgeViewController: UIViewController, CAPBridgeDelegate, WKScrip webView?.backgroundColor = UIColor.systemBackground webView?.scrollView.backgroundColor = UIColor.systemBackground } - + if let overrideUserAgent = (bridge!.config.getValue("ios.overrideUserAgent") as? String) ?? (bridge!.config.getValue("overrideUserAgent") as? String) { webView?.customUserAgent = overrideUserAgent } @@ -177,13 +177,13 @@ open class CAPBridgeViewController: UIViewController, CAPBridgeDelegate, WKScrip func printLoadError() { let fullStartPath = URL(fileURLWithPath: assetsFolder).appendingPathComponent(startDir) - + CAPLog.print("⚡️ ERROR: Unable to load \(fullStartPath.relativePath)/index.html") 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.") } - + func fatalLoadError() -> Never { printLoadError() exit(1) From c86bef6cb775ec73157ba21baed78fff19ea5b84 Mon Sep 17 00:00:00 2001 From: Felix Kirchengast Date: Sat, 20 Mar 2021 19:14:49 +0100 Subject: [PATCH 20/34] Reduce diff --- .../Capacitor/CAPBridgeViewController.swift | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/ios/Capacitor/Capacitor/CAPBridgeViewController.swift b/ios/Capacitor/Capacitor/CAPBridgeViewController.swift index a9132bc1..dbbdae9b 100644 --- a/ios/Capacitor/Capacitor/CAPBridgeViewController.swift +++ b/ios/Capacitor/Capacitor/CAPBridgeViewController.swift @@ -524,9 +524,9 @@ open class CAPBridgeViewController: UIViewController, CAPBridgeDelegate, WKScrip } open func webView(_ webView: WKWebView, runJavaScriptTextInputPanelWithPrompt prompt: String, defaultText: String?, initiatedByFrame frame: WKFrameInfo, completionHandler: @escaping (String?) -> Void) { - + let alertController = UIAlertController(title: nil, message: prompt, preferredStyle: .alert) - + alertController.addTextField { (textField) in textField.text = defaultText } @@ -541,9 +541,9 @@ open class CAPBridgeViewController: UIViewController, CAPBridgeDelegate, WKScrip })) alertController.addAction(UIAlertAction(title: "Cancel", style: .default, handler: { (action) in - + completionHandler(nil) - + })) self.present(alertController, animated: true, completion: nil) @@ -591,7 +591,7 @@ open class CAPBridgeViewController: UIViewController, CAPBridgeDelegate, WKScrip /** * Add hooks to detect failed HTTP requests - + func webView(webView: WKWebView, didFailProvisionalNavigation navigation: WKNavigation!, withError error: NSError) { @@ -604,5 +604,5 @@ open class CAPBridgeViewController: UIViewController, CAPBridgeDelegate, WKScrip } } */ - + } From 2a257b389dd408b4a57c96b8625c71413d037dde Mon Sep 17 00:00:00 2001 From: Felix Kirchengast Date: Sat, 20 Mar 2021 19:16:56 +0100 Subject: [PATCH 21/34] reduce diff --- ios/Capacitor/Capacitor/CAPBridgeViewController.swift | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ios/Capacitor/Capacitor/CAPBridgeViewController.swift b/ios/Capacitor/Capacitor/CAPBridgeViewController.swift index dbbdae9b..1aa2f503 100644 --- a/ios/Capacitor/Capacitor/CAPBridgeViewController.swift +++ b/ios/Capacitor/Capacitor/CAPBridgeViewController.swift @@ -199,7 +199,7 @@ open class CAPBridgeViewController: UIViewController, CAPBridgeDelegate, WKScrip webViewLoadingState = .initialLoad(isOpaque: webView.isOpaque) webView.isOpaque = false } - + let fullStartPath = URL(fileURLWithPath: assetsFolder).appendingPathComponent(startDir).appendingPathComponent("index") if Bundle.main.path(forResource: fullStartPath.relativePath, ofType: "html") == nil { fatalLoadError() @@ -286,7 +286,7 @@ open class CAPBridgeViewController: UIViewController, CAPBridgeDelegate, WKScrip open func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) { NotificationCenter.default.post(name: Notification.Name(CAPNotifications.DecidePolicyForNavigationAction.name()), object: navigationAction) let navUrl = navigationAction.request.url! - + /* * Give plugins the chance to handle the url */ @@ -308,7 +308,7 @@ open class CAPBridgeViewController: UIViewController, CAPBridgeDelegate, WKScrip } } } - + if let allowNavigation = allowNavigationConfig, let requestHost = navUrl.host { for pattern in allowNavigation { if matchHost(host: requestHost, pattern: pattern.lowercased()) { @@ -591,7 +591,7 @@ open class CAPBridgeViewController: UIViewController, CAPBridgeDelegate, WKScrip /** * Add hooks to detect failed HTTP requests - + func webView(webView: WKWebView, didFailProvisionalNavigation navigation: WKNavigation!, withError error: NSError) { From d165baa631d38182ab3496fe325fbc99b568c663 Mon Sep 17 00:00:00 2001 From: Felix Kirchengast Date: Sat, 20 Mar 2021 19:28:02 +0100 Subject: [PATCH 22/34] Reduce deprecation --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index 4d956318..97aff67e 100644 --- a/README.md +++ b/README.md @@ -23,7 +23,6 @@ To convince yourself, here are the differences between this project and Ionic's ## Installation Before you install this project, ensure that regular Capacitor 2.X is working with your project (e.g. it should work in "fullscreen-mode"). -See https://capacitorjs.com/ for regular Capacitor instructions. Once you finished a regular Capacitor 2.X setup, follow the Android/iOS-specific instructions below. ### Embedded Android From 279739aed836b70c24bbb57a158e584713029f25 Mon Sep 17 00:00:00 2001 From: Felix Kirchengast Date: Sat, 20 Mar 2021 20:40:42 +0100 Subject: [PATCH 23/34] symlinks --- README.md | 47 ++++++++++++++++++----------------------------- 1 file changed, 18 insertions(+), 29 deletions(-) diff --git a/README.md b/README.md index 97aff67e..7db7f7fe 100644 --- a/README.md +++ b/README.md @@ -23,23 +23,29 @@ To convince yourself, here are the differences between this project and Ionic's ## Installation Before you install this project, ensure that regular Capacitor 2.X is working with your project (e.g. it should work in "fullscreen-mode"). -Once you finished a regular Capacitor 2.X setup, follow the Android/iOS-specific instructions below. - -### Embedded Android - -Replace your `@capacitor/android` package as follows: +Once you finished a regular Capacitor 2.X setup, replace your `@capacitor/android` or `@capacitor/ios` packages as follows: `npm uninstall @capacitor/android` `npm install capacitor-embedded-android` -Next, change your `capacitor.settings.gradle` to point to the replaced package: +`npm uninstall @capacitor/ios` +`npm install capacitor-embedded-ios` + +Next, create a symlink from the original package-locations to the new package-locations: + +`ln -s "$PWD/node_modules/capacitor-embedded-android/" node_modules/@capacitor/android` +`ln -s "$PWD/node_modules/capacitor-embedded-ios/" node_modules/@capacitor/ios` + +Those symlinks need to be created every time when `node_modules` is created. +Therefore, I recommend adding the following `preinstall`-script to your `package.json`: + + + +Finally, follow the Android/iOS-specific instructions below. -````Groovy -include ':capacitor-android' -project(':capacitor-android').projectDir = new File('../node_modules/capacitor-embedded-android/capacitor') -```` +### Embedded Android -Finally, I recommend to subclass `BridgeFragment` for embedded usage: +For Android, I recommend to subclass `BridgeFragment` for embedded usage: ````Kotlin import android.os.Bundle @@ -56,19 +62,7 @@ class MyBridgeFragment : BridgeFragment() { ### Embedded iOS -Replace your `@capacitor/ios` package as follows: - -`npm uninstall @capacitor/ios` -`npm install capacitor-embedded-ios` - -Next, change your `Podfile` to point to the replaced package: - -```` - pod 'Capacitor', :path => '../../node_modules/capacitor-embedded-ios' - pod 'CapacitorCordova', :path => '../../node_modules/capacitor-embedded-ios' -```` - -Finally, I recommend to subclass `CAPBridgeViewController` for embedded usage: +For iOS, I recommend to subclass `CAPBridgeViewController` for embedded usage: ````Swift public class MyCAPBridgeViewController: CAPBridgeViewController { @@ -79,11 +73,6 @@ public class MyCAPBridgeViewController: CAPBridgeViewController { } ```` -## Limitations - -Currently, `cap sync/cap update` does not work with this package, but `cap copy` still works. -This might be fixed in the future, but I don't expect that this is a huge deal for experienced mobile developers. - ---
From 4c52e42d346b3cc2523c5bd1bebb1e3bc2728240 Mon Sep 17 00:00:00 2001 From: Felix Kirchengast Date: Sat, 20 Mar 2021 20:43:05 +0100 Subject: [PATCH 24/34] Re-publish iOS --- ios/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ios/package.json b/ios/package.json index a348f0e5..2d568b3e 100644 --- a/ios/package.json +++ b/ios/package.json @@ -1,6 +1,6 @@ { "name": "capacitor-embedded-ios", - "version": "2.4.7", + "version": "2.4.7-1", "description": "Capacitor: cross-platform mobile apps with the web", "homepage": "https://capacitor.ionicframework.com/", "author": "Ionic Team (https://ionicframework.com) ", From aeea90f2839b4ca3a2b8636a3c237e49e0305d2c Mon Sep 17 00:00:00 2001 From: Felix Kirchengast Date: Sat, 20 Mar 2021 20:54:11 +0100 Subject: [PATCH 25/34] Re-publish Android --- android/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/android/package.json b/android/package.json index d0f8d1c0..735b9def 100644 --- a/android/package.json +++ b/android/package.json @@ -1,6 +1,6 @@ { "name": "capacitor-embedded-android", - "version": "2.4.7", + "version": "2.4.7-1", "description": "Capacitor: cross-platform mobile apps with the web", "homepage": "https://capacitor.ionicframework.com/", "author": "Ionic Team (https://ionicframework.com) ", From 173a758ba768f04f6f01ae3fbe330f1d55e99713 Mon Sep 17 00:00:00 2001 From: Felix Kirchengast Date: Sat, 20 Mar 2021 20:57:56 +0100 Subject: [PATCH 26/34] Typo --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 7db7f7fe..d9fb1e26 100644 --- a/README.md +++ b/README.md @@ -31,7 +31,7 @@ Once you finished a regular Capacitor 2.X setup, replace your `@capacitor/androi `npm uninstall @capacitor/ios` `npm install capacitor-embedded-ios` -Next, create a symlink from the original package-locations to the new package-locations: +Next, create symlinks from the original package-locations to the new package-locations: `ln -s "$PWD/node_modules/capacitor-embedded-android/" node_modules/@capacitor/android` `ln -s "$PWD/node_modules/capacitor-embedded-ios/" node_modules/@capacitor/ios` From 81ef4bfd5d108e5dcbcb9a3126612c5727af17cb Mon Sep 17 00:00:00 2001 From: Felix Kirchengast Date: Sat, 20 Mar 2021 21:07:32 +0100 Subject: [PATCH 27/34] Recommend postinstall script --- README.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index d9fb1e26..f9b82bbd 100644 --- a/README.md +++ b/README.md @@ -37,8 +37,13 @@ Next, create symlinks from the original package-locations to the new package-loc `ln -s "$PWD/node_modules/capacitor-embedded-ios/" node_modules/@capacitor/ios` Those symlinks need to be created every time when `node_modules` is created. -Therefore, I recommend adding the following `preinstall`-script to your `package.json`: +Therefore, I recommend adding a `postinstall`-script to your `package.json`: +```` + "scripts": { + "postinstall": "ln -s \"$PWD/node_modules/capacitor-embedded-android/\" node_modules/@capacitor/android && ln -s \"$PWD/node_modules/capacitor-embedded-ios/\" node_modules/@capacitor/ios" + }, +```` Finally, follow the Android/iOS-specific instructions below. From 480583c398e9b50f2f0584cbe8aac6a079486cc6 Mon Sep 17 00:00:00 2001 From: Felix Kirchengast Date: Sat, 20 Mar 2021 21:10:50 +0100 Subject: [PATCH 28/34] Cleanup --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index f9b82bbd..17d1b025 100644 --- a/README.md +++ b/README.md @@ -55,7 +55,6 @@ For Android, I recommend to subclass `BridgeFragment` for embedded usage: ````Kotlin import android.os.Bundle import com.getcapacitor.BridgeFragment -import com.getcapacitor.plugin.Device class MyBridgeFragment : BridgeFragment() { override fun onCreate(savedInstanceState: Bundle?) { From 21e189da55c2d47a329f57aa3b3300f1656a0817 Mon Sep 17 00:00:00 2001 From: Felix Kirchengast Date: Sat, 20 Mar 2021 21:21:05 +0100 Subject: [PATCH 29/34] recommend capsafe --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 17d1b025..905e5beb 100644 --- a/README.md +++ b/README.md @@ -45,6 +45,7 @@ Therefore, I recommend adding a `postinstall`-script to your `package.json`: }, ```` +Optionally, I recommend the [capsafe](https://github.com/fkirc/capacitor-build-safety) tool to increase safety and traceability of your Capacitor-apps. Finally, follow the Android/iOS-specific instructions below. From b0d0d09dcb44f092ce57357e5d60238dc4f08319 Mon Sep 17 00:00:00 2001 From: Felix Kirchengast Date: Sat, 20 Mar 2021 21:47:11 +0100 Subject: [PATCH 30/34] disable workflows --- .github/{workflows => workflows-disabled}/capacitor-bot.yml | 0 .github/{workflows => workflows-disabled}/ci.yml | 0 .github/{workflows => workflows-disabled}/needs-reply.yml | 0 3 files changed, 0 insertions(+), 0 deletions(-) rename .github/{workflows => workflows-disabled}/capacitor-bot.yml (100%) rename .github/{workflows => workflows-disabled}/ci.yml (100%) rename .github/{workflows => workflows-disabled}/needs-reply.yml (100%) diff --git a/.github/workflows/capacitor-bot.yml b/.github/workflows-disabled/capacitor-bot.yml similarity index 100% rename from .github/workflows/capacitor-bot.yml rename to .github/workflows-disabled/capacitor-bot.yml diff --git a/.github/workflows/ci.yml b/.github/workflows-disabled/ci.yml similarity index 100% rename from .github/workflows/ci.yml rename to .github/workflows-disabled/ci.yml diff --git a/.github/workflows/needs-reply.yml b/.github/workflows-disabled/needs-reply.yml similarity index 100% rename from .github/workflows/needs-reply.yml rename to .github/workflows-disabled/needs-reply.yml From 8c09bfd187f8058744a319fdda5c7d87117957fd Mon Sep 17 00:00:00 2001 From: Felix Kirchengast Date: Sat, 20 Mar 2021 22:16:47 +0100 Subject: [PATCH 31/34] Document Android crashes --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 905e5beb..bd093191 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ With only minimal changes, this project provides the following improvements over - Configure custom URL-paths for Android/iOS: [3405](https://github.com/ionic-team/capacitor/pull/3405), [3106](https://github.com/ionic-team/capacitor/issues/3106) - Make iOS `CAPBridgeViewController` extensible to better support embedded usage: [1972](https://github.com/ionic-team/capacitor/pull/1972) -- Fix Android-crashes related to unneeded plugins: +- Fix Android-crashes related to unneeded plugins: [4379](https://github.com/ionic-team/capacitor/issues/4379) - Disable splashscreen-plugin by default to speedup launches (you can still enable it). To convince yourself, here are the differences between this project and Ionic's Capacitor: https://github.com/fkirc/embedded-capacitor/pull/1/files From 79df04ffc4bf0d5082889bd785ea49a6561ec578 Mon Sep 17 00:00:00 2001 From: Jakob Maierhofer Date: Mon, 9 Aug 2021 12:28:31 +0200 Subject: [PATCH 32/34] fix of capacitor-cordova-android-plugin build.gradle as implemented with the release of 2.4.8 --- capacitor-cordova-android-plugins/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/capacitor-cordova-android-plugins/build.gradle b/capacitor-cordova-android-plugins/build.gradle index 9d81326d..7d72ca94 100644 --- a/capacitor-cordova-android-plugins/build.gradle +++ b/capacitor-cordova-android-plugins/build.gradle @@ -18,7 +18,7 @@ android { compileSdkVersion project.hasProperty('compileSdkVersion') ? rootProject.ext.compileSdkVersion : 29 defaultConfig { minSdkVersion project.hasProperty('minSdkVersion') ? rootProject.ext.minSdkVersion : 21 - targetSdkVersion targetSdkVersion = project.hasProperty('targetSdkVersion') ? rootProject.ext.targetSdkVersion : 29 + targetSdkVersion project.hasProperty('targetSdkVersion') ? rootProject.ext.targetSdkVersion : 29 versionCode 1 versionName "1.0" } From 2574720cd978b38dc210e0707306f8f35f290442 Mon Sep 17 00:00:00 2001 From: Felix Kirchengast <17876666+fkirc@users.noreply.github.com> Date: Thu, 14 Oct 2021 21:30:03 +0200 Subject: [PATCH 33/34] Deprecation Notice --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.md b/README.md index bd093191..26d047db 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,9 @@ +# Deprecation Notice + +This package is deprecated because of https://ionic.io/portals. +"Portals" provides a better dev-experience and is actively supported by Ionic and newer Capacitor-versions. +__________ + # Embedded Capacitor This project enables an "embedded usage" of https://capacitorjs.com/ within existing native apps. From a4af3e19522b3249630985c78ae40f8197241a41 Mon Sep 17 00:00:00 2001 From: Felix K <17876666+fkirc@users.noreply.github.com> Date: Thu, 3 Mar 2022 15:18:38 +0100 Subject: [PATCH 34/34] in favor of --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 26d047db..1b3c3ca4 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Deprecation Notice -This package is deprecated because of https://ionic.io/portals. +This package is deprecated in favor of https://ionic.io/portals. "Portals" provides a better dev-experience and is actively supported by Ionic and newer Capacitor-versions. __________