Hybrid App: 看看第三方WebViewJavascriptBridge是如何来实现Native和JavaScript交互
一、简介
在前面两篇文章中已经介绍了Native与JavaScript交互的几种方式,依次是JavaScriptCore框架、UI组件UIWebView、WebKit框架,这几种方式都是苹果公司提供的,除了UIWebView在IOS8之后被苹果淘汰了外,其他基本都能很好地满足开发者的使用。作为一个技术人员,每个人心里都有造轮子的想法,可能有时觉得原生的API使用起来感觉还是不够方便,就对苹果原生的API再进行一层封装,这不WebViewJavascriptBridge这个轮子出来了。WebViewJavascriptBridge的star和fork量还是比较高的,仔细看看WebViewJavascriptBridge类文件相当简单,使用起来也很方便,很受开发者欢迎,它的原理还是利用WKWebView或者UIWebView的相关API,通过bridge桥梁来实现OC与JS互相注册和调用。大致结构图如下:
可以看出:OC调用JS,JS需要注册函数; JS调用OC,OC需要注册函数。

二、分析
了解基本原理结构图后,再来看看框架中的类以及它们的作用定义,如下:
WebViewJavascriptBridge_JS:Javascript环境的Bridge初始化和处理。负责接收OC发给Javascript的消息,并且把Javascript环境的消息发送给OC。
WKWebViewJavascriptBridge/WebViewJavascriptBridge:主要负责OC环境的消息处理,并且把OC环境的消息发送给Javascript环境。
WebViewJavascriptBridgeBase:主要实现了OC环境的Bridge初始化和处理。

