Flutter JavaScript执行插件js_script的使用

发布于 1周前 作者 yuanlaile 来自 Flutter

Flutter JavaScript执行插件js_script的使用

在Flutter中,js_script 是一个强大的插件,允许开发者在Dart代码中执行JavaScript脚本,并实现JavaScript与Dart对象之间的交互。以下是如何使用该插件的详细说明及完整示例。


使用方法

创建 JavaScript 上下文

首先,创建一个 JsScript 对象来管理 JavaScript 的上下文。

JsScript script = JsScript();

定义并注册 Dart 类到 JavaScript

通过 ClassInfo 将 Dart 类映射到 JavaScript,并定义其字段和方法。

var classInfo = ClassInfo<TestClass>(
    newInstance: (_) => TestClass(), // 创建实例的方法
    fields: {
        "field": JsField.ins(
            get: (obj) => obj.field, // 获取字段值
            set: (obj, val) => obj.field = val, // 设置字段值
        ),
    },
    functions: {
        "method": JsFunction.ins((obj, argv) => obj.method()), // 调用 Dart 方法
        "wait": JsFunction.ins((obj, argv) => obj.wait(argv[0])), // 带参数调用 Dart 方法
    }
);

然后将类信息注册到 JavaScript 上下文中:

script.addClass(classInfo);

在 JavaScript 中操作 Dart 对象

可以在 JavaScript 中创建 Dart 对象并调用其方法或修改其属性。

script.eval("var obj = new TestClass()"); // 在 JavaScript 中创建 Dart 对象
test("[JS] obj.field == 1", script.eval("obj.field") == 1); // 检查字段值
test("[JS] obj.method() == 3", script.eval("obj.method()") == 3); // 调用 Dart 方法

在 Dart 中操作 JavaScript 对象

通过 JsValue 可以获取 JavaScript 对象并访问其属性或调用其方法。

JsValue jsValue = script.eval("obj"); // 获取 JavaScript 对象
script.eval("obj.field = 3;"); // 修改 JavaScript 对象的字段
test("[Dart] obj.field == 3", jsValue.dartObject.field == 3); // 验证字段值
test("[Dart] obj.method() == 9", jsValue.dartObject.method() == 9); // 调用 Dart 方法

绑定 Dart 对象到 JavaScript

可以将 Dart 对象绑定到 JavaScript 上下文,并直接在 JavaScript 中操作它。

TestClass obj2 = TestClass(); // 创建 Dart 对象
obj2.field = 4; // 设置初始值
JsValue jsValue = script.bind(obj2, classInfo: classInfo); // 绑定到 JavaScript
test("[JS] obj2.field == 4", jsValue["field"] == 4); // 验证字段值

在 JavaScript 中调用 Dart 函数

可以通过 JsValue 注册 Dart 函数并在 JavaScript 中调用。

JsValue func = script.function((argv) => "hello" + argv[0]); // 注册 Dart 函数
test("[JS] call function", func.call(["world"]) == "helloworld"); // 调用函数

使用 JavaScript Promise 和 Dart Future

JavaScript 的 Promise 可以无缝转换为 Dart 的 Future。

JsValue jsPromise = script.eval("""
new Promise(async function(resolve, reject) {
    await obj.wait(3);
    resolve("over");
});
""");
var time = DateTime.now();
var res = await jsPromise.asFuture; // 等待 Promise 结果
test("[JS] wait for ${DateTime.now().difference(time).inMilliseconds}ms", res == "over");

支持文件系统

可以加载本地文件或内存中的文件,并在 JavaScript 中运行它们。

JsScript script = JsScript(
    fileSystems: [
        AsarFileSystem(await data), // 加载 ASAR 文件
        MemoryFileSystem({ // 加载内存文件
            "/test.js": """
            const md5 = require('md5');
            module.exports = md5('hello');
            """
        })
    ]
);
var ret = script.run("test.js"); // 运行 JavaScript 文件

自动类型转换

任何 Dart 对象都可以自动转换为 JavaScript 对象,并支持直接调用。

JsValue func = script.eval("""
(function (func, map) {
    return func(map["test"])
})
""");
test("[JS] test auto convert ", func.call([(content) {
    return content;
}, {"test": 26}]) == 26);

