@capacitor/ios 4.0.0-nightly-c3aa3d6c.0 → 4.0.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/CHANGELOG.md +38 -0
- package/Capacitor/Capacitor/CAPInstanceConfiguration.h +1 -0
- package/Capacitor/Capacitor/CAPInstanceConfiguration.m +2 -0
- package/Capacitor/Capacitor/CAPInstanceConfiguration.swift +8 -0
- package/Capacitor/Capacitor/CAPInstanceDescriptor.h +5 -0
- package/Capacitor/Capacitor/CAPInstanceDescriptor.swift +3 -0
- package/Capacitor/Capacitor/CAPPlugin.m +1 -1
- package/Capacitor/Capacitor/CAPPluginCall.swift +1 -1
- package/Capacitor/Capacitor/CAPWebView.swift +242 -0
- package/Capacitor/Capacitor/JSTypes.swift +9 -0
- package/Capacitor/Capacitor/PluginCallResult.swift +1 -1
- package/Capacitor/Capacitor/WebViewDelegationHandler.swift +15 -1
- package/Capacitor/Capacitor/assets/native-bridge.js +8 -0
- package/package.json +3 -3
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,44 @@
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
5
|
|
|
6
|
+
# [4.0.0](https://github.com/ionic-team/capacitor/compare/4.0.0-beta.2...4.0.0) (2022-07-27)
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
### Bug Fixes
|
|
10
|
+
|
|
11
|
+
* **ios:** error data is optional ([#5782](https://github.com/ionic-team/capacitor/issues/5782)) ([da48d79](https://github.com/ionic-team/capacitor/commit/da48d798c3463de9de188ae6a6475fd6afba6091))
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
### Features
|
|
15
|
+
|
|
16
|
+
* **android:** Add Optional Data Param for Error Object ([#5719](https://github.com/ionic-team/capacitor/issues/5719)) ([174172b](https://github.com/ionic-team/capacitor/commit/174172b6c64dc9117c48ed0e20c25e0b6c2fb625))
|
|
17
|
+
* **android:** Use addWebMessageListener where available ([#5427](https://github.com/ionic-team/capacitor/issues/5427)) ([c2dfe80](https://github.com/ionic-team/capacitor/commit/c2dfe808446717412b35e82713d123b7a052f264))
|
|
18
|
+
* **ios:** Add overrideable router var for CAPWebView. ([#5743](https://github.com/ionic-team/capacitor/issues/5743)) ([c1de1c0](https://github.com/ionic-team/capacitor/commit/c1de1c0138aad188a760118e35983d10d257f8e7))
|
|
19
|
+
* **iOS:** post install script for deployment target ([#5783](https://github.com/ionic-team/capacitor/issues/5783)) ([f5afa94](https://github.com/ionic-team/capacitor/commit/f5afa94b3b9c246d87b2af03359840f503bace90))
|
|
20
|
+
* Add option for custom error page ([#5723](https://github.com/ionic-team/capacitor/issues/5723)) ([e8bdef3](https://github.com/ionic-team/capacitor/commit/e8bdef3b4634e4ad45fa8fc34c7c0ab8dfa383f3))
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
# [4.0.0-beta.2](https://github.com/ionic-team/capacitor/compare/4.0.0-beta.1...4.0.0-beta.2) (2022-07-08)
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
### Bug Fixes
|
|
30
|
+
|
|
31
|
+
* **ios:** Add check for both serverURL and localURL in navigation ([#5736](https://github.com/ionic-team/capacitor/issues/5736)) ([8e824f3](https://github.com/ionic-team/capacitor/commit/8e824f33ad4df898fb8c0936a8f5e9041832a5c5))
|
|
32
|
+
* **ios:** properly deliver retained events after listener re-add [#5732](https://github.com/ionic-team/capacitor/issues/5732) ([c5d6328](https://github.com/ionic-team/capacitor/commit/c5d632831924a1bcc868bc46b42f7ff619408752))
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
### Features
|
|
36
|
+
|
|
37
|
+
* **ios:** Add `setServerBasePath(path:)` to CAPWebView ([#5742](https://github.com/ionic-team/capacitor/issues/5742)) ([1afbf8a](https://github.com/ionic-team/capacitor/commit/1afbf8a9dd0b8f7b1ac439d24e5d8ba26f786318))
|
|
38
|
+
* Add CapWebView ([#5715](https://github.com/ionic-team/capacitor/issues/5715)) ([143d266](https://github.com/ionic-team/capacitor/commit/143d266ef0a818bac59dbbdaeda3b5c382ebfa1d))
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
|
|
6
44
|
# [4.0.0-beta.1](https://github.com/ionic-team/capacitor/compare/4.0.0-beta.0...4.0.0-beta.1) (2022-06-27)
|
|
7
45
|
|
|
8
46
|
|
|
@@ -13,6 +13,7 @@ NS_SWIFT_NAME(InstanceConfiguration)
|
|
|
13
13
|
@property (nonatomic, readonly, nonnull) NSArray<NSString*> *allowedNavigationHostnames;
|
|
14
14
|
@property (nonatomic, readonly, nonnull) NSURL *localURL;
|
|
15
15
|
@property (nonatomic, readonly, nonnull) NSURL *serverURL;
|
|
16
|
+
@property (nonatomic, readonly, nullable) NSString *errorPath;
|
|
16
17
|
@property (nonatomic, readonly, nonnull) NSDictionary *pluginConfigurations;
|
|
17
18
|
@property (nonatomic, readonly) BOOL loggingEnabled;
|
|
18
19
|
@property (nonatomic, readonly) BOOL scrollingEnabled;
|
|
@@ -46,6 +46,7 @@
|
|
|
46
46
|
else {
|
|
47
47
|
_serverURL = _localURL;
|
|
48
48
|
}
|
|
49
|
+
_errorPath = descriptor.errorPath;
|
|
49
50
|
// extract the one value we care about from the cordova configuration
|
|
50
51
|
_cordovaDeployDisabled = [descriptor cordovaDeployDisabled];
|
|
51
52
|
}
|
|
@@ -60,6 +61,7 @@
|
|
|
60
61
|
_allowedNavigationHostnames = [[configuration allowedNavigationHostnames] copy];
|
|
61
62
|
_localURL = [[configuration localURL] copy];
|
|
62
63
|
_serverURL = [[configuration serverURL] copy];
|
|
64
|
+
_errorPath = [[configuration errorPath] copy];
|
|
63
65
|
_pluginConfigurations = [[configuration pluginConfigurations] copy];
|
|
64
66
|
_loggingEnabled = configuration.loggingEnabled;
|
|
65
67
|
_scrollingEnabled = configuration.scrollingEnabled;
|
|
@@ -15,6 +15,14 @@ extension InstanceConfiguration {
|
|
|
15
15
|
return serverURL
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
+
@objc var errorPathURL: URL? {
|
|
19
|
+
guard let errorPath = errorPath else {
|
|
20
|
+
return nil
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
return localURL.appendingPathComponent(errorPath)
|
|
24
|
+
}
|
|
25
|
+
|
|
18
26
|
@available(*, deprecated, message: "Use getPluginConfig")
|
|
19
27
|
@objc public func getPluginConfigValue(_ pluginId: String, _ configKey: String) -> Any? {
|
|
20
28
|
return (pluginConfigurations as? JSObject)?[keyPath: KeyPath("\(pluginId).\(configKey)")]
|
|
@@ -53,6 +53,11 @@ NS_SWIFT_NAME(InstanceDescriptor)
|
|
|
53
53
|
@discussion Defaults to @c capacitor. Set by @c server.iosScheme in the configuration file.
|
|
54
54
|
*/
|
|
55
55
|
@property (nonatomic, copy, nullable) NSString *urlScheme;
|
|
56
|
+
/**
|
|
57
|
+
@brief The path to a local html page to display in case of errors.
|
|
58
|
+
@discussion Defaults to nil.
|
|
59
|
+
*/
|
|
60
|
+
@property (nonatomic, copy, nullable) NSString *errorPath;
|
|
56
61
|
/**
|
|
57
62
|
@brief The hostname that will be used for the server URL.
|
|
58
63
|
@discussion Defaults to @c localhost. Set by @c server.hostname in the configuration file.
|
|
@@ -96,6 +96,9 @@ internal extension InstanceDescriptor {
|
|
|
96
96
|
if let urlString = config[keyPath: "server.url"] as? String {
|
|
97
97
|
serverURL = urlString
|
|
98
98
|
}
|
|
99
|
+
if let errorPathString = (config[keyPath: "server.errorPath"] as? String) {
|
|
100
|
+
errorPath = errorPathString
|
|
101
|
+
}
|
|
99
102
|
if let insetBehavior = config[keyPath: "ios.contentInset"] as? String {
|
|
100
103
|
let availableInsets: [String: UIScrollView.ContentInsetAdjustmentBehavior] = ["automatic": .automatic,
|
|
101
104
|
"scrollableAxes": .scrollableAxes,
|
|
@@ -41,7 +41,7 @@
|
|
|
41
41
|
|
|
42
42
|
- (void)addEventListener:(NSString *)eventName listener:(CAPPluginCall *)listener {
|
|
43
43
|
NSMutableArray *listenersForEvent = [self.eventListeners objectForKey:eventName];
|
|
44
|
-
if(
|
|
44
|
+
if(listenersForEvent == nil || [listenersForEvent count] == 0) {
|
|
45
45
|
listenersForEvent = [[NSMutableArray alloc] initWithObjects:listener, nil];
|
|
46
46
|
[self.eventListeners setValue:listenersForEvent forKey:eventName];
|
|
47
47
|
|
|
@@ -57,7 +57,7 @@ extension CAPPluginCall: JSValueContainer {
|
|
|
57
57
|
errorHandler(CAPPluginCallError(message: message, code: nil, error: error, data: data))
|
|
58
58
|
}
|
|
59
59
|
|
|
60
|
-
func reject(_ message: String, _ code: String? = nil, _ error: Error? = nil, _ data: PluginCallResultData =
|
|
60
|
+
func reject(_ message: String, _ code: String? = nil, _ error: Error? = nil, _ data: PluginCallResultData? = nil) {
|
|
61
61
|
errorHandler(CAPPluginCallError(message: message, code: code, error: error, data: data))
|
|
62
62
|
}
|
|
63
63
|
|
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
import Foundation
|
|
2
|
+
import WebKit
|
|
3
|
+
import UIKit
|
|
4
|
+
|
|
5
|
+
open class CAPWebView: UIView {
|
|
6
|
+
lazy var webView: WKWebView = createWebView(
|
|
7
|
+
with: configuration,
|
|
8
|
+
assetHandler: assetHandler,
|
|
9
|
+
delegationHandler: delegationHandler
|
|
10
|
+
)
|
|
11
|
+
|
|
12
|
+
private lazy var capacitorBridge = CapacitorBridge(
|
|
13
|
+
with: configuration,
|
|
14
|
+
delegate: self,
|
|
15
|
+
cordovaConfiguration: configDescriptor.cordovaConfiguration,
|
|
16
|
+
assetHandler: assetHandler,
|
|
17
|
+
delegationHandler: delegationHandler
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
public final var bridge: CAPBridgeProtocol {
|
|
21
|
+
return capacitorBridge
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
private lazy var configDescriptor = instanceDescriptor()
|
|
25
|
+
private lazy var configuration = InstanceConfiguration(with: configDescriptor, isDebug: CapacitorBridge.isDevEnvironment)
|
|
26
|
+
|
|
27
|
+
private lazy var assetHandler: WebViewAssetHandler = {
|
|
28
|
+
let handler = WebViewAssetHandler(router: router)
|
|
29
|
+
handler.setAssetPath(configuration.appLocation.path)
|
|
30
|
+
return handler
|
|
31
|
+
}()
|
|
32
|
+
|
|
33
|
+
private lazy var delegationHandler = WebViewDelegationHandler()
|
|
34
|
+
|
|
35
|
+
open var router: Router { _Router() }
|
|
36
|
+
|
|
37
|
+
public required init?(coder: NSCoder) {
|
|
38
|
+
super.init(coder: coder)
|
|
39
|
+
setup()
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
public init() {
|
|
43
|
+
super.init(frame: .zero)
|
|
44
|
+
setup()
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
private func setup() {
|
|
48
|
+
CAPLog.enableLogging = configuration.loggingEnabled
|
|
49
|
+
logWarnings(for: configDescriptor)
|
|
50
|
+
|
|
51
|
+
if configDescriptor.instanceType == .fixed { updateBinaryVersion() }
|
|
52
|
+
|
|
53
|
+
addSubview(webView)
|
|
54
|
+
webView.translatesAutoresizingMaskIntoConstraints = false
|
|
55
|
+
NSLayoutConstraint.activate([
|
|
56
|
+
webView.topAnchor.constraint(equalTo: topAnchor),
|
|
57
|
+
webView.bottomAnchor.constraint(equalTo: bottomAnchor),
|
|
58
|
+
webView.leadingAnchor.constraint(equalTo: leadingAnchor),
|
|
59
|
+
webView.trailingAnchor.constraint(equalTo: trailingAnchor)
|
|
60
|
+
])
|
|
61
|
+
|
|
62
|
+
guard FileManager.default.fileExists(atPath: bridge.config.appStartFileURL.path) else { fatalLoadError() }
|
|
63
|
+
capacitorDidLoad()
|
|
64
|
+
|
|
65
|
+
let url = bridge.config.appStartServerURL
|
|
66
|
+
CAPLog.print("⚡️ Loading app at \(url.absoluteString)")
|
|
67
|
+
capacitorBridge.webViewDelegationHandler.willLoadWebview(webView)
|
|
68
|
+
_ = webView.load(URLRequest(url: url))
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
public lazy final var isNewBinary: Bool = {
|
|
72
|
+
if let curVersionCode = Bundle.main.infoDictionary?["CFBundleVersion"] as? String,
|
|
73
|
+
let curVersionName = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String {
|
|
74
|
+
if let lastVersionCode = UserDefaults.standard.string(forKey: "lastBinaryVersionCode"),
|
|
75
|
+
let lastVersionName = UserDefaults.standard.string(forKey: "lastBinaryVersionName") {
|
|
76
|
+
return (curVersionCode.isEqual(lastVersionCode) == false || curVersionName.isEqual(lastVersionName) == false)
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
return false
|
|
80
|
+
}()
|
|
81
|
+
|
|
82
|
+
open func instanceDescriptor() -> InstanceDescriptor {
|
|
83
|
+
let descriptor = InstanceDescriptor.init()
|
|
84
|
+
if !isNewBinary && !descriptor.cordovaDeployDisabled {
|
|
85
|
+
if let persistedPath = UserDefaults.standard.string(forKey: "serverBasePath"), !persistedPath.isEmpty {
|
|
86
|
+
if let libPath = NSSearchPathForDirectoriesInDomains(.libraryDirectory, .userDomainMask, true).first {
|
|
87
|
+
descriptor.appLocation = URL(fileURLWithPath: libPath, isDirectory: true)
|
|
88
|
+
.appendingPathComponent("NoCloud")
|
|
89
|
+
.appendingPathComponent("ionic_built_snapshots")
|
|
90
|
+
.appendingPathComponent(URL(fileURLWithPath: persistedPath, isDirectory: true).lastPathComponent)
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
return descriptor
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
Allows any additional configuration to be performed. The `webView` and `bridge` properties will be set by this point.
|
|
99
|
+
|
|
100
|
+
- Note: This is called before the webview has been added to the view hierarchy. Not all operations may be possible at
|
|
101
|
+
this time.
|
|
102
|
+
*/
|
|
103
|
+
open func capacitorDidLoad() {
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
open func loadInitialContext(_ userContentController: WKUserContentController) {
|
|
107
|
+
CAPLog.print("in loadInitialContext base")
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
public func setServerBasePath(path: String) {
|
|
111
|
+
let url = URL(fileURLWithPath: path, isDirectory: true)
|
|
112
|
+
guard FileManager.default.fileExists(atPath: url.path) else { return }
|
|
113
|
+
|
|
114
|
+
capacitorBridge.config = capacitorBridge.config.updatingAppLocation(url)
|
|
115
|
+
capacitorBridge.webViewAssetHandler.setAssetPath(url.path)
|
|
116
|
+
|
|
117
|
+
DispatchQueue.main.async { [weak self] in
|
|
118
|
+
guard let self = self else { return }
|
|
119
|
+
_ = self.webView.load(URLRequest(url: self.capacitorBridge.config.serverURL))
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
extension CAPWebView {
|
|
125
|
+
|
|
126
|
+
open func webViewConfiguration(for instanceConfiguration: InstanceConfiguration) -> WKWebViewConfiguration {
|
|
127
|
+
let webViewConfiguration = WKWebViewConfiguration()
|
|
128
|
+
webViewConfiguration.allowsInlineMediaPlayback = true
|
|
129
|
+
webViewConfiguration.suppressesIncrementalRendering = false
|
|
130
|
+
webViewConfiguration.allowsAirPlayForMediaPlayback = true
|
|
131
|
+
webViewConfiguration.mediaTypesRequiringUserActionForPlayback = []
|
|
132
|
+
if let appendUserAgent = instanceConfiguration.appendedUserAgentString {
|
|
133
|
+
if let appName = webViewConfiguration.applicationNameForUserAgent {
|
|
134
|
+
webViewConfiguration.applicationNameForUserAgent = "\(appName) \(appendUserAgent)"
|
|
135
|
+
} else {
|
|
136
|
+
webViewConfiguration.applicationNameForUserAgent = appendUserAgent
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
return webViewConfiguration
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
private func createWebView(with configuration: InstanceConfiguration, assetHandler: WebViewAssetHandler, delegationHandler: WebViewDelegationHandler) -> WKWebView {
|
|
143
|
+
// set the cookie policy
|
|
144
|
+
HTTPCookieStorage.shared.cookieAcceptPolicy = HTTPCookie.AcceptPolicy.always
|
|
145
|
+
// setup the web view configuration
|
|
146
|
+
let webViewConfig = webViewConfiguration(for: configuration)
|
|
147
|
+
webViewConfig.setURLSchemeHandler(assetHandler, forURLScheme: configuration.localURL.scheme ?? InstanceDescriptorDefaults.scheme)
|
|
148
|
+
webViewConfig.userContentController = delegationHandler.contentController
|
|
149
|
+
// create the web view and set its properties
|
|
150
|
+
loadInitialContext(webViewConfig.userContentController)
|
|
151
|
+
let webView = WKWebView(frame: .zero, configuration: webViewConfig)
|
|
152
|
+
webView.scrollView.bounces = false
|
|
153
|
+
webView.scrollView.contentInsetAdjustmentBehavior = configuration.contentInsetAdjustmentBehavior
|
|
154
|
+
webView.allowsLinkPreview = configuration.allowLinkPreviews
|
|
155
|
+
webView.configuration.preferences.setValue(true, forKey: "allowFileAccessFromFileURLs")
|
|
156
|
+
webView.scrollView.isScrollEnabled = configuration.scrollingEnabled
|
|
157
|
+
|
|
158
|
+
if let overrideUserAgent = configuration.overridenUserAgentString {
|
|
159
|
+
webView.customUserAgent = overrideUserAgent
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
if let backgroundColor = configuration.backgroundColor {
|
|
163
|
+
self.backgroundColor = backgroundColor
|
|
164
|
+
webView.backgroundColor = backgroundColor
|
|
165
|
+
webView.scrollView.backgroundColor = backgroundColor
|
|
166
|
+
} else {
|
|
167
|
+
// Use the system background colors if background is not set by user
|
|
168
|
+
self.backgroundColor = UIColor.systemBackground
|
|
169
|
+
webView.backgroundColor = UIColor.systemBackground
|
|
170
|
+
webView.scrollView.backgroundColor = UIColor.systemBackground
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// set our delegates
|
|
174
|
+
webView.uiDelegate = delegationHandler
|
|
175
|
+
webView.navigationDelegate = delegationHandler
|
|
176
|
+
return webView
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
private func logWarnings(for descriptor: InstanceDescriptor) {
|
|
180
|
+
if descriptor.warnings.contains(.missingAppDir) {
|
|
181
|
+
CAPLog.print("⚡️ ERROR: Unable to find application directory at: \"\(descriptor.appLocation.absoluteString)\"!")
|
|
182
|
+
}
|
|
183
|
+
if descriptor.instanceType == .fixed {
|
|
184
|
+
if descriptor.warnings.contains(.missingFile) {
|
|
185
|
+
CAPLog.print("Unable to find capacitor.config.json, make sure it exists and run npx cap copy.")
|
|
186
|
+
}
|
|
187
|
+
if descriptor.warnings.contains(.invalidFile) {
|
|
188
|
+
CAPLog.print("Unable to parse capacitor.config.json. Make sure it's valid JSON.")
|
|
189
|
+
}
|
|
190
|
+
if descriptor.warnings.contains(.missingCordovaFile) {
|
|
191
|
+
CAPLog.print("Unable to find config.xml, make sure it exists and run npx cap copy.")
|
|
192
|
+
}
|
|
193
|
+
if descriptor.warnings.contains(.invalidCordovaFile) {
|
|
194
|
+
CAPLog.print("Unable to parse config.xml. Make sure it's valid XML.")
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
private func updateBinaryVersion() {
|
|
200
|
+
guard isNewBinary else {
|
|
201
|
+
return
|
|
202
|
+
}
|
|
203
|
+
guard let versionCode = Bundle.main.infoDictionary?["CFBundleVersion"] as? String,
|
|
204
|
+
let versionName = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String else {
|
|
205
|
+
return
|
|
206
|
+
}
|
|
207
|
+
let prefs = UserDefaults.standard
|
|
208
|
+
prefs.set(versionCode, forKey: "lastBinaryVersionCode")
|
|
209
|
+
prefs.set(versionName, forKey: "lastBinaryVersionName")
|
|
210
|
+
prefs.set("", forKey: "serverBasePath")
|
|
211
|
+
prefs.synchronize()
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
private func fatalLoadError() -> Never {
|
|
215
|
+
printLoadError()
|
|
216
|
+
exit(1)
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
private func printLoadError() {
|
|
220
|
+
let fullStartPath = capacitorBridge.config.appStartFileURL.path
|
|
221
|
+
|
|
222
|
+
CAPLog.print("⚡️ ERROR: Unable to load \(fullStartPath)")
|
|
223
|
+
CAPLog.print("⚡️ This file is the root of your web app and must exist before")
|
|
224
|
+
CAPLog.print("⚡️ Capacitor can run. Ensure you've run capacitor copy at least")
|
|
225
|
+
CAPLog.print("⚡️ or, if embedding, that this directory exists as a resource directory.")
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
extension CAPWebView: CAPBridgeDelegate {
|
|
230
|
+
internal var bridgedWebView: WKWebView? {
|
|
231
|
+
return webView
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
internal var bridgedViewController: UIViewController? {
|
|
235
|
+
// search for the parent view controller
|
|
236
|
+
var object = self.next
|
|
237
|
+
while !(object is UIViewController) && object != nil {
|
|
238
|
+
object = object?.next
|
|
239
|
+
}
|
|
240
|
+
return object as? UIViewController
|
|
241
|
+
}
|
|
242
|
+
}
|
|
@@ -125,6 +125,15 @@ public protocol JSValueContainer: JSStringContainer, JSBoolContainer, JSIntConta
|
|
|
125
125
|
}
|
|
126
126
|
|
|
127
127
|
extension JSValueContainer {
|
|
128
|
+
public func getValue(_ key: String) -> JSValue? {
|
|
129
|
+
return jsObjectRepresentation[key]
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
@available(*, message: "All values returned conform to JSValue, use getValue(_:) instead.", renamed: "getValue(_:)")
|
|
133
|
+
public func getAny(_ key: String) -> Any? {
|
|
134
|
+
return getValue(key)
|
|
135
|
+
}
|
|
136
|
+
|
|
128
137
|
public func getString(_ key: String) -> String? {
|
|
129
138
|
return jsObjectRepresentation[key] as? String
|
|
130
139
|
}
|
|
@@ -102,7 +102,12 @@ internal class WebViewDelegationHandler: NSObject, WKNavigationDelegate, WKUIDel
|
|
|
102
102
|
|
|
103
103
|
// otherwise, is this a new window or a main frame navigation but to an outside source
|
|
104
104
|
let toplevelNavigation = (navigationAction.targetFrame == nil || navigationAction.targetFrame?.isMainFrame == true)
|
|
105
|
-
|
|
105
|
+
|
|
106
|
+
// Check if the url being navigated to is configured as an application url (whether local or remote)
|
|
107
|
+
let isApplicationNavigation = navURL.absoluteString.starts(with: bridge.config.serverURL.absoluteString) ||
|
|
108
|
+
navURL.absoluteString.starts(with: bridge.config.localURL.absoluteString)
|
|
109
|
+
|
|
110
|
+
if !isApplicationNavigation, toplevelNavigation {
|
|
106
111
|
// disallow and let the system handle it
|
|
107
112
|
if UIApplication.shared.applicationState == .active {
|
|
108
113
|
UIApplication.shared.open(navURL, options: [:], completionHandler: nil)
|
|
@@ -132,6 +137,11 @@ internal class WebViewDelegationHandler: NSObject, WKNavigationDelegate, WKUIDel
|
|
|
132
137
|
webView.isOpaque = isOpaque
|
|
133
138
|
webViewLoadingState = .subsequentLoad
|
|
134
139
|
}
|
|
140
|
+
|
|
141
|
+
if let errorURL = bridge?.config.errorPathURL {
|
|
142
|
+
webView.load(URLRequest(url: errorURL))
|
|
143
|
+
}
|
|
144
|
+
|
|
135
145
|
CAPLog.print("⚡️ WebView failed to load")
|
|
136
146
|
CAPLog.print("⚡️ Error: " + error.localizedDescription)
|
|
137
147
|
}
|
|
@@ -139,6 +149,10 @@ internal class WebViewDelegationHandler: NSObject, WKNavigationDelegate, WKUIDel
|
|
|
139
149
|
// The force unwrap is part of the protocol declaration, so we should keep it.
|
|
140
150
|
// swiftlint:disable:next implicitly_unwrapped_optional
|
|
141
151
|
public func webView(_ webView: WKWebView, didFailProvisionalNavigation navigation: WKNavigation!, withError error: Error) {
|
|
152
|
+
if let errorURL = bridge?.config.errorPathURL {
|
|
153
|
+
webView.load(URLRequest(url: errorURL))
|
|
154
|
+
}
|
|
155
|
+
|
|
142
156
|
CAPLog.print("⚡️ WebView failed provisional navigation")
|
|
143
157
|
CAPLog.print("⚡️ Error: " + error.localizedDescription)
|
|
144
158
|
}
|
|
@@ -384,10 +384,18 @@ const nativeBridge = (function (exports) {
|
|
|
384
384
|
}
|
|
385
385
|
return null;
|
|
386
386
|
};
|
|
387
|
+
if (win === null || win === void 0 ? void 0 : win.androidBridge) {
|
|
388
|
+
win.androidBridge.onmessage = function (event) {
|
|
389
|
+
returnResult(JSON.parse(event.data));
|
|
390
|
+
};
|
|
391
|
+
}
|
|
387
392
|
/**
|
|
388
393
|
* Process a response from the native layer.
|
|
389
394
|
*/
|
|
390
395
|
cap.fromNative = result => {
|
|
396
|
+
returnResult(result);
|
|
397
|
+
};
|
|
398
|
+
const returnResult = (result) => {
|
|
391
399
|
var _a, _b;
|
|
392
400
|
if (cap.isLoggingEnabled && result.pluginId !== 'Console') {
|
|
393
401
|
cap.logFromNative(result);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@capacitor/ios",
|
|
3
|
-
"version": "4.0.0
|
|
3
|
+
"version": "4.0.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)",
|
|
@@ -24,10 +24,10 @@
|
|
|
24
24
|
"xc:build:CapacitorCordova": "cd CapacitorCordova && xcodebuild && cd .."
|
|
25
25
|
},
|
|
26
26
|
"peerDependencies": {
|
|
27
|
-
"@capacitor/core": "
|
|
27
|
+
"@capacitor/core": "next"
|
|
28
28
|
},
|
|
29
29
|
"publishConfig": {
|
|
30
30
|
"access": "public"
|
|
31
31
|
},
|
|
32
|
-
"gitHead": "
|
|
32
|
+
"gitHead": "434b1a0ff32f513973ef35258032a4df0cb331c1"
|
|
33
33
|
}
|