update with message handler string

This commit is contained in:
Xinlei(Ryan) Pan 2020-04-01 17:16:23 -04:00
parent bfe706908f
commit 83e04f0a12
2 changed files with 32 additions and 42 deletions

View File

@ -27,25 +27,19 @@ import WebKit
override open func setupView() { override open func setupView() {
super.setupView() super.setupView()
let webView = createWebView(messageHandler: mvmWebViewMessageHandler, jsScript: nil) let webView = createWebView(messageHandler: mvmWebViewMessageHandler)
addSubview(webView) addSubview(webView)
NSLayoutConstraint.constraintPinSubview(toSuperview: webView) NSLayoutConstraint.constraintPinSubview(toSuperview: webView)
self.webView = webView self.webView = webView
pinSpinnerView() pinSpinnerView()
} }
func createWebView(messageHandler: String?, jsScript:String?) -> WKWebView { func createWebView(messageHandler: String?) -> WKWebView {
let wkUserController = WKUserContentController() let wkUserController = WKUserContentController()
if let messageHandlerName = messageHandler { if let messageHandlerName = messageHandler {
wkUserController.add(self, name: messageHandlerName) wkUserController.add(self, name: messageHandlerName)
} }
//server driven addition script
if let jsScript = jsScript {
let wkScript = WKUserScript(source: jsScript, injectionTime: .atDocumentStart, forMainFrameOnly: true)
wkUserController.addUserScript(wkScript)
}
let wkConfig = WKWebViewConfiguration() let wkConfig = WKWebViewConfiguration()
wkConfig.userContentController = wkUserController wkConfig.userContentController = wkUserController
let webView = WKWebView(frame: .zero, configuration: wkConfig) let webView = WKWebView(frame: .zero, configuration: wkConfig)
@ -59,33 +53,29 @@ import WebKit
// MARK: - MVMCoreUIMoleculeViewProtocol // MARK: - MVMCoreUIMoleculeViewProtocol
override open func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable : Any]?) { override open func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable : Any]?) {
super.set(with: model, delegateObject, additionalData) super.set(with: model, delegateObject, additionalData)
guard let model = model as? WebViewModel else { return }
self.delegateObject = delegateObject self.delegateObject = delegateObject
if model.callHandler != nil || model.jsScript != nil {
/*
webView's configuration property is immutable.
In order to add call handler into webview, need to create a new webview.
*/
webView?.removeFromSuperview()
let webView = createWebView(messageHandler: model.callHandler, jsScript:model.jsScript)
addSubview(webView)
NSLayoutConstraint.constraintPinSubview(toSuperview: webView)
self.webView = webView
}
//init height for loading spinner //init height for loading spinner
webViewHeight = webView?.heightAnchor.constraint(equalToConstant: 50) webViewHeight = webView?.heightAnchor.constraint(equalToConstant: 44)
webViewHeight?.isActive = true webViewHeight?.isActive = true
if let height = model.height { if let height = webviewModel?.height {
webViewHeight?.constant = height webViewHeight?.constant = height
dynamicHeight = false dynamicHeight = false
} }
if let url = model.url { if let url = webviewModel?.url {
webView?.load(URLRequest(url: url)) webView?.load(URLRequest(url: url))
} else if let htmlString = model.htmlString { } else if let htmlString = webviewModel?.htmlString {
webView?.loadHTMLString(htmlString, baseURL: nil) webView?.loadHTMLString(htmlString, baseURL: nil)
} }
if let borderColor = webviewModel?.borderColor?.cgColor {
webView?.layer.borderWidth = 1.0
webView?.layer.borderColor = borderColor
} else {
webView?.layer.borderWidth = 0.0
webView?.layer.borderColor = UIColor.clear.cgColor
}
bringSubviewToFront(loadingSpinner) bringSubviewToFront(loadingSpinner)
} }
@ -95,8 +85,8 @@ import WebKit
loadingSpinner.clipsToBounds = true loadingSpinner.clipsToBounds = true
loadingSpinner.translatesAutoresizingMaskIntoConstraints = false loadingSpinner.translatesAutoresizingMaskIntoConstraints = false
loadingSpinner.heightAnchor.constraint(equalToConstant: 50.0).isActive = true loadingSpinner.heightAnchor.constraint(equalToConstant: 44.0).isActive = true
loadingSpinner.widthAnchor.constraint(equalToConstant: 50.0).isActive = true loadingSpinner.widthAnchor.constraint(equalToConstant: 44.0).isActive = true
loadingSpinner.centerXAnchor.constraint(equalTo: centerXAnchor).isActive = true loadingSpinner.centerXAnchor.constraint(equalTo: centerXAnchor).isActive = true
loadingSpinner.centerYAnchor.constraint(equalTo: centerYAnchor).isActive = true loadingSpinner.centerYAnchor.constraint(equalTo: centerYAnchor).isActive = true
loadingSpinner.resumeSpinner() loadingSpinner.resumeSpinner()
@ -114,7 +104,6 @@ extension WebView : WKUIDelegate {
if !dynamicHeight { if !dynamicHeight {
return return
} }
/* was using "document.readyState" to check the state, while evaluateJavaScript "document.readyState",only works when webview contains userscrpt.otherwise, it would return WKErrorDomain Code=4 "A JavaScript exception occurred". /* was using "document.readyState" to check the state, while evaluateJavaScript "document.readyState",only works when webview contains userscrpt.otherwise, it would return WKErrorDomain Code=4 "A JavaScript exception occurred".
so webView.isLoading to check load finished state so webView.isLoading to check load finished state
*/ */
@ -157,14 +146,20 @@ extension WebView : WKNavigationDelegate {
// MARK: - WKScriptMessageHandler // MARK: - WKScriptMessageHandler
extension WebView: WKScriptMessageHandler { extension WebView: WKScriptMessageHandler {
public func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) { public func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
if message.name == mvmWebViewMessageHandler, let actionMap = message.body as? [AnyHashable: Any] { if message.name == mvmWebViewMessageHandler, let text = message.body as? String {
/* /*
receiving JavaScript func webkit.messageHandlers.{callHandler}.postMessage(body); receiving JavaScript func webkit.messageHandlers.{callHandler}.postMessage(body);
if body is dictionary if body is string, will decode to actionmodel.
MVMCoreActionHanlder handleAction use legacy MVMCoreActionHanlder handleAction method for now
*/ */
MVMCoreActionHandler.shared()?.handleAction(with: actionMap, additionalData: nil, delegateObject: self.delegateObject) if let data = text.data(using: .utf8) {
do {
let actionMap = try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any]
MVMCoreActionHandler.shared()?.handleAction(with: actionMap, additionalData: nil, delegateObject: self.delegateObject)
} catch {
//actionModel should report error when actionhandler is finshed with actionmodel
}
}
} }
} }
} }