完整示例代码

以下是完整的示例代码,展示了如何使用 js_script 插件执行 JavaScript 脚本并与 Dart 进行交互。

import 'package:flutter/material.dart';
import 'dart:async';

import 'package:flutter/services.dart';
import 'package:js_script/filesystems.dart';
import 'package:js_script/js_script.dart';
import 'package:js_script/types.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatefulWidget {
  [@override](/user/override)
  _MyAppState createState() => _MyAppState();
}

class TestClass {
  int field = 1;

  int method() => field * 3;
  Future<void> wait(int sec) => Future.delayed(Duration(seconds: sec));
}

class _MyAppState extends State<MyApp> {

  late List<Widget> children = [];
  late Future<ByteData> data;

  [@override](/user/override)
  void initState() {
    super.initState();
    data = rootBundle.load("res/npmpack.asar");
  }

  dispose() {
    super.dispose();
  }

  void addLine(String str) {
    print(str);
    setState(() {
      children.add(Text(str, style: TextStyle(color: Colors.black),));
    });
  }

  void test(String str, bool test) {
    addLine("$str ===&gt; ${test ? "OK" : "Error"}");
  }

  void run() async {
    JsScript script = JsScript(
      fileSystems: [
        AsarFileSystem(await data),
        MemoryFileSystem({
          "/test.js": """
          const md5 = require('md5');
          module.exports = md5('hello');
          """
        })
      ]
    );

    test("1 + 2 = 3", script.eval("1 + 2") == 3);

    var classInfo = ClassInfo<TestClass>(
      newInstance: (_, __) => TestClass(),
      fields: {
        "field": JsField.ins(
          get: (obj) => obj.field,
          set: (obj, val) => obj.field = val,
        ),
      },
      functions: {
        "method": JsFunction.ins((obj, argv) => obj.method()),
        "method2": JsFunction.sta((argv) => 3),
        "wait": JsFunction.ins((obj, argv) => obj.wait(argv[0])),
      }
    );
    script.addClass(classInfo);

    script.eval("var obj = new TestClass()");
    test("[JS] obj.field == 1", script.eval("obj.field") == 1);
    test("[JS] obj.method() == 3", script.eval("obj.method()") == 3);

    JsValue jsValue = script.eval("obj");
    script.eval("obj.field = 3;");
    test("[Dart] obj.field == 3", jsValue.dartObject.field == 3);
    test("[Dart] obj.method() == 9", jsValue.dartObject.method() == 9);

    {
      // 测试绑定
      TestClass obj2 = TestClass();
      obj2.field = 4;
      JsValue jsValue = script.bind(obj2, classInfo: classInfo);
      test("[JS] obj2.field == 4", jsValue["field"] == 4);
    }

    {
      // 测试函数
      JsValue func = script.function((argv) => "hello" + argv[0]);
      var obj = func.call(["world"]);
      print(obj);
      test("[JS] call function", func.call(["world"]) == "helloworld");
    }

    {
      JsValue jsPromise = script.eval("""
      new Promise(async function(resolve, reject) {
        await obj.wait(3);
        resolve("over");
      });
      """);
      var time = DateTime.now();
      var res = await jsPromise.asFuture;
      test("[JS] wait for ${DateTime.now().difference(time).inMilliseconds}ms", res == "over");
    }

    {
      JsValue main = script.eval("""
      (function () {
        let ret = 0;
        for (let i = 0; i < 1000000; ++i) {
          ret += obj.method();
        }
        return ret;
      });
      """);

      var time = DateTime.now();
      var res = main.call();
      test("[JS] call dart method 1000000 times, using ${DateTime.now().difference(time).inMilliseconds}ms", res == 9000000);
    }

    {
      var ret = script.eval("""
      const md5 = require('md5');
      md5('hello');
      """);
      test("[JS] require md5", ret == '5d41402abc4b2a76b9719d911017c592');
      ret = script.run("test.js");
      test("[JS] run file in FileSystem", ret == '5d41402abc4b2a76b9719d911017c592');
    }
    {
      JsValue func = script.eval("""
      (function (func, map) {
        return func(map["test"])
      })
      """);
      test("[JS] test auto convert ", func.call([(content) {
        return content;
      }, {"test": 26}]) == 26);
    }

    script.dispose();
  }

