2021-01-24 21:12:13 +08:00
2021-01-22 16:05:19 +08:00
2020-09-16 00:42:07 +08:00
2020-09-25 00:01:18 +08:00
2021-01-24 21:12:13 +08:00
2021-01-24 21:12:13 +08:00
2021-01-21 19:50:16 -08:00
2021-01-24 21:12:13 +08:00
2020-09-25 00:01:18 +08:00
2021-01-21 19:50:16 -08:00
2021-01-24 21:12:13 +08:00
2020-09-25 00:01:18 +08:00
2021-01-21 19:50:16 -08:00
2020-09-16 00:43:16 +08:00
2020-08-08 18:00:21 +08:00
2021-01-24 21:12:13 +08:00
2020-08-12 23:24:01 +08:00
2020-08-15 14:52:53 +08:00
2020-12-02 11:39:21 +08:00
2021-01-24 21:12:13 +08:00
2021-01-24 21:12:13 +08:00

flutter_qjs

Pub Test

This plugin is a simple js engine for flutter using the quickjs project with dart:ffi. Plugin currently supports all the platforms except web!

Getting Started

Basic usage

Firstly, create a FlutterQjs object, then call dispatch to dispatch event loop:

final engine = FlutterQjs(
  stackSize: 1024 * 1024, // change stack size here.
);
engine.dispatch();

Use evaluate method to run js script, now you can use it synchronously, or use await to resolve Promise:

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.

engine.port.close(); // stop dispatch loop
engine.close();      // close engine
engine = null;

Data conversion between dart and js are implemented as follow:

dart js
Bool boolean
Int number
Double number
String string
Uint8List ArrayBuffer
List Array
Map Object
Function function(....args)
Future Promise
Object DartObject

notice: Dart function parameter thisVal is used to store this in js.

Use modules

ES6 module with import function is supported and can be managed in dart with moduleHandler:

final engine = FlutterQjs(
  moduleHandler: (String module) {
    if(module == "hello")
      return "export default (name) => `hello \${name}!`;";
    throw Exception("Module Not found");
  },
);

then in JavaScript, import function is used to get modules:

import("hello").then(({default: greet}) => greet("world"));

notice: Module handler should be called only once for each module name. To reset the module cache, call FlutterQjs.close then evaluate again.

To use async function in module handler, try Run on isolate thread

Run on isolate thread

Create a IsolateQjs object, pass handlers to resolving modules. Async function such as rootBundle.loadString can be used now to get modules:

dynamic methodHandler(String method, List arg) {
  switch (method) {
    case "http":
      return Dio().get(arg[0]).then((response) => response.data);
    default:
      throw Exception("No such method");
  }
}
final engine = IsolateQjs(
  methodHandler: methodHandler,
  moduleHandler: (String module) async {
    return await rootBundle.loadString(
        "js/" + module.replaceFirst(new RegExp(r".js$"), "") + ".js");
  },
);
// not need engine.dispatch();

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:

try {
  print(await engine.evaluate(code ?? ''));
} catch (e) {
  print(e.toString());
}

Method close can destroy quickjs runtime that can be recreated again if you call evaluate.

notice: Make sure arguments passed to IsolateJSFunction are avaliable for isolate, such as primities and top level function. Method bind can help to pass instance function to isolate:

await setToGlobalObject("func", await engine.bind(() {
  // DO SOMETHING
}))

This example contains a complete demonstration on how to use this plugin.

Breaking change in v0.3.0

channel function is no longer utilized by default. Use js function to set to global:

final setToGlobalObject = await engine.evaluate("(key, val) => this[key] = val;");
setToGlobalObject("channel", methodHandler);
Description
A quickjs engine for flutter.
Readme MIT 3 MiB
Languages
C 95%
Dart 2.5%
C++ 1.3%
CMake 0.8%
Ruby 0.2%