Flutter:platform channel

Flutter使用了一個靈活的系統,允許您調用特定平臺的API,無論在Android上的Java或Kotlin代碼中,還是iOS上的ObjectiveC或Swift代碼中均可用。

參考文獻:Writing custom platform-specific code

Flutter與原生之間的通信依賴靈活的消息傳遞方式:

  • 應用的Flutter部分通過平臺通道(platform channel)將消息發送到其應用程序的所在的宿主(iOS或Android)應用(原生應用)。
  • 宿主監聽平臺通道,並接收該消息。然後它會調用該平臺的API,並將響應發送回客戶端,即應用程序的Flutter部分。

平臺通道

使用平臺通道在Flutter(client)和原生(host)之間傳遞消息,如下圖所示:


當在Flutter中調用原生方法時,調用信息通過平臺通道傳遞到原生,原生收到調用信息後方可執行指定的操作,如需返回數據,則原生會將數據再通過平臺通道傳遞給Flutter。值得注意的是消息傳遞是異步的,這確保了用戶界面在消息傳遞時不會被掛起。

在客戶端,MethodChannel API 可以發送與方法調用相對應的消息。 在宿主平臺上,MethodChannelAndroid APIFlutterMethodChanneliOS API可以接收方法調用並返回結果。這些類可以幫助我們用很少的代碼就能開發平臺插件。

注意: 如果需要,方法調用(消息傳遞)可以是反向的,即宿主作爲客戶端調用Dart中實現的API。 quick_actions插件就是一個具體的例子。

創建一個新的應用程序項目
首先創建一個新的應用程序:

在終端中運行:flutter create systemversion
默認情況下,模板支持使用Java編寫Android代碼,或使用Objective-C編寫iOS代碼。要使用Kotlin或Swift,請使用-i和/或-a標誌:

在終端中運行: flutter create -i swift -a kotlin systemversion

Flutter端代碼

首先,我們構建通道。我們使用MethodChannel調用一個方法來返回系統版本。

通道的客戶端和宿主通過通道構造函數中傳遞的通道名稱進行連接。單個應用中使用的所有通道名稱必須是唯一的; 我們建議在通道名稱前加一個唯一的“域名前綴”,例如samples.flutter.io/systemVersion。

import 'dart:async';

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';

void main() => runApp(MyApp());

class MyApp extends StatefulWidget {
  // This widget is the root of your application.
  @override
  State<StatefulWidget> createState() {
    // TODO: implement createState
    return MyAppState();
  }
}

class MyAppState extends State<MyApp> {

static const platform = const MethodChannel('samples.flutter.io/systemVersion');
 // Get battery level.
  String _systemVersion = 'Unknown system version.';

// 我們調用通道上的方法,指定通過字符串標識符調用方法getSystemVersion。 
// 該調用可能失敗(平臺不支持平臺API,例如在模擬器中運行時),
// 所以我們將invokeMethod調用包裝在try-catch語句中
  Future<Null> _getSystemVersion() async {
    String systemVersion;
    try {
      final String result = await platform.invokeMethod('systemVersion');
      systemVersion = 'iOS當前系統 $result.';
    } on PlatformException catch (e) {
      systemVersion = "Failed to get system version: '${e.message}'.";
    }
    // 在setState中來更新用戶界面狀態systemVersion
    setState(() {
      _systemVersion = systemVersion;
    });
  }

// 我們在build創建包含一個小字體顯示當前系統systemVersion
// 和一個用於刷新值的按鈕的用戶界面。
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
        title: 'Flutter Demo',
        theme: ThemeData(
          primarySwatch: Colors.blue,
        ),
        home: Scaffold(
          appBar: AppBar(title: Text("platform channel:與原生交互"),),
          body: Center(
              
              child: new Column(
                children: <Widget>[
                  RaisedButton(
                onPressed: (){_getSystemVersion();},
                child: Text('show current systemVersion'),
              ),
              Text(_systemVersion),
                ],
              )
          ),
        )
    );
  }
}

iOS端代碼

我們接着之前"獲取當前系統版本"插件的示例,來完成iOS端API的實現。以下步驟使用Objective-C

首先打開Xcode中Flutter應用程序的iOS部分:

  1. 啓動 Xcode
  2. 選擇 File > Open…
  3. 定位到您 Flutter app目錄, 然後選擇裏面的 iOS文件夾,點擊 OK
  4. 確保Xcode項目的構建沒有錯誤。
  5. 選擇 Runner > Runner ,打開AppDelegate.m

接下來,在application didFinishLaunchingWithOptions:方法內部創建一個FlutterMethodChannel,並添加一個處理方法。 確保與在Flutter客戶端使用的通道名稱相同。

// ----------  AppDelegate.m  ----------
#include "AppDelegate.h"
#include "GeneratedPluginRegistrant.h"

@implementation AppDelegate

- (BOOL)application:(UIApplication *)application
    didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    [GeneratedPluginRegistrant registerWithRegistry:self];
    FlutterViewController* controller = (FlutterViewController*)self.window.rootViewController;
    FlutterMethodChannel* systemVersionChannel = [FlutterMethodChannel
                                            methodChannelWithName:@"samples.flutter.io/systemVersion"
                                            binaryMessenger:controller];
    
    [systemVersionChannel setMethodCallHandler:^(FlutterMethodCall* call, FlutterResult result) {
        if ([@"systemVersion" isEqualToString:call.method]) {
            result([self getSystemVersion]); // 回調數據
        } else {
            result(FlutterMethodNotImplemented);
        }
    }];
  // Override point for customization after application launch.
  return [super application:application didFinishLaunchingWithOptions:launchOptions];
}

- (NSString *)getSystemVersion {
    UIDevice* device = UIDevice.currentDevice;
    NSLog(@"systemVersion==%@", device.systemVersion);
     return device.systemVersion;
}

@end

效果如下:


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章