【开源鸿蒙 Flutter 实战】小白也能懂!用 ArkTs 开发 Flutter 鸿蒙插件

「鸿蒙心迹」“2025・领航者闯关记“主题征文活动 10w+人浏览 166人参与

一、前言

很多开发者在做 Flutter 跨端开发时,遇到鸿蒙平台需要调用原生能力(比如读写本地数据)的场景,就不知道该怎么下手了。这篇文章就带大家从零开始,用 ArkTs 开发一个 Flutter 鸿蒙插件,实现 Flutter 和鸿蒙原生的消息通信,甚至能直接调用鸿蒙的 “首选项 API” 完成 Token 的存储和读取 —— 全程大白话,小白也能跟着做!

二、核心思路

Flutter 和鸿蒙 ArkTs 之间的通信,核心靠MethodChannel(方法通道):

  1. Flutter 侧:通过MethodChannel发起方法调用(比如 “存 Token”“读 Token”);

  2. ArkTs 侧:监听这个通道,接收 Flutter 的调用请求,调用鸿蒙原生 API 处理,再把结果返回给 Flutter。

简单说,MethodChannel就是 Flutter 和 ArkTs 之间的 “传话员”,我们只需要让两边的 “传话员” 用同一个 “暗号”(通道名称),就能实现双向通信。

三、实战步骤

3.1 第一步:Flutter 侧编写 MethodChannel(发起调用)

首先在 Flutter 项目里,创建 MethodChannel 并封装 Token 的读写方法,代码如下(复制就能用,注释已经写满了):

import 'package:flutter/services.dart';

// 核心:创建MethodChannel,通道名称必须和ArkTs侧一致!
const MethodChannel _methodChannel = MethodChannel('xxx.com/app');

/// 读取本地存储的Token
static Future<dynamic> getToken() {
  // 调用ArkTs侧的"getPrefs"方法,参数传"token"(要读取的键名)
  return _methodChannel.invokeMethod("getPrefs", 'token');
}

/// 存储Token到鸿蒙本地
static Future<dynamic> setToken(String token) {
  // 调用ArkTs侧的"setPrefs"方法,传键值对(key=token,value=传入的token值)
  return _methodChannel.invokeMethod("setPrefs", {'key': 'token', 'value': token});
}

3.2 第二步:ArkTs 侧配置 EntryAbility(初始化环境)

在鸿蒙项目的src/main/ets/entryability/EntryAbility.ets文件中,完成 Flutter 引擎配置、插件注册,同时初始化鸿蒙的 “首选项”(用来存数据的本地存储):

import { FlutterAbility, FlutterEngine } from '@ohos/flutter_ohos';
import { GeneratedPluginRegistrant } from '../plugins/GeneratedPluginRegistrant';
// 后面要写的插件类,先引入
import ForestPlugin from './ForestPlugin';
import { BusinessError } from '@kit.BasicServicesKit';
import { window } from '@kit.ArkUI';
import { preferences } from '@kit.ArkData';

// 全局变量:保存首选项实例,方便后续读写数据
let dataPreferences: preferences.Preferences | null = null;

export default class EntryAbility extends FlutterAbility {
  // 窗口创建时初始化首选项
  onWindowStageCreate(windowStage: window.WindowStage): void {
    super.onWindowStageCreate(windowStage);
    // 获取鸿蒙首选项实例,名称叫"forestStore"(自定义,随便取)
    preferences.getPreferences(this.context, 'forestStore', (err: BusinessError, val: preferences.Preferences) => {
      if (err) {
        console.error("读取首选项失败:" + err.message);
        return;
      }
      // 初始化成功,把实例赋值给全局变量
      dataPreferences = val;
      console.info("首选项初始化成功!");
    })
  }

  // 配置Flutter引擎,注册插件
  configureFlutterEngine(flutterEngine: FlutterEngine) {
    super.configureFlutterEngine(flutterEngine)
    // 注册默认插件
    GeneratedPluginRegistrant.registerWith(flutterEngine)
    // 注册我们自己写的ForestPlugin插件
    this.addPlugin(new ForestPlugin());
  }
}

// 导出首选项实例,供插件类使用
export {dataPreferences};

3.3 第三步:ArkTs 侧编写 ForestPlugin(处理 Flutter 调用)

创建src/main/ets/entryability/ForestPlugin.ets文件,这是核心插件类,用来接收 Flutter 的调用并处理:

import { Any, FlutterPlugin, Log, MethodCall, MethodChannel, MethodResult } from '@ohos/flutter_ohos';
import { FlutterPluginBinding } from '@ohos/flutter_ohos/src/main/ets/embedding/engine/plugins/FlutterPlugin';
import { BusinessError } from '@kit.BasicServicesKit';
import { preferences } from '@kit.ArkData';
// 引入上面初始化的首选项实例
import {dataPreferences} from './EntryAbility';

