Flutter使用了一個(gè)靈活的系統(tǒng)脂信,允許您調(diào)用特定平臺(tái)的API,無(wú)論在Android上的Java或Kotlin代碼中剥险,還是iOS上的ObjectiveC或Swift代碼中均可用聪蘸。
Flutter平臺(tái)特定的API支持不依賴于代碼生成,而是依賴于靈活的消息傳遞的方式:
- 應(yīng)用的Flutter部分通過(guò)平臺(tái)通道(platform channel)將消息發(fā)送到其應(yīng)用程序的所在的宿主(iOS或Android)表制。
- 宿主監(jiān)聽(tīng)平臺(tái)通道健爬,并接收該消息。然后它會(huì)調(diào)用特定于該平臺(tái)的API(使用原生編程語(yǔ)言) - 并將響應(yīng)發(fā)送回客戶端么介,即應(yīng)用程序的Flutter部分娜遵。
框架概述: 平臺(tái)通道
使用平臺(tái)通道在客戶端(Flutter UI)和宿主(平臺(tái))之間傳遞消息,如下圖所示:
注意消息和響應(yīng)是異步傳遞的壤短,以確保用戶界面保持響應(yīng)(不會(huì)掛起)设拟。
在客戶端,MethodChannel
(API)可以發(fā)送與方法調(diào)用相對(duì)應(yīng)的消息久脯。 在宿主平臺(tái)上纳胧,MethodChannel
在Android((API) 和 FlutterMethodChannel iOS (API) 可以接收方法調(diào)用并返回結(jié)果。這些類(lèi)允許您用很少的“腳手架”代碼開(kāi)發(fā)平臺(tái)插件帘撰。
-
注意: 如果需要跑慕,方法調(diào)用也可以反向發(fā)送,宿主作為客戶端調(diào)用Dart中實(shí)現(xiàn)的API。 這個(gè)
quick_actions
插件就是一個(gè)具體的例子
平臺(tái)通道數(shù)據(jù)類(lèi)型支持和解碼器
標(biāo)準(zhǔn)平臺(tái)通道使用標(biāo)準(zhǔn)消息編解碼器核行,以支持簡(jiǎn)單的類(lèi)似JSON值的高效二進(jìn)制序列化牢硅,例如 booleans,numbers, Strings, byte buffers, List, Maps(請(qǐng)參閱StandardMessageCodec
了解詳細(xì)信息)。
- 當(dāng)您發(fā)送和接收值時(shí)芝雪,這些值在消息中的序列化和反序列化會(huì)自動(dòng)進(jìn)行减余。*
下表顯示了如何在宿主上接收Dart值,反之亦然:
Dart | Android | iOS |
---|---|---|
null | null | nil (NSNull when nested) |
bool | java.lang.Boolean | NSNumber numberWithBool: |
int | java.lang.Integer | NSNumber numberWithInt: |
int, if 32 bits not enough | java.lang.Long | NSNumber numberWithLong: |
int, if 64 bits not enough | java.math.BigInteger | FlutterStandardBigInteger |
double | java.lang.Double | NSNumber numberWithDouble: |
String | java.lang.String | NSString |
Uint8List | byte[] | FlutterStandardTypedData typedDataWithBytes: |
Int32List | int[] | FlutterStandardTypedData typedDataWithInt32: |
Int64List | long[] | FlutterStandardTypedData typedDataWithInt64: |
Float64List | double[] | FlutterStandardTypedData typedDataWithFloat64: |
List | java.util.ArrayList | NSArray |
Map | java.util.HashMap | NSDictionary |
舉例
1打開(kāi)終端隨便cd一個(gè)目錄下绵脯,生成flutterIosMix 目錄
mkdir flutterIosMix |ls
2 進(jìn)入該目錄并且創(chuàng)建一個(gè)新的應(yīng)用程序
cd flutterIosMix
flutter create flutteriosmix
這個(gè)時(shí)候的目錄結(jié)構(gòu)如下
3.用vscode 打開(kāi)該工程并運(yùn)行該工程
結(jié)果如下:
這個(gè)時(shí)候有默認(rèn)工程的代碼
4.修改main.dart 代碼
修改main.dart 代碼如下
import 'package:flutter/material.dart';
import 'dart:async';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
// This is the theme of your application.
//
// Try running your application with "flutter run". You'll see the
// application has a blue toolbar. Then, without quitting the app, try
// changing the primarySwatch below to Colors.green and then invoke
// "hot reload" (press "r" in the console where you ran "flutter run",
// or simply save your changes to "hot reload" in a Flutter IDE).
// Notice that the counter didn't reset back to zero; the application
// is not restarted.
primarySwatch: Colors.blue,
),
home: PlatformChannel(),
);
}
}
class PlatformChannel extends StatefulWidget {
@override
_PlatformChannelState createState() => _PlatformChannelState();
}
class _PlatformChannelState extends State<PlatformChannel> {
int _hitNum = 0;
int _time = 0;
Future<void> _hitEvent() async{
}
@override
Widget build(BuildContext context) {
return Material(
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text("當(dāng)前點(diǎn)擊次數(shù):$_hitNum", key: const Key('hitEvent')),
Padding(
padding: const EdgeInsets.all(16.0),
child: RaisedButton(
child: const Text('hit'),
onPressed: _hitEvent,
),
),
],
),
Text("計(jì)時(shí)器時(shí)間${_time}s"),
],
),
);
}
}
運(yùn)行上述代碼結(jié)果如下
這是準(zhǔn)備好的工程基本工程.接下來(lái)我們就準(zhǔn)備flutter 和ios平臺(tái)的混合開(kāi)發(fā)代碼佳励。我們準(zhǔn)備開(kāi)發(fā)的內(nèi)容如下
- 1 點(diǎn)擊hit按鈕,我們從ios平臺(tái)獲取已經(jīng)點(diǎn)擊的次數(shù)
- 2.我們從ios平臺(tái)的計(jì)時(shí)器中獲取回調(diào)給flutter的計(jì)時(shí)時(shí)間蛆挫。
我們調(diào)用ios平臺(tái)的方法是通過(guò)MethodChannel 類(lèi)來(lái)實(shí)現(xiàn)的
我們監(jiān)聽(tīng)來(lái)自ios的調(diào)用是通過(guò)EventChannel 類(lèi)來(lái)實(shí)現(xiàn)的
5. 實(shí)現(xiàn)點(diǎn)擊hit 按鈕獲取ios平臺(tái)回傳回來(lái)的點(diǎn)擊次數(shù)
<1> 添加引用文件
import 'package:flutter/services.dart';
在main.dart 文件中頭部添加上述代碼赃承。
<2>類(lèi)_PlatformChannelState增加一個(gè)成員變量
class _PlatformChannelState extends State<PlatformChannel> {
static const MethodChannel methodChannel =
MethodChannel('hit.flutter.io/count');
...
}
這里我們生成一個(gè)MethodChannel類(lèi)型的變量methodChannel 并且實(shí)例化
"hit.flutter.io/count" 這里需要注意,這是與ios平臺(tái)橋接的key悴侵,可以隨便命名瞧剖,但是必須和ios平臺(tái)接受時(shí)候的key 一致。
<3> 在_hitEvent 函數(shù)中添加如下函數(shù)
Future<void> _hitEvent() async{
int hitNum;
try {
final int result = await methodChannel.invokeMethod('getBatteryLevel');
hitNum =result;
} on PlatformException {
}
if (hitNum !=null) {
setState(() {
_hitNum = hitNum;
});
}
}
這個(gè)時(shí)候保存main.dart 代碼可免。點(diǎn)擊hit按鈕是崩潰的
<4> 打開(kāi)ios工程代碼
打開(kāi)ios工程ios->右鍵reveal in finder -> xcode 打開(kāi)該工程
<5>編輯ios工程代碼
打開(kāi)appdelegate.m 文件抓于,修改文件如下
#include "AppDelegate.h"
#include "GeneratedPluginRegistrant.h"
#import <Flutter/Flutter.h>
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
[GeneratedPluginRegistrant registerWithRegistry:self];
FlutterViewController* controller = (FlutterViewController*)self.window.rootViewController;
///hit.flutter.io/count 必須與flutter 請(qǐng)求的key一樣才會(huì)調(diào)用到函數(shù)中
FlutterMethodChannel* batteryChannel = [FlutterMethodChannel methodChannelWithName:@"hit.flutter.io/count" binaryMessenger:controller];
[batteryChannel setMethodCallHandler:^(FlutterMethodCall* call, FlutterResult result) {
///這個(gè)是flutter 請(qǐng)求的事件
if ([@"hitCount" isEqualToString:call.method]) {
static int count =0;
return result(@(++count));
}
}];
return [super application:application didFinishLaunchingWithOptions:launchOptions];
}
@end
這個(gè)時(shí)候,我們就實(shí)現(xiàn)了flutter 平臺(tái)調(diào)用ios平臺(tái)的函數(shù)了
停止應(yīng)用浇借,重新啟動(dòng)app捉撮。保證app對(duì)ios平臺(tái)的代碼進(jìn)行了重新編譯。
運(yùn)行結(jié)果如下
6.實(shí)現(xiàn)ios平臺(tái)調(diào)用flutter平臺(tái)的方法
ios 平臺(tái)調(diào)用flutter 是通過(guò)flutter監(jiān)聽(tīng)事件來(lái)完成的
<1> 引入頭文件
import 'package:flutter/services.dart';
<2>添加成員變量
class _PlatformChannelState extends State<PlatformChannel> {
static const EventChannel eventChannel =
EventChannel('time.flutter.io/count');
...
}
<3>添加監(jiān)聽(tīng)事件
@override
void initState() {
super.initState();
eventChannel.receiveBroadcastStream().listen(_onEvent, onError: _onError);
}
void _onEvent(Object event) {
setState(() {
print("{$event}");
_chargingStatus =
"Battery status: ${event}";
});
}
void _onError(Object error) {
setState(() {
_chargingStatus = 'Battery status: unknown.';
});
}
<4>打開(kāi)ios工程代碼 并添加代碼如下
- (BOOL)application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
[GeneratedPluginRegistrant registerWithRegistry:self];
···
FlutterEventChannel* chargingChannel = [FlutterEventChannel eventChannelWithName:@"time.flutter.io/count" binaryMessenger:controller];
[chargingChannel setStreamHandler:self];
···
return [super application:application didFinishLaunchingWithOptions:launchOptions];
}
給appdelegate類(lèi)添加成員變量
@interface AppDelegate()
{
FlutterEventSink _eventSink;
}
@end
增加代理函數(shù)
- (FlutterError*)onListenWithArguments:(id)arguments
eventSink:(FlutterEventSink)eventSink {
_eventSink = eventSink;
static int mm = 0;
[NSTimer scheduledTimerWithTimeInterval:1 repeats:YES block:^(NSTimer * _Nonnull timer) {
if (!_eventSink) return;
_eventSink(@(++mm));
}];
return nil;
}
- (FlutterError*)onCancelWithArguments:(id)arguments {
[[NSNotificationCenter defaultCenter] removeObserver:self];
_eventSink = nil;
return nil;
}
這樣就實(shí)現(xiàn)了ios 調(diào)用flutter函數(shù)