Flutter跨平台开发鸿蒙化JS-Dart通信桥接组件使用指南

1. 插件介绍

JS-Dart通信桥接组件是一个专为OpenHarmony平台优化的Flutter插件,用于实现JavaScript(WebView)与Dart(Flutter)之间的双向通信。该组件提供了一套完整的通信机制,支持异步调用、回调处理和错误管理,适用于需要在Flutter应用中嵌入Web内容并实现复杂交互的场景。

核心功能

  • 支持JS调用Dart方法并获取返回值
  • 支持Dart调用JS方法并获取返回值
  • 提供异步通信机制
  • 完整的错误处理流程
  • 支持参数和返回值的序列化与反序列化
  • 与OpenHarmony WebView完美集成

2. 环境设置

在使用该组件之前,需要确保开发环境满足以下要求:

Flutter环境

  • Flutter SDK: ≥2.19.6
  • Dart SDK: ≥2.19.6

OpenHarmony环境

  • OpenHarmony SDK API: ≥9
  • DevEco Studio: ≥3.0

项目配置

确保项目已正确配置OpenHarmony开发环境,并已创建Flutter for OpenHarmony项目。

3. 包的引入

由于该组件是自定义修改版本,需要以git形式通过AtomGit引入。在项目的pubspec.yaml文件中添加以下依赖:

yaml 复制代码
dependencies:
  flutter:
    sdk: flutter

  webview_flutter:
    git:
      url: "https://atomgit.com/openharmony-tpc/flutter_packages.git"
      path: "packages/webview_flutter/webview_flutter"

然后运行以下命令安装依赖:

bash 复制代码
flutter pub get

4. API调用与使用示例

4.1 WebView初始化

首先,需要初始化WebView并配置JavaScript支持:

dart 复制代码
import 'package:flutter/material.dart';
import 'package:webview_flutter/webview_flutter.dart';
import 'js_bridge.dart';

class WebPage extends StatefulWidget {
  const WebPage({Key? key}) : super(key: key);

  @override
  State<WebPage> createState() => _WebPageState();
}

class _WebPageState extends State<WebPage> {
  late WebViewController controller;
  final JSBridge _jsBridge = JSBridge();

  @override
  void initState() {
    super.initState();
    _initWebView();
    _initJsBridge();

    Future.delayed(const Duration(seconds: 1), () {
      controller.loadFlutterAsset("assets/html/index.html");
    });
  }

  _initWebView() async {
    controller = WebViewController()
      ..setJavaScriptMode(JavaScriptMode.unrestricted)
      ..addJavaScriptChannel(
        JSBridge.name,
        onMessageReceived: (JavaScriptMessage message) {
          _jsBridge.receiverMessage(message.message);
        },
      )
      ..setNavigationDelegate(NavigationDelegate(
        onUrlChange: (change) {
          _jsBridge.injectBridgeJS(controller);
        },
      ));
  }

  _initJsBridge() {
    _jsBridge.messageExecutor = controller.runJavaScript;

    // 注册Dart方法供JS调用
    _jsBridge.register("getToken", (data, callback) {
      print("JS调用了getToken方法,参数:$data");
      // 模拟异步操作
      Future.delayed(const Duration(seconds: 1), () {
        callback("flutter_token_123"); // 返回结果给JS
      });
    });
  }

  // 其他代码...
}

4.2 JS调用Dart方法

在HTML页面中,通过注入的bridge对象调用Dart方法:

html 复制代码
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width,initial-scale=1.0">
</head>
<body>
    <p id="demo">WebView Content</p>
    <button type="button" onclick="jsCallAsync()">调用Dart方法</button>

    <script>
        async function jsCallAsync() {
            var param = { "userId": "12345" };
            let result = await window.bridge.call("getToken", param);
            document.getElementById("demo").innerHTML = "从Dart获取的Token: " + result;
        }
    </script>
</body>
</html>

4.3 Dart调用JS方法

在Dart代码中,通过JSBridge调用JS方法:

dart 复制代码
_callJsMethod() {
  var param = {"userName": "flutter_user"};
  _jsBridge.call(
    "userInfo",
    param,
    callback: (responseData) {
      print("JS返回结果: $responseData");
      setState(() {
        message = "JS返回结果: $responseData";
      });
    },
    errorCallback: (errorMessage) {
      print("调用JS方法出错: $errorMessage");
    },
  );
}

4.4 JS注册方法供Dart调用

在JS代码中注册方法供Dart调用:

javascript 复制代码
// 注册JS方法
window.bridge.register("userInfo", function(data, callback) {
    console.log("Dart调用了userInfo方法,参数:", data);
    var result = { "name": "JS User", "id": "js_123" };
    callback(result); // 返回结果给Dart
});

5. 资源配置

5.1 添加本地HTML和JS文件

将HTML和JS文件放在项目的assets目录下:

复制代码
assets/
├── html/
│   └── index.html
└── js/
    └── bridge.js

5.2 配置pubspec.yaml

pubspec.yaml文件中配置资源路径:

yaml 复制代码
flutter:
  assets:
    - assets/html/
    - assets/js/

5.3 OpenHarmony权限配置

ohos/entry/src/main/module.json5文件中添加网络权限(如果需要加载远程内容):

json5 复制代码
{
  "module": {
    "name": "entry",
    "type": "entry",
    "description": "...",
    "mainElement": "...",
    "deviceTypes": ["phone", "tablet"],
    "distro": {
      "deliveryWithInstall": true,
      "moduleName": "entry",
      "moduleType": "entry"
    },
    "abilities": [...],
    "requestPermissions": [
      {
        "name": "ohos.permission.INTERNET"
      }
    ]
  }
}

