1. 插件介绍

Pigeon 是一个强大的代码生成工具,专为 Flutter 与主机平台之间的通信而设计。它能够生成类型安全的通信代码,消除了跨平台通信中常见的字符串管理问题,提高了代码效率和可维护性。
在这里插入图片描述

主要特性

  • 类型安全:使用 Dart 定义接口,自动生成各平台类型安全的通信代码
  • 跨平台支持:支持 Android (Kotlin/Java)、iOS/macOS (Swift/Objective-C)、Windows (C++) 和鸿蒙系统 (ArkTS)
  • 高效通信:比传统的方法通道模式更高效
  • 简化开发:自动生成平台通道代码,无需手动编写
  • 支持多种数据类型:包括基本类型、自定义类、嵌套数据类型和枚举
  • 同步和异步方法支持:支持同步方法调用和异步方法回调

鸿蒙平台支持

Pigeon 为鸿蒙系统提供了完整的支持,能够生成 ArkTS 代码,使 Flutter 应用能够与鸿蒙原生代码进行无缝通信。这为开发跨平台应用提供了极大的便利,特别是对于需要调用鸿蒙特有功能的场景。

2. 依赖配置

由于需要使用自定义修改版本,我们将通过 Git 形式引入依赖。

2.1 配置 pubspec.yaml

在 Flutter 项目的 pubspec.yaml 文件中,添加以下依赖配置:

dependencies:
  flutter:
    sdk: flutter
  pigeon:
    git:
      url: "https://gitcode.com/openharmony-tpc/flutter_packages.git"
      path: "packages/pigeon"

2.2 安装依赖

添加依赖后,执行以下命令获取包:

flutter pub get

3. 基本使用流程

使用 Pigeon 的基本流程分为以下几个步骤:

  1. 定义通信接口(Dart 文件)
  2. 运行代码生成命令
  3. 在 Flutter 和鸿蒙平台实现接口
  4. 调用通信接口

3.1 定义通信接口

首先,创建一个 Dart 文件来定义通信接口。这个文件将作为 Pigeon 的输入,用于生成各平台的代码。

示例:pigeons/messages.dart

import 'package:pigeon/pigeon.dart';

// 配置 Pigeon 生成选项
(PigeonOptions(
  dartOut: 'lib/src/messages.g.dart',
  javaOut: 'android/app/src/main/java/io/flutter/plugins/Messages.java',
  javaOptions: JavaOptions(package: 'io.flutter.plugins'),
  swiftOut: 'ios/Runner/Messages.g.swift',
  objcHeaderOut: 'ios/Runner/messages.g.h',
  objcSourceOut: 'ios/Runner/messages.g.m',
  objcOptions: ObjcOptions(prefix: 'PGN'),
  arkTSOut: 'ohos/entry/src/main/ets/plugins/Messages.ets',
  arkTSOptions: ArkTSOptions(),
))

// 定义枚举
enum MessageType {
  text,
  image,
  video,
}

// 定义数据模型
class ChatMessage {
  ChatMessage({
    required this.id,
    required this.content,
    required this.type,
    required this.timestamp,
  });
  
  String id;
  String content;
  MessageType type;
  int timestamp;
  Map<String, dynamic>? extraData;
}

// 定义由鸿蒙平台实现,供 Flutter 调用的接口
()
abstract class ChatHostApi {
  // 获取当前平台信息
  String getPlatformVersion();
  
  // 发送消息(同步方法)
  bool sendMessage(ChatMessage message);
  
  // 异步获取历史消息
  
  List<ChatMessage?> getHistoryMessages(int limit, int offset);
}

// 定义由 Flutter 实现,供鸿蒙平台调用的接口
()
abstract class ChatFlutterApi {
  // 接收来自鸿蒙平台的消息
  void onMessageReceived(ChatMessage message);
  
  // 消息状态更新
  void onMessageStatusUpdated(String messageId, String status);
}

3.2 运行代码生成命令

定义好接口后,运行以下命令生成各平台的代码:

flutter pub run pigeon --input pigeons/messages.dart

执行成功后,Pigeon 将在指定的输出路径生成对应的代码文件:

  • Flutter 端:lib/src/messages.g.dart
  • 鸿蒙端:ohos/entry/src/main/ets/plugins/Messages.ets

3.3 在鸿蒙平台实现接口

在鸿蒙端,需要实现 Pigeon 生成的 ArkTS 接口。

示例:ohos/entry/src/main/ets/plugins/ChatHostApiImpl.ets

import { ChatHostApi, ChatMessage, MessageType } from './Messages.ets';

