英文| 简体中文
DSBridge for IOS
现代的跨平台JavaScript桥,通过它可以同步或异步地在JavaScript和原生应用之间调用对方的功能。
DSBridge-Android:https://github.com/wendux/DSBridge-Android
注意
DSBridge v3.0是一个里程碑版本。与v2.0相比,我们做了很多改动。请注意v3.0与v2.0不兼容,但v2.0将继续维护。如果您是新人用户,请使用>=v3.0。
特性
-
Android、IOS和JavaScript的三个端都易于使用,轻量级且功能强大,安全可靠
-
支持同步和异步调用
-
支持
API对象
,可以在Java类或JavaScript对象中集中实现API -
支持API命名空间
-
支持调试模式
-
支持测试API是否存在
-
支持
Progress Callback
:一次调用,多次返回 -
支持为JavaScript提供页面关闭的事件监听器
-
支持为JavaScript提供模态和非模态弹窗
-
支持Android的腾讯X5 webcore
安装
pod "dsBridge"
示例
请查看dsbridgedemo/
包,运行app
项目来查看实际效果。
要在自己的项目中使用dsBridge
使用方法
-
在类中实现API
#import "dsbridge.h" ... @implementation JsApiTest //for synchronous invocation - (NSString *) testSyn:(NSString *) msg { return [msg stringByAppendingString:@"[ syn call]"]; } //for asynchronous invocation - (void) testAsyn:(NSString *) msg :(JSCallback)completionHandler { completionHandler([msg stringByAppendingString:@" [ asyn call]"],YES); } @end
-
将API对象添加到DWKWebView
DWKWebView * dwebview=[[DWKWebView alloc] initWithFrame:bounds]; // register api object without namespace [dwebview addJavascriptObject:[[JsApiTest alloc] init] namespace:nil];
-
在JavaScript中调用原生(Java/Object-c/swift)API,并注册JavaScript API。
-
初始化dsBridge
//cdn //<script src="https://cdn.jsdelivr.net.cn/npm/[email protected]/dist/dsbridge.js"> //</script> //npm //npm install [email protected] var dsBridge=require("dsbridge")
-
调用原生API并注册JavaScript API以供原生调用
//Call synchronously var str=dsBridge.call("testSyn","testSyn"); //Call asynchronously dsBridge.call("testAsyn","testAsyn", function (v) { alert(v); }) //Register javascript API for Native dsBridge.register('addValue',function(l,r){ return l+r; })
-
-
在Object-C中调用JavaScript API
[dwebview callHandler:@"addValue" arguments:@[@3,@4] completionHandler:^(NSNumber* value){ NSLog(@"%@",value); }];
Object-C API签名
为了与iOS兼容,我们对Object-C API签名有以下约定
-
对于同步API。
(id) handler:(id) msg
- 参数类型可以是任何类类型,但返回值类型不能是
void
。
- 参数类型可以是任何类类型,但返回值类型不能是
-
对于异步API。
(void) handler:(id) arg :(JSCallback)completionHandler)
JSCallback
是一个块类型typedef void (^JSCallback)(NSString * _Nullable result,BOOL complete);
注意:API名称不能以"init"开头,因为它已在OC类中保留。
在Swift中使用
在Swift中,您应该这样声明API
//MUST USE "_" to ignore the first argument name explicitly。
@objc func testSyn( _ arg:String) -> String {
return String(format:"%@[Swift sync call:%@]", arg, "test")
}
@objc func testAsyn( _ arg:String, handler: (String, Bool)->Void) {
handler(String(format:"%@[Swift async call:%@]", arg, "test"), true)
}
请注意以下几点
- 必须将"@objc"添加到Swift API中。
- 必须使用"_"显式忽略第一个参数名称
完整示例请参阅此处 .
命名空间
命名空间可以帮助您更好地管理API,这对于混合应用非常有用,因为这些应用拥有大量的API。DSBridge (>= v3.0.0) 允许您通过命名空间对API进行分类。命名空间可以多级,不同级别之间以'.'分割。
调试模式
在调试模式下,一些错误将通过弹出对话框提示,由原生API引起的异常不会被捕获以暴露问题。我们建议在开发阶段开启调试模式。您可以开启调试模式
// open debug mode
[dwebview setDebugMode:true];
进度回调
通常,当一个API调用结束时,它返回一个结果,这与对应项一一对应。但有时一个调用需要多次返回,假设在原生端,有一个下载文件的API,在下载过程中,它将多次发送进度信息到JavaScript,然后JavaScript将在H5页面上显示进度信息。哼...你会发现很难实现这个功能。幸运的是,DSBridge支持 进度回调。您可以使用非常简单和方便的方式实现需要多次返回的调用。以下是一个倒计时的示例:
在Objective-C
- ( void )callProgress:(NSDictionary *) args :(JSCallback)completionHandler
{
value=10;
hanlder=completionHandler;
timer = [NSTimer scheduledTimerWithTimeInterval:1.0
target:self
selector:@selector(onTimer:)
userInfo:nil
repeats:YES];
}
-(void)onTimer:t{
if(value!=-1){
hanlder([NSNumber numberWithInt:value--],NO);
}else{
hanlder(@"",YES);
[timer invalidate];
}
}
在JavaScript
dsBridge.call("callProgress", function (value) {
document.getElementById("progress").innerText = value
})
对于完整的样本代码,请参阅示例项目。
JavaScript弹出框
对于JavaScript弹出框功能(alert/confirm/prompt),DSBridge默认实现了所有这些。默认对话框标签文字语言是中文,您可以通过调用 customJavascriptDialogLabelTitles
来自定义文本。如果您还想自己实现它们,请设置 DSUIDelegate
属性,该属性是 WKUIDelegate
的代理。
注意,DSBridge实现的默认对话框是模态的。这会阻塞UI线程。如果需要非模态对话框,请参考 disableJavascriptDialogBlock
。
WKUIDelegate
在 DWKWebView
中,请使用 DSUIDelegate
而不是 UIDelegate
,因为 UIDelegate
已经在 DWKWebView
内部设置,DSUIDelegate
是 UIDelegate
的代理。
API 参考
Obj-C API
在 Obj-C 中,实现 JavaScript 接口的对象被称为 Obj-C API 对象。
addJavascriptObject:(NSString *)id object:(id)object namespace:(NSString *)namespace
将带有指定命名空间的 Obj-C API 对象添加到 DWKWebView 中。JavaScript 可以通过 bridge.call("namespace.api",...)
调用 OC API。
如果命名空间为空,Obj-C API 对象没有命名空间。JavaScript 可以通过 bridge.call("api",...)
调用 OC API。
示例
在Objective-C
@implementation JsEchoApi
- (id) syn:(id) arg
{
return arg;
}
- (void) asyn: (id) arg :(JSCallback)completionHandler
{
completionHandler(arg,YES);
}
@end
// register api object with namespace "echo"
[dwebview addJavascriptObject:[[JsEchoApi alloc] init] namespace:@"echo"];
在JavaScript
// call echo.syn
var ret=dsBridge.call("echo.syn",{msg:" I am echoSyn call", tag:1})
alert(JSON.stringify(ret))
// call echo.asyn
dsBridge.call("echo.asyn",{msg:" I am echoAsyn call",tag:2},function (ret) {
alert(JSON.stringify(ret));
})
removeJavascriptObject:(NSString *)namespace
移除带有指定命名空间的 Obj-C API 对象。
callHandler:(NSString *)methodName arguments:(NSArray *)args
callHandler:(NSString *) methodName completionHandler:(void (^)(id value))completionHandler
callHandler:(NSString *) methodName arguments:(NSArray *) args completionHandler:(void (^ )(id value))completionHandler
调用javascript API。如果提供了 completionHandler
,javascript处理器可以响应。 methodName
可以包含命名空间。completionHandler 将在主线程中调用。
示例
[dwebview callHandler:@"append" arguments:@[@"I",@"love",@"you"]
completionHandler:^(NSString * _Nullable value) {
NSLog(@"call succeed, append string is: %@",value);
}];
// call with namespace 'syn', More details to see the Demo project
[dwebview callHandler:@"syn.getInfo" completionHandler:^(NSDictionary * _Nullable value) {
NSLog(@"Namespace syn.getInfo: %@",value);
}];
disableJavascriptDialogBlock:(bool) disable
请注意使用,如果调用任何javascript弹出框函数(alert
, confirm
和 prompt
),应用将挂起,javascript执行流程将被阻塞。如果要避免阻塞javascript执行流程,请调用此方法,弹出框函数将立即返回(confirm
返回 true
,而 prompt
返回空字符串)。
示例
[dwebview disableJavascriptDialogBlock: true]
如果想启用阻塞,只需将此方法与参数值 false
一起调用。
setJavascriptCloseWindowListener:(void(^_Nullable)(void))callback
DWKWebView 在JavaScript调用 window.close
时调用 callback
,您可以为添加处理器提供块。
示例
[dwebview setJavascriptCloseWindowListener:^{
NSLog(@"window.close called");
}];
hasJavascriptMethod:(NSString*) handlerName methodExistCallback:(void (^)(bool exist))callback
测试handler是否存在于javascript
示例
// test if javascript method exists.
[dwebview hasJavascriptMethod:@"addValue" methodExistCallback:^(bool exist) {
NSLog(@"method 'addValue' exist : %d",exist);
}];
setDebugMode:(bool) debug
设置调试模式。如果处于调试模式,一些错误将通过弹出对话框提示,并且不捕获由原生API引起的异常以暴露问题。我们建议在开发阶段开启调试模式。
customJavascriptDialogLabelTitles:(NSDictionary*) dic
自定义包含alert/confirm/prompt的javascript对话框的标签文本,默认文本语言为中文。
示例
[dwebview customJavascriptDialogLabelTitles:@{
@"alertTitle":@"Notification",
@"alertBtn":@"OK",
@"confirmTitle":@"",
@"confirmCancelBtn":@"CANCEL",
@"confirmOkBtn":@"OK",
@"promptCancelBtn":@"CANCEL",
@"promptOkBtn":@"OK"
}];
JavaScript API
dsBridge
"dsBridge" 在初始化 dsBridge 后使用。
dsBridge.call(method,[arg,callback])
同步和异步调用 Java API。
method
:Java API 名称,可以包含命名空间。
arg
:参数,只允许一个,如果您需要多个参数,您可以使用一个 json 对象传递。
callback(String returnValue)
:处理结果的回调函数。仅异步调用需要。
dsBridge.register(methodName|namespace,function|synApiObject)
dsBridge.registerAsyn(methodName|namespace,function|asyApiObject)
注册用于Native调用的JavaScript同步和异步API。有两种调用方式
-
仅注册一个方法。例如
在JavaScript
dsBridge.register('addValue',function(l,r){ return l+r; }) dsBridge.registerAsyn('append',function(arg1,arg2,arg3,responseCallback){ responseCallback(arg1+" "+arg2+" "+arg3); })
在Objective-C
// call javascript method [dwebview callHandler:@"addValue" arguments:@[@3,@4] completionHandler:^(NSNumber * value){ NSLog(@"%@",value); }]; [dwebview callHandler:@"append" arguments:@[@"I",@"love",@"you"] completionHandler:^(NSString * _Nullable value) { NSLog(@"call succeed, append string is: %@",value); }];
-
注册具有指定命名空间的JavaScript API对象。例如
在JavaScript
//namespace test for synchronous dsBridge.register("test",{ tag:"test", test1:function(){ return this.tag+"1" }, test2:function(){ return this.tag+"2" } }) //namespace test1 for asynchronous calls dsBridge.registerAsyn("test1",{ tag:"test1", test1:function(responseCallback){ return responseCallback(this.tag+"1") }, test2:function(responseCallback){ return responseCallback(this.tag+"2") } })
由于JavaScript不支持方法重载,因此无法定义具有相同名称的异步函数和同步函数。
在Objective-C
[dwebview callHandler:@"test.test1" completionHandler:^(NSString * _Nullable value) { NSLog(@"Namespace test.test1: %@",value); }]; [dwebview callHandler:@"test1.test1" completionHandler:^(NSString * _Nullable value) { NSLog(@"Namespace test1.test1: %@",value); }];
dsBridge.hasNativeMethod(handlerName,[type])
检查Java中的处理器是否存在,handlerName
可以包含命名空间。
type
: 可选["all"|"syn"|"asyn" ]
,默认是 "all"。
dsBridge.hasNativeMethod('testAsyn')
//test namespace method
dsBridge.hasNativeMethod('test.testAsyn')
// test if exist a asynchronous function that named "testSyn"
dsBridge.hasNativeMethod('testSyn','asyn') //false
dsBridge.disableJavascriptDialogBlock(disable)
调用dsBridge.disableJavascriptDialogBlock(...)
与在Java中调用disableJavascriptDialogBlock
具有相同的效果。
示例
//disable
dsBridge.disableJavascriptDialogBlock()
//enable
dsBridge.disableJavascriptDialogBlock(false)
与fly.js合作
众所周知,在浏览器中,AJax请求受到同源策略的限制,因此无法跨域发起请求。然而,Fly.js通过任何JavaScript桥支持将http请求转发到Native,fly.js已经提供了dsBridge适配器。由于Native端没有同源策略限制,fly.js可以请求来自任何域的资源。
另一个典型场景是在混合App中,Fly.js会将所有请求转发到Native,然后在Native上进行统一请求管理、cookie管理、证书验证、请求过滤等。
更多详情请参考https://github.com/wendux/fly。
最终
如果您喜欢DSBridge,请给它点star,让更多人了解它,谢谢!