当前环境: Xcode10.0 Swift4.2 iOS SDK 12.1
下面是原理实现代码,可以查看参考文章 + Demo 查看。 Demo: https://github.com/zColdWater/wkwebviewdemo
前提掌握
背景概述: 随着 App 端 H5 的应用越来越多,H5 同学会遇到与 Native 同学一样的 Native 需求,那么这个时候就需要 Native 同学 与 H5 同学能进行 通信了,那么为基于 iOS 的 WKWebView 该如何找到正确通信方式呢?
在这里我们参考 DSBridge-IOS,当然如果你已经看过这个库的源码,那么此篇文章可以跳过了。我这里会根据DSBridge
的源码介绍下它的JSBridge
的实践
关于 WKWebView 一些必要的方法使用可以点击这里
了解 JavaScript ===[调用]
===> Native
如何实现 Javascript
调用 Native
呢? 其实 Apple 已经提供了这个通道 ,这个通道就是 WKUIDelegate
,如果还不清楚可以点击这里查看
这里我们只提 WKUIDelegate
中的其中的一个方法,至于为什么选用这个回调方法,原因是因为 这个通道 可以让 Javascript
传递二个参数,并且还能得到一个同步的返回值。
// Javascript 调用 prompt 方法 会触发 这个代理方法
// 例如: var result = prompt("AA", "BB")
func webView(_ webView: WKWebView, runJavaScriptTextInputPanelWithPrompt prompt: String, defaultText: String?, initiatedByFrame frame: WKFrameInfo, completionHandler: @escaping (String?) -> Void) {
// 参数1
var param1 = prompt //"AA"
// 参数2
var param2 = defaultText // "BB"
// 回调 result
completionHandler("同步返回值 给Javascript")
}
了解 Native ===[调用]
===> JavaScript
如何实现 Native
调用 Javascript
的方法呢,Apple 同样也给我们提供了通道, 这个通道就是 evaluateJavaScript
方法,如果你还不了解,如果还不清楚可以点击这里查看
我们事先准备好 JS 方法 nativeMessageHandler
然后在代码中 找到一个时机, 调用即可 触发 Javascript方法
。
function nativeMessageHandler(method,param) {
// 'action1','param1'
console.log(method,param)
}
// Native 代码
// 注意: 此方法 只有在整个WebView都加载完成 才会有反应。
webview.evaluateJavaScript("nativeMessageHandler('action1', 'param1')", completionHandler: { (feedback, error) in
})
了解 DSBridge-IOS 原理
下面是纯干货了,至于为什么我们研究 DSBridge-IOS
这个库,是因为它能够满足我们开发的大部分场景,是基于 WKWebView
实现 JSBridge
的比较好的实现,那么我们就看看它的工作原理是什么,这样也有助于我们使用这种库。
我们只会针对其中的两种方法进行研究其原理 ,如果你没使用过可以去看下再回来可能会更好。DSBridge-IOS
下面是 DSBridge
与 Native
交互的两种方式: 一种是 JS
调用 Native
方法,另一种是 Native
调用 JS
方法
1. 同步调用 使用DSBridge第三方
如下:
// 同步 调用
function callSyn() {
Void) {
}
然后这个协议回调方法里面,通过 JS
给 Native
的类名,方法名,通过 OC 的 Runtime 去动态的调用此方法,得到返回值,并且返回给回调函数 completionHandler
实现 Native
返回值给 JS
方法。 ">
// 对应原生方法名: `testSyn`
// 参数: `Hello`
// 类型: 同步调用
dsBridge.call("testSyn", "Hello")
}
```
**实现原理**: 在`DSBridge`里面是通过[`WKUIDelegate`](https://zcoldwater.github.io/blog/article/ios/wkwebview/)去实现同步调用的,JS会通过调用`prompt`方法,唤起`Native`层的`WKUIDelegate`代理协议中的下面的方法
```Swift
func webView(_ webView: WKWebView, runJavaScriptTextInputPanelWithPrompt prompt: String, defaultText: String?, initiatedByFrame frame: WKFrameInfo, completionHandler: @escaping (String?) -> Void) {
}
```
然后这个协议回调方法里面,通过`JS`给`Native`的类名,方法名,通过OC的Runtime去动态的调用此方法,得到返回值,并且返回给回调函数`completionHandler` 实现`Native`返回值给`JS`方法。
2. 异步调用 使用DSBridge第三方
如下:
// 异步 调用
function callAsyn() {
Void) {
}
然后在拿到 WKUIDelegate
的回调后,Native
还会通过传来类名,方法名,根据 OC Runtime 去动态调用方法,然后拿到同步返回值,给 completionHandler
方法调用,返回给 JS,当通过 Runtime 动态调用到 Native
方法内的时候,我们触发回调参数,来回调给 JS
,这步就需要方法 evaluateJavaScript
来实现,因为当初我们挂在整个 JS
下有一个回调函数,并且起了名,现在就需要回调给写调用 JS
这个全局的回调,并且把结果告知给它。 ">
// 对应原生方法名: `testAsyn`
// 参数: `hello`
// 类型: 异步调用
dsBridge.call("testAsyn","hello", function (value) {
// 得到原生回调 参数。
console.log(value)
})
}
```
**实现原理**: 在`DSBridge`里面是通过[`WKUIDelegate`](https://zcoldwater.github.io/blog/article/ios/wkwebview/)和`evaluateJavaScript`方法来实现的`JS`调用`Native`然后`Native`回调给`JS`的。
首先,`JS`方法调用`Native`附加回调参数,`JS`会把这个回调函数注册在`JS`全局下,比如说,挂在全局叫`BlockA`,然后继续通过调用`prompt`方法触发`WKUIDelegate`协议回调,方法在下面。
```Swift
func webView(_ webView: WKWebView, runJavaScriptTextInputPanelWithPrompt prompt: String, defaultText: String?, initiatedByFrame frame: WKFrameInfo, completionHandler: @escaping (String?) -> Void) {
}
```
然后在拿到`WKUIDelegate`的回调后,`Native`还会通过传来类名,方法名,根据OC Runtime去动态调用方法,然后拿到同步返回值,给`completionHandler`方法调用,返回给JS,当通过Runtime动态调用到`Native`方法内的时候,我们触发回调参数,来回调给`JS`,这步就需要方法`evaluateJavaScript`来实现,因为当初我们挂在整个`JS`下有一个回调函数,并且起了名,现在就需要回调给写调用`JS`这个全局的回调,并且把结果告知给它。
总结
上面我们分析了实现方式,无非都是用系统提供的与 JS 的通信能力,再来借助一下动态运行时来完成,虽然外表看起来神秘,但是经过源码阅读后,会发现其实还是很简单的。 以上全部是原作,如有建议和提议,不妨在下面留言,希望能对一些朋友有所帮助。