Flutter鸿蒙终端一体化—鹊桥相会

在鸿蒙中开发Flutter项目,一个最大的问题,就是「不太会写鸿蒙代码」,这对于一个Flutter开发者来说,虽然不是一件很麻烦的事,但由于现在鸿蒙的版本和文档还略有一些混乱,所以要写好还是有一些麻烦的,所以,秉着能用工具解决的问题就不要自己写的原则,我们参考Native的Flutter Channel的实现,也就是pigeon的方式,不熟悉的同学可以参考我之前的文章。
Flutter混编工程之高速公路Pigeon

这套东西在鸿蒙中也有的适配,可以一键生成ets代码,方便我们进行多端复用,项目地址如下。
gitee.com/openharmony...

在鸿蒙中使用也非常简单,指定引用即可,代码如下所示。

yaml 复制代码
pigeon:
    git:
      url: "https://gitee.com/openharmony-sig/flutter_packages.git"
      path: "packages/pigeon"

pub get之后,参考我们之前的实现,创建一个接口协议文件,这里就用之前的来示例。

dart 复制代码
import 'package:pigeon/pigeon.dart';

@HostApi()
abstract class NativeNetApi {
  @async
  String getNativeNetBridge(String path, Map<String, Object> params);

  @async
  String postNativeNetBridge(String path, Map<String, Object> params);

  void doActionUrlCall(String actionUrl);
}

接下来执行命令:

shell 复制代码
flutter pub run pigeon --input lib/native_api.dart --arkts_out lib/native_channel.ets --dart_out lib/native_channel.dart

执行完成后,就会在指定目录下生成我们需要的Channel文件,dart代码我就不贴了,和之前文章中的一样,我们来看下鸿蒙的代码。

arkts 复制代码
import StandardMessageCodec from '@ohos/flutter_ohos/src/main/ets/plugin/common/StandardMessageCodec';
import BasicMessageChannel, { Reply } from '@ohos/flutter_ohos/src/main/ets/plugin/common/BasicMessageChannel';
import { BinaryMessenger,TaskQueue } from '@ohos/flutter_ohos/src/main/ets/plugin/common/BinaryMessenger';
import MessageCodec from '@ohos/flutter_ohos/src/main/ets/plugin/common/MessageCodec';
import { ByteBuffer } from '@ohos/flutter_ohos/src/main/ets/util/ByteBuffer';


/** Error class for passing custom error details to Flutter via a thrown PlatformException. */
export class FlutterError implements Error {

  /** The error code. */
  public code: string;

  /** The error name. */
  public name: string;

  /** The error message. */
  public message: string;
  /** The error stack. */
  public stack?: string;

  constructor(code: string, name: string,  message: string, stack: string) 
  {
    this.code = code;
    this.name = name;
    this.message = message;
    this.stack = stack;
  }
}

function wrapError(error: Error): Array<Object> {
  let errorList: Array<Object> = new Array<Object>(3);
  if (error instanceof FlutterError) {
    let err: FlutterError = error as FlutterError;
    errorList[0] = err.code;
    errorList[1] = err.name;
    errorList[2] = err.message;
  } else {
    errorList[0] = error.toString();
    errorList[1] = error.name;
    errorList[2] = "Cause: " + error.message + ", Stacktrace: " + error.stack;
  }
  return errorList;
}

export interface Result<T> {
  success( result: T ): void;

  error( error: Error): void;
}
/* Generated abstract class from Pigeon that represents a handler of messages from Flutter.*/
export abstract class NativeNetApi {

  abstract getNativeNetBridge(path: string , params: Map<string, Object> , result: Result<string>): void;

  abstract postNativeNetBridge(path: string , params: Map<string, Object> , result: Result<string>): void;

