Flutter之初識iOS外掛

A踐行者發表於2019-06-12

Flutter外掛

同時發表於簡書

簡介

Flutter 的庫是以 package 的方式來管理。Package 分為兩種,Dart package(也叫 library package) 和 plugin package。日常使用的 import 'package:flutter/material.dart'; 就是 Dart 包,它只能使用 Dart 和 Flutter 提供的 API, 決定了它只能用在 Flutter 上;今天文章內容主要講解 Flutter 外掛開發指的是後者,即 plugin package。Flutter 外掛既包含了dart程式碼編寫的api,又包含了平臺( Android/iOS )特定實現的package,可以被 Android 和 iOS 呼叫。

使用

可以在 pub.dev 網站查詢你所需要的包。

我們以 shared_preferences 這個庫為例,在專案中的 pubspec.yaml 宣告一個依賴:

dependencies:
  shared_preferences: ^0.5.2
複製程式碼

^0.5.2 與 0.5.2 相容的版本版本號,同時你也可以使用如下格式:

  • any:任意版本
  • 1.2.3:特定的版本
  • <1.2.3:小於 1.2.3 的版本,此外還有 <=、>、>= 可以使用
  • =1.2.3 <2.0.0’:指定一個範圍

更加詳細的配置可以參考 versioning

儲存後 Android Studio 會自動去下載此包,或者通過命令,在專案的根目錄執行 flutter packages get 使用就相對簡單了,如下: import 'package:shared_preferences/shared_preferences.dart'; ##開發

外掛通訊機制

15584954324475.png

如上圖所示,Flutter 跟平臺相關程式碼可以通過 MethodChannel 進行通訊。客戶端通過 MethodChannel 將方法呼叫和引數發生給 FlutterFlutter也通過 MethodChannel 接收相關的資料。

訊息和響應是非同步傳遞的,以確保使用者介面保持響應(不會掛起)

建立外掛專案

接下來利用 Android Studio 來進行外掛開發, 建立成功後,目錄結構如下:

dir_struct.png

  • android:外掛原生程式碼的 Android 端實現
  • ios:iOS 端的實現
  • lib:Dart 程式碼。外掛的客戶將會使用這裡實現的介面
  • example:外掛的使用示例
  • test: 測試

其中,一個最package最少包含了兩部分: * 一個pubspec.yaml檔案:後設資料檔案,宣告瞭package的名稱、版本、作者等資訊。

一個lib資料夾:包含裡package的公開程式碼,資料夾至少需要存在.dart這個檔案。

也可以利用 Flutter 命令來生成

flutter create --org com.kinsomy --template=plugin -i swift -a kotlin hello 
複製程式碼

預設情況下,建立的plugin專案是使用 objective-c(iOS)和 java(Android)編寫,如果需要增加對swift和kotlin的支援,可以在命令中新增 -i 和 -a。

注意點:外掛命名符合 lowercase_with_underscores

編寫 iOS 外掛

FlutterPluginTestPlugin_m.png

Flutter 與 iOS 通訊

iOS-Flutter外掛_pdf.png
!

Dart 程式碼
import 'dart:async';
import 'package:flutter/services.dart';

class FlutterPluginTest {
  static const MethodChannel _channel =
  const MethodChannel('flutter_plugin_test');

  static Future<String> get platformVersion async {
    final String version = await _channel.invokeMethod('getPlatformVersion');
    return version;
  }
}
複製程式碼
iOS 程式碼
@implementation FlutterPluginTestPlugin
+ (void)registerWithRegistrar:(NSObject<FlutterPluginRegistrar>*)registrar {
  FlutterMethodChannel* channel = [FlutterMethodChannel
      methodChannelWithName:@"flutter_plugin_test"
            binaryMessenger:[registrar messenger]];
 //兩種回撥方式:
    //1.代理本質:內部呼叫channel 的Block執行代理函式
  FlutterPluginTestPlugin* instance = [[FlutterPluginTestPlugin alloc] init];
  [registrar addMethodCallDelegate:instance channel:channel];
//    //2.
//    channel setMethodCallHandler:^(FlutterMethodCall * _Nonnull call, FlutterResult  _Nonnull result) {
//
//    }
}

- (void)handleMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result {
  if ([@"getPlatformVersion" isEqualToString:call.method]) {
    result([@"iOS " stringByAppendingString:[[UIDevice currentDevice] systemVersion]]);
  } else {
    result(FlutterMethodNotImplemented);
  }
}
@end
複製程式碼

其中,在 dart 端傳入引數被解析為Map ,到了 oc 中會變成 NSDictionary,然後通過 key 獲取到對應的值 如下為:型別對應表

15585074766210.jpg

iOS 與 Flutter 通訊

Dart端

Channel.setMethodCallHandler((MethodCall call) async {
      assert(call.method == 'launch');
      handler(call.arguments);
    });
複製程式碼

iOS端

 [self.channel invokeMethod:@"FunctionName" arguments:引數];
複製程式碼

補充

在 通訊機制中,還有兩類 FlutterEventChannel,FlutterBasicMessageChannel,同時在Dart端使用同型別的Channel

參考文章

  1. packages 官方文件

相關文章