1. 创建WKWebView
let configuration = WKWebViewConfiguration.init()
configuration.selectionGranularity = WKSelectionGranularity.dynamic
//允许播放视频
configuration.allowsInlineMediaPlayback = true
let preferrnce = WKPreferences.init();
//设置是否支持javaScript
preferrnce.javaScriptEnabled = true
//不用通过交互是否可以打开窗口
preferrnce.javaScriptCanOpenWindowsAutomatically = true
configuration.preferences = preferrnce
// 通过JS与webview内容交互
configuration.userContentController = WKUserContentController()
let wkWebview = WKWebView.init(frame: frame, configuration: configuration)
wkWebview.navigationDelegate = self
wkWebview.uiDelegate = self
wkWebview.allowsBackForwardNavigationGestures = true //二级网页是否可以左划返回
2 IOS调用H5
- 我们可以通过以下方法来调用H5的方法,已获取H5标题为例:
//1.需要发送一个js命令获取网页的标题
webView.evaluateJavaScript("document.title") { (data, error) in
}
- IOS调用vue中的方法,那么在vue中,只需要将方法绑定到window中即可,ios就能够调用到
//vue中需要注册的方法
created(){
//供iso调用前需要绑定到window上
window.AppToHTMLUserInfo = this.AppToHTMLUserInfo;
},
//OC中调用
let methodName = "AppToHTMLUserInfo(\(lgoniInfoString()))"
wkWebView!.evaluateJavaScript(methodName) { (data, error) in
print("data=====\(data) error=========\(error)")
}
- 如何实现实时的获取H5的标题,并且显示在导航栏:
- 首先我们知道
WKWebView
有一个属性title
(支持KVO),这个属性值就是当前H5页面的标题 - 当我们发送指令获取H5标题的时候,
WKWebView
会把H5的标题获取并赋值给这个title
属性 - 想要实时获取H5标题,只需使用KVO监听title舒心即可
- 首先我们知道
//2.需要使用webview来监听标题的实时改变
wkWebView.addObserver(self, forKeyPath: "title", options: NSKeyValueObservingOptions.new, context: nil)
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
if keyPath == "title" {
if (object as! WKWebView) == wkWebView {
titlelable.text = wkWebView.title
}
} else {
super.observeValue(forKeyPath: keyPath, of: object, change: change, context: context)
}
}
3. H5调用原生
3.1 通过连接
H5和app端可以置顶一种连接的形式,当app打开网页时 在delegate方法中截取连接,判断是否是定好的链接,然后再解析,并调用原生方法:
func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
print("在发送请求之前,决定是否跳转=====\(navigationAction.request.url)")
do {
let url = try String.init(contentsOf: navigationAction.request.url!)
if url.starts(with: "xiangzhengapp") {
//表示需要调用方法
print("取消访问这个地址====")
decisionHandler(WKNavigationActionPolicy.cancel)
}
} catch {
print("webView--error=======\(error)")
}
//表示允许
decisionHandler(WKNavigationActionPolicy.allow)
}
3.2 通过方法
- 通过调用非方法格式如下:
// JS调OC,需要 H5端统一如下写法,方法名就是交互的名称,数据就是JS给OC传的值
window.webkit.messageHandlers.<方法名>.postMessage(<数据>)
- 首先我们需要再app单注册和H5定义好的方法名称
- 注册方法
configuration.userContentController.add()
,在不适用之后需要移出,不然会形成循环引用
// 通过JS与webview内容交互
configuration.userContentController = WKUserContentController()
//注册js接ios中公用方法名称
configuration.userContentController.add(self, name: openAppMenu)
configuration.userContentController.add(self, name: openAppLogin)
configuration.userContentController.add(self, name: openAppPay)
//configuration.userContentController.removeAllScriptMessageHandlers()- 移出所有注册方法
//configuration.userContentController.removeScriptMessageHandler(forName: openAppMenu)-移出单个方法
- 实现WKScriptMessageHandler协议,通过代理方法接收,并解析
func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
//print("name========\(message.name)")
//print("body=======\(message.body)")
/**
1.JS传值首先需要约定,然后注册 调用的方法名称: ->configuration.userContentController.add(self, name: openAppMenu)
2.如果交互 ,没有任何参数的情况, JS传递必须传递一个null,如果不传递任何参数, IOS这边回调方法不会执行
3. 传递参数智能是一个, 多个参数,也只会读取第一个参数,建议使用集合来传递参数
*/
if message.name == openAppMenu {
let cp_id = message.body as! Int
let detaileVC = GYLP_Utils.getControllerToStroyBoard("HomeMian", "home_ZNCPDetail") as! GYZNCP_DetailViewController
detaileVC.currentCP_ID = cp_id
GYLP_Utils.getCurrentController().navigationController?.pushViewController(detaileVC, animated: true)
} else if message.name == openAppLogin {
//登录
let loginVC = GYLP_Utils.getControllerToStroyBoard("Main", "login")
GYLP_Utils.getCurrentController().navigationController?.pushViewController(loginVC, animated: true)
} else if message.name == openAppPay {
//支付
let order_id = (message.body as! String).components(separatedBy: ",").first!
let payType = Int((message.body as! String).components(separatedBy: ",").last!)!
if payType == 0 {
AlipaySDK.defaultService()?.payOrder(order_id, fromScheme: "zhongxiang", callback: { (resultDic) in
print("orderPay========\(resultDic)")
})
} else {
//代表微信
}
}
}
3.3 在网页加载之前,传递值给H5
- app需要写的代码:
let param = ["uid":GYUserInfo.user_uid()!, "token":GYUserInfo.user_token()!]
let data = try? JSONSerialization.data(withJSONObject: param, options: JSONSerialization.WritingOptions.prettyPrinted)
let jsonString = String.init(data: data!, encoding: String.Encoding.utf8)
let js = "userInfo = \(jsonString!)"
let script = WKUserScript.init(source: js, injectionTime: WKUserScriptInjectionTime.atDocumentStart, forMainFrameOnly: true)
configuration.userContentController.addUserScript(script)
- H5 接收
mounted(){
let iOSInfo = JSON.parse(JSON.stringify(window.iOSInfo));
// iOSInfo. username iOSInfo. token iOSInfo.avatar
}