//初始化桥接器
+ (instancetype)bridgeForWebView:(id)webView;
+ (instancetype)bridge:(id)webView; //设置日志相关
+ (void)enableLogging;
+ (void)setLogMaxLength:(int)length; //注册函数, handlerName: 函数名称 handler:传递数据的block
- (void)registerHandler:(NSString*)handlerName handler:(WVJBHandler)handler;
- (void)removeHandler:(NSString*)handlerName; //调用函数, handlerName:函数名称 data:参数 responseCallback:接收数据的block
- (void)callHandler:(NSString*)handlerName;
- (void)callHandler:(NSString*)handlerName data:(id)data;
- (void)callHandler:(NSString*)handlerName data:(id)data responseCallback:(WVJBResponseCallback)responseCallback; //设置网页代理
- (void)setWebViewDelegate:(id)webViewDelegate; //禁用超时安全弹框
- (void)disableJavscriptAlertBoxSafetyTimeout;
调用相关知识点 :
// OC 调用 JS
// 1、单纯的调用 JSFunction。
[self.jsBridge callHandler:@"JSFunction"]; // 2、调用 JSFunction,并传递给js需要的参数,但不需要 JSFunciton 的返回值。
[self.jsBridge callHandler:@"JSFunction" data:"arg of js"]; // 3、调用 JSFunction ,并传递给js需要的参数,也需要 JSFunction 的返回值。
[self.jsBridge callHandler:@"JSFunction" data:"arg of js" responseCallback:^(id responseData) {
NSLog(@"%@",responseData);
}]; // ------------------------------------------------------------------------------- // //JS 调用 OC // 1、JS 单纯的调用 OC 的 OCMethod
WebViewJavascriptBridge.callHandler('OCMethod'); // 2、JS 调用 OC 的 OCMethod,并传递给OC需要的参数
WebViewJavascriptBridge.callHandler('OCMethod',"arg of oc"); // 3、JS 调用 OC 的 OCMethod,传递给OC需要的参数,并接受OC的返回值。
WebViewJavascriptBridge.callHandler('OCMethod', "arg of oc", function(responseValue){
alert(responseValue);
});
三、核心
使用该框架,还需要完成某些初始化的工作,也即在HTML或者JavaScript文件中,拷贝进官方指定的函数,在函数内进行初始化操作:
//固定格式的函数
function setupWebViewJavascriptBridge(callback) {
if (window.WebViewJavascriptBridge) { return callback(WebViewJavascriptBridge); }
if (window.WVJBCallbacks) { return window.WVJBCallbacks.push(callback); }
window.WVJBCallbacks = [callback];
var WVJBIframe = document.createElement('iframe');
WVJBIframe.style.display = 'none';
WVJBIframe.src = 'https://__bridge_loaded__';
document.documentElement.appendChild(WVJBIframe);
setTimeout(function() { document.documentElement.removeChild(WVJBIframe) }, )
} //官方说这里主要进行初始化,有两个功能:1、进行JS函数的注册提供OC调用(必须在此实现) 2、JS调用OC在端上注册的函数(不用在此处实现)
//这里需要说明一下: 至于第2点如果放在这里会立即执行且执行一次。可以挪到某一个js事件中执行,例如按钮事件等,可以频繁触发,后面的使用会有demo演示
setupWebViewJavascriptBridge(function(bridge) { /* Initialize your app here */ bridge.registerHandler('JavaScript_functionName', function(data, responseCallback) {
responseCallback(data); //传递数据给OC
}) bridge.callHandler('OC_methodName', function responseCallback(responseData) {
alert(responseData); //接收OC的数据
})
})
四、使用
Example introduce: 页面有一个原生按钮和H5按钮,点击原生按钮调用JS,切换H5的div背景色;点击H5按钮,调用OC方法,切换原生按钮背景颜色。
完整代码:
//
// ViewController.m
// WebViewJavaScriptBridge
//
// Created by 夏远全 on 2019/11/17.
// Copyright © 2019 Beijing Huayue Education Technology Co., Ltd. All rights reserved.
// #import "ViewController.h"
#import "WebViewJavascriptBridge/WebViewJavascriptBridge.h" @interface ViewController ()
@property (nonatomic, strong) WebViewJavascriptBridge *bridge;
@property (nonatomic, strong) UIButton *topButton;
@property (nonatomic, strong) WKWebView *wkWebView;
@end @implementation ViewController #pragma mark - init - (void)viewDidLoad {
[super viewDidLoad]; //创建topView
CGFloat width = [UIScreen mainScreen].bounds.size.width;
self.topButton = [[UIButton alloc] initWithFrame:CGRectMake(, , width, )];
self.topButton.titleLabel.numberOfLines = ;
self.topButton.backgroundColor = [UIColor blueColor];
self.topButton.titleLabel.font = [UIFont systemFontOfSize:];
[self.topButton setTitle:@"我是TopButton\n点击我调用JS方法,切换div盒子的背景色" forState:UIControlStateNormal];
[self.topButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
[self.topButton addTarget:self action:@selector(topButtonAction) forControlEvents:UIControlEventTouchUpInside]; //创建wkWebView
CGFloat height = [UIScreen mainScreen].bounds.size.height-CGRectGetHeight(self.topButton.frame);
self.wkWebView = [[WKWebView alloc] initWithFrame:CGRectMake(, CGRectGetMaxY(self.topButton.frame), width, height)]; //添加wkWebView视图
[self.view addSubview:self.topButton];
[self.view addSubview:self.wkWebView]; //为wkWebView创建桥接器
self.bridge = [WebViewJavascriptBridge bridgeForWebView:self.wkWebView]; //OC注册方法,提供给JavaScript调用,并给JavaScript传递数据
[self.bridge registerHandler:@"updateTopButtonBgColor" handler:^(id data, WVJBResponseCallback responseCallback) {
UIColor *randomColor = [UIColor colorWithRed:arc4random_uniform()/255.0 green:arc4random_uniform()/255.0 blue:arc4random_uniform()/255.0 alpha:1.0];
self.topButton.backgroundColor = randomColor;
[self showAlertView:@"JavaScript调用OC ----- success! "];
responseCallback(@"JavaScript调用OC ----- success! "); //可以回调给JavaScript一个结果
}]; //加载资源
NSString *file = [[NSBundle mainBundle] pathForResource:@"example" ofType:@"html"];
NSString *html = [NSString stringWithContentsOfFile:file encoding:NSUTF8StringEncoding error:nil];
[self.wkWebView loadHTMLString:html baseURL:nil];
} #pragma mark - remove
- (void)viewDidDisappear:(BOOL)animated {
[super viewDidDisappear:animated];
[self.bridge removeHandler:@"updateTopButtonBgColor"];
} #pragma mark -action
-(void)topButtonAction { //调用JavaScript函数,传递颜色参数,并接收JavaScript回传的数据
NSArray *colors = [NSArray arrayWithObjects:@"orange",@"green",@"red",@"blue",nil];
[self.bridge callHandler:@"updateDivBgColor" data:colors[arc4random_uniform()] responseCallback:^(id responseData) {
[self showAlertView:responseData];
}];
} #pragma mark - method
-(void)showAlertView:(NSString *)message {
UIAlertController *aletVc = [UIAlertController alertControllerWithTitle:@"提示" message:message preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction *action = [UIAlertAction actionWithTitle:@"知道了" style:UIAlertActionStyleDefault handler:nil];
[aletVc addAction:action];
[self presentViewController:aletVc animated:YES completion:nil];
} @end
细分步骤:
1、创建HTML,完成初始工作
<!DOCTYPE html>
<html lang="en"> <head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title> <style>
.divcss{ background:#F00; color:#FFF; width:300px; height:200px}
</style> <script type="text/javascript"> function button_onclick(){
//JavaScript调用OC注册的方法,并接收OC的数据
WebViewJavascriptBridge.callHandler('updateTopButtonBgColor',function(responseValue) {
alert(responseValue);
});
} // 固定函数
function setupWebViewJavascriptBridge(callback) {
if (window.WebViewJavascriptBridge) { return callback(WebViewJavascriptBridge); }
if (window.WVJBCallbacks) { return window.WVJBCallbacks.push(callback); }
window.WVJBCallbacks = [callback];
var WVJBIframe = document.createElement('iframe');
WVJBIframe.style.display = 'none';
WVJBIframe.src = 'https://__bridge_loaded__';
document.documentElement.appendChild(WVJBIframe);
setTimeout(function() { document.documentElement.removeChild(WVJBIframe) }, 0)
} // 初始化
setupWebViewJavascriptBridge(function(bridge){ //JavaScript调用OC注册的方法,并接收OC的数据,页面启动后会立即调用且调用一次,我把它放到了上面的Hybrid App: 看看第三方WebViewJavascriptBridge是如何来实现Native和JavaScript交互的更多相关文章
- Hybrid APP基础篇(三)->Hybrid APP之Native和H5页面交互原理
本文已经不维护,新地址: http://www.cnblogs.com/dailc/p/8097598.html 说明 Hybrid模式原生和H5交互原理 目录 前言 参考来源 前置技术要求 楔子 A ...
- Hybrid App简介
Hybrid App 是混合模式应用的简称,兼具 Native App 和 Web App 两种模式应用的优势,开发成本低,拥有Web技术跨平台特性.目前大家所知道的基于中间件的移动开发框架都是采用的 ...
- Hybrid APP之Native和H5页面交互原理
Hybrid APP之Native和H5页面交互原理 Hybrid APP的关键是原生页面与H5页面直接的交互,如下图,痛过JSBridge,H5页面可以调用Native的api,Native也可调用 ...
- Hybrid App 开发模式
开发移动App主要有三种模式:Native. Hybrid 和 Web App. 需要注意的一点是在选择开发模式的时候,要根据你的项目类型(图片类?视频类?新闻类?等),产品业务和人员技术储备等做权衡 ...
- Hybrid App 开发初探:使用 WebView 装载页面
Hybrid App 是混合模式应用的简称,兼具 Native App 和 Web App 两种模式应用的优势,开发成本低,拥有 Web 技术跨平台特性.目前大家所知道的基于中间件的移动开发框架都是采 ...
- Hybrid App 应用开发中 9 个必备知识点复习(WebView / 调试 等)
前言 我们大前端团队内部 ?每周一练 的知识复习计划继续加油,本篇文章是 <Hybrid APP 混合应用专题> 主题的第二期和第三期的合集. 这一期共整理了 10 个问题,和相应的参考答 ...
- 分享 Ionic 开发 Hybrid App 中遇到的问题以及后期发布 iOS/Android 的方方面面
此篇文章主要整理了最近在使用 Ionic 开发 Hybrid App 过程中遇到的一些疑难点以及后期发布生成 iOS 和 Android 版本过程中的种种问题. 文章目录 Ionic 简介和项目需求介 ...
- 进击的Hybrid App,量身定做缓存机制
引用张图,简单粗俗的解释下 Native App.Web App 和 Hybrid App Navtie App: 使用平台系统提供的原生语言来编写的 App,如果Android用java,ios用o ...
- 【Hybrid App】Hybrid App开发实战
[引言]近年来随着移动设备类型的变多,操作系统的变多,用户需求的增加,对于每个项目启动前,大家都会考虑到的成本,团队成员, 技术成熟度,时间,项目需求等一堆的因素.因此,开发App的方案已经变得越来越 ...
随机推荐
- indexeddb:浏览器中的数据库
随着浏览器功能的不断加强,越来越多的网站开始考虑将大量的数据存储在客户端.这样的考虑是为了直接从本地获取数据,减少从服务器获取数据耗费的网络资源. 原有的浏览器数据存储方案都不适合存储大量数据.Coo ...
- Jenkins源代码管理(SVN)
Subversion 安装插件 1.首先将本地的自动化用例打包上传svn 2.配置jenkins源代码管理(每次执行jenkins时,会自动check-out配置地址中的代码到Jenkins的工作空间 ...
- Redis系列(一):Redis简介
一.Redis概述 Redis是一个开源(遵循BSD协议)Key-Value数据结构的内存存储系统,用作数据库.缓存和消息代理.它支持5种数据结构:字符串string.哈希hash.列表list.集合 ...
- Redis 3.0中文版学习(二)
网址:http://wiki.jikexueyuan.com/project/redis-guide/entry-to-master-middle.html 1.Redis的列表: 采用链表的实现方法 ...
- HTML CSS3中2D转换、3D转换、过渡效果总结
一.CSS3 2D转换 通过 CSS3 转换,我们可以对元素进行移动.缩放.转动.拉长或拉伸. 特别注意,我们在使用css3动画效果时,必须给他们加相应的浏览器前缀,以便浏览器识别,让我们更好的去应用 ...
- NServiceBus+Saga开发分布式应用
前言 当你在处理异步消息时,每个单独的消息处理程序都是一个单独的handler,每个handler之间互不影响.这时如果一个消息依赖另一个消息的状态呢? 这时业务逻辑怎么处理? ...
- MFC连接Sqlserver
下载 ado2.h和ado2.cpp文件 在VC++ 目录-->包含目录 -->添加 msado15.dll, msjro.dll 目录. // TODO: 连接sqlserver, 在 ...
- [Abp vNext 源码分析] - 12. 后台作业与后台工作者
一.简要说明 文章信息: 基于的 ABP vNext 版本:1.0.0 创作日期:2019 年 10 月 24 日晚 更新日期:暂无 ABP vNext 提供了后台工作者和后台作业的支持,基本实现与原 ...
- java读取存在src目录下和存在同级目录下的配置文件
如果我有个文件存在src下一级的地方和存在src同级的目录应该怎么用相对路径去获取如图: 一.如果存在src同级的地方应该是InputStream in = new BufferedInputStre ...
- 06 Node.js学习笔记之自动路由
在以往客户端请求的文件,我们都得判断匹配才能返回相应的数据,其实我们可以设置一个自动路由,就可以不用每次去判断用户访问的是那个文件了 //1.载入http和fs模块 var http=require( ...