mirror of
https://github.com/wgh136/flutter_qjs.git
synced 2025-09-27 05:27:23 +00:00
update readme
This commit is contained in:
@@ -6,6 +6,10 @@
|
|||||||
* @LastEditTime: 2020-12-02 11:36:40
|
* @LastEditTime: 2020-12-02 11:36:40
|
||||||
-->
|
-->
|
||||||
|
|
||||||
|
## 0.2.1
|
||||||
|
|
||||||
|
* code cleanup.
|
||||||
|
|
||||||
## 0.2.0
|
## 0.2.0
|
||||||
|
|
||||||
* breakdown change with new constructor.
|
* breakdown change with new constructor.
|
||||||
|
96
README.md
96
README.md
@@ -7,17 +7,38 @@
|
|||||||
-->
|
-->
|
||||||
# flutter_qjs
|
# flutter_qjs
|
||||||
|
|
||||||
A quickjs engine for flutter.
|
|
||||||
|
|
||||||
## Feature
|
|
||||||
|
|
||||||
This plugin is a simple js engine for flutter using the `quickjs` project with `dart:ffi`. Plugin currently supports all the platforms except web!
|
This plugin is a simple js engine for flutter using the `quickjs` project with `dart:ffi`. Plugin currently supports all the platforms except web!
|
||||||
|
|
||||||
Event loop of `FlutterQjs` should be implemented by calling `FlutterQjs.dispatch()`.
|
## Getting Started
|
||||||
|
|
||||||
ES6 module with `import` function is supported and can be managed in dart with `setModuleHandler`.
|
### Basic usage
|
||||||
|
|
||||||
A global function `channel` is presented to invoke dart function. Data conversion between dart and js are implemented as follow:
|
Firstly, create a `FlutterQjs` object, then call `dispatch` to dispatch event loop:
|
||||||
|
|
||||||
|
```dart
|
||||||
|
final engine = FlutterQjs()
|
||||||
|
engine.dispatch();
|
||||||
|
```
|
||||||
|
|
||||||
|
Use `evaluate` method to run js script, now you can use it synchronously, or use await to resolve `Promise`:
|
||||||
|
|
||||||
|
```dart
|
||||||
|
try {
|
||||||
|
print(engine.evaluate(code ?? ''));
|
||||||
|
} catch (e) {
|
||||||
|
print(e.toString());
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Method `close` can destroy quickjs runtime that can be recreated again if you call `evaluate`. Parameter `port` should be close to stop `dispatch` loop when you do not need it.
|
||||||
|
|
||||||
|
```dart
|
||||||
|
engine.port.close(); // stop dispatch loop
|
||||||
|
engine.close(); // close engine
|
||||||
|
engine = null;
|
||||||
|
```
|
||||||
|
|
||||||
|
Data conversion between dart and js are implemented as follow:
|
||||||
|
|
||||||
| dart | js |
|
| dart | js |
|
||||||
| --------------------------------------------------- | ------------------ |
|
| --------------------------------------------------- | ------------------ |
|
||||||
@@ -31,13 +52,13 @@ A global function `channel` is presented to invoke dart function. Data conversio
|
|||||||
| JSFunction(...args) <br> IsolateJSFunction(...args) | function(....args) |
|
| JSFunction(...args) <br> IsolateJSFunction(...args) | function(....args) |
|
||||||
| Future | Promise |
|
| Future | Promise |
|
||||||
|
|
||||||
**notice:** `function` can only be sent from js to dart. `IsolateJSFunction` always returns asynchronously.
|
**notice:** `function` can only be sent from js to dart.
|
||||||
|
|
||||||
## Getting Started
|
### Invoke dart function
|
||||||
|
|
||||||
### Run on main thread
|
A global JavaScript function `channel` is presented to invoke dart function.
|
||||||
|
|
||||||
1. Create a `FlutterQjs` object, pass handlers to implement js-dart interaction and resolving modules. For example, you can use `Dio` to implement http in js:
|
In constructor, pass handler function to manage JavaScript call. For example, you can use `Dio` to implement http in JavaScript:
|
||||||
|
|
||||||
```dart
|
```dart
|
||||||
final engine = FlutterQjs(
|
final engine = FlutterQjs(
|
||||||
@@ -49,6 +70,21 @@ final engine = FlutterQjs(
|
|||||||
throw Exception("No such method");
|
throw Exception("No such method");
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
then, in java script you can use channel function to invoke `methodHandler`, make sure the second parameter is a list:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
channel("http", ["http://example.com/"]);
|
||||||
|
```
|
||||||
|
|
||||||
|
### Use modules
|
||||||
|
|
||||||
|
ES6 module with `import` function is supported and can be managed in dart with `moduleHandler`:
|
||||||
|
|
||||||
|
```dart
|
||||||
|
final engine = FlutterQjs(
|
||||||
moduleHandler: (String module) {
|
moduleHandler: (String module) {
|
||||||
if(module == "hello")
|
if(module == "hello")
|
||||||
return "export default (name) => `hello \${name}!`;";
|
return "export default (name) => `hello \${name}!`;";
|
||||||
@@ -57,41 +93,19 @@ final engine = FlutterQjs(
|
|||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
in javascript, `channel` function is equiped to invoke `methodHandler`, make sure the second parameter is a list:
|
then in JavaScript, `import` function is used to get modules:
|
||||||
|
|
||||||
```javascript
|
|
||||||
channel("http", ["http://example.com/"]);
|
|
||||||
```
|
|
||||||
|
|
||||||
`import` function is used to get modules:
|
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
import("hello").then(({default: greet}) => greet("world"));
|
import("hello").then(({default: greet}) => greet("world"));
|
||||||
```
|
```
|
||||||
|
|
||||||
**notice:** To use async function in module handler, try [Run on isolate thread](#Run-on-isolate-thread)
|
**notice:** Module handler should be called only once for each module name. To reset the module cache, call `FlutterQjs.close` then `evaluate` again.
|
||||||
|
|
||||||
2. Then call `dispatch` to dispatch event loop.
|
To use async function in module handler, try [Run on isolate thread](#Run-on-isolate-thread)
|
||||||
|
|
||||||
```dart
|
|
||||||
engine.dispatch();
|
|
||||||
```
|
|
||||||
|
|
||||||
1. Use `evaluate` to run js script, now you can use it synchronously, or use await to resolve `Promise`:
|
|
||||||
|
|
||||||
```dart
|
|
||||||
try {
|
|
||||||
print(engine.evaluate(code ?? ''));
|
|
||||||
} catch (e) {
|
|
||||||
print(e.toString());
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
1. Method `close` can destroy quickjs runtime that can be recreated again if you call `evaluate`.
|
|
||||||
|
|
||||||
### Run on isolate thread
|
### Run on isolate thread
|
||||||
|
|
||||||
1. Create a `IsolateQjs` object, pass handlers to implement js-dart interaction and resolving modules. The `methodHandler` is used in isolate, so **the handler function must be a top-level function or a static method**. Async function such as `rootBundle.loadString` can be used now to get module:
|
Create a `IsolateQjs` object, pass handlers to implement js-dart interaction and resolving modules. The `methodHandler` is used in isolate, so **the handler function must be a top-level function or a static method**. Async function such as `rootBundle.loadString` can be used now to get modules:
|
||||||
|
|
||||||
```dart
|
```dart
|
||||||
dynamic methodHandler(String method, List arg) {
|
dynamic methodHandler(String method, List arg) {
|
||||||
@@ -112,7 +126,7 @@ final engine = IsolateQjs(
|
|||||||
// not need engine.dispatch();
|
// not need engine.dispatch();
|
||||||
```
|
```
|
||||||
|
|
||||||
2. Same as run on main thread, use `evaluate` to run js script. In this way, `Promise` return by `evaluate` will be automatically tracked and return the resolved data:
|
Same as run on main thread, use `evaluate` to run js script. In this way, `Promise` return by `evaluate` will be automatically tracked and return the resolved data:
|
||||||
|
|
||||||
```dart
|
```dart
|
||||||
try {
|
try {
|
||||||
@@ -122,11 +136,11 @@ try {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
3. Method `close` can destroy quickjs runtime that can be recreated again if you call `evaluate`.
|
Method `close` can destroy quickjs runtime that can be recreated again if you call `evaluate`.
|
||||||
|
|
||||||
[This example](example/lib/main.dart) contains a complete demonstration on how to use this plugin.
|
[This example](example/lib/main.dart) contains a complete demonstration on how to use this plugin.
|
||||||
|
|
||||||
## For Mac & IOS developer
|
## For macOS & iOS developer
|
||||||
|
|
||||||
I am new to Xcode and iOS developing, and I cannot find a better way to support both simulators and real devices without combining the binary frameworks. To reduce build size, change the `s.vendored_frameworks` in `ios/flutter_qjs.podspec` to the specific framework.
|
I am new to Xcode and iOS developing, and I cannot find a better way to support both simulators and real devices without combining the binary frameworks. To reduce build size, change the `s.vendored_frameworks` in `ios/flutter_qjs.podspec` to the specific framework.
|
||||||
|
|
||||||
@@ -146,4 +160,4 @@ Two additional notes:
|
|||||||
|
|
||||||
1. quickjs built with `release` config has bug in resolving `Promise`. Please let me know if you know the solution.
|
1. quickjs built with `release` config has bug in resolving `Promise`. Please let me know if you know the solution.
|
||||||
|
|
||||||
2. `ios/make.sh` limit the build architectures to avoid combine conflicts. Change the `make.sh` to support another architectures.
|
2. `ios/make.sh` limits the build architectures to avoid combining conflicts. Change the `make.sh` to support another architectures.
|
@@ -82,7 +82,7 @@ packages:
|
|||||||
path: ".."
|
path: ".."
|
||||||
relative: true
|
relative: true
|
||||||
source: path
|
source: path
|
||||||
version: "0.2.0"
|
version: "0.2.1"
|
||||||
flutter_test:
|
flutter_test:
|
||||||
dependency: "direct dev"
|
dependency: "direct dev"
|
||||||
description: flutter
|
description: flutter
|
||||||
|
@@ -13,23 +13,28 @@ import 'package:ffi/ffi.dart';
|
|||||||
import 'package:flutter_qjs/ffi.dart';
|
import 'package:flutter_qjs/ffi.dart';
|
||||||
import 'package:flutter_qjs/wrapper.dart';
|
import 'package:flutter_qjs/wrapper.dart';
|
||||||
|
|
||||||
/// Handle function to manage js call with `dart(method, ...args)` function.
|
/// Handler function to manage js call.
|
||||||
typedef JsMethodHandler = dynamic Function(String method, List args);
|
typedef JsMethodHandler = dynamic Function(String method, List args);
|
||||||
|
|
||||||
/// Handle function to manage js module.
|
/// Handler function to manage js module.
|
||||||
typedef JsModuleHandler = String Function(String name);
|
typedef JsModuleHandler = String Function(String name);
|
||||||
|
|
||||||
class FlutterQjs {
|
class FlutterQjs {
|
||||||
Pointer _rt;
|
Pointer _rt;
|
||||||
Pointer _ctx;
|
Pointer _ctx;
|
||||||
|
|
||||||
|
/// Message Port for event loop. Close it to stop dispatching event loop.
|
||||||
ReceivePort port = ReceivePort();
|
ReceivePort port = ReceivePort();
|
||||||
|
|
||||||
/// Set a handler to manage js call with `channel(method, args)` function.
|
/// Handler function to manage js call with `channel(method, [...args])` function.
|
||||||
JsMethodHandler methodHandler;
|
JsMethodHandler methodHandler;
|
||||||
|
|
||||||
/// Set a handler to manage js module.
|
/// Handler function to manage js module.
|
||||||
JsModuleHandler moduleHandler;
|
JsModuleHandler moduleHandler;
|
||||||
|
|
||||||
|
/// Quickjs engine for flutter.
|
||||||
|
///
|
||||||
|
/// Pass handlers to implement js-dart interaction and resolving modules.
|
||||||
FlutterQjs({this.methodHandler, this.moduleHandler});
|
FlutterQjs({this.methodHandler, this.moduleHandler});
|
||||||
|
|
||||||
_ensureEngine() {
|
_ensureEngine() {
|
||||||
@@ -77,7 +82,7 @@ class FlutterQjs {
|
|||||||
_ctx = null;
|
_ctx = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// DispatchMessage
|
/// Dispatch JavaScript Event loop.
|
||||||
Future<void> dispatch() async {
|
Future<void> dispatch() async {
|
||||||
await for (var _ in port) {
|
await for (var _ in port) {
|
||||||
if (_rt == null) continue;
|
if (_rt == null) continue;
|
||||||
|
@@ -211,13 +211,17 @@ typedef JsIsolateSpawn = void Function(SendPort sendPort);
|
|||||||
class IsolateQjs {
|
class IsolateQjs {
|
||||||
Future<SendPort> _sendPort;
|
Future<SendPort> _sendPort;
|
||||||
|
|
||||||
/// Set a handler to manage js call with `channel(method, args)` function.
|
/// Handler to manage js call with `channel(method, [...args])` function.
|
||||||
/// The function must be a top-level function or a static method
|
/// The function must be a top-level function or a static method.
|
||||||
JsMethodHandler methodHandler;
|
JsMethodHandler methodHandler;
|
||||||
|
|
||||||
/// Set a handler to manage js module.
|
/// Asynchronously handler to manage js module.
|
||||||
JsAsyncModuleHandler moduleHandler;
|
JsAsyncModuleHandler moduleHandler;
|
||||||
|
|
||||||
|
/// Quickjs engine runing on isolate thread.
|
||||||
|
///
|
||||||
|
/// Pass handlers to implement js-dart interaction and resolving modules. The `methodHandler` is
|
||||||
|
/// used in isolate, so **the handler function must be a top-level function or a static method**.
|
||||||
IsolateQjs({this.methodHandler, this.moduleHandler});
|
IsolateQjs({this.methodHandler, this.moduleHandler});
|
||||||
|
|
||||||
_ensureEngine() {
|
_ensureEngine() {
|
||||||
@@ -257,6 +261,7 @@ class IsolateQjs {
|
|||||||
_sendPort = completer.future;
|
_sendPort = completer.future;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Free Runtime and close isolate thread that can be recreate when evaluate again.
|
||||||
close() {
|
close() {
|
||||||
if (_sendPort == null) return;
|
if (_sendPort == null) return;
|
||||||
_sendPort.then((sendPort) {
|
_sendPort.then((sendPort) {
|
||||||
@@ -267,6 +272,7 @@ class IsolateQjs {
|
|||||||
_sendPort = null;
|
_sendPort = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Evaluate js script.
|
||||||
Future<dynamic> evaluate(String command, {String name, int evalFlags}) async {
|
Future<dynamic> evaluate(String command, {String name, int evalFlags}) async {
|
||||||
_ensureEngine();
|
_ensureEngine();
|
||||||
var evaluatePort = ReceivePort();
|
var evaluatePort = ReceivePort();
|
||||||
@@ -281,8 +287,7 @@ class IsolateQjs {
|
|||||||
var result = await evaluatePort.first;
|
var result = await evaluatePort.first;
|
||||||
if (result['error'] == null) {
|
if (result['error'] == null) {
|
||||||
return _decodeData(result['data'], sendPort);
|
return _decodeData(result['data'], sendPort);
|
||||||
}
|
} else
|
||||||
else
|
|
||||||
throw result['error'];
|
throw result['error'];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
name: flutter_qjs
|
name: flutter_qjs
|
||||||
description: This plugin is a simple js engine for flutter using the `quickjs` project. Plugin currently supports all the platforms except web!
|
description: This plugin is a simple js engine for flutter using the `quickjs` project. Plugin currently supports all the platforms except web!
|
||||||
version: 0.2.0
|
version: 0.2.1
|
||||||
homepage: https://github.com/ekibun/flutter_qjs
|
homepage: https://github.com/ekibun/flutter_qjs
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
|
Reference in New Issue
Block a user