flutter 和ios平臺(tái)混合開(kāi)發(fā)

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))之間傳遞消息,如下圖所示:

平臺(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)如下


目錄結(jié)構(gòu)

3.用vscode 打開(kāi)該工程并運(yùn)行該工程

結(jié)果如下:


image.png

這個(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)該工程

image.png
<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ù)


flutter 中文網(wǎng)相關(guān)文章

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末妇垢,一起剝皮案震驚了整個(gè)濱河市巾遭,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌闯估,老刑警劉巖灼舍,帶你破解...
    沈念sama閱讀 206,482評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異涨薪,居然都是意外死亡骑素,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,377評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門(mén)刚夺,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)献丑,“玉大人,你說(shuō)我怎么就攤上這事侠姑⊙艟啵” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 152,762評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵结借,是天一觀的道長(zhǎng)筐摘。 經(jīng)常有香客問(wèn)我,道長(zhǎng),這世上最難降的妖魔是什么咖熟? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,273評(píng)論 1 279
  • 正文 為了忘掉前任圃酵,我火速辦了婚禮,結(jié)果婚禮上馍管,老公的妹妹穿的比我還像新娘郭赐。我一直安慰自己,他們只是感情好确沸,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,289評(píng)論 5 373
  • 文/花漫 我一把揭開(kāi)白布捌锭。 她就那樣靜靜地躺著,像睡著了一般罗捎。 火紅的嫁衣襯著肌膚如雪观谦。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 49,046評(píng)論 1 285
  • 那天桨菜,我揣著相機(jī)與錄音豁状,去河邊找鬼。 笑死倒得,一個(gè)胖子當(dāng)著我的面吹牛泻红,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播霞掺,決...
    沈念sama閱讀 38,351評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼谊路,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了菩彬?” 一聲冷哼從身側(cè)響起凶异,我...
    開(kāi)封第一講書(shū)人閱讀 36,988評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎挤巡,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體酷麦,經(jīng)...
    沈念sama閱讀 43,476評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡矿卑,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,948評(píng)論 2 324
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了沃饶。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片母廷。...
    茶點(diǎn)故事閱讀 38,064評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖糊肤,靈堂內(nèi)的尸體忽然破棺而出琴昆,到底是詐尸還是另有隱情,我是刑警寧澤馆揉,帶...
    沈念sama閱讀 33,712評(píng)論 4 323
  • 正文 年R本政府宣布业舍,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏舷暮。R本人自食惡果不足惜态罪,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,261評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望下面。 院中可真熱鬧复颈,春花似錦、人聲如沸沥割。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,264評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)机杜。三九已至帜讲,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間叉庐,已是汗流浹背舒帮。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,486評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留陡叠,地道東北人玩郊。 一個(gè)月前我還...
    沈念sama閱讀 45,511評(píng)論 2 354
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像枉阵,于是被迫代替她去往敵國(guó)和親译红。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,802評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容