View File

@ -15,8 +15,7 @@ import Foundation
public var url: URL? public var url: URL?
public var htmlString: String? public var htmlString: String?
public var height: CGFloat? public var height: CGFloat?
public var jsScript: String? public var borderColor: Color?
public var callHandler: String?
public var buttonMap: [String: ButtonModel]? public var buttonMap: [String: ButtonModel]?
private enum CodingKeys: String, CodingKey{ private enum CodingKeys: String, CodingKey{
@ -26,8 +25,7 @@ import Foundation
case htmlString case htmlString
case height case height
case buttonMap case buttonMap
case jsScript case borderColor
case callHandler
} }
required public init(from decoder: Decoder) throws { required public init(from decoder: Decoder) throws {
@ -37,8 +35,7 @@ import Foundation
htmlString = try typeContainer.decodeIfPresent(String.self, forKey: .htmlString) htmlString = try typeContainer.decodeIfPresent(String.self, forKey: .htmlString)
height = try typeContainer.decodeIfPresent(CGFloat.self, forKey: .height) height = try typeContainer.decodeIfPresent(CGFloat.self, forKey: .height)
buttonMap = try typeContainer.decodeIfPresent([String: ButtonModel].self, forKey: .buttonMap) buttonMap = try typeContainer.decodeIfPresent([String: ButtonModel].self, forKey: .buttonMap)
jsScript = try typeContainer.decodeIfPresent(String.self, forKey: .jsScript) borderColor = try typeContainer.decodeIfPresent(Color.self, forKey: .borderColor)
callHandler = try typeContainer.decodeIfPresent(String.self, forKey: .callHandler)
} }
public func encode(to encoder: Encoder) throws { public func encode(to encoder: Encoder) throws {
@ -48,8 +45,6 @@ import Foundation
try container.encodeIfPresent(url, forKey: .url) try container.encodeIfPresent(url, forKey: .url)
try container.encodeIfPresent(htmlString, forKey: .htmlString) try container.encodeIfPresent(htmlString, forKey: .htmlString)
try container.encodeIfPresent(height, forKey: .height) try container.encodeIfPresent(height, forKey: .height)
try container.encodeIfPresent(jsScript, forKey: .jsScript) try container.encodeIfPresent(borderColor, forKey: .borderColor)
try container.encodeIfPresent(callHandler, forKey: .callHandler)
} }
} }