  [@override](/user/override)
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: const Text('Plugin example app'),
        ),
        body: ListView.builder(
          itemBuilder: (context, index) {
            return children[index];
          },
          itemCount: children.length,
        ),
        floatingActionButton: FloatingActionButton(
          onPressed: run,
          child: Icon(Icons.run_circle_outlined),
        ),
      ),
    );
  }
}

更多关于Flutter JavaScript执行插件js_script的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter JavaScript执行插件js_script的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


js_script 是一个 Flutter 插件,允许你在 Flutter 应用中执行 JavaScript 代码。它基于 flutter_webview_pluginflutter_js 实现,提供了一个简单的方式来在 Flutter 应用中运行 JavaScript 代码。

安装 js_script 插件

首先,你需要在 pubspec.yaml 文件中添加 js_script 插件的依赖:

dependencies:
  flutter:
    sdk: flutter
  js_script: ^0.0.1  # 请检查最新版本

然后运行 flutter pub get 来安装依赖。

使用 js_script 插件

1. 导入插件

在你的 Dart 文件中导入 js_script 插件:

import 'package:js_script/js_script.dart';

2. 创建 JsScript 实例

你可以通过 JsScript 类来执行 JavaScript 代码。首先,创建一个 JsScript 实例:

final jsScript = JsScript();

3. 执行 JavaScript 代码

使用 evaluate 方法来执行 JavaScript 代码。这个方法返回一个 Future,你可以通过 await 来获取执行结果。

void runJavaScript() async {
  try {
    final result = await jsScript.evaluate('1 + 1');
    print('Result: $result');  // 输出: Result: 2
  } catch (e) {
    print('Error: $e');
  }
}

4. 处理异步 JavaScript 代码

如果你的 JavaScript 代码是异步的,你可以使用 Promise 并返回一个值。js_script 插件会自动处理 Promise 并返回其结果。

void runAsyncJavaScript() async {
  try {
    final result = await jsScript.evaluate('''
      new Promise((resolve, reject) => {
        setTimeout(() => {
          resolve("Hello, Flutter!");
        }, 1000);
      });
    ''');
    print('Result: $result');  // 输出: Result: Hello, Flutter!
  } catch (e) {
    print('Error: $e');
  }
}

5. 传递参数

你可以通过 evaluate 方法的第二个参数传递参数给 JavaScript 代码:

void runJavaScriptWithArguments() async {
  try {
    final result = await jsScript.evaluate('a + b', {'a': 2, 'b': 3});
    print('Result: $result');  // 输出: Result: 5
  } catch (e) {
    print('Error: $e');
  }
}

6. 清理资源

当你不再需要使用 JsScript 实例时,可以调用 dispose 方法来释放资源:

void disposeJsScript() {
  jsScript.dispose();
}

完整示例

以下是一个完整的示例,展示了如何在 Flutter 应用中使用 js_script 插件执行 JavaScript 代码:

import 'package:flutter/material.dart';
import 'package:js_script/js_script.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  [@override](/user/override)
  Widget build(BuildContext context) {
    return MaterialApp(
      home: JsScriptExample(),
    );
  }
}

class JsScriptExample extends StatefulWidget {
  [@override](/user/override)
  _JsScriptExampleState createState() => _JsScriptExampleState();
}

class _JsScriptExampleState extends State<JsScriptExample> {
  final jsScript = JsScript();
  String result = '';

  void runJavaScript() async {
    try {
      final res = await jsScript.evaluate('1 + 1');
      setState(() {
        result = 'Result: $res';
      });
    } catch (e) {
      setState(() {
        result = 'Error: $e';
      });
    }
  }

  [@override](/user/override)
  void dispose() {
    jsScript.dispose();
    super.dispose();
  }

  [@override](/user/override)
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('JsScript Example'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            ElevatedButton(
              onPressed: runJavaScript,
              child: Text('Run JavaScript'),
            ),
            SizedBox(height: 20),
            Text(result),
          ],
        ),
      ),
    );
  }
}
回到顶部
AI 助手
你好,我是IT营的 AI 助手
您可以尝试点击下方的快捷入口开启体验!