Flutter和原生iOS交互

具體集成請看下面文章
此篇記錄的是集成之后的iOS界面和flutter的交互,iOS界面怎么跳轉到不同的flutter界面。

老項目集成Flutter中文文檔
老項目集成Flutter詳細一篇
老項目集成Flutter詳細另一篇
老項目集成Flutter閑魚一篇
github flutter

下載新的項目demo
1、 Native跳轉到不同的flutter界面
2、 Native傳值給flutter
3、 Flutter傳值給Native
項目地址

flutter主動和iOS交互

flutter MyApp界面里
1、flutter點擊事件之后 iOS跳轉界面
2、flutter傳map類型參數給iOS進行相應交互
3、在flutter界面的事件響應之后,iOS返回響應數據給flutter

iOS代碼如下:
//
//  ViewController.m
//  FlutterD
//
//  Created by 侯佳男 on 2018/10/30.
//  Copyright ? 2018年 侯佳男. All rights reserved.
//

#import "ViewController.h"
#import "TargetViewController.h"
#import <Flutter/Flutter.h>

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
}


- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

- (void)pushFlutterViewController {
    FlutterViewController* flutterViewController = [[FlutterViewController alloc] initWithProject:nil nibName:nil bundle:nil];
    // 設置路由名字 跳轉到不同的flutter界面
    /*flutter代碼*/
    /*
    import 'dart:ui';
    
    void main() => runApp(_widgetForRoute(window.defaultRouteName));
    
    Widget _widgetForRoute(String route) {
        switch (route) {
            case 'myApp':
                return new MyApp();
            case 'home':
                return new HomePage();
            default:
                return Center(
                  child: Text('Unknown route: $route', textDirection: TextDirection.ltr),
            );
        }
    }
    */
    [flutterViewController setInitialRoute:@"myApp"];
    __weak __typeof(self) weakSelf = self;

    // 要與main.dart中一致
    NSString *channelName = @"com.pages.your/native_get";

    FlutterMethodChannel *messageChannel = [FlutterMethodChannel methodChannelWithName:channelName binaryMessenger:flutterViewController];

    [messageChannel setMethodCallHandler:^(FlutterMethodCall * _Nonnull call, FlutterResult  _Nonnull result) {
        // call.method 獲取 flutter 給回到的方法名,要匹配到 channelName 對應的多個 發送方法名,一般需要判斷區分
        // call.arguments 獲取到 flutter 給到的參數,(比如跳轉到另一個頁面所需要參數)
        // result 是給flutter的回調, 該回調只能使用一次
        NSLog(@"method=%@ \narguments = %@", call.method, call.arguments);
        
        // method和WKWebView里面JS交互很像
        // flutter點擊事件執行后在iOS跳轉TargetViewController
        if ([call.method isEqualToString:@"iOSFlutter"]) {
            TargetViewController *vc = [[TargetViewController alloc] init];
            [self.navigationController pushViewController:vc animated:YES];
        }
        // flutter傳參給iOS
        if ([call.method isEqualToString:@"iOSFlutter1"]) {
            NSDictionary *dic = call.arguments;
            NSLog(@"arguments = %@", dic);
            NSString *code = dic[@"code"];
            NSArray *data = dic[@"data"];
            NSLog(@"code = %@", code);
            NSLog(@"data = %@",data);
            NSLog(@"data 第一個元素%@",data[0]);
            NSLog(@"data 第一個元素類型%@",[data[0] class]);
        }
        // iOS給iOS返回值
        if ([call.method isEqualToString:@"iOSFlutter2"]) {
            if (result) {
                result(@"返回給flutter的內容");
            }
        }
    }];
    
    [self.navigationController pushViewController:flutterViewController animated:YES];
}
// 點擊跳轉到flutter界面
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    [self pushFlutterViewController];
}

@end

flutter代碼
import 'dart:ui' as ui; // 調用window拿到route判斷跳轉哪個界面
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_module/HomePage.dart';


void main() => runApp(_widgetForRoute(ui.window.defaultRouteName));

// 根據iOS端傳來的route跳轉不同界面
Widget _widgetForRoute(String route) {
  switch (route) {
    case 'myApp':
      return new MyApp();
    case 'home':
      return new HomePage();
    default:
      return Center(
        child: Text('Unknown route: $route', textDirection: TextDirection.ltr),
      );
  }
}

class MyApp extends StatelessWidget {

  Widget _home(BuildContext context) {
    return new MyHomePage(title: 'Flutter Demo Home Page');
  }

  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      title: 'Flutter Demo',
      theme: new ThemeData(
        primarySwatch: Colors.blue,
      ),
      routes: <String, WidgetBuilder>{
        "/home":(BuildContext context) => new HomePage(),
      },
      home: _home(context),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);

  final String title;

  @override
  _MyHomePageState createState() => new _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {

  // 創建一個給native的channel (類似iOS的通知)
  static const methodChannel = const MethodChannel('com.pages.your/native_get');

  
  _iOSPushToVC() async {
    await methodChannel.invokeMethod('iOSFlutter', '參數');
  }

  _iOSPushToVC1() async {
    Map<String, dynamic> map = {"code": "200", "data":[1,2,3]};
    await methodChannel.invokeMethod('iOSFlutter1', map);
  }

  _iOSPushToVC2() async {
    dynamic result;
    try {
      result = await methodChannel.invokeMethod('iOSFlutter2');
    } on PlatformException {
      result = "error";
    }
    if (result is String) {
      print(result);
      showModalBottomSheet(context: context, builder: (BuildContext context) {
        return new Container(
          child: new Center(
            child: new Text(result, style: new TextStyle(color: Colors.brown), textAlign: TextAlign.center,),
          ),
          height: 40.0,
        );
      });
    }
  }

  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      body: new Center(
        child: new Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            new FlatButton(onPressed: () {
              _iOSPushToVC();
            }, child: new Text("跳轉ios新界面,參數是字符串")),
            new FlatButton(onPressed: () {
              _iOSPushToVC1();
            }, child: new Text("傳參,參數是map,看log")),
            new FlatButton(onPressed: () {
              _iOSPushToVC2();
            }, child: new Text("接收客戶端相關內容")),
          ],
        ),
      ),
    );
  }
}


