前言
当下,移动端 APP 嵌套 HTML5 网页已成常态,我们除了简单地用 WebView 加载显示之外,很多情况下,我们还需要和 WebView 进行交互,比如点击 WebView 上面的按钮调用 OC 端的函数实现具体的操作……
iOS 开发中,H5 和原生交互有多种方式, JSBridge 就是最常用的一种,各 JSBridge 类库的实现原理大同小异…今天呢,介绍一下盛名已久的 WebViewJavascriptBridge ,它主要帮助我们优雅地实现 OC 与 JS 的交互,非常方便简洁。
目录结构
- WebViewJavascriptBridge_JS
JS 端用来收发消息的类,纯 JS 代码。其做为 html 的 bridge,负责(主动)对原生界面发送消息,整理并(被动的向原生界面)传输数据,并向 html 发送回调信息;
- WebViewJavascriptBridge
桥接的入口,针对不同类型的 webView(UIWebView,WKWebView,WebView)进行分发;
针对 UIWebView 和 WebView 做的一层封装,主要用来执行 JS 代码,以及实现 UIWebView 和 WebView的代理方法,并通过拦截 URL 来通知 WebViewJavascriptBridgeBase 做相应操作
- WKWebViewJavascriptBridge
针对 WKWebView 做的一层封装,主要用来执行 JS 代码,以及实现 WKWebView 的代理方法,并通过拦截 URL 来通知 WebViewJavascriptBridgeBase 做相应操作
- WebViewJavascriptBridgeBase
用来进行 bridge 初始化和消息处理的核心类;
这个类是在支持 WKWebView 后从 WebViewJavascriptBridge 中独立出来的逻辑,专门用来处理 bridge 相关的逻辑,不再与具体的 Web View 相关联了
理一下它们的关系
WebViewJavascriptBridge_JS 可以看成是 html 文件中 JS 代码的 bridge,主要服务于 html 中的 JS 方法功能的;另外的三个 WebViewJavascriptBridge, WKWebViewJavascriptBridge, WebViewJavascriptBridgeBase 是 webView 的 bridge,主要服务于原生的。这两个 bridge 之间主要通过 webView 的代理方法webView:decidePolicyForNavigationAction:decisionHandler: 和 stringByEvaluatingJavaScriptFromString: 方法进行消息的传递和数据的传输。
众所周知,WKWebView 和 UIWebView 的性能差异很大。WKWebView 比 UIWebView 加载网页的速度更快,效率更高,内存消耗小,所以现在在开发中我都是选择使用 WKWebView。
并且,在当前时间节点,大多数 iOS App 都是基于 iOS 8.0+ 的,这是一个 WKWebView 的时代。
使用步骤
1、导入 WebViewJavaScriptBridge 框架:
pod ‘WebViewJavascriptBridge’
2、创建 WKWebView 和 WKWebViewJavascriptBridge 示例:
#import
@interface H5WebViewController ()
@property (strong, nonatomic) WKWebView *webView;
@property WKWebViewJavascriptBridge *bridge;
@end
- (void)viewDidLoad {
[super viewDidLoad];
[self setUpWebView];
[self setUpWebViewJavascriptBridge];
}
- (void)setUpWebView {
self.wkWebView = [[WKWebView alloc] initWithFrame:self.view.bounds];
self.wkWebView.navigationDelegate = self;
self.wkWebView.UIDelegate = self;
[self.view addSubview:self.wkWebView];
}
/**
* 使用 WebViewJavascriptBridge 实现 OC 与 JS 交互
*/
- (void)setUpWebViewJavascriptBridge {
if (_bridge) {
return;
}
// 设置能够进行桥接
[WebViewJavascriptBridge enableLogging];
// 初始化 WebViewJavascriptBridge 实例, 设置代理, 进行桥接
_bridge = [WebViewJavascriptBridge bridgeForWebView:self.webView];
[_bridge setWebViewDelegate:self];
__weak __typeof(self)weakSelf = self;
/**
JS 调用 OC ,设置导航条 title
@param data 后台 JS 页面传过来的参数
@param registerHandler 要注册的事件名称(这里我们为 locationAlertViewWithMessage)
@param handler 回调 block 函数 当后台触发这个事件的时候会执行 block 里面的代码
*/
[_bridge registerHandler:@"_app_setTitle" handler:^(id data, WVJBResponseCallback responseCallback) {
if (data) {
NSDictionary *dic = (NSDictionary *)data;
weakSelf.title = dic[@"title"];
}
// responseCallback 给后台 JS 的回复
responseCallback(@"OK,已收到标题信息!");
}];
/**
* JS 调用 OC ,关闭当前 H5 控制器
*/
[_bridge registerHandler:@"_app_closeWebView" handler:^(id data, WVJBResponseCallback responseCallback) {
[weakSelf closeTheView];
responseCallback(@"OK,已关闭当前 WebView ");
}];
/**
* OC 调用 JS ,获取 OC 的值
*/
[_bridge callHandler:@"_app_getToken" data:@"userToken"];
}
- (void)dealloc {
[_bridge removeHandler:@"_app_setTitle"];
[_bridge removeHandler:@"_app_closeWebView"];
[_bridge removeHandler:@"_app_getToken"];
}
// 关闭当前窗口
- (void)closeTheView {
[self dismissViewControllerAnimated:YES completion:nil];
[self.navigationController popViewControllerAnimated:YES];
}
3、HTML 代码:
Document
js调用oc
结束语
WebViewJavascriptBridge 使用起来比较方便快捷,并且还有 Android 版本的。如果 Android 和 iOS 都使用的话,就避免了前端既要写一份 Android 又要写一份 iOS 的 JS 与 OC 交互,调试起来只要一端通了,JS 那边应该就没啥问题,排查问题方便、高效,不用针对两个端分别设置不同的代码,统一性很重要哦。
如有不足,欢迎批评指正!