Flutter JavaScript引擎插件flutter_qjs的使用
Flutter JavaScript引擎插件flutter_qjs的使用
flutter_qjs
该插件是基于quickjs
项目和dart:ffi
构建的一个简单的Flutter JavaScript引擎。目前该插件支持所有平台,除了web!
开始使用
基本用法
首先,创建一个FlutterQjs
对象,然后调用dispatch
来建立事件循环:
final engine = FlutterQjs(
stackSize: 1024 * 1024, // 更改堆栈大小
);
engine.dispatch();
使用evaluate
方法运行JavaScript脚本,它会同步执行,你可以使用await
来解析Promise
:
try {
print(engine.evaluate(code ?? ''));
} catch (e) {
print(e.toString());
}
方法close
可以销毁quickjs
运行时,如果再次调用evaluate
,它可以被重新创建。参数port
应该关闭以停止dispatch
循环,当不再需要它时。自v0.3.3版本起,将抛出引用泄漏异常。
try {
engine.port.close(); // 停止事件循环
engine.close(); // 关闭引擎
} on JSError catch(e) {
print(e); // 捕获引用泄漏异常
}
engine = null;
Dart与JavaScript之间的数据转换实现如下:
Dart | JavaScript |
---|---|
Bool | boolean |
Int | number |
Double | number |
String | string |
Uint8List | ArrayBuffer |
List | Array |
Map | Object |
Function(arg1, arg2, …, {thisVal}) JSInvokable.invoke([arg1, arg2, …], thisVal) |
function.call(thisVal, arg1, arg2, …) |
Future | Promise |
JSError | Error |
Object | DartObject |
使用模块
支持ES6模块并使用import
函数管理模块,可以通过moduleHandler
在Dart中进行处理:
final engine = FlutterQjs(
moduleHandler: (String module) {
if(module == "hello")
return "export default (name) => `hello ${name}!`;";
throw Exception("Module Not found");
},
);
然后在JavaScript中使用import
函数获取模块:
import("hello").then(({default: greet}) => greet("world"));
注意: 模块处理器对于每个模块名称只能调用一次。要重置模块缓存,调用FlutterQjs.close
然后再评估一次。
要在模块处理器中使用异步函数,请尝试在隔离线程上运行。
在隔离线程上运行
创建一个IsolateQjs
对象,并传递处理程序来解析模块。现在可以使用异步函数如rootBundle.loadString
来获取模块:
final engine = IsolateQjs(
moduleHandler: (String module) async {
return await rootBundle.loadString(
"js/" + module.replaceFirst(new RegExp(r".js$"), "") + ".js");
},
);
// 不需要调用engine.dispatch();
与在主线程上运行一样,使用evaluate
来运行JavaScript脚本。在隔离线程中,一切都返回异步结果,使用await
获取结果:
try {
print(await engine.evaluate(code ?? ''));
} catch (e) {
print(e.toString());
}
方法close
可以销毁隔离线程,如果再次调用evaluate
,它将被重新创建。
使用Dart函数(v0.3.0中的破坏性更改)
JavaScript脚本返回的函数将被转换为JSInvokable
。它不扩展Function
,使用invoke
方法来调用它:
(func as JSInvokable).invoke([arg1, arg2], thisVal);
注意: 评估返回JSInvokable
可能会导致引用泄漏。
你应该手动调用free
来释放JS引用。
(obj as JSRef).free();
// 或 JSRef.freeRecursive(obj);
传递给JSInvokable
的参数将自动释放。使用dup
来保持引用。
(obj as JSRef).dup();
// 或 JSRef.dupRecursive(obj);
自v0.3.0版本起,你可以在JSInvokable
参数中传递一个函数,默认情况下不再包含channel
函数。你可以使用JavaScript函数设置全局Dart对象。
例如,使用Dio
实现qjs中的HTTP请求:
final setToGlobalObject = await engine.evaluate("(key, val) => { this[key] = val; }");
await setToGlobalObject.invoke(["http", (String url) {
return Dio().get(url).then((response) => response.data);
}]);
setToGlobalObject.free();
在隔离线程中,传递到JSInvokable
的顶级函数将在隔离线程中调用。使用IsolateFunction
传递一个即时函数:
await setToGlobalObject.invoke([
"http",
IsolateFunction((String url) {
return Dio().get(url).then((response) => response.data);
}),
]);
示例代码
以下是一个完整的示例代码,展示了如何使用flutter_qjs
插件:
/*
* [@Description](/user/Description): example
* [@Author](/user/Author): ekibun
* [@Date](/user/Date): 2020-08-08 08:16:51
* [@LastEditors](/user/LastEditors): ekibun
* [@LastEditTime](/user/LastEditTime): 2020-12-02 11:28:06
*/
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_qjs/flutter_qjs.dart';
import 'highlight.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key key}) : super(key: key);
[@override](/user/override)
Widget build(BuildContext context) {
return MaterialApp(
title: 'flutter_qjs',
debugShowCheckedModeBanner: false,
theme: ThemeData(
appBarTheme: AppBarTheme(brightness: Brightness.dark, elevation: 0),
backgroundColor: Colors.grey[300],
primaryColorBrightness: Brightness.dark,
),
routes: {
'home': (BuildContext context) => TestPage(),
},
initialRoute: 'home',
);
}
}
class TestPage extends StatefulWidget {
[@override](/user/override)
State<StatefulWidget> createState() => _TestPageState();
}
class _TestPageState extends State<TestPage> {
String resp;
IsolateQjs engine;
CodeInputController _controller = CodeInputController(
text: 'import("hello").then(({default: greet}) => greet("world"));');
_ensureEngine() async {
if (engine != null) return;
engine = IsolateQjs(
moduleHandler: (String module) async {
return await rootBundle.loadString(
"js/" + module.replaceFirst(new RegExp(r".js$"), "") + ".js");
},
);
}
[@override](/user/override)
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("JS引擎测试"),
),
body: SingleChildScrollView(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: Row(
children: [
TextButton(
child: Text("评估"),
onPressed: () async {
await _ensureEngine();
try {
resp = (await engine.evaluate(_controller.text ?? '',
name: "<eval>"))
.toString();
} catch (e) {
resp = e.toString();
}
setState(() {});
}),
TextButton(
child: Text("重置引擎"),
onPressed: () async {
if (engine == null) return;
await engine.close();
engine = null;
}),
],
),
),
Container(
padding: const EdgeInsets.all(12),
color: Colors.grey.withOpacity(0.1),
constraints: BoxConstraints(minHeight: 200),
child: TextField(
autofocus: true,
controller: _controller,
decoration: null,
expands: true,
maxLines: null),
),
SizedBox(height: 16),
Text("结果:"),
SizedBox(height: 16),
Container(
width: double.infinity,
padding: const EdgeInsets.all(12),
color: Colors.green.withOpacity(0.05),
constraints: BoxConstraints(minHeight: 100),
child: Text(resp ?? ''),
),
],
),
),
);
}
}
更多关于Flutter JavaScript引擎插件flutter_qjs的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter JavaScript引擎插件flutter_qjs的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
flutter_qjs
是一个 Flutter 插件,它允许在 Flutter 应用中嵌入 QuickJS JavaScript 引擎。QuickJS 是一个轻量级、高效的 JavaScript 引擎,由 Fabrice Bellard 开发。使用 flutter_qjs
可以在 Flutter 应用中执行 JavaScript 代码,实现与 JavaScript 的互操作。
主要功能
- 在 Flutter 应用中执行 JavaScript 代码。
- 在 Dart 和 JavaScript 之间传递数据。
- 支持异步 JavaScript 执行。
- 支持 ES2020 标准。
安装
首先,在 pubspec.yaml
文件中添加 flutter_qjs
依赖:
dependencies:
flutter:
sdk: flutter
flutter_qjs: ^0.5.0 # 请使用最新版本
然后运行 flutter pub get
来安装依赖。
基本用法
-
初始化引擎
首先,需要初始化
Qjs
实例:import 'package:flutter_qjs/flutter_qjs.dart'; final engine = Qjs();
-
执行 JavaScript 代码
可以使用
evaluate
方法来执行 JavaScript 代码:void main() async { final engine = Qjs(); final result = await engine.evaluate('1 + 2'); print(result); // 输出: 3 }
-
在 Dart 和 JavaScript 之间传递数据
可以在 Dart 和 JavaScript 之间传递基本数据类型(如
int
,double
,String
,List
,Map
等)。void main() async { final engine = Qjs(); await engine.evaluate(''' function add(a, b) { return a + b; } '''); final result = await engine.call('add', [1, 2]); print(result); // 输出: 3 }
-
异步 JavaScript 执行
flutter_qjs
支持在 JavaScript 中使用 Promise 进行异步操作。你可以使用await
关键字来等待 Promise 的结果。void main() async { final engine = Qjs(); final result = await engine.evaluate(''' new Promise((resolve) => { setTimeout(() => resolve("Hello, World!"), 1000); }); '''); print(result); // 输出: Hello, World! }
-
在 JavaScript 中调用 Dart 函数
你可以将 Dart 函数传递给 JavaScript,并在 JavaScript 中调用它们。
void main() async { final engine = Qjs(); engine.setProperty('dartFunction', (args) { print('Called from JavaScript: $args'); return 'Dart response'; }); final result = await engine.evaluate(''' dartFunction("Hello from JavaScript"); '''); print(result); // 输出: Dart response }
-
销毁引擎
当不再需要引擎时,可以调用
dispose
方法来释放资源:engine.dispose();