有没有iOS,android 通用dialog通用的Javascript Bridge组建

JavaScript调用App原生代码(iOS、Android)通用解决方案 - 简书
JavaScript调用App原生代码(iOS、Android)通用解决方案
以前写的一篇 ,很多人问有没有实例代码,今天来说一个对iOS与Android通用的代码实践
场景:现在有一个H5活动页面,上面有一个登陆按钮,要求点击登陆按钮以后,唤出App内部的登录界面,当登录成功以后将用户的手机号返回给H5页面,显示出来。
这个场景应该算是比较完整的一次H5中的JavaScript与App原生代码进行交互了,这个过程,我们制定的方案满足以下几点:
满足基本的交互流程的功能
Android与iOS都能适用
H5的前端开发者,在书写JavaScript的业务代码的时候不需要为了迁就移动端语言的特性而写特殊的磨合代码
上一篇文章里提到,当H5页面上的JavaScript代码要调用原生的页面或者组件的时候,调用最好是双向的,一来一回,这样比较容易满足一些比较复杂的业务场景,就像上面的场景一样,有调用,有回调告知H5调用的结果。前端开发写的JavaScript代码基本上都是异步风格的,就拿上面的场景,如果登录是H5前端的,那么这个流程就会是:
function loginClick() {
loginComponent.login(function (error,result) {
//处理登录完成以后的逻辑
var loginComponent = {
callBack:null,
"login":function (callBack) {
this.show();
this.callBack = callB
show:function (loginComponent) {
//登录组件显示的逻辑
confirm:function (userName,password) {
ajax.post('/login',function (error,result) {
if(this.callBack !== null){
this.callBack(error,result);
如果要改成调用原生登录,那么这个流程就应该是这样:
确定了流程,接下来就可以详细设计和实现
原生与JavaScript的桥梁
为了实现上述流程,并且能让H5的前端开发尽可能少的语法损失,我们需要构建一个JavaScript与原生App进行交互的桥梁,这个桥梁来处理与App的协议交互,兼容iOS与Android的交互实现。
Android与iOS都支持在打开H5页面的时候,向H5页面的window对象上注入一个JavaScript可以访问到的对象,Android端使用的是
webView.addJavascriptInterface(myJavaScriptInterface, “bridge”);
iOS则可以使用JavaScriptCore来完成:
#import &Foundation/Foundation.h&
#import &JavaScriptCore/JavaScriptCore.h&
@protocol PICBridgeExport &JSExport&
@interface PICBridge : NSObject&PICBridgeExport&
self.jsContext =
[self.webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
self.bridge =[[PICBridge alloc]init];
这里面Android的myJavaScriptInterface与PICBridge都是作为与JavaScript进行通信的桥梁。
我们使用设计这个桥梁的时候,需要使用一个具体的语法约定和数据约定,比方说,当前端开发调用App登录的时候,他一定是希望就像调用其他JavaScript的组件一样,而登录的结果通过传入callBack的函数来完成,对于callBack函数,我们希望借助NodeJS的规范:
function(error,res) {
//回调函数第一个参数是错误,第二个参数是结果
以上我们可以看到,bridge必须有能力将前端开发写的JavaScript回调函数传入到App内部,然后App处理完逻辑以后通过回调函数来告知前端处理,并且这个需要通过约定好的数据格式来传递入参和返回值。
为了完成双向通信,我们就需要在JavaScript设置一个bridge,原生再注入一个bridge,这两个bridge按照一定的数据约定来进行双向通信和分发逻辑。
原生端注入到JS当中的“桥”(iOS端)
通过使用JavaScriptCore这个库,我们能很容易的将JavaScript传入的回调函数在objective-c或者是swift端持有,并回去回调这个回调函数。
#import &Foundation/Foundation.h&
#import &JavaScriptCore/JavaScriptCore.h&
@protocol PICBridgeExport &JSExport&
JSExportAs(callRouter, -(void)callRouter:(JSValue *)requestObject callBack:(JSValue *)callBack);
@interface PICBridge : NSObject&PICBridgeExport&
-(void)addActionHandler:(NSString *)actionHandlerName forCallBack:(void(^)(NSDictionary * params,void(^errorCallBack)(NSError * error),void(^successCallBack)(NSDictionary * responseDict)))callB
需要说明的是,JavaScript没有函数参数标签的概念,JSExportAs是用来将objective-c的方法映射为JavaScript的函数。
-(void)callRouter:(JSValue *)requestObject callBack:(JSValue *)callBack);
这个方法是暴露给JavaScript端调用的。
第一个参数requestObject是一个JavaScript对象,传入到objective-c中以后就可以转换为key-value结构的字典,那么这个字典的数据约定是:
'Method':'Login',
'Data':null
其中Method是App内部对外提供的API,而这个Data则是该API需要的入参。
第二个参数是一个callBack函数,该类型的JSValue可以调用callWithArguments:方法来invoke这个回调函数。
前面已经说明,回调函数的第一个参数是error,第二个参数是一个结果,而回调的结果我们也进行一下约定,那就是:
'result':{}
这样的好处是,业务逻辑可以讲返回的结果放入result中,跟result同级别的我们还可以加入统一的签名认证的东西,在此暂时不延伸。
原生端的bridge的来实现一下callRouter:
-(void)callRouter:(JSValue *)requestObject callBack:(JSValue *)callBack{
NSDictionary * dict = [requestObject toDictionary];
NSString * methodName = [dict objectForKey:@"Method"];
if (methodName != nil && methodName.length&0) {
NSDictionary * params = [dict objectForKey:@"Data"];
__weak PICBridge * weakSelf =
//因为JavaScript是单线程的,需要尽快完成调用逻辑,耗时操作需要异步提交到主线程中执行
dispatch_async(dispatch_get_main_queue(), ^{
[weakSelf callAction:methodName params:params success:^(NSDictionary *responseDict) {
if (responseDict != nil) {
NSString * result = [weakSelf responseStringWith:responseDict];
if (result) {
[callBack callWithArguments:@[@"null",result]];
[callBack callWithArguments:@[@"null",@"null"]];
[callBack callWithArguments:@[@"null",@"null"]];
} failure:^(NSError *error) {
if (error) {
[callBack callWithArguments:@[[error description],@"null"]];
[callBack callWithArguments:@[@"App Inner Error",@"null"]];
[callBack callWithArguments:@[@NO,[PICError ErrorWithCode:PICUnkonwError].description]];
//将返回的结果字典转换为字符串通过回调函数传回给JavaScript
-(NSString *)responseStringWith:(NSDictionary *)responseDict{
if (responseDict) {
NSDictionary * dict = @{@"result":responseDict};
NSData * data = [NSJSONSerialization dataWithJSONObject:dict options:NSJSONWritingPrettyPrinted error:nil];
NSString * result = [[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding];
callAction函数实际上就是分发业务逻辑用的
-(void)callAction:(NSString *)actionName params:(NSDictionary *)params success:(void(^)(NSDictionary * responseDict))success failure:(void(^)(NSError * error))failure{
void(^callBack)(NSDictionary * params,void(^errorCallBack)(NSError * error),void(^successCallBack)(NSDictionary * responseDict)) = [self.handlers objectForKey:actionName];
if (callBack != nil) {
callBack(params,failure,success);
这个callBack Block是在self.handlers的字典中存储,比较复杂,block第一个参数是传入的入参,后面两个参数是成功以后的回调和失败以后的回调,以便业务逻辑完成后进行回调给JavaScript。
同时会有注册业务逻辑的方法:
-(void)addActionHandler:(NSString *)actionHandlerName forCallBack:(void(^)(NSDictionary * params,void(^errorCallBack)(NSError * error),void(^successCallBack)(NSDictionary * responseDict)))callBack{
if (actionHandlerName.length&0 && callBack != nil) {
[self.handlers setObject:callBack forKey:actionHandlerName];
至此,原生端路由实现完毕。
JavaScript端路由
先贴上完整代码:
(function(win) {
var ua = navigator.userA
function getQueryString(name) {
var reg = new RegExp('(^|&)' + name + '=([^&]*)(&|$)', 'i');
var r = window.location.search.substr(1).match(reg);
if (r !== null) return unescape(r[2]);
function isAndroid() {
return ua.indexOf('Android') & 0;
function isIOS() {
return /(iPhone|iPad|iPod)/i.test(ua);
var mobile = {
*通过bridge调用app端的方法
* @param method
* @param params
* @param callback
callAppRouter: function(method, params, callback) {
var req = {
'Method': method,
'Data': params
if (isIOS()) {
win.bridge.callRouter(req, function(err, result) {
var resultObj =
var errorMsg =
if (typeof(result) !== 'undefined' && result !== 'null' && result !== null) {
resultObj = JSON.parse(result);
if (resultObj) {
resultObj = resultObj['result'];
if (err !== 'null' && typeof(err) !== 'undefined' && err !== null) {
errorMsg =
callback(err, resultObj);
} else if (isAndroid()) {
//生成回调函数方法名称
var cbName = 'CB_' + Date.now() + '_' + Math.ceil(Math.random() * 10);
//挂载一个临时函数到window变量上,方便app回调
win[cbName] = function(err, result) {
var resultO
if (typeof(result) !== 'undefined' && result !== null) {
resultObj = JSON.parse(result)['result'];
callback(err, resultObj);
//回调成功之后删除挂载到window上的临时函数
delete win[cbName];
win.bridge.callRouter(JSON.stringify(req), cbName);
login: function() {
// body...
this.callAppRouter('Login', null, function(errMsg, res) {
// body...
if (errMsg !== null && errMsg !== 'undefined' && errMsg !== 'null') {
var name = res['phone'];
if (name !== 'undefined' && name !== 'null') {
var button = document.getElementById('loginButton');
button.innerHTML =
//将mobile对象挂载到window全局
win.webBridge =
})(window);
在window上挂在一个叫webBridge的对象,其他业务JavaScript可以通过webBridge.login来进行调用原生端开放的API。
callAppRouter方法的实现我们来分析一下:
如果判断是iOS设备,则使用iOS注册的bridge对象进行调用callRouter方法:
if (isIOS()) {
win.bridge.callRouter(req, function(err, result) {
var resultObj =
var errorMsg =
if (typeof(result) !== 'undefined' && result !== 'null' && result !== null) {
resultObj = JSON.parse(result);
if (resultObj) {
resultObj = resultObj['result'];
if (err !== 'null' && typeof(err) !== 'undefined' && err !== null) {
errorMsg =
callback(err, resultObj);
req是标准的包含Method和Data的对象,紧接着传入回调函数,回调函数有err与result,里面做好各种类型检查。
着重说一下Android端的实现,因为Android端的JavaScript方法注册,参数类型只能字符串,java语言本身没有匿名函数的概念,所以只能给Java端传入回调函数的名字,而回调函数的实现则在JavaScript端持有。
else if (isAndroid()) {
//生成回调函数方法名称
var cbName = 'CB_' + Date.now() + '_' + Math.ceil(Math.random() * 10);
//挂载一个临时函数到window变量上,方便app回调
win[cbName] = function(err, result) {
var resultO
if (typeof(result) !== 'undefined' && result !== null) {
resultObj = JSON.parse(result)['result'];
callback(err, resultObj);
//回调成功之后删除挂载到window上的临时函数
delete win[cbName];
win.bridge.callRouter(JSON.stringify(req), cbName);
本质上就是将其他业务JavaScript代码传入的callBack函数通过随机生成函数名,挂在到window变量上,回调以后将其删除:delete win[cbName]。
当调用Java端的bridge.callRouter(JSON.stringify(req), cbName),Java端拿到cbName,在完成业务逻辑后,按照标准数据格式,在JavaScript执行的上下文中,回调这个名字的方法。
至此,前端的webBridge完成。
最后附上Demo地址:
此Demo是通过H5调用原生的登录界面,登录成功以后将手机号在H5上的登录按钮显示出来,完成一整套逻辑交互。喜欢的给个?,有任何问题大家多多交流!
会写一些iOS开发的代码,喜欢那部叫《春风化雨》的电影,雨天开个Instagram的滤镜拍点照片,有时候散支烟,小酌一下。
用两张图告诉你,为什么你的 App 会卡顿? - Android - 掘金Cover 有什么料? 从这篇文章中你能获得这些料: 知道setContentView()之后发生了什么? ... Android 获取 View 宽高的常用正确方式,避免为零 - 掘金相信有很多朋友...
用两张图告诉你,为什么你的 App 会卡顿? - Android - 掘金 Cover 有什么料? 从这篇文章中你能获得这些料: 知道setContentView()之后发生了什么? ... Android 获取 View 宽高的常用正确方式,避免为零 - 掘金 相信有很多...
前言:iOS 开发中,h5 和原生实现通信有多种方式, JSBridge 就是最常用的一种,各 JSBridge 类库的实现原理大同小异,这篇文章主要是针对当前使用最为广泛的 WebViewJavascriptBridge(v6.0.2),从功能 API、实现原理到源码解读...
JavaScript 函数式编程 - 前端 - 掘金引言 面向对象编程一直以来都是JavaScript中的主导范式。JavaScript作为一门多范式编程语言,然而,近几年,函数式编程越来越多得受到开发者的青睐。函数式编程是一种强调减少对程序外部状态产生改变的方式。因此,它...
2016 腾讯 TST 校招面试经历,电面、笔试写代码、技术面、hr 面,共 5 轮 - 后端 - 掘金(出处:/linguanh/) 前序: 距离2016 腾讯 TST 校招面试结束已经5天了,3月27日至今,目前还在等待消息。...
继上一篇WebView拦截器出来Cookie后,在测试过程中又发现了问题。使用拦截器来强塞Cookie在Android5.0之后的版本是没有问题,但是之前的版本使用过时的api来强塞Cookie就会发生线程阻塞。过时api如下: 思考问题 开始我一直思路在为什么会发生阻塞上...
潘德格拉丝是名小学女教师,她被控肉体惩罚自己的学生(但并未造成永久伤害)。大法官加斯顿令人信服的说明这位女教师并不应该被判有罪,并建立了在相关判例上的一条一般性原则:如果对学生的惩罚造成了永久性伤害,那么教师们就超越了权限;如果只是暂时性痛苦,那么教师们就是在权限内行事。(...
我是个胖子,我想瘦下来,我了解科学的控制体重的方法,我知道应该每天进行一定量的有氧运动,每天摄入的卡路里应该低于消耗的卡路里且应该保持饮食结构健康,要多吃蔬菜,少吃油炸的、口味重的或太甜的东西。不应该中午猛地吃一顿然后晚上觉得应该减肥就不吃了,不应该在过年的时候大鱼大...
参考链接:/p/ded/p/055002aaf1ca/p/34cf96b72102 Android上我们很多时候通过匿名类的...
被人误解的时候 ,能微微一笑,是一种素养; 受委屈的时候,能坦然一笑,是一种大度; 吃亏的时候,能开心一笑,是一种豁达; 无奈的时候,能豁然一笑,是一种境界; 危难的时候,能泰然一笑,是一种大气; 被轻蔑的时候,能平静一笑,是一种自信; 失意的时候,能轻轻一笑,是一种洒脱;...使用WebViewJavascriptBridge的安卓和iOS可不可以共用一套js代码_百度知道
色情、暴力
我们会通过消息、邮箱等方式尽快将举报结果通知您。
使用WebViewJavascriptBridge的安卓和iOS可不可以共用一套js代码
我有更好的答案
([0-9.test(platform),
wp = ua.]+)&#47.*]{0.match(/Version\/),
ie = ua.match(/)?/),
iphone = ;);Trident\/([&#92,
osx = .match(/(BlackBerry);sOS)\s([\d_]+)/),
webos = ua.match(/(webOShpwOS)[\PlayBook/),
chrome = ua:([\d.]+)\).*Firefox\Firefox\(RIM\sTablet\sOS)&#92,
safari = webview
ipad = ua.match(&#47.]+)/);)!!ua.]+)/s([&#92,
touchpad = webos &&);/[\d.]+&#47.match(/&#92.match(/Chrome&#92.)/((?,
playbook = ua.match(&#47.match(/Windows Phone ([&#92.match(/TouchPad/(iPad).*OS\s([\d_]+)/),
webview = !.*Safari)&#47.match(/\/([\d,1}([\d.]+)/),
android = ua.match(/ Intel /MSIE\s([\d.]+)/)
ua.match(&#47._]+)/),
blackberry = ua.match(/CriOS\&#47.match(/(iPod)(.*OS\s([\d_]+));/([&#92!ipad && ua.match(/([\d.]+)/),
silk =);([\d.]+)/),
bb10 =);d;d;);(iPhone&#92.]+)/([\d.]+)/),
rimtabletos = ua.match(&#47,
kindle = ua.match(//[\d](?=[^\;)]+([\d.]+)?//]([\d.]+)/),
win = /Win\d{2}Windows/;(iPhoneiPodiPad).*AppleWebKit(?;Kindle\&#47.match(/Silk&#92!chrome && ua.match(/d;?[\s\&#47.match(/(BB10);Web[kK]it[\/([\d.]+)/),
firefox = ua.match(&#47.*Version\&#47.]:MobileTablet);(Macintosh\var os = this.os = {}, browser = this.browser = {},
webkit = ua.match(&#47.*Version\/s&#92,
firefoxos = ua?]+);(Android)
为您推荐:
其他类似问题
换一换
回答问题,赢新手礼包相关文章推荐
Js bridge 实习Aandroid 和js 交互,对js和java双方来说,如果html中的js需要调用java代码,而java代码没做任何实现,那么这个js也是无效的,反之java代码注册的回...
写在前面的话:背景介绍:
转自ionichina作者ParryQiu
1. Ionic 简介和项目需求介绍
2. View 缓存的处理
3. 键盘的不同模式的支持
4. 设备网络状况的检查
5. iOS 设备和 A...
Hybrid App 使用 native.js 实现搜索蓝牙列表
1.检查网络状态,提示用户检查网络,android端可进入系统设置页面。/*
* 检查网络
function checkNet() {
//检查网络
var network = plus...
(function(w, _, $, u) {
_.plusReady(function() {
plus.webview.currentWebview().setStyle(...
作者董一凡自述:作为一名写了十年代码的程序员,目前我最擅长的领域是移动平台的客户端开发,在移动领域的开发时间超过七年,前前后后涉猎过很多个平台。随着大部分移动平台自己走向死亡,现在我也主要专注在了iO...
作者董一凡自述:作为一名写了十年代码的程序员,目前我最擅长的领域是移动平台的客户端开发,在移动领域的开发时间超过七年,前前后后涉猎过很多个平台。随着大部分移动平台自己走向死亡,现在我也主要专注在了iO...
基于 Hybrid App(混合模式移动应用)中IOS开发证书创建和打包使用
Hybrid App在最近两年是一个很火的话题,目前国内做的比较好的就是Hbuilder官网http://www.dclo...
他的最新文章
讲师:Array
讲师:李志伟
他的热门文章
您举报文章:
举报原因:
原文地址:
原因补充:
(最多只允许输入30个字)有没有iOS,android通用的Javascript Bridge组建_百度知道
色情、暴力
我们会通过消息、邮箱等方式尽快将举报结果通知您。
有没有iOS,android通用的Javascript Bridge组建
我有更好的答案
现在Facebook的开源框架react native很不错,也是一种选择。phonegap, JavaScriptnatived都是可以尝试下。
采纳率:98%
来自团队:
为您推荐:
其他类似问题
换一换
回答问题,赢新手礼包有没有iOS,android通用的Javascript Bridge组建_百度知道
色情、暴力
我们会通过消息、邮箱等方式尽快将举报结果通知您。
有没有iOS,android通用的Javascript Bridge组建
我有更好的答案
self.bridge = [WebViewJavascriptBridge bridgeForWebView.To use a WebViewJavascriptBridge in your own project:Usage1) Import the header file and declare an ivar property:#import &WebViewJavascriptBridge.h&quot, WVJBResponseCallback responseCallback) {NSLog(@&quot:^(id responseData) {NSLog(@&ObjC received response:[self..@property WebViewJavascriptBridge*2) Instantiate WebViewJavascriptBridge with a UIWebView (iOS) or WebView (OSX);ObjC EObjC Echo& handler:^(id data, uncheck &Copy items into destination group's folder& and select &Create groups for any folders&quotInstallation (iOS & OSX)Installation with CocoaPodsAdd this to your podfile and run pod install to install. Open either the iOS or OSX project and hit run to see it in action, responseData);}];.ExamplesSee the Example Apps/ 5.0'`Manual installationDrag the WebViewJavascriptBridge folder into your project.In the dialog that appears:`pod &#39: %@&; responseCallback:webView];3) Register a handler in ObjC, and call a JS}];[self.bridge callH folder:@&JS Echo&WebViewJavascriptBridge'., data);responseCallback(data): %@&;, '~&gt.bridge registerHandler:@&quot
为您推荐:
其他类似问题
换一换
回答问题,赢新手礼包

我要回帖

更多关于 android通用驱动 的文章

 

随机推荐