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 可以發送與方法調用相對應的消息。 在宿主平臺上,MethodChannel
在Android API 和 FlutterMethodChannel
在 iOS 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部分:
- 啓動 Xcode
- 選擇 File > Open…
- 定位到您 Flutter app目錄, 然後選擇裏面的 iOS文件夾,點擊 OK
- 確保Xcode項目的構建沒有錯誤。
- 選擇 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
效果如下:
- 本文作者: Dwyane
- 本文鏈接: http://nihao6.top/2019/05/18/platformchannel/
- 版權聲明:本博客所有文章除特別聲明外,均採用 CC BY-NC-SA 3.0 許可協議。轉載請註明出處!