简介
Pigeon 是在 Flutter 1.20 发布的,为了解决 Flutter 调用 native 代码过于麻烦和困难,需要在字符串的基础上匹配函数名和参数,通过使用这个包可以实现,写这篇文章的初衷是官方虽然也提供有demo,但与自己的项目使用上还是有一点区别。
-
与 native 类型安全通信
-
通过自动生成减少手写代码量
这篇文章主要是详细描述了如何使用 Pigeon 从 Flutter 端调用一个在 Swift/Kotlin 中实现的简单 getPlatformVersion
方法。实例项目可在此处获得。
创建 Flutter app
$ flutter create -i swift -a kotlin flutter_pigeon
复制代码
Pigeon 是做什么的
Java/Objective-C 接口协议是根据 Dart 端定义的参数和返回值信息自动生成
的。
原生基于这些接口实现,可以与 Flutter 端进行类型安全通信。
类似于使用 TypeScript 创建类型定义文件。
安装
# pubspec.yaml
dev_dependencies:
pigeon: ^1.0.0
复制代码
Dart
首先,创建一个定义与原生通信的 dart 文件。在根目录下创建 pigeon/schema.dart 文件
// schema.dart
import 'package:pigeon/pigeon.dart';
class Version {
late String string;
}
@HostApi()
abstract class Api {
Version getPlatformVersion();
}
复制代码
新建脚本文件 run_pigeon.sh
# run_pigeon.h
$ flutter pub run pigeon \
--input pigeon/schema.dart \
--dart_out lib/api_generated.dart \
--objc_header_out ios/Runner/Pigeon.h \
--objc_source_out ios/Runner/Pigeon.m \
--objc_prefix FLT \
--java_out android/app/src/main/java/io/flutter/plugins/Pigeon.java \
--java_package "io.flutter.plugins"
复制代码
运行脚本自动生成对应的接口文件
$ ./run_pigeon.sh
复制代码
在需要调用原生方法函数的地方导入并使用 Pigeon 生成的 dart 文件
Kotlin
API接口写在Pigeon生成的Java文件中,所以创建一个实现它的类,并传递给setup方法。
// MainActivity.kt
package com.example.flutter_pigeon
import io.flutter.embedding.android.FlutterActivity
import io.flutter.embedding.engine.FlutterEngine
import io.flutter.plugins.Pigeon
class MainActivity: FlutterActivity() {
private class MyApi: Pigeon.Api {
override fun getPlatformVersion(): Pigeon.Version {
var result = Pigeon.Version()
result.string = "Android ${android.os.Build.VERSION.RELEASE}"
return result
}
}
override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
super.configureFlutterEngine(flutterEngine)
// 2. setup()
Pigeon.Api.setup(flutterEngine.dartExecutor.binaryMessenger, MyApi())
}
}
复制代码
Swift
在桥接文件 ios/RunnerRunner-Bridging-Header.h
添加 import 语句,让 Pigeon 生成的 Objective-C 文件对 Swift 可见
// ios / Runner / Runner-Bridging-Header.h
#import "Pigeon.h"
复制代码
由于 API 协议写在生成的文件中,创建一个实现该协议的类 MyApi
创建 SwiftPigeonService.swift 文件 实现协议方法
// SwiftPigeonService.swift
import Flutter
import UIKit
public class SwiftPigeonService: NSObject, FLTApi {
public func getPlatformVersionWithError(_ error: AutoreleasingUnsafeMutablePointer<FlutterError?>) -> FLTVersion? {
let result = FLTVersion.init()
result.string = "iOS " + UIDevice.current.systemVersion
return result
}
}
复制代码
在 AppDelegate 中实例化 API 并将其传递给 setup 方法
// AppDelegate.swift
import UIKit
import Flutter
@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate {
override func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
let controller : FlutterViewController = window?.rootViewController as! FlutterViewController
FLTApiSetup(controller.binaryMessenger, SwiftPigeonService())
GeneratedPluginRegistrant.register(with: self)
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}
}
复制代码
总结
-
Pigeon 自动生成使用 MethodChannel 相关部分内容。(严格来说,Pigeon 使用的是BasicMessageChannel)
-
预定义模式允许与 native 进行类型安全通信
-
生成的代码是 Java/Objective-C,但是由于 Kotlin 可以调用 Java,Swift 可以调用 Objective-C
-
不必了解 Dart 端代码 (只需调用自动生成的 API)
-
不必了解原生代码 (只需实现自动生成的接口)
-
实际官方插件中 video_player 已经在使用了