6. 完整示例

6.1 Dart端完整代码

dart 复制代码
import 'package:flutter/material.dart';
import 'package:webview_flutter/webview_flutter.dart';
import 'js_bridge.dart';

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

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'JS-Dart Bridge Demo',
      theme: ThemeData(primarySwatch: Colors.blue),
      home: const WebPage(),
    );
  }
}

class WebPage extends StatefulWidget {
  const WebPage({Key? key}) : super(key: key);

  @override
  State<WebPage> createState() => _WebPageState();
}

class _WebPageState extends State<WebPage> {
  late WebViewController controller;
  String message = "初始化中...";
  final JSBridge _jsBridge = JSBridge();

  @override
  void initState() {
    super.initState();
    _initWebView();
    _initJsBridge();

    Future.delayed(const Duration(seconds: 1), () {
      controller.loadFlutterAsset("assets/html/index.html");
    });
  }

  _initWebView() async {
    controller = WebViewController()
      ..setJavaScriptMode(JavaScriptMode.unrestricted)
      ..addJavaScriptChannel(
        "flutterObj",
        onMessageReceived: (JavaScriptMessage message) {
          setState(() {
            this.message = message.message;
          });
        },
      )
      ..addJavaScriptChannel(
        JSBridge.name,
        onMessageReceived: (JavaScriptMessage message) {
          _jsBridge.receiverMessage(message.message);
        },
      )
      ..setNavigationDelegate(NavigationDelegate(
        onUrlChange: (change) {
          _jsBridge.injectBridgeJS(controller);
        },
      ));
  }

  _initJsBridge() {
    _jsBridge.messageExecutor = controller.runJavaScript;

    _jsBridge.register("getToken", (data, callback) {
      print("JS调用了getToken方法,参数:$data");
      Future.delayed(const Duration(seconds: 1), () {
        callback("flutter_token_123");
      });
    });

    _jsBridge.register("testCallback", (data, callback) {
      print("JS调用了testCallback方法,参数:$data");
    });
  }

  _callJsBridge() {
    var param = {"userName": "flutter_user"};
    _jsBridge.call(
      "userInfo",
      param,
      callback: (responseData) {
        setState(() {
          message = "JS返回结果: $responseData";
        });
      },
      errorCallback: (errorMessage) {
        setState(() {
          message = "调用JS方法出错: $errorMessage";
        });
      },
    );
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('JS-Dart Bridge Demo')),
      body: Column(children: [
        ElevatedButton(
          onPressed: () => _callJsBridge(),
          child: const Text("调用JS方法"),
        ),
        Text(message),
        Expanded(
          child: WebViewWidget(controller: controller),
        )
      ]),
    );
  }
}

6.2 HTML端完整代码

html 复制代码
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width,initial-scale=1.0">
</head>
<body>
    <p id="demo">WebView Content</p>
    <button type="button" onclick="callFlutterFunction()">发送消息给Flutter</button>
    <button type="button" onclick="jsCallAsync()">调用Dart方法</button>

    <script>
        var count = 0;

        function callFlutterFunction() {
            flutterObj.postMessage('JS 调用了 Flutter ' + (++count));
        }

        async function jsCallAsync() {
            var param = { "userId": "12345" };
            let result = await window.bridge.call("getToken", param);
            document.getElementById("demo").innerHTML = "从Dart获取的Token: " + result;
        }

        // 注册JS方法供Dart调用
        window.bridge.register("userInfo", function(data, callback) {
            console.log("Dart调用了userInfo方法,参数:", data);
            var result = { "name": "JS User", "id": "js_123" };
            callback(result);
        });
    </script>
</body>
</html>

7. 总结

JS-Dart通信桥接组件为OpenHarmony平台上的Flutter应用提供了强大的WebView与Flutter通信能力。该组件支持双向通信、异步调用、回调处理和错误管理,适用于需要在Flutter应用中嵌入Web内容并实现复杂交互的场景。

通过本指南,您可以快速了解该组件的使用方法,包括环境设置、包的引入、API调用和完整示例。该组件已经过OpenHarmony平台优化,确保在OpenHarmony设备上稳定运行。

欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net

相关推荐
passerby60615 小时前
如何自己造一个时间处理库
前端·javascript·github
小羊没烦恼!6 小时前
Hello Web API系列教程——Web API与国际化
java·服务器·前端·javascript·php
mayaairi8 小时前
Vue2 组件通讯(三):全局事件总线、PubSub、插槽与组件实例属性
前端·javascript·vue.js
kyriewen9 小时前
面试官问我:AI 都能写代码了,前端凭什么还值 25K
前端·javascript·人工智能
BillKu10 小时前
全局样式变量:CSS 自定义属性(--border-color)和SCSS 变量($border-color)的说明
javascript·css·scss
Java的搬运工10 小时前
HarmonyOS ArkUI V2 实战:Schema 驱动表单、2in1 适配与实时通信
harmonyos·arkts·openharmony·harmonyos next·表单校验·arkui v2·2in1
花先锋队长10 小时前
HarmonyOS 7.0正式发布|华为天气空间运镜城市皮肤从4城增至10城
华为·智能手机·harmonyos
默_笙10 小时前
❗ 给金鱼装记忆(上):从白板到笔记本,AI 的短期记忆生存指南
前端·javascript
贾伟康11 小时前
【口算王|01】HarmonyOS ArkTS 口算题生成实战:按年级、运算类型和难度生成可控题目
算法·harmonyos·arkts·随机生成·口算题
兜里只有三分钱~11 小时前
翻卡_3D 的仪式感,和三个让它穿帮的写法
javascript·css·3d