WKWebView和JS交互(事件响应、参数传递)
2017-10-11 本文已影响450人
c338388782c3
1、效果图
native&web.gifDemo说明
- 点击网页的 弹框 按钮,触发js事件,Native通过web的代理方法响应
- 点击 分享 按钮,触发js事件,Native通过指定的handler类响应
- 点击 支付 按钮,触发js事件,Native通过制定的handler类响应,并获取参数
- 点击 ToWeb 按钮,触发Native事件,传递数组参数[1,2,3,4,5]给web,并显示在Input标签中
2、WKWebview的介绍
3、Native响应JS事件
第一部分的1,2,3均属于这一范畴
初始化WKWebview
fileprivate lazy var web: WKWebView = {[unowned self] in
let w = WKWebView(frame: CGRect.init(x: 0, y: 0, width: screenWidth, height: screenHeight))
w.uiDelegate = self
w.navigationDelegate = self
//取web默认的配置选项
let configuration = w.configuration
//指定处理js事件的对象,该对象必须遵守WKScriptMessageHandler协议
let hander = ScriptMessageHandler()
hander.delegate = self
configuration.userContentController.add(hander, name: Mobile)
return w
}()
deinit {
//清除handler,保证释放
web.configuration.userContentController.removeScriptMessageHandler(forName: Mobile)
}
handler对象(使用handle对象的目的是避免循环引用)
class ScriptMessageHandler: NSObject {
//设置代理,把捕获到的js事件转发给代理处理
weak var delegate: WKScriptMessageHandler?
}
extension ScriptMessageHandler: WKScriptMessageHandler {
func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
//代理响应捕获到的事件
if let target = delegate{
target.userContentController(userContentController, didReceive: message)
}
}
}
web点击弹框触发的方法+web代理WKUIDelegate的响应
//js事件
function presentAlert() {
alert("I am alert");
}
//native事件,message参数的值是js中的"I am alert"
func webView(_ webView: WKWebView, runJavaScriptAlertPanelWithMessage message: String, initiatedByFrame frame: WKFrameInfo, completionHandler: @escaping () -> Void) {
showAlert(title: "Alert框", message: message)
completionHandler()
}
web点击分享、支付触发的方法+handler响应+hander代理响应
//1. js事件
function share() {
//这里可以传任何类型
var param = {
message: "share",
};
window.webkit.messageHandlers.Mobile.postMessage(param);
}
function pay() {
//这里可以传任何类型
var param = {
message: "pay",
param:888888
};
window.webkit.messageHandlers.Mobile.postMessage(param);
}
//2. Native,handler响应
func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
//代理响应捕获到的事件
if let target = delegate{
target.userContentController(userContentController, didReceive: message)
}
}
//3.Native,handler的代理响应
func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
guard message.name == Mobile else {
print("不是绑定的响应对象")
return
}
let dic = message.body as! Dictionary<String, Any>
let title = dic["message"] as! String
let message = dic["param"]
showAlert(title: title, message: "\(message ?? "no Parameter")")
}
总结一下:
- 网页触发js事件,js中使用window.webkit.messageHandlers.Mobile.postMessage(param),传递一个任意类型的参数
- Native的handler接收到参数,解析参数。根据与前端协商好的方法名,决定事件处理
4、Native调用JS事件
第一部分的4属于这一范畴
初始化WKWebview
fileprivate lazy var web: WKWebView = {[unowned self] in
let w = WKWebView(frame: CGRect.init(x: 0, y: 0, width: screenWidth, height: screenHeight))
w.uiDelegate = self
w.navigationDelegate = self
//取web默认的配置选项
let configuration = w.configuration
let param = [1,2,3,4,5]
//向网页注入一个用户脚本,点击rightIten时响应
let script = WKUserScript(source: "function callJavaScript() {passAnArray(\(param));}", injectionTime: .atDocumentEnd, forMainFrameOnly: true)
configuration.userContentController.addUserScript(script)
return w
}()
deinit {
//清除所有注入的脚本
web.configuration.userContentController.removeAllUserScripts()
}
点击导航栏的右侧按钮时,执行js方法,让网页中的js响应
//传递一个数组给web
@objc func rightClick(item: UIBarButtonItem) -> Void {
//调用的JS方法,执行(注入脚本时,已指定该方法)
let js = "callJavaScript()";
//闭包处理js不通过的问题,并不是js代码的回调
web.evaluateJavaScript(js) { (object, error) in
}
}
总结一下:
- 先在Native的web配置中添加一个用户脚本,这个脚本会注入到网页中(脚本中要运行的函数名,参数,需要和前端商量好)
- 在Native中执行js代码,运行注入的脚本
总结
完整的代码在Demo里,三个文件
- 包含WKWebview的控制器
- 事件处理的handler
- 一个本地的html文件
交互和传参不难,但是我理解时花了不少时间,总结了一下花时间的原因:
- 不会前端,想到js响应事件就头疼
- WKWebview引入了很多新的类,如WKUserScript,理解这些类的功能需要借助一点前端的知识
- 大神们的博客没Demo参照的不直观。