iOS主動和flutter交互

flutter MyApp界面里
1、初始化flutter界面時候iOS傳值給flutter

iOS代碼
//
//  TargetViewController.m
//  FlutterD
//
//  Created by 侯佳男 on 2018/10/30.
//  Copyright ? 2018年 侯佳男. All rights reserved.
//

#import "TargetViewController.h"
#import <Flutter/Flutter.h>

@interface TargetViewController () <FlutterStreamHandler>

@end

@implementation TargetViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    self.title = @"TargetViewController";
    self.view.backgroundColor = [UIColor whiteColor];
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

- (void)pushFlutterViewController_EventChannel {
    FlutterViewController* flutterViewController = [[FlutterViewController alloc] initWithProject:nil nibName:nil bundle:nil];
    flutterViewController.navigationItem.title = @"Demo";
    [flutterViewController setInitialRoute:@"home"];
    // 要與main.dart中一致
    NSString *channelName = @"com.pages.your/native_post";
    
    FlutterEventChannel *evenChannal = [FlutterEventChannel eventChannelWithName:channelName binaryMessenger:flutterViewController];
    // 代理FlutterStreamHandler
    [evenChannal setStreamHandler:self];
    
    [self.navigationController pushViewController:flutterViewController animated:YES];
}

#pragma mark - <FlutterStreamHandler>
// // 這個onListen是Flutter端開始監聽這個channel時的回調,第二個參數 EventSink是用來傳數據的載體。
- (FlutterError* _Nullable)onListenWithArguments:(id _Nullable)arguments
                                       eventSink:(FlutterEventSink)events {
    // arguments flutter給native的參數
    // 回調給flutter, 建議使用實例指向,因為該block可以使用多次
    if (events) {
        events(@"push傳值給flutter的vc");
    }
    return nil;
}

/// flutter不再接收
- (FlutterError* _Nullable)onCancelWithArguments:(id _Nullable)arguments {
    // arguments flutter給native的參數
    NSLog(@"%@", arguments);
    return nil;
}

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    [self pushFlutterViewController_EventChannel];
}

@end

flutter代碼
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';

class HomePage extends StatefulWidget {
  _HomePageState createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {

  // 注冊一個通知
  static const EventChannel eventChannel = const EventChannel('com.pages.your/native_post');

  // 渲染前的操作,類似viewDidLoad
  @override
  void initState() {
    super.initState();

    // 監聽事件,同時發送參數12345
    eventChannel.receiveBroadcastStream(12345).listen(_onEvent,onError: _onError);
  }

  String naviTitle = 'title' ;
  // 回調事件
  void _onEvent(Object event) {
    setState(() {
      naviTitle =  event.toString();
    });
  }
  // 錯誤返回
  void _onError(Object error) {

  }

  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      home: new Material(
        child: new Scaffold(
          body: new Center(
            child: new Text(naviTitle),
          ),
        ),
      ),
    );
  }
}


UI界面搭建相關記錄
網絡請求相關記錄

后續:
如果有報錯如下,解決辦法:進入到項目目錄flutter_module下,執行flutter create -t module flutter_module

/Users/xxxx/Library/Developer/Xcode/DerivedData/FlutterD-ahzvxiwdocategdkaaadxprgaqbj/Build/Intermediates.noindex/FlutterD.build/Debug-iphonesimulator/FlutterD.build/Script-DC57D7F321880EB20048BF54.sh: line 3: /packages/flutter_tools/bin/xcode_backend.sh: No such file or directory
如下錯誤
The path /Users/houjianan/Desktop/FlutterDemo/flutter_module does not exist The path /Users/houjianan/Desktop/FlutterDemo/flutter_module does not exist

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,345評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,494評論 3 416
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,283評論 0 374
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,953評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,714評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,186評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,255評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,410評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,940評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,776評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,976評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,518評論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,210評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,642評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,878評論 1 286
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,654評論 3 391
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,958評論 2 373

推薦閱讀更多精彩內容

  • 1、通過CocoaPods安裝項目名稱項目信息 AFNetworking網絡請求組件 FMDB本地數據庫組件 SD...
    陽明先生_X自主閱讀 16,000評論 3 119
  • 凌晨之前,圈里滿是緬懷的氣息。十年了,逝者已逝,生者可好? 依然記得2008年那個地震的午后,我在...
    王小年兒閱讀 169評論 0 0
  • 抖腿,因渾身有點酸痛,再,椅子硌得慌,抖抖可以挑最佳受力部位,屁股可以勻稱的鋪開!無意識的! 但,被店里的年輕孩看...
    縱情嬉戲天地間閱讀 328評論 0 0
  • 1.spice 2.intrige 3.doze off vi.假寐;打盹兒,打瞌睡 vt.打瞌睡度過 n.瞌睡 ...
    自由的靈魂一梅閱讀 634評論 0 0
  • 偷個懶,先去聽聽別人講的故事。 有一個人想學醫 ,可是又猶豫不決 ,就去問他的一個朋友 : “再過四年 ,我就44...
    蝸牛小姐ms閱讀 362評論 0 0