// 实现 ChatHostApi 接口
export class ChatHostApiImpl implements ChatHostApi {
  getPlatformVersion(): string {
    return 'OpenHarmony ' + ohos.app.Context.getApplicationContext().getApplicationInfo().versionName;
  }
  
  sendMessage(message: ChatMessage): boolean {
    // 实现消息发送逻辑
    console.log(`发送消息: ${message.content}`);
    return true;
  }
  
  getHistoryMessages(limit: number, offset: number, callback: (result: Array<ChatMessage | null> | null, error: Error | null) => void): void {
    // 异步获取历史消息
    setTimeout(() => {
      const messages: Array<ChatMessage | null> = [
        ChatMessage({
          id: '1',
          content: 'Hello from OpenHarmony!',
          type: MessageType.text,
          timestamp: Date.now() - 3600000,
          extraData: {'sender': 'system'}
        }),
        ChatMessage({
          id: '2',
          content: 'Welcome to Pigeon!',
          type: MessageType.text,
          timestamp: Date.now() - 1800000,
          extraData: {'sender': 'system'}
        })
      ];
      callback(messages, null);
    }, 1000);
  }
}

// 注册实现类
export function registerChatHostApi() {
  ChatHostApi.setup(new ChatHostApiImpl());
}

示例:ohos/entry/src/main/ets/index.ets

import { registerChatHostApi } from './plugins/ChatHostApiImpl.ets';

// 注册 Pigeon API
export function onEvent(event: string, data: any): void {
  if (event === 'flutterInit') {
    registerChatHostApi();
  }
}

3.4 在 Flutter 端调用接口

在 Flutter 端,可以直接调用生成的 API 类。

示例:lib/main.dart

import 'package:flutter/material.dart';
import 'src/messages.g.dart';
import 'src/messages.dart';

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

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

  
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Pigeon Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: const MyHomePage(title: 'Pigeon Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({Key? key, required this.title}) : super(key: key);
  final String title;

  
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  final ExampleHostApi _api = ExampleHostApi();
  String _platformVersion = 'Unknown';
  int _result = 0;

  
  void initState() {
    super.initState();
    _initPlatformState();
  }

  // 获取平台版本
  Future<void> _initPlatformState() async {
    String platformVersion;
    
    try {
      platformVersion = await _api.getPlatformVersion() ?? 'Unknown platform version';
    } on PlatformException {
      platformVersion = 'Failed to get platform version.';
    }

    if (!mounted) return;

    setState(() {
      _platformVersion = platformVersion;
    });
  }

  // 调用加法方法
  Future<void> _addNumbers() async {
    int result;
    
    try {
      result = await _api.add(10, 20);
    } on PlatformException {
      result = -1;
    }

    setState(() {
      _result = result;
    });
  }

  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text('Running on: $_platformVersion'),
            const SizedBox(height: 20),
            ElevatedButton(
              onPressed: _addNumbers,
              child: const Text('Add 10 + 20'),
            ),
            const SizedBox(height: 10),
            Text('Result: $_result'),
          ],
        ),
      ),
    );
  }
}

3.5 在 Flutter 端实现供鸿蒙调用的接口

示例:lib/src/chat_flutter_api_impl.dart

import 'package:flutter/services.dart';
import '../messages.g.dart';
import '../messages.dart';

class ChatFlutterApiImpl implements ChatFlutterApi {
  
  void onMessageReceived(ChatMessage message) {
    // 处理从鸿蒙平台接收的消息
    print('Received message from HarmonyOS: ${message.content}');
    // 可以在这里更新 UI 或触发其他操作
  }

  
  void onMessageStatusUpdated(String messageId, String status) {
    // 处理消息状态更新
    print('Message $messageId status updated to: $status');
  }
}

// 初始化 Flutter API
void initChatFlutterApi() {
  ChatFlutterApi.setup(ChatFlutterApiImpl());
}

4. 核心 API 介绍

4.1 主要注解

注解 描述 鸿蒙支持
@HostApi() 定义由主机平台(如鸿蒙)实现,供 Flutter 调用的接口 支持
@FlutterApi() 定义由 Flutter 实现,供主机平台调用的接口 支持
@async 标记方法为异步,需要通过回调返回结果 支持
@ObjCSelector() 为 Objective-C 生成更符合语言习惯的方法名 支持
@SwiftFunction() 为 Swift 生成更符合语言习惯的方法名 支持
@ConfigurePigeon() 配置 Pigeon 的代码生成选项 支持

4.2 主要命令选项

