Flutter Native 与 Pigeon 集成实用指南

 先决条件

  • 对学习新 🔥 🚀 事物充满热情
  • 一些使用 Flutter 💙 构建应用的经验
  • 基本的编程知识 👾

什么是 Pigeon?

Pigeon 是一个代码生成器工具,使 Flutter 和主机平台之间的通信类型安全、更轻松、更快捷。— pub

Pigeon 是一个代码生成工具,通过在常见的 Flutter 的外函数接口(FFI)上生成类型安全的惯用代码,使它们更容易、更快速地进行类型安全(具有更高的错误处理保真度)之间的通信,它们也被称为方法通道、模式。

Pigeon 无需编写任何接口或方法通道代码来在主机平台之间进行通信,因为它生成了我们需要的所有代码。本文中涉及 Pigeon 从设置到使用,但不会涵盖它的所有功能,要了解更多信息,请访问官方文档。

在撰写本文时,Pigeon 版本是 17.1.2。

Pigeon 配置

在 lib 之外创建一个文件夹,用于放置项目所需的任意数量 Pigeon,我们称之为 Pigeons。在该文件夹中创建一个 native_moible_pigeon.dart 文件,在其中写入 Pigeon 的构建配置。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
import 'package:pigeon/pigeon.dart';

@ConfigurePigeon(PigeonOptions(
  dartOut: 'lib/native_api/native_mobile_ui.g.dart',
  kotlinOut: 'android/app/src/main/kotlin/com/example/mobile_declarative_ui/NativeMobileUi.g.kt',
  javaOut: 'android/app/src/main/java/io/flutter/plugins/NativeMobileUi.java',
  swiftOut: 'ios/Runner/NativeMobileUi.g.swift',
  dartPackageName: 'native_mobile_ui',
))
@HostApi()
abstract class NativeMobileHostApi {
  @async
  String getNativeUiResult();
}

下面我们将介绍 ConfigurePigeon 注解的每个选项:

  • dartOut:生成文件的输出路径,此处我们将其指定为 lib/native_api/native_mobile_ui.g.dart 告诉 Pigeon 在 lib 文件夹中创建文件,以便我们的项目可以访问它,文件扩展名前的 .g 是 flutter/dart 约定,用于区分自动生成的文件。
  • kotlinOut:如果项目使用 kotlin,则指定输出 kotlin 生成文件的路径。
  • javaOut:指定我们要输出为项目生成的 java 代码的路径。
  • swiftOut:指定生成的 swift 文件的创建路径。
  • dartPackagename: Pigeon 所生成软件包的包名

HostApi 注解用于告诉 Pigeon 我们需要生成主机平台代码,因为 Pigeon 可以从两端生成代码(flutter <-> host)。async 注解告诉 Pigeon 该方法是一个耗时的调用,因此它将其作为系统两端的 Future/Async 任务处理。

使用以下命令生成代码:

1
dart run pigeon --input pigeons/native_mobile_pigeon.dart

Flutter

生成的文件现在在 lib 文件夹中创建,为了更简洁的 API 实现,我们将在与生成的文件相同的文件夹中创建一个 native_mobile_ui.dart 文件,其中代码如下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
import 'native_mobile_ui.g.dart';

final _api = NativeMobileHostApi();

Future<String> getNativeUiResult() async {
  try {
    return await _api.getNativeUiResult();
  } catch (e) {
    return 'Failed to retrieve result';
  }
}

现在我们从 main.dart 中直接调用 getNativeUiResult,就是这样!!!

 Android

检查 android 文件夹中生成的代码,可以看到 Pigeon 为我们的 NativeMobileHostApi 生成了一个接口,该接口有一个配套对象类,用于处理通信通道的设置。我们可以使用 setUp 函数调用该通道,该函数采用 binaryMessenger 和可为 null 的 NativeMobileHostApi。

由于它是一个接口,我们只需要实现它即可,就像下面代码所做的一样。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
package com.example.mobile_declarative_ui

import FlutterError
import NativeMobileHostApi
import android.content.Intent
import io.flutter.embedding.android.FlutterActivity
import io.flutter.embedding.engine.FlutterEngine
import io.flutter.plugin.common.MethodChannel

typealias FlutterResultCallback = (Result<String>) -> Unit

class MainActivity : FlutterActivity(), NativeMobileHostApi {
    private var nativeUiResultCallback: FlutterResultCallback? = null
    private val composeActivityRequestCode: Int = 4

    override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
        super.configureFlutterEngine(flutterEngine)

        NativeMobileHostApi.setUp(flutterEngine.dartExecutor.binaryMessenger, this)
    }

    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        super.onActivityResult(requestCode, resultCode, data)

        if (nativeUiResultCallback == null) return@onActivityResult

        if (requestCode == composeActivityRequestCode && resultCode == RESULT_OK) {

            val value = data?.getStringExtra(ComposeActivity.REPLY_MESSAGE)
            if (value == null) {
                nativeUiResultCallback?.invoke(
                    Result.failure(FlutterError("code", "message", "details"))
                )
                return@onActivityResult
            }
            nativeUiResultCallback?.invoke(Result.success(value))
        }
    }

    override fun getNativeUiResult(callback: (Result<String>) -> Unit) {
        nativeUiResultCallback = callback
        val intent = Intent(this, ComposeActivity::class.java)
        startActivityForResult(intent, composeActivityRequestCode)
    }
}

结论

Pigeno 通过一种类型安全并且惯用的方法来改进我们的 Flutter 应用程序与原生 API 的交互,其官方文档和示例项目是进行更多探索的好地方。

快乐编码 🚀

 Referent

Licensed under CC BY-NC-SA 4.0