  abstract doActionUrlCall(actionUrl: string ): void;
  /** The codec used by NativeNetApi. */
  static getCodec(): MessageCodec<Object>{
    return new StandardMessageCodec();
  }
  /*Sets up an instance of `NativeNetApi` to handle messages through the `binaryMessenger`.*/
  static setup(binaryMessenger: BinaryMessenger, api: NativeNetApi | null): void {
    {
      let channel: BasicMessageChannel<Object> =
          new BasicMessageChannel(
              binaryMessenger, "dev.flutter.pigeon.test1.NativeNetApi.getNativeNetBridge", NativeNetApi.getCodec());
      if (api != null) {
        channel.setMessageHandler({
            onMessage(message: Object ,reply: Reply<Object> ) {
              let args: Array<Object> = message as Array<Object>;
              class ResultImp implements Result<string>{
                    success(result: string): void {
                      let res: Array<Object> = [];
                      res.push(result);
                      reply.reply(res);
                    }

                    error(error: Error): void {
                      let wrappedError: Array<Object> = wrapError(error);
                      reply.reply(wrappedError);
                    }
              }
              let resultCallback: Result<string> = new ResultImp();

              api!.getNativeNetBridge(args[0] as string, args[1] as Map<string, Object>, resultCallback);
            } });
      } else {
        channel.setMessageHandler(null);
      }
    }
    {
      let channel: BasicMessageChannel<Object> =
          new BasicMessageChannel(
              binaryMessenger, "dev.flutter.pigeon.test1.NativeNetApi.postNativeNetBridge", NativeNetApi.getCodec());
      if (api != null) {
        channel.setMessageHandler({
            onMessage(message: Object ,reply: Reply<Object> ) {
              let args: Array<Object> = message as Array<Object>;
              class ResultImp implements Result<string>{
                    success(result: string): void {
                      let res: Array<Object> = [];
                      res.push(result);
                      reply.reply(res);
                    }

                    error(error: Error): void {
                      let wrappedError: Array<Object> = wrapError(error);
                      reply.reply(wrappedError);
                    }
              }
              let resultCallback: Result<string> = new ResultImp();

              api!.postNativeNetBridge(args[0] as string, args[1] as Map<string, Object>, resultCallback);
            } });
      } else {
        channel.setMessageHandler(null);
      }
    }
    {
      let channel: BasicMessageChannel<Object> =
          new BasicMessageChannel(
              binaryMessenger, "dev.flutter.pigeon.test1.NativeNetApi.doActionUrlCall", NativeNetApi.getCodec());
      if (api != null) {
        channel.setMessageHandler({
            onMessage(message: Object ,reply: Reply<Object> ) {
              let args: Array<Object> = message as Array<Object>;
              let res: Array<Object> = [];
              try {
                api!.doActionUrlCall(args[0] as string);
                res.push(null);
              }
 catch (error) {
                let wrappedError: Array<Object> = wrapError(error);
                res = wrappedError;
              }
              reply.reply(res);
            } });
      } else {
        channel.setMessageHandler(null);
      }
    }
  }
}

整体代码和Java的代码很类似,阅读基本没什么障碍,使用方式也和Native保持一致,通过调用setup方法,传入接口的实现即可,这里就不赘述了。

这样一来,我们的通信协议就打通了,Flutter的代码基本可以无损迁移,在鸿蒙侧,只需要根据协议实现对应的Channel接口即可,这样就完成了Android、iOS、鸿蒙的UI多端统一,Flutter & 鸿蒙,真香。

欢迎大家关注我的公众号------【群英传】,专注于「Android」「Flutter」「Kotlin」

我的语雀知识库------www.yuque.com/xuyisheng

相关推荐
一只大侠的侠3 分钟前
Flutter开源鸿蒙跨平台训练营 Day14React Native表单开发
flutter·开源·harmonyos
听麟6 分钟前
HarmonyOS 6.0+ APP AR文旅导览系统开发实战:空间定位与文物交互落地
人工智能·深度学习·华为·ar·wpf·harmonyos
子春一11 分钟前
Flutter for OpenHarmony:音律尺 - 基于Flutter的Web友好型节拍器开发与节奏可视化实现
前端·flutter
空白诗29 分钟前
高级进阶React Native 鸿蒙跨平台开发:slider 滑块组件 - 音量调节器完整实现
react native·react.js·harmonyos
微祎_39 分钟前
Flutter for OpenHarmony:单词迷宫一款基于 Flutter 构建的手势驱动字母拼词游戏,通过滑动手指连接字母路径来组成单词。
flutter·游戏
●VON1 小时前
HarmonyOS应用开发实战(基础篇)Day01-《ArkTS基本知识》
学习·华为·harmonyos·鸿蒙·von
BlackWolfSky1 小时前
鸿蒙高级课程笔记2—应用性能优化
笔记·华为·harmonyos
ujainu1 小时前
护眼又美观:Flutter + OpenHarmony 鸿蒙记事本一键切换夜间模式(四)
android·flutter·harmonyos
ujainu1 小时前
让笔记触手可及:为 Flutter + OpenHarmony 鸿蒙记事本添加实时搜索(二)
笔记·flutter·openharmony
一只大侠的侠1 小时前
Flutter开源鸿蒙跨平台训练营 Day 13从零开发注册页面
flutter·华为·harmonyos