选项 描述 鸿蒙支持
--input <path> 指定输入的 Dart 文件路径 支持
--dart_out <path> 指定生成的 Dart 文件输出路径 支持
--arkts_out <path> 指定生成的鸿蒙 ArkTS 文件输出路径 支持
--java_out <path> 指定生成的 Java 文件输出路径 支持
--kotlin_out <path> 指定生成的 Kotlin 文件输出路径 支持
--swift_out <path> 指定生成的 Swift 文件输出路径 支持
--objc_header_out <path> 指定生成的 Objective-C 头文件输出路径 支持
--objc_source_out <path> 指定生成的 Objective-C 源文件输出路径 支持
--cpp_header_out <path> 指定生成的 C++ 头文件输出路径 支持
--cpp_source_out <path> 指定生成的 C++ 源文件输出路径 支持

5. 鸿蒙平台注意事项

  1. 权限配置

    • 确保在鸿蒙应用的 config.json5 中配置了必要的权限
    • 特别是涉及网络、文件访问等功能时
  2. ArkTS 版本兼容性

    • 确保使用的 ArkTS 版本与项目要求一致
    • Pigeon 生成的代码可能需要特定版本的 ArkTS 支持
  3. 包结构

    • 建议将生成的 ArkTS 文件放在 ohos/entry/src/main/ets/plugins/ 目录下
    • 保持清晰的包结构,便于管理和维护
  4. 错误处理

    • 在异步方法中,确保正确处理错误并通过回调返回
    • 鸿蒙平台的异常需要正确映射到 Flutter 的 PlatformException
  5. 线程模型

    • 注意鸿蒙平台的线程模型,避免在 UI 线程执行耗时操作
    • 可以使用 @TaskQueue 注解控制方法的执行线程

6. 高级功能

6.1 自定义数据类型

Pigeon 支持复杂的自定义数据类型,包括嵌套类和集合类型:

class User {
  User({required this.id, required this.name, required this.profile});
  
  String id;
  String name;
  Profile profile;
  List<String>? tags;
  Map<String, dynamic>? extraInfo;
}

class Profile {
  Profile({required this.avatar, required this.bio, required this.contact});
  
  String avatar;
  String bio;
  Contact contact;
}

class Contact {
  Contact({required this.email, required this.phone});
  
  String email;
  String phone;
}

6.2 异步方法

使用 @async 注解标记异步方法,在鸿蒙平台实现时需要通过回调返回结果:

()
abstract class FileHostApi {
  
  void downloadFile(String url, String savePath, void Function(bool success, String? error) callback);
}

鸿蒙平台实现:

downloadFile(url: string, savePath: string, callback: (success: boolean, error: string | null) => void): void {
  // 异步下载文件
  downloadManager.download(url, savePath).then(() => {
    callback(true, null);
  }).catch((error) => {
    callback(false, error.message);
  });
}

6.3 测试支持

Pigeon 提供了测试支持,可以在 Dart 端模拟主机平台的实现:

flutter pub run pigeon --input pigeons/messages.dart --dart_test_out lib/src/messages_test.g.dart

然后在测试中使用:

class MockChatHostApi implements ChatHostApi {
  
  String getPlatformVersion() => 'Mock Platform 1.0.0';
  
  
  bool sendMessage(ChatMessage message) => true;
  
  
  void getHistoryMessages(int limit, int offset, void Function(List<ChatMessage?>?, PlatformException?) callback) {
    callback([], null);
  }
}

void main() {
  test('Test chat functionality', () {
    final mockApi = MockChatHostApi();
    ChatHostApi.setup(mockApi);
    
    // 测试代码
  });
}

7. 总结

Pigeon 是 Flutter 开发中实现跨平台通信的强大工具,它为鸿蒙平台提供了完整的支持。通过本文的介绍,开发者可以:

  1. 了解 Pigeon 包的基本功能和鸿蒙平台支持情况
  2. 掌握通过 Git 形式引入自定义修改版本的依赖配置方法
  3. 熟悉 Pigeon 的完整使用流程,包括接口定义、代码生成和实现调用
  4. 了解核心 API 和高级功能的使用方法
  5. 注意在鸿蒙平台上使用时的特殊事项

使用 Pigeon 可以大大简化 Flutter 与鸿蒙平台之间的通信开发,提高代码的类型安全性和可维护性。通过自动生成的代码,开发者可以专注于业务逻辑的实现,而无需关心底层的通信细节。

Pigeon 不仅支持基本的数据传递,还支持复杂的自定义类型、异步方法和错误处理,为构建复杂的跨平台应用提供了坚实的基础。

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

Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