工具插件:pigeon
推薦必看的官方例子:pigeon_plugin_example
其他pigeon寫法的例子:
① pigeon/example
② pigeons
Pigeon is a code generator tool to make communication between Flutter and the host platform type-safe, easier and faster.
一個代碼生成工具鸠信,讓Flutter
和宿主平臺更安全纵寝、更簡單、更快地通信星立。
通過Dart
入口爽茴,生成兩端通用的模板代碼,原生則只需重寫模板內(nèi)的接口绰垂,無需管理Method Channel
的實現(xiàn)室奏。參數(shù)可以通過模板來同步生成。
目前的pigeon
只支持生成OC
和Java
代碼劲装。
1胧沫、命令創(chuàng)建Plugin
$ flutter create --template=plugin --platforms=android,ios -i swift -a kotlin flutter_pigeon_plugin
2、flutter
項目中pubspec.yaml
的dev_dependencies
中占业,添加pigeon
插件依賴
dev_dependencies:
flutter_test:
sdk: flutter
flutter_lints: ^1.0.0
pigeon:
3绒怨、在Flutter
項目的lib
目錄外創(chuàng)建一個pigeons
文件夾,在pigeons
文件夾中創(chuàng)建all_types_pigeon.dart
import 'package:pigeon/pigeon.dart';
class Everything {
bool? aBool;
int? anInt;
double? aDouble;
String? aString;
Uint8List? aByteArray;
Int32List? a4ByteArray;
Int64List? a8ByteArray;
Float64List? aFloatArray;
// ignore: always_specify_types
List? aList;
// ignore: always_specify_types
Map? aMap;
List<List<bool?>?>? nestedList;
Map<String?, String?>? mapWithAnnotations;
}
/// Flutter調(diào)用原生的方法
@HostApi()
abstract class HostEverything {
Everything giveMeEverything();
Everything echo(Everything everything);
}
/// 原生調(diào)用Flutter的方法
@FlutterApi()
abstract class FlutterEverything {
Everything giveMeEverythingFlutter();
Everything echoFlutter(Everything everything);
}
4纺酸、執(zhí)行命令
首先創(chuàng)建存放生成文件的文件夾:
在android/src/mian
下創(chuàng)建java/com/example/flutter_pigeon_plugin/
文件夾窖逗,存放生成的Java
文件。
在項目目錄~/flutter_pigeon_plugin
下餐蔬,執(zhí)行以下命令:
$ flutter pub run pigeon --input pigeons/all_types_pigeon.dart --dart_out lib/all_types_pigeon.dart --objc_header_out ios/Classes/AllTypesPigeon.h --objc_source_out ios/Classes/AllTypesPigeon.m --java_out android/src/main/java/com/example/flutter_pigeon_plugin/AllTypesPigeon.java --java_package "com.example.flutter_pigeon_plugin"
命令拆解:
①` flutter pub run pigeon`
生成代碼的命令
②` --input pigeons/all_types_pigeon.dart `
指定生成代碼的輸入`dart`文件
③ `--dart_out lib/all_types_pigeon.dart `
指定輸出生成`dart`文件的目錄文件
④ `--objc_header_out ios/Classes/AllTypesPigeon.h `
指定要生成的`iOS`的`.h`文件路徑
⑤ `--objc_source_out ios/Classes/AllTypesPigeon.m `
指定要生成的`iOS`的`.m`文件路徑
⑥ `--java_out android/src/main/java/com/example/flutter_pigeon_plugin/AllTypesPigeon.java `
指定要生成的`Android`的`.java`文件路徑
⑦ `--java_package "com.example.flutter_pigeon_plugin`
指定`Android`的包名碎紊,在`android/src/main/`下的`AndroidManifest.xml`里的`package`
⑧ `--objc_prefix FLT`(可選)指定生成OC文件的前綴為FLT,前綴自己定義為自己的樊诺。
可以參考官方的例子里的做法:
① 項目目錄下創(chuàng)建一個run_pigeon.sh
文件
② 每次有改動仗考,執(zhí)行命令:. ./run_pigeon.sh
即可
③ run_pigeon.sh
文件內(nèi)容如下:
flutter pub run pigeon \
--input pigeons/all_types_pigeon.dart \
--dart_out lib/all_types_pigeon.dart \
--objc_header_out ios/Classes/AllTypesPigeon.h \
--objc_source_out ios/Classes/AllTypesPigeon.m \
--objc_prefix FLT \
--java_out android/src/main/java/com/example/flutter_pigeon_plugin/AllTypesPigeon.java \
--java_package "com.example.flutter_pigeon_plugin"
命令執(zhí)行完成,會自動在命令中指定的幾個位置生成響應(yīng)的文件词爬。
5秃嗜、iOS
實現(xiàn)Flutter
調(diào)用原生的方法
① 刪掉項目中之前的獲取版本的原生的和Flutter
側(cè)的相關(guān)channel
代碼
② 在AllTypesPigeon.m
中自動生成了一個方法HostEverythingSetup
void HostEverythingSetup(id<FlutterBinaryMessenger> binaryMessenger, NSObject<HostEverything> *api) {
{
FlutterBasicMessageChannel *channel =
[FlutterBasicMessageChannel
messageChannelWithName:@"dev.flutter.pigeon.HostEverything.giveMeEverything"
binaryMessenger:binaryMessenger
codec:HostEverythingGetCodec()];
if (api) {
NSCAssert([api respondsToSelector:@selector(giveMeEverythingWithError:)], @"HostEverything api doesn't respond to @selector(giveMeEverythingWithError:)");
[channel setMessageHandler:^(id _Nullable message, FlutterReply callback) {
FlutterError *error;
Everything *output = [api giveMeEverythingWithError:&error];
callback(wrapResult(output, error));
}];
}
else {
[channel setMessageHandler:nil];
}
}
{
FlutterBasicMessageChannel *channel =
[FlutterBasicMessageChannel
messageChannelWithName:@"dev.flutter.pigeon.HostEverything.echo"
binaryMessenger:binaryMessenger
codec:HostEverythingGetCodec()];
if (api) {
NSCAssert([api respondsToSelector:@selector(echoEverything:error:)], @"HostEverything api doesn't respond to @selector(echoEverything:error:)");
[channel setMessageHandler:^(id _Nullable message, FlutterReply callback) {
NSArray *args = message;
Everything *arg_everything = args[0];
FlutterError *error;
Everything *output = [api echoEverything:arg_everything error:&error];
callback(wrapResult(output, error));
}];
}
else {
[channel setMessageHandler:nil];
}
}
}
③ 在SwiftFlutterPigeonPlugin.swift
的注冊方法里,調(diào)用這個setup
方法進行初始化和設(shè)置
public static func register(with registrar: FlutterPluginRegistrar) {
let messenger: FlutterBinaryMessenger = registrar.messenger()
let api: HostEverything & NSObjectProtocol = SwiftFlutterPigeonPlugin.init()
HostEverythingSetup(messenger, api)
}
④ SwiftFlutterPigeonPlugin
遵循HostEverything
協(xié)議顿膨,實現(xiàn)Flutter
調(diào)原生的方法
import Flutter
import UIKit
/// 遵循HostEverything協(xié)議锅锨,實現(xiàn)Flutter調(diào)原生的方法
public class SwiftFlutterPigeonPlugin: NSObject, FlutterPlugin, HostEverything {
public static func register(with registrar: FlutterPluginRegistrar) {
let messenger: FlutterBinaryMessenger = registrar.messenger()
let api: HostEverything & NSObjectProtocol = SwiftFlutterPigeonPlugin.init()
HostEverythingSetup(messenger, api)
}
// MARK: HostEverything
public func giveMeEverythingWithError(_ error: AutoreleasingUnsafeMutablePointer<FlutterError?>) -> Everything? {
let everyThing = Everything()
everyThing.aString = "原生返給Flutter的字符串"
everyThing.aBool = false
everyThing.anInt = 11
return everyThing
}
/// 遵循HostEverything協(xié)議,實現(xiàn)Flutter調(diào)原生的方法
public func echo(_ everything: Everything, error: AutoreleasingUnsafeMutablePointer<FlutterError?>) -> Everything? {
everything.aString = "原生交換的給Flutter的字符串"
everything.aBool = false
everything.anInt = 12
return everything
}
}
⑤ iOS/Classes
目錄下恋沃,創(chuàng)建flutter_pigeon_plugin.h
文件必搞,導(dǎo)入頭文件,此文件在iOS
自動生成的<flutter_pigeon_plugin/flutter_pigeon_plugin-Swift.h>
文件中會自動引用囊咏。
//
// flutter_pigeon_plugin.h
// Pods
//
// Created by yuanzhiying on 2021/9/13.
//
#ifndef flutter_pigeon_plugin_h
#define flutter_pigeon_plugin_h
#import "AllTypesPigeon.h"
#endif /* flutter_pigeon_plugin_h */
6恕洲、 flutter_pigeon_plugin.dart
中實現(xiàn)插件調(diào)原生方法
import 'dart:async';
import 'package:flutter_pigeon_plugin/all_types_pigeon.dart';
class FlutterPigeonPlugin {
static final HostEverything _hostEverything = HostEverything();
/// Flutter 調(diào)用原生方法
static Future<Everything> getEverything() async {
return await _hostEverything.giveMeEverything();
}
/// Flutter 調(diào)用原生方法
static Future<Everything> echoEveryThing(Everything everything) async {
return await _hostEverything.echo(everything);
}
}
7塔橡、使用插件的方法
Future<void> getHostData() async {
/// 通過插件調(diào)用原生方法
Everything everything = await FlutterPigeonPlugin.getEverything();
debugPrint('everything.aString: ${everything.aString}');
debugPrint('everything.aBool: ${everything.aBool}');
debugPrint('everything.anInt:${everything.anInt}');
}
void echoHostData() async {
Everything echoEveryThing = Everything();
echoEveryThing.aString = '我要跟原生交換的字符串';
echoEveryThing.aBool = true;
echoEveryThing.anInt = 10;
/// 通過插件調(diào)用原生方法
Everything everything = await FlutterPigeonPlugin.echoEveryThing(echoEveryThing);
debugPrint('everything.aString: ${everything.aString}');
debugPrint('everything.aBool: ${everything.aBool}');
debugPrint('everything.anInt:${everything.anInt}');
}
至此,flutter
調(diào)用原生iOS
方法完成霜第。
8葛家、flutter
調(diào)用安卓原生的實現(xiàn)
① 刪除原有的獲取版本號的channel
的代碼
② FlutterPigeonPlugin.kt
中繼承AllTypesPigeon.HostEverything
,并實現(xiàn)對應(yīng)的方法
override fun giveMeEverything(): AllTypesPigeon.Everything {
var everything: AllTypesPigeon.Everything = AllTypesPigeon.Everything()
everything.aString = "原生返給Flutter的字符串"
everything.aBool = false
everything.anInt = 11
return everything
}
override fun echo(everything: AllTypesPigeon.Everything?): AllTypesPigeon.Everything? {
everything?.aString = "原生交換的給Flutter的字符串"
everything?.aBool = false
everything?.anInt = 12
return everything
}
③ 通過自動生成的setup方法泌类,進行初始化和設(shè)置
override fun onAttachedToEngine(@NonNull flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) {
AllTypesPigeon.HostEverything.setup(flutterPluginBinding.binaryMessenger, this)
}
override fun onDetachedFromEngine(@NonNull binding: FlutterPlugin.FlutterPluginBinding) {
AllTypesPigeon.HostEverything.setup(binding.binaryMessenger, null)
}
最終如下:
package com.example.flutter_pigeon_plugin
import androidx.annotation.NonNull
import io.flutter.embedding.engine.plugins.FlutterPlugin
import io.flutter.plugin.common.MethodCall
import io.flutter.plugin.common.MethodChannel
import io.flutter.plugin.common.MethodChannel.MethodCallHandler
import io.flutter.plugin.common.MethodChannel.Result
/** FlutterPigeonPlugin */
class FlutterPigeonPlugin: FlutterPlugin, MethodCallHandler, AllTypesPigeon.HostEverything {
override fun onAttachedToEngine(@NonNull flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) {
AllTypesPigeon.HostEverything.setup(flutterPluginBinding.binaryMessenger, this)
}
override fun onMethodCall(@NonNull call: MethodCall, @NonNull result: Result) {
result.notImplemented()
}
override fun onDetachedFromEngine(@NonNull binding: FlutterPlugin.FlutterPluginBinding) {
AllTypesPigeon.HostEverything.setup(binding.binaryMessenger, null)
}
override fun giveMeEverything(): AllTypesPigeon.Everything {
var everything: AllTypesPigeon.Everything = AllTypesPigeon.Everything()
everything.aString = "原生返給Flutter的字符串"
everything.aBool = false
everything.anInt = 11
return everything
}
override fun echo(everything: AllTypesPigeon.Everything?): AllTypesPigeon.Everything? {
everything?.aString = "原生交換的給Flutter的字符串"
everything?.aBool = false
everything?.anInt = 12
return everything
}
}
項目代碼見:flutter_pigeon_plugin