Flutter嵌入式JavaScript引擎插件quickjs的使用
Flutter嵌入式JavaScript引擎插件quickjs的使用
简介
quickjs-dart
是一个基于 Dart 的 quickjs
绑定,使用最新的 ffi
工具 native_assets_cli
。它允许在 Dart 应用中运行 JavaScript 代码,而无需使用 Flutter 的通道机制。quickjs-dart
支持所有平台(除 Web 外),集成的 quickjs
版本为 2024-02-14
。
你可以通过以下命令运行示例:
dart --enable-experiment=native-assets run example/example.dart
异步操作
所有与 quickjs
原生代码的交互都通过 dart:ffi
在一个独立的隔离区(isolate)中运行,这确保了 JavaScript 评估不会阻塞主线程,这也是与 flutter_js
的不同之处。
以下是异步执行 JavaScript 代码的示例:
import 'package:quickjs/quickjs.dart';
void _runAsync() async {
// 创建引擎管理器
final manager = await JsEngineManager.create();
// 创建一个名为 'my-tag' 的引擎实例
final engine = await manager.createEngine('my-tag');
// 执行 JavaScript 代码并获取结果
final result = await engine.eval('console.log("Hello~");');
// 打印 JavaScript 控制台输出
print(result.stdout); // "Hello~"
// 释放引擎资源
await engine.dispose();
// 释放管理器资源
await manager.dispose();
}
同步操作
quickjs-dart
也可以在主线程中同步执行 JavaScript 代码,只需使用不同的对象:
import 'package:quickjs/src/native_js_engine.dart';
void _runSync() {
// 创建原生引擎管理器
final manager = NativeEngineManager();
// 创建一个名为 'my-tag' 的原生引擎实例
final engine = NativeJsEngine(name: 'my-tag');
// 执行 JavaScript 代码并获取结果
final result = engine.eval('3-4');
// 打印计算结果
print(result.value); // "-1"
// 释放引擎资源
engine.dispose();
// 释放管理器资源
manager.dispose();
}
回调通知
如果你想从 JavaScript 代码中直接接收数据,需要在 Dart 侧注册一个回调函数:
import 'package:quickjs/quickjs.dart';
void _registerBridge(int n) async {
// 创建引擎管理器
final manager = await JsEngineManager.create();
// 创建一个名为 'tag' 的引擎实例
final engine = await manager.createEngine('tag');
// 注册一个名为 '_onDataChanged' 的回调函数
engine.registerBridge('_onDataChanged', (data) {
print('notified from js: $data');
});
// 定义 JavaScript 代码
final code = """
let obj = {
update(v) {
let s = JSON.stringify(v);
console.log(`update: \${s}`);
_ffiNotify("_onDataChanged", s);
return s;
}
};
obj.update({"key": $n});
""";
// 执行 JavaScript 代码并获取结果
final result = await engine.eval(code);
// 打印评估结果和控制台输出
print("eval result: '${result.value}'");
print("eval stdout: '${result.stdout?.trim()}'");
// 释放引擎资源
await engine.dispose();
// 释放管理器资源
await manager.dispose();
}
内置 JavaScript 函数
quickjs-dart
提供了一些内置的 JavaScript 函数:
console.log
setTimeout
_ffiNotify
这些函数可以直接在 JavaScript 代码中使用,例如 _ffiNotify
用于从 JavaScript 调用 Dart 侧的回调函数。
完整示例 Demo
以下是一个完整的示例,展示了如何在 Flutter 应用中使用 quickjs-dart
:
import 'package:flutter/material.dart';
import 'package:quickjs/quickjs.dart';
import 'package:quickjs/src/native_js_engine.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
[@override](/user/override)
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(title: Text('QuickJS Demo')),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
ElevatedButton(
onPressed: _runAsync,
child: Text('Run Async JS'),
),
ElevatedButton(
onPressed: _runSync,
child: Text('Run Sync JS'),
),
ElevatedButton(
onPressed: () => _registerBridge(5),
child: Text('Register Bridge'),
),
],
),
),
),
);
}
void _runAsync() async {
final manager = await JsEngineManager.create();
final engine = await manager.createEngine('tag');
final result = await engine.eval('console.log(3+4);');
print(result.stdout?.trim());
await engine.dispose();
await manager.dispose();
}
void _runSync() {
final manager = NativeEngineManager();
final engine = NativeJsEngine(name: 'tag');
final result = engine.eval('3-4');
print(result.value);
engine.dispose();
manager.dispose();
}
void _registerBridge(int n) async {
final manager = await JsEngineManager.create();
final engine = await manager.createEngine('tag');
engine.registerBridge('_onDataChanged', (data) {
print('notified from js: $data');
});
final code = """
let obj = {
update(v) {
let s = JSON.stringify(v);
console.log(`update: \${s}`);
_ffiNotify("_onDataChanged", s);
return s;
}
};
obj.update({"key": $n});
""";
final result = await engine.eval(code);
print("eval result: '${result.value}'");
print("eval stdout: '${result.stdout?.trim()}'");
await engine.dispose();
await manager.dispose();
}
}
更多关于Flutter嵌入式JavaScript引擎插件quickjs的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter嵌入式JavaScript引擎插件quickjs的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
在Flutter中,使用QuickJS作为嵌入式JavaScript引擎插件,可以通过创建一个自定义的Flutter插件来实现。QuickJS是一个小型的、快速的JavaScript引擎,适用于嵌入式应用。以下是一个基本的代码案例,展示了如何在Flutter中集成和使用QuickJS。
步骤 1: 创建Flutter插件项目
首先,创建一个新的Flutter插件项目。你可以使用以下命令:
flutter create --org com.example --template=plugin quickjs_flutter_plugin
步骤 2: 添加QuickJS到原生代码
在quickjs_flutter_plugin/ios
和quickjs_flutter_plugin/android
目录下,分别添加QuickJS的依赖和代码。
iOS
- 在
quickjs_flutter_plugin/ios/Podfile
中添加QuickJS的依赖(如果QuickJS有CocoaPods支持的话;否则,你可能需要手动集成)。
platform :ios, '10.0'
target 'quickjs_flutter_plugin' do
use_frameworks!
pod 'QuickJS', '~> 1.0' # 假设QuickJS有一个CocoaPods包
# Flutter Pod
flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__))
end
- 创建一个Objective-C或Swift桥接文件,用于与QuickJS交互。
// QuickJSPlugin.m
#import <Flutter/Flutter.h>
#import <QuickJS/QuickJS.h> // 假设QuickJS头文件是这样导入的
@interface QuickJSPlugin : NSObject<FlutterPlugin>
@end
@implementation QuickJSPlugin
+ (void)registerWithRegistrar:(NSObject<FlutterPluginRegistrar> *)registrar {
FlutterMethodChannel *channel = [FlutterMethodChannel
methodChannelWithName:@"quickjs_flutter_plugin"
binaryMessenger:registrar.messenger];
QuickJSPlugin *instance = [[QuickJSPlugin alloc] init];
[channel setMethodCallHandler:[instance methodCallHandler]];
}
- (FlutterMethodCallHandler)methodCallHandler {
return ^(FlutterMethodCall *call, FlutterResult result) {
if ([@"execute" isEqualToString:call.method]) {
NSString *jsCode = call.arguments[@"code"];
// 初始化QuickJS环境
JSRuntime *rt = JS_NewRuntime();
JSContext *ctx = JS_NewContext(rt);
// 执行JavaScript代码
JSValue resultVal = JS_Eval(ctx, [jsCode UTF8String], strlen([jsCode UTF8String]), "<input>", JS_EVAL_TYPE_GLOBAL);
// 处理JavaScript执行结果
if (JS_IsException(resultVal)) {
result(@[@"Error executing JavaScript"]);
} else {
// 将结果转换为字符串并返回给Flutter
char *str = JS_ToCString(ctx, resultVal);
result(@[NSString stringWithUTF8String:str]);
JS_FreeCString(ctx, str);
}
// 清理QuickJS环境
JS_FreeContext(ctx);
JS_FreeRuntime(rt);
} else {
result(FlutterMethodNotImplemented);
}
};
}
@end
Android
- 在
quickjs_flutter_plugin/android/build.gradle
中添加QuickJS的依赖(如果QuickJS有Gradle支持的话;否则,你可能需要手动集成)。
dependencies {
implementation 'com.example:quickjs:1.0' // 假设QuickJS有一个Gradle包
}
- 创建一个Java或Kotlin桥接文件,用于与QuickJS交互。
// QuickJSPlugin.java
package com.example.quickjs_flutter_plugin;
import androidx.annotation.NonNull;
import io.flutter.embedding.engine.plugins.FlutterPlugin;
import io.flutter.embedding.engine.plugins.activity.ActivityAware;
import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding;
import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.MethodChannel;
import io.flutter.plugin.common.MethodChannel.MethodCallHandler;
import io.flutter.plugin.common.MethodChannel.Result;
public class QuickJSPlugin implements FlutterPlugin, MethodCallHandler, ActivityAware {
private MethodChannel channel;
@Override
public void onAttachedToEngine(@NonNull FlutterPluginBinding flutterPluginBinding) {
channel = new MethodChannel(flutterPluginBinding.getBinaryMessenger(), "quickjs_flutter_plugin");
channel.setMethodCallHandler(this);
}
@Override
public void onMethodCall(@NonNull MethodCall call, @NonNull Result result) {
if (call.method.equals("execute")) {
String jsCode = (String) call.arguments;
// 初始化QuickJS环境(这里需要根据QuickJS的API来实现)
// 假设QuickJS有一个静态方法`execute`用于执行JavaScript代码
String resultStr = QuickJSEngine.execute(jsCode);
result.success(resultStr);
} else {
result.notImplemented();
}
}
@Override
public void onDetachedFromEngine(@NonNull FlutterPluginBinding binding) {
channel.setMethodCallHandler(null);
}
@Override
public void onAttachedToActivity(ActivityPluginBinding binding) {
// No-op
}
@Override
public void onDetachedFromActivityForConfigChanges() {
// No-op
}
@Override
public void onReattachedToActivityForConfigChanges(ActivityPluginBinding binding) {
// No-op
}
@Override
public void onDetachedFromActivity() {
// No-op
}
}
注意:由于QuickJS没有直接的Gradle包或CocoaPods包,这里的依赖添加是假设性的。你可能需要从QuickJS的官方仓库手动下载并集成其源码。
步骤 3: 在Flutter中使用插件
最后,在你的Flutter项目中使用这个插件。
import 'package:flutter/material.dart';
import 'package:quickjs_flutter_plugin/quickjs_flutter_plugin.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('Flutter QuickJS Example'),
),
body: Center(
child: ElevatedButton(
onPressed: () async {
String jsCode = 'console.log("Hello from Flutter!"); 42;';
String result = await QuickJSPlugin().execute(jsCode);
print('Result: $result');
},
child: Text('Execute JS'),
),
),
),
);
}
}
确保你已经在你的pubspec.yaml
文件中添加了插件的依赖:
dependencies:
flutter:
sdk: flutter
quickjs_flutter_plugin:
path: ../quickjs_flutter_plugin # 指向你的插件项目路径
注意事项
- QuickJS的集成可能涉及到底层C代码的编译和链接,这在Flutter插件中可能比较复杂。
- 考虑到性能和安全性,确保你正确地管理QuickJS的生命周期和内存。
- 这个示例代码是基于假设的QuickJS API和集成方式,实际使用时你可能需要根据QuickJS的文档和API进行调整。
希望这个代码案例能帮助你在Flutter项目中集成和使用QuickJS!