Flutter使用(yòng)了(le)一個靈活的系統,允許您調用(yòng)特定平台的API,無論在Android上(shàng)的Java或Kotlin代碼中,還是iOS上(shàng)的ObjectiveC或Swift代碼中均可用(yòng)。
Flutter平台特定的API支持不依賴于代碼生成,而是依賴于靈活的消息傳遞的方式:
應用(yòng)的Flutter部分通過平台通道(dào)(platform channel)将消息發送到(dào)其應用(yòng)程序的所在的宿主(iOS或Android)。
宿主監聽的平台通道(dào),并接收該消息。然後它會(huì)調用(yòng)特定于該平台的API(使用(yòng)原生編程語言) - 并将響應發送回客戶端,即應用(yòng)程序的Flutter部分。
框架概述: 平台通道(dào)
使用(yòng)平台通道(dào)在客戶端(Flutter UI)和(hé)宿主(平台)之間傳遞消息,如下(xià)圖所示:
Platform channels architecture
消息和(hé)響應是異步傳遞的,以确保用(yòng)戶界面保持響應(不會(huì)挂起)。
在客戶端,MethodChannel (API)可以發送與方法調用(yòng)相對(duì)應的消息。 在宿主平台上(shàng),MethodChannel 在Android((API) 和(hé) FlutterMethodChannel iOS (API) 可以接收方法調用(yòng)并返回結果。這(zhè)些(xiē)類允許您用(yòng)很(hěn)少的“腳手架”代碼開(kāi)發平台插件。
注意: 如果需要,方法調用(yòng)也(yě)可以反向發送,宿主作(zuò)爲客戶端調用(yòng)Dart中實現(xiàn)的API。 這(zhè)個quick_actions插件就是一個具體的例子
平台通道(dào)數據類型支持和(hé)解碼器
标準平台通道(dào)使用(yòng)标準消息編解碼器,以支持簡單的類似JSON值的高(gāo)效二進制序列化,例如 booleans,numbers, Strings, byte buffers, List, Maps(請(qǐng)參閱StandardMessageCodec了(le)解詳細信息)。 當您發送和(hé)接收值時(shí),這(zhè)些(xiē)值在消息中的序列化和(hé)反序列化會(huì)自(zì)動進行。
示例: 使用(yòng)平台通道(dào)調用(yòng)iOS和(hé)Android代碼
以下(xià)演示如何調用(yòng)平台特定的API來(lái)獲取和(hé)顯示當前的電池電量。它通過一個平台消息getBatteryLevel 調用(yòng)Android BatteryManager API和(hé)iOS device.batteryLevel API。 。
該示例在應用(yòng)程序内添加了(le)特定于平台的代碼。如果您想開(kāi)發一個通用(yòng)的平台包,可以在其它應用(yòng)中也(yě)使用(yòng)的話(huà),你(nǐ)需要開(kāi)發一個插件, 則項目創建步驟稍有不同(請(qǐng)參閱開(kāi)發 packages),但(dàn)平台通道(dào)代碼仍以相同方式編寫。
注意: 此示例的完整的可運行源代碼位于:/examples/platform_channel/, 這(zhè)個示例Android是用(yòng)的Java, IOS用(yòng)的是Objective-C,IOS Swift版本請(qǐng)參閱 /examples/platform_channel_swift/
Step 1: 創建一個新的應用(yòng)程序項目
首先創建一個新的應用(yòng)程序:
在終端運行中:flutter create batterylevel
默認情況下(xià),模闆支持使用(yòng)Java編寫Android代碼,或使用(yòng)Objective-C編寫iOS代碼。要使用(yòng)Kotlin或Swift,請(qǐng)使用(yòng)-i和(hé)/或-a标志:
在終端中運行: flutter create -i swift -a kotlin batterylevel
Step 2: 創建Flutter平台客戶端
該應用(yòng)的State類擁有當前的應用(yòng)狀态。我們需要延長這(zhè)一點以保持當前的電量
首先,我們構建通道(dào)。我們使用(yòng)MethodChannel調用(yòng)一個方法來(lái)返回電池電量。
通道(dào)的客戶端和(hé)宿主通過通道(dào)構造函數中傳遞的通道(dào)名稱進行連接。單個應用(yòng)中使用(yòng)的所有通道(dào)名稱必須是唯一的; 我們建議(yì)在通道(dào)名稱前加一個唯一的“域名前綴”,例如samples.flutter.io/battery。
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
...
class _MyHomePageState extends State
static const platform = const MethodChannel('samples.flutter.io/battery');
// Get battery level.
}
接下(xià)來(lái),我們調用(yòng)通道(dào)上(shàng)的方法,指定通過字符串标識符調用(yòng)方法getBatteryLevel。 該調用(yòng)可能(néng)失敗 - 例如,如果平台不支持平台API(例如在模拟器中運行時(shí)),所以我們将invokeMethod調用(yòng)包裝在try-catch語句中。
我們使用(yòng)返回的結果,在setState中來(lái)更新用(yòng)戶界面狀态batteryLevel。
// Get battery level.
String _batteryLevel = 'Unknown battery level.';
Future
String batteryLevel;
try {
final int result = await platform.invokeMethod('getBatteryLevel');
batteryLevel = 'Battery level at $result % .';
} on PlatformException catch (e) {
batteryLevel = "Failed to get battery level: '${e.message}'.";
}
setState(() {
_batteryLevel = batteryLevel;
});
}
最後,我們在build創建包含一個小(xiǎo)字體顯示電池狀态和(hé)一個用(yòng)于刷新值的按鈕的用(yòng)戶界面。
@override
Widget build(BuildContext context) {
return new Material(
child: new Center(
child: new Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
new RaisedButton(
child: new Text('Get Battery Level'),
onPressed: _getBatteryLevel,
),
new Text(_batteryLevel),
],
),
),
);
}
Step 3a: 使用(yòng)Java添加Android平台特定的實現(xiàn)
注意: 以下(xià)步驟使用(yòng)Java。如果您更喜歡Kotlin,請(qǐng)跳到(dào)步驟3b.
首先在Android Studio中打開(kāi)您的Flutter應用(yòng)的Android部分:
啓動 Android Studio
選擇 ‘File > Open…’
定位到(dào)您 Flutter app目錄, 然後選擇裏面的 android文(wén)件夾,點擊 OK
在java目錄下(xià)打開(kāi) MainActivity.java
接下(xià)來(lái),在onCreate裏創建MethodChannel并設置一個MethodCallHandler。确保使用(yòng)與在Flutter客戶端使用(yòng)的通道(dào)名稱相同。
import io.flutter.app.FlutterActivity;
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;
public class MainActivity extends FlutterActivity {
private static final String CHANNEL = "samples.flutter.io/battery";
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
new MethodChannel(getFlutterView(), CHANNEL).setMethodCallHandler(
new MethodCallHandler() {
@Override
public void onMethodCall(MethodCall call, Result result) {
// TODO
}
});
}
}
接下(xià)來(lái),我們添加Java代碼,使用(yòng)Android電池API來(lái)獲取電池電量。此代碼與您在原生Android應用(yòng)中編寫的代碼完全相同。
首先,添加需要導入的依賴。
import android.content.ContextWrapper;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.BatteryManager;
import android.os.Build.VERSION;
import android.os.Build.VERSION_CODES;
import android.os.Bundle;
然後,将下(xià)面的新方法添加到(dào)activity類中的,位于onCreate 方法下(xià)方:
private int getBatteryLevel() {
int batteryLevel = -1;
if (VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP) {
BatteryManager batteryManager = (BatteryManager) getSystemService(BATTERY_SERVICE);
batteryLevel = batteryManager.getIntProperty(BatteryManager.BATTERY_PROPERTY_CAPACITY);
} else {
Intent intent = new ContextWrapper(getApplicationContext()).
registerReceiver(null, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
batteryLevel = (intent.getIntExtra(BatteryManager.EXTRA_LEVEL, -1) * 100) /
intent.getIntExtra(BatteryManager.EXTRA_SCALE, -1);
}
return batteryLevel;
}
最後,我們完成之前添加的onMethodCall方法。我們需要處理(lǐ)平台方法名爲getBatteryLevel,所以我們在call參數中進行檢測是否爲getBatteryLevel。 這(zhè)個平台方法的實現(xiàn)隻需調用(yòng)我們在前一步中編寫的Android代碼,并使用(yòng)response參數返回成功和(hé)錯誤情況的響應。如果調用(yòng)未知(zhī)的方法,我們也(yě)會(huì)通知(zhī)返回:
@Override
public void onMethodCall(MethodCall call, Result result) {
if (call.method.equals("getBatteryLevel")) {
int batteryLevel = getBatteryLevel();
if (batteryLevel != -1) {
result.success(batteryLevel);
} else {
result.error("UNAVAILABLE", "Battery level not available.", null);
}
} else {
result.notImplemented();
}
}
您現(xiàn)就可以在Android上(shàng)運行該應用(yòng)程序。如果您使用(yòng)的是Android模拟器,則可以通過工(gōng)具欄中的...按鈕訪問Extended Controls面闆中的電池電量
Step 3b: 使用(yòng)Kotlin添加Android平台特定的實現(xiàn)
注意: 以下(xià)步驟與步驟3a類似,隻是使用(yòng)Kotlin而不是Java。
此步驟假定您在step 1.中 使用(yòng)該-a kotlin選項創建了(le)項目
首先在Android Studio中打開(kāi)您的Flutter應用(yòng)的Android部分
啓動 Android Studio
選擇 the menu item ‘File > Open…’
定位到(dào)您 Flutter app目錄, 然後選擇裏面的 android文(wén)件夾,點擊 OK
在kotlin目錄中打開(kāi)MainActivity.kt. (注意:如果您使用(yòng)Android Studio 2.3進行編輯,請(qǐng)注意’kotlin’文(wén)件夾将顯示爲’java’。)
接下(xià)來(lái),在onCreate裏創建MethodChannel并設置一個MethodCallHandler。确保使用(yòng)與在Flutter客戶端使用(yòng)的通道(dào)名稱相同。
import android.os.Bundle
import io.flutter.app.FlutterActivity
import io.flutter.plugin.common.MethodChannel
import io.flutter.plugins.GeneratedPluginRegistrant
class MainActivity() : FlutterActivity() {
private val CHANNEL = "samples.flutter.io/battery"
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
GeneratedPluginRegistrant.registerWith(this)
MethodChannel(flutterView, CHANNEL).setMethodCallHandler { call, result ->
// TODO
}
}
}
接下(xià)來(lái),我們添加Kotlin代碼,使用(yòng)Android電池API來(lái)獲取電池電量。此代碼與您在原生Android應用(yòng)中編寫的代碼完全相同。
首先,添加需要導入的依賴。
import android.content.Context
import android.content.ContextWrapper
import android.content.Intent
import android.content.IntentFilter
import android.os.BatteryManager
import android.os.Build.VERSION
import android.os.Build.VERSION_CODES
然後,将下(xià)面的新方法添加到(dào)activity類中的,位于onCreate 方法下(xià)方:
private fun getBatteryLevel(): Int {
val batteryLevel: Int
if (VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP) {
val batteryManager = getSystemService(Context.BATTERY_SERVICE) as BatteryManager
batteryLevel = batteryManager.getIntProperty(BatteryManager.BATTERY_PROPERTY_CAPACITY)
} else {
val intent = ContextWrapper(applicationContext).registerReceiver(null, IntentFilter(Intent.ACTION_BATTERY_CHANGED))
batteryLevel = intent!!.getIntExtra(BatteryManager.EXTRA_LEVEL, -1) * 100 / intent.getIntExtra(BatteryManager.EXTRA_SCALE, -1)
}
return batteryLevel
}
最後,我們完成之前添加的onMethodCall方法。我們需要處理(lǐ)平台方法名爲getBatteryLevel,所以我們在call參數中進行檢測是否爲getBatteryLevel。 這(zhè)個平台方法的實現(xiàn)隻需調用(yòng)我們在前一步中編寫的Android代碼,并使用(yòng)response參數返回成功和(hé)錯誤情況的響應。如果調用(yòng)未知(zhī)的方法,我們也(yě)會(huì)通知(zhī)返回:
MethodChannel(flutterView, CHANNEL).setMethodCallHandler { call, result ->
if (call.method == "getBatteryLevel") {
val batteryLevel = getBatteryLevel()
if (batteryLevel != -1) {
result.success(batteryLevel)
} else {
result.error("UNAVAILABLE", "Battery level not available.", null)
}
} else {
result.notImplemented()
}
}
您現(xiàn)就可以在Android上(shàng)運行該應用(yòng)程序。如果您使用(yòng)的是Android模拟器,則可以通過工(gōng)具欄中的...按鈕訪問Extended Controls面闆中的電池電量
Step 4a: 使用(yòng)Objective-C添加iOS平台特定的實現(xiàn)
注意: 以下(xià)步驟使用(yòng)Objective-C。如果您喜歡Swift,請(qǐng)跳到(dào)步驟4b
首先打開(kāi)Xcode中Flutter應用(yòng)程序的iOS部分:
啓動 Xcode
選擇 ‘File > Open…’
定位到(dào)您 Flutter app目錄, 然後選擇裏面的 iOS文(wén)件夾,點擊 OK
确保Xcode項目的構建沒有錯誤。
選擇 Runner > Runner ,打開(kāi)`AppDelegate.m
接下(xià)來(lái),在application didFinishLaunchingWithOptions:方法内部創建一個FlutterMethodChannel,并添加一個處理(lǐ)方法。 确保與在Flutter客戶端使用(yòng)的通道(dào)名稱相同。
#import
@implementation AppDelegate
- (BOOL)application:(UIApplication*)application didFinishLaunchingWithOptions:(NSDictionary*)launchOptions {
FlutterViewController* controller = (FlutterViewController*)self.window.rootViewController;
FlutterMethodChannel* batteryChannel = [FlutterMethodChannel
methodChannelWithName:@"samples.flutter.io/battery"
binaryMessenger:controller];
[batteryChannel setMethodCallHandler:^(FlutterMethodCall* call, FlutterResult result) {
// TODO
}];
return [super application:application didFinishLaunchingWithOptions:launchOptions];
}
接下(xià)來(lái),我們添加ObjectiveC代碼,使用(yòng)iOS電池API來(lái)獲取電池電量。此代碼與您在本機iOS應用(yòng)程序中編寫的代碼完全相同。
在AppDelegate類中添加以下(xià)新的方法:
- (int)getBatteryLevel {
UIDevice* device = UIDevice.currentDevice;
device.batteryMonitoringEnabled = YES;
if (device.batteryState == UIDeviceBatteryStateUnknown) {
return -1;
} else {
return (int)(device.batteryLevel * 100);
}
}
最後,我們完成之前添加的setMethodCallHandler方法。我們需要處理(lǐ)的平台方法名爲getBatteryLevel,所以我們在call參數中進行檢測是否爲getBatteryLevel。 這(zhè)個平台方法的實現(xiàn)隻需調用(yòng)我們在前一步中編寫的IOS代碼,并使用(yòng)response參數返回成功和(hé)錯誤情況的響應。如果調用(yòng)未知(zhī)的方法,我們也(yě)會(huì)通知(zhī)返回:
[batteryChannel setMethodCallHandler:^(FlutterMethodCall* call, FlutterResult result) {
if ([@"getBatteryLevel" isEqualToString:call.method]) {
int batteryLevel = [self getBatteryLevel];
if (batteryLevel == -1) {
result([FlutterError errorWithCode:@"UNAVAILABLE"
message:@"Battery info unavailable"
details:nil]);
} else {
result(@(batteryLevel));
}
} else {
result(FlutterMethodNotImplemented);
}
}];
您現(xiàn)在可以在iOS上(shàng)運行應用(yòng)程序。如果您使用(yòng)的是iOS模拟器,請(qǐng)注意,它不支持電池API,因此應用(yòng)程序将顯示“電池信息不可用(yòng)”。
Step 4b: 使用(yòng)Swift添加一個iOS平台的實現(xiàn)
注意: 以下(xià)步驟與步驟4a類似,隻不過是使用(yòng)Swift而不是Objective-C.
此步驟假定您在步驟1中 使用(yòng)-i swift選項創建了(le)項目。
首先打開(kāi)Xcode中Flutter應用(yòng)程序的iOS部分:
啓動 Xcode
選擇 ‘File > Open…’
定位到(dào)您 Flutter app目錄, 然後選擇裏面的 ios文(wén)件夾,點擊 OK
确保Xcode項目的構建沒有錯誤。
選擇 Runner > Runner ,然後打開(kāi)AppDelegate.swift
接下(xià)來(lái),覆蓋application方法并創建一個FlutterMethodChannel綁定通道(dào)名稱samples.flutter.io/battery:
@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate {
override func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
GeneratedPluginRegistrant.register(with: self);
let controller : FlutterViewController = window?.rootViewController as! FlutterViewController;
let batteryChannel = FlutterMethodChannel.init(name: "samples.flutter.io/battery",
binaryMessenger: controller);
batteryChannel.setMethodCallHandler({
(call: FlutterMethodCall, result: FlutterResult) -> Void in
// Handle battery messages.
});
return super.application(application, didFinishLaunchingWithOptions: launchOptions);
}
}
接下(xià)來(lái),我們添加Swift代碼,使用(yòng)iOS電池API來(lái)獲取電池電量。此代碼與您在本機iOS應用(yòng)程序中編寫的代碼完全相同。
将以下(xià)新方法添加到(dào)AppDelegate.swift底部
private func receiveBatteryLevel(result: FlutterResult) {
let device = UIDevice.current;
device.isBatteryMonitoringEnabled = true;
if (device.batteryState == UIDeviceBatteryState.unknown) {
result(FlutterError.init(code: "UNAVAILABLE",
message: "Battery info unavailable",
details: nil));
} else {
result(Int(device.batteryLevel * 100));
}
}
最後,我們完成之前添加的setMethodCallHandler方法。我們需要處理(lǐ)的平台方法名爲getBatteryLevel,所以我們在call參數中進行檢測是否爲getBatteryLevel。 這(zhè)個平台方法的實現(xiàn)隻需調用(yòng)我們在前一步中編寫的IOS代碼,并使用(yòng)response參數返回成功和(hé)錯誤情況的響應。如果調用(yòng)未知(zhī)的方法,我們也(yě)會(huì)通知(zhī)返回:
batteryChannel.setMethodCallHandler({
(call: FlutterMethodCall, result: FlutterResult) -> Void in
if ("getBatteryLevel" == call.method) {
receiveBatteryLevel(result: result);
} else {
result(FlutterMethodNotImplemented);
}
});
您現(xiàn)在可以在iOS上(shàng)運行應用(yòng)程序。如果您使用(yòng)的是iOS模拟器,請(qǐng)注意,它不支持電池API,因此應用(yòng)程序将顯示“電池信息不可用(yòng)”。
從(cóng)UI代碼中分離平台特定的代碼
如果您希望在多個Flutter應用(yòng)程序中使用(yòng)特定于平台的代碼,将代碼分離爲位于主應用(yòng)程序之外(wài)的目錄中,做一個平台插件會(huì)很(hěn)有用(yòng)。詳情請(qǐng)參閱開(kāi)發 packages 。
将平台特定的代碼作(zuò)爲一個包發布
如果您希望與Flutter生态系統中的其他(tā)開(kāi)發人員分享您的特定平台的代碼,請(qǐng)參閱發[發布 packages](/developing-packages/#publish以了(le)解詳細信息。
自(zì)定義平台通道(dào)和(hé)編解碼器
除了(le)上(shàng)面提到(dào)的MethodChannel,你(nǐ)還可以使用(yòng)BasicMessageChannel,它支持使用(yòng)自(zì)定義消息編解碼器進行基本的異步消息傳遞。 此外(wài),您可以使用(yòng)專門(mén)的BinaryCodec,StringCodec和(hé) JSONMessageCodec類,或創建自(zì)己的編解碼器。
網站(zhàn)建設開(kāi)發|APP設計(jì)開(kāi)發|小(xiǎo)程序建設開(kāi)發