# flujs **Repository Path**: flujs_project/flujs ## Basic Information - **Project Name**: flujs - **Description**: flujs: js engine binding for flutter - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: main - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 1 - **Created**: 2024-12-28 - **Last Updated**: 2025-07-25 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # flujs 基于 JavaScriptCore 和 QuickJS 实现的 js engine binding. | js engine | android | iOS | windows | linux | macOS | web | | :-: | :-: | :-: | :-: | :-: | :-: | :-: | | QuickJS | ✅ | ✅ | ✅ | ✅ | ✅ | 🔳 | | JavaScriptCore | 🔳 | ✅ | 🔳 | 🔳 | ✅ | 🔳 | > ✅ : 支持 > 🔳 : 正在进行 ## 特性 - 开发者友好的 API: js 和 dart 互相调用 - 内置 xhr(支持cookie)、fetch、promise、timer、console 能力 - 支持多个 JSRuntime 并行 ## 快速开始 添加 `flujs`、`flujs_jsc` 或者 `flujs_qjs` 依赖 ```sh flutter pub add flujs flujs_qjs flujs_jsc ``` 1、创建 JSFRuntime ```dart import 'package:flujs_qjs/qjs.dart' as qjs; import 'package:flujs_jsc/jsc.dart' as jsc; var rt = qjs.getJSFRuntime(); ``` > 按需获取不同的 js 引擎实现。 > > jsc 的优势是成熟. > > qjs 的优势是动态库较小. 2、创建 JSFContext ```dart var ctx = rt.newContext(); ``` 3、加载内置函数 ```dart ctx.loadExtension(); ``` > 需要显式调用。也可以按需加载不同的内置函数。 4、执行 js 代码 ```dart var res = ctx.eval('''eval('2+2')'''); print(res.toString()); ``` > 当前只支持全局变量、全局函数. 5、js 调用 dart 函数 ```dart // 普通函数 ctx.addInterface('run', (args) { debugPrint('[native] $args'); return 1; }); // 异步函数 ctx.addInterface('runAsync1', (args) async { var completer = Completer(); Timer(const Duration(seconds: 1), () { completer.complete(1); }); return completer.future; }); ctx.addInterface('runAsync2', (args) async { var r = await asyn2(1); return r; }); Future asyn2(int delaySecs) async { var completer = Completer(); Timer(const Duration(seconds: delaySecs), () { completer.complete(1); }); return completer.future; } var res = ctx.eval(''' run('from js', 2); runAsync1().then(() => runAsync2()).then(console.log); 3; '''); debugPrint('runAsync: $res'); ``` 6、dart 调用 js 函数 ```js function injs(time) { console.log('injs -> ', time); } ``` ```dart var injs = ctx.globalObject.getProperty('injs'); assert(injs.isFunction()); injs.callAsFunction(arguments: [ JSFValueFactory.makeNumber(ctx, id) ]); ``` > 通过 context.globalObject 获取 js 定义的全局变量和全局函数 > > 如果需要隔离上下文,创建不同的 JSFContext 即可 7、自定义扩展 ```dart class CustomExtension extends JSFExtension {} ``` > 扩展的主要目的是在上下文中提前注入自定义逻辑。 > 内置的 xhr 依赖了 http 库, 而且支持自定义 HttpClient, 以便可以实现 http cache、rpc 等其他能力 ```dart class DioAdapter extends http.BaseClient { final dio = Dio(); @override Future send(http.BaseRequest request) async { final response = await dio.requestUri( request.url, options: Options(headers: request.headers), ); return http.StreamedResponse(response.data, response.statusCode ?? 400); } } class LoggingInterceptor implements InterceptorContract { @override Future interceptRequest({ required http.BaseRequest request, }) { print('[Logging] 😯 request: make cache or something.'); return Future.value(request); } @override Future interceptResponse({ required http.BaseResponse response, }) { print('[Logging] 😊 response: make cache or something.'); return Future.value(response); } @override Future shouldInterceptRequest() { return Future.value(true); } @override Future shouldInterceptResponse() { return Future.value(true); } } var ctx = rt.newContext()..loadExtension(xhr: client == null); final client = InterceptedClient.build( interceptors: [LoggingInterceptor()], ); final client = DioAdapter(); final client = HttpPackageAdapter(); ctx.extension ?.chain(XhrExtension(ctx, client_: client).chain(FetchExtension(ctx))) .load(); ``` > 注意: 调用 `extension?.chain` 后必须调用 `load` 才能将扩展加载到 `globalObject` 中 ## 调试 通过手动设置动态库文件或者自定义环境变量,你可以使用自己编译的 qjs 引擎来调试 ```sh # 安卓 将 libqjs.so 替换到 /flujs_qjs/android/src/main/jniLibs 目录下 或者 在 gradle.properties 配置文件或环境变量指定 flujs.qjs_baseUrl=https://xxxx, libqjs.so 打包为 qjs_android_[abi].tar.gz 即可 # iOS & macOS 将 libqjs.dylib 复制到 /flujs_qjs/[ios|macos]/Frameworks/ 目录下 或者 设置 QJS_BASEURL=https://xxx, libqjs.dylib 打包为 qjs_iphoneos.tar.gz/qjs_macosx.tar.gz # windows & linux 设置 QJS_BASEURL=https://xxx, libqjs.dll/libqjs.so 打包为 qjs_linux_abi.tar.gz/qjs_mingw_abi.tar.gz ``` 指定环境变量 QJS_FORCE_DOWNLOAD=true 强制从远端下载,不读取本地缓存动态库 quickjs 交叉编译参考文档[xmake quickjs-ng 交叉编译实践](https://blog.dang8080.cn/2024/11/17/09/) ## 待支持 - [x] esm module support. - [x] arrayBuffer/Blob support.fetch multiple response type support. ## 已知 bug - [x] toDart isArray cause crash. - [x] QJS xhr addInterface decode HttpHeader failed. - [x] QJS JSContext.create(rt,intrinsic: true) will cause crash. ## 致谢 - [flutter-js](https://github.com/abner/flutter_js) - [flutter-jscore](https://github.com/xuelongqy/flutter_jscore) - [flutter-qjs](https://github.com/ekibun/flutter_qjs) - [quickjs-android](https://github.com/seven332/quickjs-android) - [jsx](https://github.com/RxReader/jsc) - [minnet-quickjs](https://github.com/khanhas/minnet-quickjs)