// 日志标签,方便调试
const TAG = "[flutter][plugin][forest]";

// 实现FlutterPlugin接口,这是鸿蒙Flutter插件的标准写法
export default class ForestPlugin implements FlutterPlugin {
  // 声明MethodChannel对象
  private channel?: MethodChannel;
  // 声明API类(后面封装读写逻辑)
  private api = new ForestApi();

  // Flutter引擎加载成功后调用,核心方法!
  onAttachedToEngine(binding: FlutterPluginBinding): void {
    // 创建MethodChannel,通道名称必须和Flutter侧一致!
    this.channel = new MethodChannel(binding.getBinaryMessenger(), "xxx.com/app");
    // 设置方法调用处理器,接收Flutter的指令
    this.channel.setMethodCallHandler({
      onMethodCall : (call: MethodCall, result: MethodResult) => {
        console.log(`${TAG} 收到Flutter调用:${call.method},参数:${JSON.stringify(call.args)}`);
        // 根据Flutter传的指令名,分情况处理
        switch (call.method) {
          // 处理"读取数据"指令
          case "getPrefs":
            this.api.getPrefs(String(call.args), result);
            break;
          // 处理"存储数据"指令
          case "setPrefs":
            let key = String(call.argument("key")); // 取参数里的key
            let value = String(call.argument("value")); // 取参数里的value
            this.api.setPrefs(key, value);
            break;
          // 未知指令,返回"未实现"
          default:
            result.notImplemented();
            break;
        }
      }
    })
  }

  // 插件销毁时清空处理器,避免内存泄漏
  onDetachedFromEngine(binding: FlutterPluginBinding): void {
    Log.i(TAG, "插件已销毁");
    this.channel?.setMethodCallHandler(null);
  }

  // 插件唯一标识,自定义即可
  getUniqueClassName(): string {
    return "ForestPlugin";
  }
}

// 封装鸿蒙首选项的读写逻辑
class ForestApi {
  // 读取数据:key是要读的键名,result用来返回结果给Flutter
  getPrefs(key: string, result: MethodResult) {
    dataPreferences?.get(key, '', (err: BusinessError, val: preferences.ValueType) => {
      if (err) {
        console.error(`${TAG} 读取${key}失败:${err.message}`);
        result.success(''); // 读取失败返回空字符串
        return;
      }
      console.info(`${TAG} 读取${key}成功:${val}`);
      result.success(val); // 读取成功,把值返回给Flutter
    })
  }

  // 存储数据:key是键名,value是要存的值
  setPrefs(key: string, value: string) {
    dataPreferences?.put(key, value, (err: BusinessError) => {
      if (err) {
        console.error(`${TAG} 存储${key}失败:${err.message}`);
        return;
      }
      console.info(`${TAG} 存储${key}成功`);
    })
  }

  // 扩展:清空指定key的数据(可选)
  clearPrefs(key: string) {
    dataPreferences?.delete(key, (err: BusinessError) => {
      if (err) {
        console.error(`${TAG} 删除${key}失败:${err.message}`);
        return;
      }
      console.info(`${TAG} 删除${key}成功`);
    })
  }
}

四、必看的注意事项(小白踩坑点)

MethodChannel 名称必须完全一致:Flutter 侧的xxx.com/app和 ArkTs 侧的通道名称要一字不差,否则通信会失败;

异步返回要加 await:ArkTs 侧用result.success()返回数据是异步的,Flutter 侧调用getToken()时要加await,比如:

String token = await getToken();

数据类型只支持基础类型:Flutter 和 ArkTs 通信只能传字符串、数字、布尔等基础类型,复杂对象(比如自定义类)要先序列化(转 JSON 字符串);

Flutter 侧接收数据要转类型:Flutter 侧getToken()返回的是dynamic类型,要手动转成字符串 / 数字等,避免类型错误;

首选项初始化要提前:一定要在onWindowStageCreate里初始化首选项,否则读写时会报null错误。

五、总结

其实用 ArkTs 开发 Flutter 鸿蒙插件的核心就两点:

  1. 两边用同一个MethodChannel名称建立通信;

  2. ArkTs 侧监听方法调用,调用鸿蒙原生 API 处理,再把结果返回。

这篇教程实现了 Token 的读写,你可以照着这个思路扩展 —— 比如调用鸿蒙的电池 API、路由 API 等,都是换汤不换药,只需要在onMethodCall里加新的case即可。

六、扩展小技巧

如果想实现更复杂的通信(比如实时消息推送),可以用EventChannel(事件通道),用法和MethodChannel类似,只是支持持续的消息推送,感兴趣的可以自己试试~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值