DSBridge for Flutter
在 Android 和 iOS 渠道上做过 Hybrid 开发的同学根本都会知道 DSBridge,该结构现在最受欢迎的 JSBridge 结构之一,为了在 Flutter 侧完成原生 Hybrid 的能力,于是咱们将其适配到了Flutter 渠道。
三端易用的现代跨渠道 JavaScript bridge,经过它你能够在 JavaScript 和 Flutter 之间同步或异步的调用互相的函数.
概述
DSBridge for Flutter 彻底兼容 Android 和 iOS DSBridge 的 dsbridge.js。不像其他类似的结构无法完成JavaScript 调用 Dart 并同步回来结果,本结构完好支撑同步调用和异步调用。dsbridge_flutter
是首个完好完成了 DSBridge 在原 Android 和 iOS 上的一切功用,因此能够完成将原来经过原生完成的 Webview 事务彻底迁移到 Flutter 完成,即一套代码完成APP与H5的Hybrid开发。在现有运用了 dsbridge.js 的 Web 项目中无须修改任何代码即可运用 DSBridge for Flutter。
本结构现在支撑Android 和 iOS 渠道,行将支撑纯鸿蒙渠道(OpenHarmony & HarmonyOS Next),敬请期待!
DSBridge for Flutter 基于 Flutter官方的 webview_flutter。
现在已发布到官方pub.dev:dsbridge_flutter
特性
-
Android、iOS、JavaScript 三端易用,轻量且强大、安全且强健。
-
一起支撑同步调用和异步调用
-
支撑以类的方式会集统一管理API
-
支撑API命名空间
-
支撑调试方式
-
支撑 API 存在性检测
-
支撑进展回调:一次调用,屡次回来
-
支撑 JavaScript 关闭页面事件回调
-
支撑 JavaScript 模态对话框
安装
-
增加依赖
dependencies: ... dsbridge_flutter: x.y.z
示例
请参阅工程目录下的 example
包。运转 example
工程并查看示例交互。
假如要在你自己的项目中运用 dsBridge :
运用
-
新建一个Dart类,完成API
import 'package:dsbridge_flutter/dsbridge_flutter.dart'; class JsApi extends JavaScriptNamespaceInterface { @override void register() { registerFunction(testSyn); registerFunction(testAsyn); } /// for synchronous invocation String testSyn(dynamic msg) { return "$msg[syn call]"; } /// for asynchronous invocation void testAsyn(dynamic msg, CompletionHandler handler) { handler.complete("$msg [ asyn call]"); } }
一切Dart APIs有必要在register函数中运用registerFunction来注册。
-
增加API类实例到DWebViewController
import 'package:dsbridge_flutter/dsbridge_flutter.dart'; ... late final DWebViewController _controller; ... _controller.addJavaScriptObject(JsApi(), null);
-
在 JavaScript 中调用 Dart API ,并注册一个 JavaScript API 供原生调用.
-
初始化 dsBridge
//cdn //<script src="https://unpkg.com/dsbridge@3.1.3/dist/dsbridge.js"> </script> //npm //npm install dsbridge@3.1.3 var dsBridge=require("dsbridge")
-
调用 Dart API;以及注册一个 JavaScript API 供 Dart 调用.
//同步调用 var str=dsBridge.call("testSyn","testSyn"); //异步调用 dsBridge.call("testAsyn","testAsyn", function (v) { alert(v); }) //注册 JavaScript API dsBridge.register('addValue',function(l,r){ return l+r; })
-
-
在 Dart 中调用 JavaScript API
import 'package:dsbridge_flutter/dsbridge_flutter.dart'; ... late final DWebViewController _controller; ... _controller.callHandler('addValue', args: [3, 4], handler: (retValue) { print(retValue.toString()); });
Dart API 签名
为了兼容Android&iOS,咱们约定Dart API 签名,留意,假如API签名不合法,则不会被调用!签名如下:
-
同步API.
any handler(dynamic msg)
参数有必要是
dynamic
类型,而且有必要声明(假如不需求参数,声明后不适用即可)。回来值类型没有约束,能够是任意类型。 -
异步 API.
void handler(dynamic arg, CompletionHandler handler)
命名空间
命名空间能够协助你更好的管理API,这在API数量多的时候十分实用,比方在混合应用中。DSBridge支撑你经过命名空间将API分类管理,而且命名空间支撑多级的,不同级之间只需用’.’ 分隔即可。
调试方式
在调试方式时,产生一些错误时,将会以弹窗方式提示,而且Dart API假如触发反常将不会被主动捕获,因为在调试阶段应该将问题露出出来。
进展回调
通常情况下,调用一个办法完毕后会回来一个结果,是一一对应的。但是有时会遇到一次调用需求屡次回来的场景,比方在 JavaScript 中调用端上的一个下载文件功用,端上在下载过程中会屡次通知 JavaScript 进展, 然后 JavaScript 将进展信息展现在h5页面上,这是一个典型的一次调用,屡次回来的场景,假如运用其它 JavaScript bridge, 你将会发现要完成这个功用会比较麻烦,而 DSBridge 本身支撑进展回调,你能够十分简略便利的完成一次调用需求屡次回来的场景,下面咱们完成一个倒计时的比如:
In Dart
void callProgress(dynamic args, CompletionHandler handler) {
var i = 10;
final timer = Timer.periodic(const Duration(seconds: 1), (timer) {
if (i == 0) {
timer.cancel();
handler.complete(0);
} else {
handler.setProgressData(i--);
}
});
}
In JavaScript
dsBridge.call("callProgress", function (value) {
document.getElementById("progress").innerText = value
})
完好的示例代码请参阅example工程。
Javascript 对话框
DSBridge 已经完成了 JavaScript 的对话框函数(alert/confirm/prompt),假如你想自定义它们,经过DWebViewController
设置相关回调函数即可。DSBridge完成的对话框默许设置是模态的,这会挂起UI线程。
API 列表
Dart API
在 Dart 中咱们把完成了供 JavaScript 调用的 API 类的实例称为 Dart API object.
DWebViewController.addJavaScriptObject(JavaScriptNamespaceInterface? object, String? namespace)
Dart API object到DWebViewController,并为它指定一个命名空间。然后,在 JavaScript 中就能够经过bridge.call("namespace.api",...)
来调用Dart API object中的原生API了。
假如命名空间是空(null或空字符串), 那么这个增加的Dart API object就没有命名空间。在 JavaScript 经过 bridge.call("api",...)
调用。
示例:
In Dart
class JsEchoApi extends JavaScriptNamespaceInterface {
@override
void register() {
registerFunction(syn);
registerFunction(asyn);
}
dynamic syn(dynamic args) {
return args;
}
void asyn(dynamic args, CompletionHandler handler) {
handler.complete(args);
}
}
//namespace is "echo"
controller.addJavaScriptObject(JsEchoApi(), 'echo');
In 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));
})
DWebViewController.removeJavaScriptObject(String namespace)
经过命名空间称号移除相应的Dart API object。
DWebViewController.callHandler(String method, {List? args, OnReturnValue? handler})
调用 JavaScript API。handlerName
为 JavaScript API 的称号,能够包括命名空间;参数以数组传递,args
数组中的元素依次对应 JavaScript API的形参; handler
用于接纳 JavaScript API 的回来值,留意:handler将在Dart主isolate中被执行。
示例:
_controller.callHandler('append', args: ["I", "love", "you"],
handler: (retValue) {
print(retValue.toString());
});
/// call with namespace 'syn', More details to see the Demo project
_controller.callHandler('syn.getInfo', handler: (retValue) {
print(retValue.toString());
});
DWebViewController.javaScriptCloseWindowListener
当 JavaScript 中调用window.close
时,DWebViewController 会触发此监听器,你能够自定义回调进行处理。
Example:
controller.javaScriptCloseWindowListener = () {
print('window.close called');
};
DWebViewController.hasJavaScriptMethod(String handlerName, OnReturnValue existCallback)
检测是否存在指定的 JavaScript API,handlerName
能够包括命名空间.
示例:
_controller.hasJavaScriptMethod('addValue', (retValue) {
print(retValue.toString());
});
DWebViewController.dispose()
开释资源。在当前页面处于dispose状态时,你应该显式调用它。
JavaScript API
dsBridge
“dsBridge” 在初始化之后可用 .
dsBridge.call(method,[arg,callback])
同步或异步的调用Dart API。
method
: Dart API 称号, 能够包括命名空间。
arg
:传递给Dart API 的参数。只能传一个,假如需求多个参数时,能够合并成一个json目标参数。
callback(String returnValue)
: 处理Dart API的回来结果. 可选参数,只要异步调用时才需求供给.
dsBridge.register(methodName|namespace,function|synApiObject)
dsBridge.registerAsyn(methodName|namespace,function|asynApiObject)
注册同步/异步的 JavaScript API. 这两个办法都有两种调用方式:
-
注册一个一般的办法,如:
In JavaScript
dsBridge.register('addValue',function(l,r){ return l+r; }) dsBridge.registerAsyn('append',function(arg1,arg2,arg3,responseCallback){ responseCallback(arg1+" "+arg2+" "+arg3); })
In Dart
_controller.callHandler('addValue', args: [3, 4], handler: (retValue) { print(retValue.toString()); }); _controller.callHandler('append', args: ["I", "love", "you"], handler: (retValue) { print(retValue.toString()); });
-
注册一个目标,指定一个命名空间:
In JavaScript
//namespace test for synchronous calls 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 并不支撑函数重载,所以不能在同一个 JavaScript 目标中定义同名的同步函数和异步函数
In Dart
_controller.callHandler('test.test1', handler: (retValue) { print(retValue.toString()); }); _controller.callHandler('test1.test1', handler: (retValue) { print(retValue.toString()); });
dsBridge.hasNativeMethod(handlerName,[type])
检测Dart中是否存在名为handlerName
的API, handlerName
能够包括命名空间.
type
: 可选参数,["all"|"syn"|"asyn" ]
, 默许是 “all”.
//检测是否存在一个名为'testAsyn'的API(无论同步还是异步)
dsBridge.hasNativeMethod('testAsyn')
//检测test命名空间下是否存在一个’testAsyn’的API
dsBridge.hasNativeMethod('test.testAsyn')
// 检测是否存在一个名为"testSyn"的异步API
dsBridge.hasNativeMethod('testSyn','asyn') //false
最终
假如你喜爱DSBridge for Flutter,欢迎点点star和like,以便更多的人知道它, 谢谢 !