前言
WebView:由于引入WebKit即成为"应用里的浏览器",可以支持对网页解析,支持浏览器加载网页
JS(JavaScript):开发Web页面的脚本语言,是前端的语言
WebView和h5前端页面之间需要存在一种通讯机制来使WebView上的h5可以使用应用的原生能力,即产生JSBridge
JSBridge :Native代码与JS代码的通信桥梁,JS 代码调用”桥“的机制来使用原生的能力,而原生代码通过“桥”来给JS代码发事件
JS桥的使用
JavaScript调用Native的方式
-
注入API
对于UIWebView
import Foundation
import Foundation
import UIKit
import WebKit
import JavaScriptCore
//如果一个协议遵守了JSExport,那么该协议的方法会对JS开放,允许JS直接调用该方法
protocol JSDelegate:JSExport{
//原生方法定义
func checkExecuteJSBridge(str:NSString)
}
class JSModel:NSObject,JSDelegate{
var jsContext:JSContext!
weak var controller: UIWebViewController?
//对应的某原生方法
func checkExecuteJSBridge(str:NSString){
//TODO
print(str)
}
}
class UIWebViewController: UIViewController,UIWebViewDelegate{
var webView: UIWebView!
var jscontext: JSContext{
var context: JSContext
//向 JavaScript 的 Context(window)中注入对象或者方法(self.jscontext),获取JS代码的执行环境/上下文/作用域
context = webView.value(forKeyPath: "documentView.webView.mainFrame.javaScriptContext") as! JSContext
return context
}
override func loadView() {
webView = UIWebView(frame: .zero)
webView.delegate = self
view = webView
}
override func viewDidLoad() {
super.viewDidLoad()
let myURL = URL(string: "https://www.baidu.com")
let myRequest = URLRequest(url: myURL!)
webView.loadRequest(myRequest)
}
func webViewDidFinishLoad(_ webView: UIWebView) {
let model = JSModel()
model.controller = self
model.jsContext = self.jscontext
//在context注册JSDelegate对象,使JS可以通过UIWebViewBridge方法来调用原生的方法checkExecuteJSBridge
self.jscontext.setValue(model, forKey: "UIWebViewBridge")
}
}
前端通过JS桥调用Native功能
if(window.UIWebViewBridge)return window.UIWebViewBridge(e)
对于WKWebView
import Foundation
import UIKit
import WebKit
import JavaScriptCore
class WKWebViewController: UIViewController, WKUIDelegate,WKNavigationDelegate, WKScriptMessageHandler{
//监听JS调用原生方法的代理方法
func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
//JS如果调用了WKWebViewBridge方法,执行对应的原生操作
if message.name == "WKWebViewBridge" {
self.checkExecuteJSBridge(str: message.body as! NSString)
}
}
var jscontext: JSContext!
var webView: WKWebView!
override func loadView() {
//网页配置类
let webConfiguration = WKWebViewConfiguration()
//WKUserContentController控制JS与原生的交互,是向js方法注入和移除注入方法的类
let usercontentController = WKUserContentController()
//向JS注入了WKWebViewBridge方法
usercontentController.add(self, name: "WKWebViewBridge")
webConfiguration.userContentController = usercontentController
webView = WKWebView(frame: .zero, configuration: webConfiguration)
webView.uiDelegate = self
webView.navigationDelegate = self
webView.allowsBackForwardNavigationGestures = true
view = webView
}
override func viewDidLoad() {
super.viewDidLoad()
let myURL = URL(string: "https://www.baidu.com")
let myRequest = URLRequest(url: myURL!)
webView.load(myRequest)
}
//原生方法
func checkExecuteJSBridge(str:NSString){
// TODO
print(str)
}
}
前端通过JS桥调用Native功能
if(window.webkit&&window.webkit.messageHandlers&&window.webkit.messageHandlers.WKWebViewBridge)
return window.webkit.messageHandlers.WKWebViewBridge.postMessage({str}),f
-
拦截URL SCHEME
URL SCHEME:类似于url的链接,是为了方便app直接互相调用设计的,形式和普通的 url 近似,主要区别是 protocol 和 host 一般是自定义的
对于UIWebView
//webView准备加载前的一个代理方法
func webView(_ webView: UIWebView, shouldStartLoadWith request: URLRequest, navigationType: UIWebView.NavigationType) -> Bool {
var requestString = request.url?.absoluteString
if((requestString?.hasPrefix("special")) != nil){
//JS以前缀为“special”的特殊URL加载来调用原生的对应方法
//TODO
//停止正常http网络协议加载URL
return false
}
//正常以http网络协议加载URL
return true
}
对于WKWebView
func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
var requestString = navigationAction.request.url?.absoluteString
if((requestString?.hasPrefix("special")) != nil){
//JS以前缀为“special”的特殊URL加载来调用原生的对应方法
//TODO
//停止正常http网络协议加载URL
decisionHandler(.cancel)
}
//正常以http网络协议加载URL
decisionHandler(.allow)
}
Native 调用 JavaScript 的方式
Native 调用 JavaScript 较为简单,直接执行拼接好的 JavaScript 代码即可
对于UIWebVIew
//这里的JavaScript 代码 是”refresh“
self.webView.evaluateJavaScript("refresh", completionHandler: nil)
对于WKWebView
//这里的JavaScript 代码 是”refresh“
self.webView.stringByEvaluatingJavaScript(from: "refresh")