Flutter's first truly commercial JSBridge framework (supports Android, iOS, HarmonyOS Next)
DSBridge for Flutter
Update: Official support for pure Harmony platforms (OpenHarmony & HarmonyOS Next)
Students who have done hybrid development on Android and iOS platforms will basically know DSBridge, which is currently the most popular JSBridge framework (there may not be one of them), in order to implement the native Hybrid ability (that is, the ability of H5 to interact with Dart) on the Flutter side, so we adapted it to the Flutter platform.
A modern, easy-to-use cross-platform JavaScript bridge that allows you to call each other's functions between JavaScript and Flutter synchronously or asynchronously.
overview
DSBridge for Flutter is fully compatible with Android and iOS DSBridge's dsbridge.js. Unlike other similar frameworks that can't make JavaScript calls to Dart and return results synchronously, this framework fully supports both synchronous and asynchronous calls. It is the first to fully implement all the functions of DSBridge on the original Android and iOS, so it can realize the complete migration of the original native Webview business to the Flutter implementation, that is, a set of code to implement the hybrid development of APP and H5. DSBridge for Flutter can be used in existing web projects that use dsbridge.js without any code modifications. DSBridge for Flutter is based on Flutter's official webview_flutter.dsbridge_flutter
Currently released on the official pub.dev: dsbridge_flutter
Also open sourced on github: dsbridge_flutter
If you think it's good, welcome to dot star and like, so that more people know about it, thank you !
With the help of this framework, the JS bridging methods that originally need to be implemented on the three platforms can be unified by Dart, which greatly reduces the communication and collaboration costs between developers on different devices of the App, and enables developers to focus more on the business itself rather than platform differences.
HarmonyOS’s Flutter SDK:gitee.com/openharmony…
In the example, ohos is a HarmonyOS project, and if Huawei provides a Next prototype (the system version is 300SP2 or later), it can be run directly after setting up a Flutter environment that supports HarmonyOS.
characteristic
Android、iOS 、OpenHarmony & HarmonyOS Next、JavaScript is easy to use, lightweight, powerful, secure and robust.
Both synchronous and asynchronous calls are supported
APIs can be managed in a centralized manner in the form of classes
API namespaces are supported
Debug mode is supported
API presence detection is supported
Progress callbacks: one call, multiple returns
JavaScript is supported to close page event callbacks
JavaScript modal dialogs are supported
Installation
Add dependencies
yml
Code Interpretation
Copying the code
dependencies: ... dsbridge_flutter: x.y.z
example
Please refer to Packages in the Project Directory. Run the project and see the sample interactions.exampleexample
If you want to use dsBridge in your own project:
use
Create a Dart class to implement the API
dart
Code Interpretation
Copy Code
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]"); } }
All Dart APIs must be registered with registerFunction in the register function.
Adding API Class Instances to DWebViewController
dart
Code Interpretation
Copy Code
import 'package:dsbridge_flutter/dsbridge_flutter.dart'; ... late final DWebViewController _controller; ... _controller.addJavaScriptObject(JsApi(), null);
Call the Dart API in JavaScript and register a JavaScript API for native calls.
Initialize dsBridge
javascript
//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")
Call the Dart API, and register a JavaScript API for Dart to call.
javascript
//synchronous call var str=dsBridge.call("testSyn","testSyn"); //asynchronous call dsBridge.call("testAsyn","testAsyn", function (v) { alert(v); }) //注册 JavaScript API dsBridge.register('addValue',function(l,r){ return l+r; })
Calling JavaScript APIs in Dart
dart
import 'package:dsbridge_flutter/dsbridge_flutter.dart'; ... late final DWebViewController _controller; ... _controller.callHandler('addValue', args: [3, 4], handler: (retValue) { print(retValue.toString()); });
Dart API signatures
In order to be compatible with Android, iOS, and HarmonyOS, we agree on Dart API signatures, note that if the API signature is not valid, it will not be called! The signature is as follows:
Sync API.
any handler(dynamic msg)
The parameter must be of type and must be declared (if the parameter is not required, it will not be applicable). There is no limit to the type of return value, which can be arbitrary.
dynamic
Asynchronous API.
void handler(dynamic arg, CompletionHandler handler)
Namespace
Namespaces can help you better manage APIs, which is useful when there are a lot of APIs, such as in hybrid applications. DSBridge allows you to classify and manage APIs by namespace, and the namespace supports multiple levels, and the different levels only need to be separated by '.'.
Debug mode
In debug mode, when some errors occur, they will be prompted in the form of pop-ups, and the Dart API will not be automatically caught if the exception is triggered, as the problem should be exposed during the debugging phase.
Progress callbacks
Normally, a method will be called after it will return a result, which is a one-to-one correspondence. However, sometimes there are scenarios where a call needs to be returned multiple times, such as calling a download file function on the end in JavaScript, the server will notify the JavaScript progress many times during the download process, and then the JavaScript will display the progress information on the h5 page, which is a typical scenario of one call and multiple returns, if you use other JavaScript bridges, you will find that it will be more troublesome to implement this function, and DSBridge itself supports progress callbacks, you can easily and conveniently implement the scenario that a call needs to be returned multiple times, and we will implement an example of a countdown below:
In Dart
dart
Code Interpretation
Copy Code
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
javascript
Code Interpretation
Copy Code
dsBridge.call("callProgress", function (value) { document.getElementById("progress").innerText = value })
For the complete sample code, see the example project.
Javascript dialog box
DSBridge already implements JavaScript dialog functions (alert/confirm/prompt), and if you want to customize them, you can do so by setting the relevant callback functions. The dialog default settings implemented by DSBridge are modal, which suspends the UI thread.DWebViewController
List of APIs
Dart API
In Dart, we call an instance of an API class that implements a JavaScript call a Dart API object.
DWebViewController.addJavaScriptObject(JavaScriptNamespaceInterface? object, String? namespace)
Dart API object to the DWebViewController and specify a namespace for it. Then, in JavaScript, you can call the native API in the Dart API object.bridge.call("namespace.api",...)
If the namespace is empty (null or empty string), then the added Dart API object does not have a namespace. In JavaScript via .bridge.call("api",...)
Examples:
In Dart
dart
Code Interpretation
Copy Code
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
javascript
Code Interpretation
Copy Code
// 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)
Removes the corresponding Dart API object by namespace name.
DWebViewController.callHandler(String method, {List? args, OnReturnValue? handler})
Call the JavaScript API. is the name of the JavaScript API, which can contain a namespace; Parameters are passed in arrays, and the elements in the array correspond to the JavaScript API parameters. Used to receive the return value of the JavaScript API, note: the handler will be executed in the main Dart isolate.handlerNameargshandler
Example:
dart
_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
When called in JavaScript, DWebViewController triggers this listener, and you can customize the callback to handle it.window.close
Example:
dart
Code Interpretation
Copy Code
controller.javaScriptCloseWindowListener = () { print('window.close called'); };
DWebViewController.hasJavaScriptMethod(String handlerName, OnReturnValue existCallback)
Detects the presence of a specified JavaScript API, which can contain namespaces.handlerName
Example:
dart
Code Interpretation
Copy Code
_controller.hasJavaScriptMethod('addValue', (retValue) { print(retValue.toString()); });
DWebViewController.dispose()
Free up resources. You should explicitly call it when the current page is in the dispose state.
JavaScript API
dsBridge
"dsBridge" is available after initialization.
dsBridge.call(method,[arg,callback])
Synchronous or asynchronous calls to the Dart API.
method
: The name of the Dart API, which can contain a namespace.
arg
: Arguments passed to the Dart API. You can only pass one, and if you need multiple parameters, you can merge them into one JSON object parameter.
callback(String returnValue)
: Handles the return result of the Dart API. Optional arguments, which are only required for asynchronous calls.
dsBridge.register(methodName|namespace,function|synApiObject)
dsBridge.registerAsyn(methodName|namespace,function|asynApiObject)
Register synchronous/asynchronous JavaScript APIs. Both methods can be called in two ways:
Sign up for a common method such as:
In JavaScript
javascript
dsBridge.register('addValue',function(l,r){ return l+r; }) dsBridge.registerAsyn('append',function(arg1,arg2,arg3,responseCallback){ responseCallback(arg1+" "+arg2+" "+arg3); })
In Dart
dart
_controller.callHandler('addValue', args: [3, 4], handler: (retValue) { print(retValue.toString()); }); _controller.callHandler('append', args: ["I", "love", "you"], handler: (retValue) { print(retValue.toString()); });
To register an object, specify a namespace:
In JavaScript
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") } })
Because JavaScript doesn't support function overloading, you can't define synchronous and asynchronous functions with the same name in the same JavaScript object
In Dart
dart
_controller.callHandler('test.test1', handler: (retValue) { print(retValue.toString()); }); _controller.callHandler('test1.test1', handler: (retValue) { print(retValue.toString()); });
dsBridge.hasNativeMethod(handlerName,[type])
Detects the presence of an API named in Dart, which can contain namespaces.handlerNamehandlerName
type
: Optional, default is "all".["all"|"syn"|"asyn" ]
javascript
//Detects the presence of a file named 'testAsyn' API (whether synchronous or asynchronous) dsBridge.hasNativeMethod('testAsyn') // Detect if there is a 'testAsyn' API in the test namespace dsBridge. hasNativeMethod('test.testAsyn') // Detect if there is an asynchronous API named “testSyn”. dsBridge.hasNativeMethod('testSyn','asyn') //false
At last
If you like DSBridge for Flutter, welcome to dot star and like so that more people know about it, thank you !