Flutter 官方嘗試放只“鴿子”來簡化Native外掛開發

戀貓de小郭發表於2020-03-18

Flutter 在原生外掛的開發上預設是需要開發者重複地寫模版程式碼來接入,而近期 Flutter 團隊最近釋出了一個 package: pub.flutter-io.cn/packages/pi… , 主要是用來解決和優化 native 外掛開發上 platform channel 相關的問題。

該專案目前處於實驗性階段。

Flutter 官方嘗試放只“鴿子”來簡化Native外掛開發

該專案主要通過 Dart 指令碼去自動生成通用的模板程式碼,專案剛剛釋出測試所以也相對簡陋,而官方表示 pigeon 僅僅用於生成 Flutter 和宿主平臺的模版程式碼,沒有任何執行時的要求,所以也不需要擔心引入的衝突。

Flutter 官方嘗試放只“鴿子”來簡化Native外掛開發

接入

整合 pigeon 首先需要在 dev_dependencies 引入 pigeon 依賴。

dev_dependencies:
  flutter_test:
    sdk: flutter
  pigeon: ^0.1.0-experimental.3
複製程式碼

之後在專案內建立一個 dart 檔案,按照官方提供的建議我們在專案根目錄建立了一個 pigeons 的目錄,然後建立一個 message.dart 檔案。

import 'package:pigeon/pigeon_lib.dart';

class SearchRequest {
  String query;
}

class SearchReply {
  String result;
}

@HostApi()
abstract class Api {
  SearchReply search(SearchRequest request);
}
複製程式碼

如上程式碼所示, message.dart 檔案中通過 @HostApi() 註解標示了通訊物件和介面,之後我們只需要執行如下命令,就可以生成對應程式碼到工程中。

flutter pub run pigeon  --input pigeons/message.dart  --dart_out lib/pigeon.dart  --objc_header_out ios/Runner/pigeon.h --objc_source_out ios/Runner/pigeon.m --java_out android/app/src/main/java/com/shuyu/testpigeon/Pigeon.java --java_package "com.shuyu.testpigeon"
複製程式碼

如上所示命令列:

  • 通過 --input 引入了我們建立的 message.dart 檔案;
  • 通過 --dart_out 輸出了 dart 模板檔案;
  • 通過 --objc_header_out--objc_source_out 輸出了 object-c 檔案;
  • 通過 --java_out 輸出了 java 檔案;

命令執行後 dart 檔案輸出到 lib 目錄下, object-c 檔案輸出到了 ios/Runner 目錄下,java 檔案輸出到指定的 com.shuyu.testpigeon" 包名路徑下,之後就可以開始正式接入。

Android

首先看 Android 專案,在生成的 Pigeon.java 中包含了 Api 介面用於開發者實現互動邏輯,同時開發者可以通過 SearchRequest 獲取 dart 傳送過來的請求,通過 SearchReply 返回資料給 dart 。

所以在 MainActivity 中通過實現 Api 介面就可以完成資料互動,如下程式碼所示:

  • 通過繼承 Pigeon.Api 實現了 MyApi 物件;
  • search 方法中通過 request.getQuery() 獲取 dart 的請求資料,並且通過 Pigeon.SearchReplysetResult 返回 String.format("Hi %s!", request.getQuery()),在收到的 dart 文字之前加上 Hi 並返回;
  • 最後通過 Pigeon.Api.setup(getFlutterView(), new MyApi()); 就可以完成引用;
package com.shuyu.testpigeon;

import android.os.Bundle;
import io.flutter.app.FlutterActivity;
import io.flutter.plugins.GeneratedPluginRegistrant;

public class MainActivity extends FlutterActivity {

  private class MyApi implements Pigeon.Api {
    @Override
    public Pigeon.SearchReply search(Pigeon.SearchRequest request) {
      Pigeon.SearchReply reply = new Pigeon.SearchReply();
      reply.setResult(String.format("Hi %s!", request.getQuery()));
      return reply;
    }
  }

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    GeneratedPluginRegistrant.registerWith(this);
    Pigeon.Api.setup(getFlutterView(), new MyApi());
  }
}

複製程式碼

iOS

在 iOS 上首先要先把生成的 pigeon.hpigeon.m 檔案 link 到 Xcode 工程裡,之後如下程式碼所示在 AppDelegate.h 引入 Api 協議。

#import <Flutter/Flutter.h>
#import <UIKit/UIKit.h>
#import "pigeon.h"

@interface AppDelegate : FlutterAppDelegate<Api>

@end
複製程式碼

如下程式碼所示,接下來在 AppDelegate.m 中實現 search 介面,然後在收到的 dart 文字之前加上 Hi 並返回,最後呼叫 ApiSetup 方法將完成註冊。

#include "AppDelegate.h"
#include "GeneratedPluginRegistrant.h"

@implementation AppDelegate

- (BOOL)application:(UIApplication *)application
    didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
  [GeneratedPluginRegistrant registerWithRegistry:self];
  // Override point for customization after application launch.
  FlutterViewController* controller =
      (FlutterViewController*)self.window.rootViewController;
  ApiSetup(controller.binaryMessenger, self);
  return [super application:application didFinishLaunchingWithOptions:launchOptions];
}


-(SearchReply *)search:(SearchRequest*)input error:(FlutterError **)error {
    SearchReply* result = [[SearchReply alloc] init];
    result.result  = [NSString stringWithFormat:@"%s%@","Hi ",input.query];
    return result;
}


@end

複製程式碼

Dart

如下程式碼所示,最後在 Dart 程式碼中,我們只需要通過 pigeon.dart 中的 Api 去呼叫 search 方法,就可以完成 dart 到原生的通訊邏輯,最後在終端看到 Hi GSY 的輸出。

  void _incrementCounter()  async{
    SearchRequest request = SearchRequest()..query = "GSY";
    Api api = Api();
    SearchReply reply = await api.search(request);
    print("###### ${reply.result}");
  }

複製程式碼

我們可以看到在 igeon.dart 檔案中其實就是通過 dev.flutter.pigeon.Api.search 標示的 StandardMessageCodec 去通訊,並且 SearchReplySearchRequest 也是按照我們起初建立的 message.dart 中的物件去生成。

而對於 message.dart 官方目前也有一些要求,比如:

  • 該檔案不能包含任何方法或函式定義。
  • 資料型別需要時 platform channel 支援的。
  • Api必須是一個“抽象類”,可以使用“HostApi()”或 FlutterApi() 作為後設資料。
  • Api類的方法宣告應該有一個引數和一個返回 其型別在檔案中定義的值。

通過這套規則,在實現原生外掛時我們可以少些很多重複程式碼,當然上述是直接在 Flutter App 工程中整合接入 pigeon ,正常流程應該是在外掛工程中去使用。

同時官方也表示 pigeon 目前是實驗性的,未來可能會被刪除或者出現 Api 變動,Flutter 也 歡迎大家試一下在 GitHub 上提供反饋:github.com/flutter/pac…

資源推薦

Flutter 官方嘗試放只“鴿子”來簡化Native外掛開發

相關文章