Flutter使用了(le)一(yī)個靈活的系統,允許您調用特定平台的API,無論在Android上(shàng)的Java或Kotlin代碼中,還是iOS上(shàng)的ObjectiveC或Swift代碼中均可(kě)用。
Flutter平台特定的API支持不依賴于代碼生成,而是依賴于靈活的消息傳遞的方式:
應用的Flutter部分通(tōng)過平台通(tōng)道(dào)(platform channel)将消息發送到其應用程序的所在的宿主(iOS或Android)。
宿主監聽的平台通(tōng)道(dào),并接收該消息。然後它會調用特定于該平台的API(使用原生編程語言) - 并将響應發送回客戶端,即應用程序的Flutter部分。
框架概述: 平台通(tōng)道(dào)
使用平台通(tōng)道(dào)在客戶端(Flutter UI)和(hé)宿主(平台)之間(jiān)傳遞消息,如(rú)下(xià)圖所示:
Platform channels architecture
消息和(hé)響應是異步傳遞的,以确保用戶界面保持響應(不會挂起)。
在客戶端,MethodChannel (API)可(kě)以發送與方法調用相對應的消息。 在宿主平台上(shàng),MethodChannel 在Android((API) 和(hé) FlutterMethodChannel iOS (API) 可(kě)以接收方法調用并返回結果。這(zhè)些類允許您用很(hěn)少(shǎo)的“腳手架”代碼開(kāi)發平台插件。
注意: 如(rú)果需要(yào),方法調用也可(kě)以反向發送,宿主作(zuò)為(wèi)客戶端調用Dart中實現的API。 這(zhè)個quick_actions插件就是一(yī)個具體的例子
平台通(tōng)道(dào)數(shù)據類型支持和(hé)解碼器
标準平台通(tōng)道(dào)使用标準消息編解碼器,以支持簡單的類似JSON值的高效二進制序列化,例如(rú) booleans,numbers, Strings, byte buffers, List, Maps(請(qǐng)參閱StandardMessageCodec了(le)解詳細信息)。 當您發送和(hé)接收值時(shí),這(zhè)些值在消息中的序列化和(hé)反序列化會自(zì)動進行(xíng)。
示例: 使用平台通(tōng)道(dào)調用iOS和(hé)Android代碼
以下(xià)演示如(rú)何調用平台特定的API來獲取和(hé)顯示當前的電池電量。它通(tōng)過一(yī)個平台消息getBatteryLevel 調用Android BatteryManager API和(hé)iOS device.batteryLevel API。 。
該示例在應用程序內(nèi)添加了(le)特定于平台的代碼。如(rú)果您想開(kāi)發一(yī)個通(tōng)用的平台包,可(kě)以在其它應用中也使用的話,你需要(yào)開(kāi)發一(yī)個插件, 則項目創建步驟稍有不同(請(qǐng)參閱開(kāi)發 packages),但(dàn)平台通(tōng)道(dào)代碼仍以相同方式編寫。
注意: 此示例的完整的可(kě)運行(xíng)源代碼位于:/examples/platform_channel/, 這(zhè)個示例Android是用的Java, IOS用的是Objective-C,IOS Swift版本請(qǐng)參閱 /examples/platform_channel_swift/
Step 1: 創建一(yī)個新的應用程序項目
首先創建一(yī)個新的應用程序:
在終端運行(xíng)中:flutter create batterylevel
默認情況下(xià),模闆支持使用Java編寫Android代碼,或使用Objective-C編寫iOS代碼。要(yào)使用Kotlin或Swift,請(qǐng)使用-i和(hé)/或-a标志:
在終端中運行(xíng): flutter create -i swift -a kotlin batterylevel
Step 2: 創建Flutter平台客戶端
該應用的State類擁有當前的應用狀态。我們需要(yào)延長(cháng)這(zhè)一(yī)點以保持當前的電量
首先,我們構建通(tōng)道(dào)。我們使用MethodChannel調用一(yī)個方法來返回電池電量。
通(tōng)道(dào)的客戶端和(hé)宿主通(tōng)過通(tōng)道(dào)構造函數(shù)中傳遞的通(tōng)道(dào)名稱進行(xíng)連接。單個應用中使用的所有通(tōng)道(dào)名稱必須是唯一(yī)的; 我們建議(yì)在通(tōng)道(dào)名稱前加一(yī)個唯一(yī)的“域名前綴”,例如(rú)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à)來,我們調用通(tōng)道(dào)上(shàng)的方法,指定通(tōng)過字符串标識符調用方法getBatteryLevel。 該調用可(kě)能(néng)失敗 - 例如(rú),如(rú)果平台不支持平台API(例如(rú)在模拟器中運行(xíng)時(shí)),所以我們将invokeMethod調用包裝在try-catch語句中。
我們使用返回的結果,在setState中來更新用戶界面狀态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創建包含一(yī)個小字體顯示電池狀态和(hé)一(yī)個用于刷新值的按鈕的用戶界面。
@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: 使用Java添加Android平台特定的實現
注意: 以下(xià)步驟使用Java。如(rú)果您更喜歡Kotlin,請(qǐng)跳(tiào)到步驟3b.
首先在Android Studio中打開(kāi)您的Flutter應用的Android部分:
啓動 Android Studio
選擇 ‘File > Open…’
定位到您 Flutter app目錄, 然後選擇裏面的 android文件夾,點擊 OK
在java目錄下(xià)打開(kāi) MainActivity.java
接下(xià)來,在onCreate裏創建MethodChannel并設置一(yī)個MethodCallHandler。确保使用與在Flutter客戶端使用的通(tō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à)來,我們添加Java代碼,使用Android電池API來獲取電池電量。此代碼與您在原生Android應用中編寫的代碼完全相同。
首先,添加需要(yào)導入的依賴。
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à)面的新方法添加到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方法。我們需要(yào)處理平台方法名為(wèi)getBatteryLevel,所以我們在call參數(shù)中進行(xíng)檢測是否為(wèi)getBatteryLevel。 這(zhè)個平台方法的實現隻需調用我們在前一(yī)步中編寫的Android代碼,并使用response參數(shù)返回成功和(hé)錯誤情況的響應。如(rú)果調用未知的方法,我們也會通(tōng)知返回:
@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();
}
}
您現就可(kě)以在Android上(shàng)運行(xíng)該應用程序。如(rú)果您使用的是Android模拟器,則可(kě)以通(tōng)過工(gōng)具欄中的...按鈕訪問(wèn)Extended Controls面闆中的電池電量
Step 3b: 使用Kotlin添加Android平台特定的實現
注意: 以下(xià)步驟與步驟3a類似,隻是使用Kotlin而不是Java。
此步驟假定您在step 1.中 使用該-a kotlin選項創建了(le)項目
首先在Android Studio中打開(kāi)您的Flutter應用的Android部分
啓動 Android Studio
選擇 the menu item ‘File > Open…’
定位到您 Flutter app目錄, 然後選擇裏面的 android文件夾,點擊 OK
在kotlin目錄中打開(kāi)MainActivity.kt. (注意:如(rú)果您使用Android Studio 2.3進行(xíng)編輯,請(qǐng)注意’kotlin’文件夾将顯示為(wèi)’java’。)
接下(xià)來,在onCreate裏創建MethodChannel并設置一(yī)個MethodCallHandler。确保使用與在Flutter客戶端使用的通(tō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à)來,我們添加Kotlin代碼,使用Android電池API來獲取電池電量。此代碼與您在原生Android應用中編寫的代碼完全相同。
首先,添加需要(yào)導入的依賴。
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à)面的新方法添加到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方法。我們需要(yào)處理平台方法名為(wèi)getBatteryLevel,所以我們在call參數(shù)中進行(xíng)檢測是否為(wèi)getBatteryLevel。 這(zhè)個平台方法的實現隻需調用我們在前一(yī)步中編寫的Android代碼,并使用response參數(shù)返回成功和(hé)錯誤情況的響應。如(rú)果調用未知的方法,我們也會通(tōng)知返回:
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()
}
}
您現就可(kě)以在Android上(shàng)運行(xíng)該應用程序。如(rú)果您使用的是Android模拟器,則可(kě)以通(tōng)過工(gōng)具欄中的...按鈕訪問(wèn)Extended Controls面闆中的電池電量
Step 4a: 使用Objective-C添加iOS平台特定的實現
注意: 以下(xià)步驟使用Objective-C。如(rú)果您喜歡Swift,請(qǐng)跳(tiào)到步驟4b
首先打開(kāi)Xcode中Flutter應用程序的iOS部分:
啓動 Xcode
選擇 ‘File > Open…’
定位到您 Flutter app目錄, 然後選擇裏面的 iOS文件夾,點擊 OK
确保Xcode項目的構建沒有錯誤。
選擇 Runner > Runner ,打開(kāi)`AppDelegate.m
接下(xià)來,在application didFinishLaunchingWithOptions:方法內(nèi)部創建一(yī)個FlutterMethodChannel,并添加一(yī)個處理方法。 确保與在Flutter客戶端使用的通(tō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à)來,我們添加ObjectiveC代碼,使用iOS電池API來獲取電池電量。此代碼與您在本機iOS應用程序中編寫的代碼完全相同。
在AppDelegate類中添加以下(xià)新的方法:
- (int)getBatteryLevel {
UIDevice* device = UIDevice.currentDevice;
device.batteryMonitoringEnabled = YES;
if (device.batteryState == UIDeviceBatteryStateUnknown) {
return -1;
} else {
return (int)(device.batteryLevel * 100);
}
}
最後,我們完成之前添加的setMethodCallHandler方法。我們需要(yào)處理的平台方法名為(wèi)getBatteryLevel,所以我們在call參數(shù)中進行(xíng)檢測是否為(wèi)getBatteryLevel。 這(zhè)個平台方法的實現隻需調用我們在前一(yī)步中編寫的IOS代碼,并使用response參數(shù)返回成功和(hé)錯誤情況的響應。如(rú)果調用未知的方法,我們也會通(tōng)知返回:
[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);
}
}];
您現在可(kě)以在iOS上(shàng)運行(xíng)應用程序。如(rú)果您使用的是iOS模拟器,請(qǐng)注意,它不支持電池API,因此應用程序将顯示“電池信息不可(kě)用”。
Step 4b: 使用Swift添加一(yī)個iOS平台的實現
注意: 以下(xià)步驟與步驟4a類似,隻不過是使用Swift而不是Objective-C.
此步驟假定您在步驟1中 使用-i swift選項創建了(le)項目。
首先打開(kāi)Xcode中Flutter應用程序的iOS部分:
啓動 Xcode
選擇 ‘File > Open…’
定位到您 Flutter app目錄, 然後選擇裏面的 ios文件夾,點擊 OK
确保Xcode項目的構建沒有錯誤。
選擇 Runner > Runner ,然後打開(kāi)AppDelegate.swift
接下(xià)來,覆蓋application方法并創建一(yī)個FlutterMethodChannel綁定通(tōng)道(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à)來,我們添加Swift代碼,使用iOS電池API來獲取電池電量。此代碼與您在本機iOS應用程序中編寫的代碼完全相同。
将以下(xià)新方法添加到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方法。我們需要(yào)處理的平台方法名為(wèi)getBatteryLevel,所以我們在call參數(shù)中進行(xíng)檢測是否為(wèi)getBatteryLevel。 這(zhè)個平台方法的實現隻需調用我們在前一(yī)步中編寫的IOS代碼,并使用response參數(shù)返回成功和(hé)錯誤情況的響應。如(rú)果調用未知的方法,我們也會通(tōng)知返回:
batteryChannel.setMethodCallHandler({
(call: FlutterMethodCall, result: FlutterResult) -> Void in
if ("getBatteryLevel" == call.method) {
receiveBatteryLevel(result: result);
} else {
result(FlutterMethodNotImplemented);
}
});
您現在可(kě)以在iOS上(shàng)運行(xíng)應用程序。如(rú)果您使用的是iOS模拟器,請(qǐng)注意,它不支持電池API,因此應用程序将顯示“電池信息不可(kě)用”。
從(cóng)UI代碼中分離平台特定的代碼
如(rú)果您希望在多個Flutter應用程序中使用特定于平台的代碼,将代碼分離為(wèi)位于主應用程序之外(wài)的目錄中,做(zuò)一(yī)個平台插件會很(hěn)有用。詳情請(qǐng)參閱開(kāi)發 packages 。
将平台特定的代碼作(zuò)為(wèi)一(yī)個包發布
如(rú)果您希望與Flutter生态系統中的其他(tā)開(kāi)發人(rén)員(yuán)分享您的特定平台的代碼,請(qǐng)參閱發[發布 packages](/developing-packages/#publish以了(le)解詳細信息。
自(zì)定義平台通(tōng)道(dào)和(hé)編解碼器
除了(le)上(shàng)面提到的MethodChannel,你還可(kě)以使用BasicMessageChannel,它支持使用自(zì)定義消息編解碼器進行(xíng)基本的異步消息傳遞。 此外(wài),您可(kě)以使用專門的BinaryCodec,StringCodec和(hé) JSONMessageCodec類,或創建自(zì)己的編解碼器。
網站建設開(kāi)發|APP設計開(kāi)發|小程序建設開(kāi)發