<kbd id="5sdj3"></kbd>
<th id="5sdj3"></th>

  • <dd id="5sdj3"><form id="5sdj3"></form></dd>
    <td id="5sdj3"><form id="5sdj3"><big id="5sdj3"></big></form></td><del id="5sdj3"></del>

  • <dd id="5sdj3"></dd>
    <dfn id="5sdj3"></dfn>
  • <th id="5sdj3"></th>
    <tfoot id="5sdj3"><menuitem id="5sdj3"></menuitem></tfoot>

  • <td id="5sdj3"><form id="5sdj3"><menu id="5sdj3"></menu></form></td>
  • <kbd id="5sdj3"><form id="5sdj3"></form></kbd>

    iOS 原生項目嵌入 Flutter

    共 14555字,需瀏覽 30分鐘

     ·

    2021-12-27 02:54


    ????關(guān)注后回復(fù) “進群” ,拉你進程序員交流群????


    作者:晨曦_iOS

    https://juejin.cn/post/7036393182053007367


    雖然一般不建議在原生項目中嵌入Flutter,但是Flutter也可以支持這種方式,下面我們來看一下具體的實現(xiàn)。

    原生嵌入 Flutter 的工程配置

    如圖,我們想使原生嵌入Flutter的話,使用Android Studio創(chuàng)建項目的時候就要選擇Module進行創(chuàng)建,使之作為一個模塊來開發(fā)。

    打開我們新建的flutter_module工程目錄可以看到,與創(chuàng)建的Flutter App相比,文件里面仍然有AndroidiOS工程文件,但是這里只是為了讓我們做調(diào)試用的,而且這兩個文件都是隱藏文件,不過Android、iOS工程中不建議加入原生代碼,而且即使加了,打包的時候也不會被打包進去。flutter_module是一個純Flutter的工程。

    • Podfile文件配置
    flutter_application_path = '../flutter_module'
    load File.join(flutter_application_path,'.iOS','Flutter','podhelper.rb')

    platform :ios, '9.0'

    target 'NativeDemo' do
      install_all_flutter_pods(flutter_application_path)
      use_frameworks!

      # Pods for NativeDemo

    end

    我們使用Xcode創(chuàng)建一個原生工程,NativeDemo,使用終端,cdNativeDemo目錄下,pod init,然后配置Podfile文件,然后執(zhí)行pod install。

    pod install完成之后,打開原生項目,引用頭文件#import <Flutter/Flutter.h>,可以成功的話就代表配置成功,現(xiàn)在的話原生工程與Flutter就有聯(lián)系了,下面我們就可以實現(xiàn)代碼了,來使原生工程中嵌入Flutter。

    原生項目調(diào)起 Flutter 頁面

    • 原生代碼部分
    #import "ViewController.h"
    #import <Flutter/Flutter.h>

    @interface ViewController ()
    @property(nonatomic, strong) FlutterEngine* flutterEngine;
    @property(nonatomic, strong) FlutterViewController* flutterVc;
    @property(nonatomic, strong) FlutterBasicMessageChannel * msgChannel;
    @end

    @implementation ViewController

    -(FlutterEngine *)flutterEngine
    {
        if (!_flutterEngine) {
            FlutterEngine * engine = [[FlutterEngine alloc] initWithName:@"hank"];
            if (engine.run) {
                _flutterEngine = engine;
            }
        }
        return _flutterEngine;
    }

    - (IBAction)pushFlutter:(id)sender {
        
        self.flutterVc.modalPresentationStyle = UIModalPresentationFullScreen;

        //創(chuàng)建channel
        FlutterMethodChannel * methodChannel = [FlutterMethodChannel methodChannelWithName:@"one_page" binaryMessenger:self.flutterVc.binaryMessenger];
        //告訴Flutter對應(yīng)的頁面
        [methodChannel invokeMethod:@"one" arguments:nil];
        
        //彈出頁面
        [self presentViewController:self.flutterVc animated:YES completion:nil];
        
        //監(jiān)聽退出
        [methodChannel setMethodCallHandler:^(FlutterMethodCall * _Nonnull call, FlutterResult  _Nonnull result) {
            //如果是exit我就退出頁面!
            if ([call.method isEqualToString:@"exit"]) {
                [self.flutterVc dismissViewControllerAnimated:YES completion:nil];
            }
        }];
    }
    - (IBAction)pushFlutterTwo:(id)sender {
        self.flutterVc.modalPresentationStyle = UIModalPresentationFullScreen;

        //創(chuàng)建channel
        FlutterMethodChannel * methodChannel = [FlutterMethodChannel methodChannelWithName:@"two_page" binaryMessenger:self.flutterVc.binaryMessenger];
        //告訴Flutter對應(yīng)的頁面
        [methodChannel invokeMethod:@"two" arguments:nil];
        
        //彈出頁面
        [self presentViewController:self.flutterVc animated:YES completion:nil];
        
        //監(jiān)聽退出
        [methodChannel setMethodCallHandler:^(FlutterMethodCall * _Nonnull call, FlutterResult  _Nonnull result) {
            //如果是exit我就退出頁面!
            if ([call.method isEqualToString:@"exit"]) {
                [self.flutterVc dismissViewControllerAnimated:YES completion:nil];
            }
        }];
    }

    - (void)viewDidLoad {
        [super viewDidLoad];
        
        self.flutterVc = [[FlutterViewController alloc] initWithEngine:self.flutterEngine nibName:nil bundle:nil];
        self.msgChannel = [FlutterBasicMessageChannel messageChannelWithName:@"messageChannel" binaryMessenger:self.flutterVc.binaryMessenger];
        
        [self.msgChannel setMessageHandler:^(id  _Nullable message, FlutterReply  _Nonnull callback) {
            NSLog(@"收到Flutter的:%@",message);
        }];
        
    }

    -(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
    {
        static int a = 0;
        [self.msgChannel sendMessage:[NSString stringWithFormat:@"%d",a++]];
    }

    在原生代碼部分我們定義了三個屬性,flutterEngine代表引擎對象,flutterVcFlutterViewController類型的控制器對象,msgChannel是通信方式中的一種channel,為FlutterBasicMessageChannel類型,下面會有介紹。

    在這里我們實現(xiàn)了pushFlutterpushFlutterTwo兩個方法,代表調(diào)起兩個不同的Flutter頁面。在這兩個方法中,我們首先創(chuàng)建methodChannel對象,并分別傳入onetwo兩個字符串標識,并且binaryMessenger傳參傳入的都是self.flutterVc.binaryMessenger。在兩個方法中分別調(diào)用invokeMethod方法,向Flutter頁面發(fā)送消息,然后彈出頁面,并且實現(xiàn)setMethodCallHandler方法,在閉包中判斷call.method isEqualToString:@"exit",進行頁面的退出。

    • Flutter 代碼部分
    // ignore_for_file: avoid_print

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

    void main() => runApp(const MyApp());

    class MyApp extends StatefulWidget {
      const MyApp({Key? key}) : super(key: key);

      @override
      _MyAppState createState() => _MyAppState();
    }

    class _MyAppState extends State<MyApp> {
      final MethodChannel _oneChannel = const MethodChannel('one_page');
      final MethodChannel _twoChannel = const MethodChannel('two_page');
      final BasicMessageChannel _messageChannel =
          const BasicMessageChannel('messageChannel', StandardMessageCodec());

      String pageIndex = 'one';

      @override
      void initState() {
        super.initState();

        _messageChannel.setMessageHandler((message) {
          print('收到來自iOS的$message');
          return Future(() {});
        });

        _oneChannel.setMethodCallHandler((call) {
          pageIndex = call.method;
          print(call.method);
          setState(() {});
          return Future(() {});
        });
        _twoChannel.setMethodCallHandler((call) {
          pageIndex = call.method;
          print(call.method);
          setState(() {});
          return Future(() {});
        });
      }

      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          title: 'Flutter Demo',
          theme: ThemeData(
            primarySwatch: Colors.blue,
          ),
          home: _rootPage(pageIndex),
        );
      }

      //根據(jù)pageIndex來返回頁面!
      Widget _rootPage(String pageIndex) {
        switch (pageIndex) {
          case 'one':
            return Scaffold(
              appBar: AppBar(
                title: Text(pageIndex),
              ),
              body: Column(
                mainAxisAlignment: MainAxisAlignment.center,
                children: [
                  ElevatedButton(
                    onPressed: () {
                      _oneChannel.invokeMapMethod('exit');
                    },
                    child: Text(pageIndex),
                  ),
                  TextField(
                    onChanged: (String str) {
                      _messageChannel.send(str);
                    },
                  )
                ],
              ),
            );
          case 'two':
            return Scaffold(
              appBar: AppBar(
                title: Text(pageIndex),
              ),
              body: Center(
                child: ElevatedButton(
                  onPressed: () {
                    _twoChannel.invokeMapMethod('exit');
                  },
                  child: Text(pageIndex),
                ),
              ),
            );
          default:
            return Scaffold(
              appBar: AppBar(
                title: Text(pageIndex),
              ),
              body: Center(
                child: ElevatedButton(
                  onPressed: () {
                    const MethodChannel('default_page').invokeMapMethod('exit');
                  },
                  child: Text(pageIndex),
                ),
              ),
            );
        }
      }
    }

    Flutter代碼中我們定義了_oneChannel_twoChannel這兩個變量用了接收原生頁面發(fā)送的消息,并且向原生頁面發(fā)送消息。定義了變量pageIndex用來標識創(chuàng)建那個頁面。

    initState方法中調(diào)用setMethodCallHandler方法,獲取到原生頁面?zhèn)鱽淼臄?shù)據(jù)并賦值給pageIndex,然后調(diào)用setState方法。

    build方法中我們調(diào)用_rootPage方法來判斷創(chuàng)建哪個頁面。并且分別在這兩個頁面的點擊事件中調(diào)用invokeMapMethod方法,代表退出頁面,原生頁面在setMethodCallHandler閉包中接收到exit數(shù)據(jù)后就會調(diào)用[self.flutterVc dismissViewControllerAnimated:YES completion:nil],進行頁面的退出。

    Flutter 與原生的通信

    • MethodChannelFlutterNative端相互調(diào)用,調(diào)用后可以返回結(jié)果,可以Native端主動調(diào)用,也可以Flutter主動調(diào)用,屬于雙向通信。此方式為最常用的方式,Native端調(diào)用需要在主線程中執(zhí)行。
    • BasicMessageChannel: 用于使用指定的編解碼器對消息進行編碼和解碼,屬于雙向通信,可以Native端主動調(diào)用,也可Flutter主動調(diào)用。
    • EventChannel:用于數(shù)據(jù)流(event streams)的通信,Native端主動發(fā)送數(shù)據(jù)給Flutter,通常用于狀態(tài)的監(jiān)聽,比如網(wǎng)絡(luò)變化、傳感器數(shù)據(jù)等。

    Flutter與原生通信有三種方式,Flutter為我們提供了三種Channel,分別是MethodChannelBasicMessageChannelEventChannel。但是我們比較常用的就是MethodChannelBasicMessageChannel這兩種。因為MethodChannel前面已經(jīng)講過了,所以這里我們介紹一下BasicMessageChannel的用法。

    BasicMessageChannel 用法

    BasicMessageChannel的用法與FlutterMethodChannel類似,在上面的代碼示例中,首先在Flutter代碼中我們也是定義一個BasicMessageChannel類型的變量_messageChannel,在_messageChannelsetMessageHandler閉包中接收來自于原生頁面發(fā)來的消息,調(diào)用_messageChannelsend方法向原生頁面進行通信,在輸入框文字變化的時候都會調(diào)用send方法。在原生代碼中也是類似,定義了msgChannel屬性,setMessageHandler中的block負責(zé)接收消息,sendMessage發(fā)送消息,在touchesBegan中向Flutter傳遞a的累加值。

    作者:晨曦_iOS

    https://juejin.cn/post/7036393182053007367


    -End-

    最近有一些小伙伴,讓我?guī)兔φ乙恍?nbsp;面試題 資料,于是我翻遍了收藏的 5T 資料后,匯總整理出來,可以說是程序員面試必備!所有資料都整理到網(wǎng)盤了,歡迎下載!

    點擊??卡片,關(guān)注后回復(fù)【面試題】即可獲取

    在看點這里好文分享給更多人↓↓

    瀏覽 61
    點贊
    評論
    收藏
    分享

    手機掃一掃分享

    分享
    舉報
    評論
    圖片
    表情
    推薦
    點贊
    評論
    收藏
    分享

    手機掃一掃分享

    分享
    舉報

    <kbd id="5sdj3"></kbd>
    <th id="5sdj3"></th>

  • <dd id="5sdj3"><form id="5sdj3"></form></dd>
    <td id="5sdj3"><form id="5sdj3"><big id="5sdj3"></big></form></td><del id="5sdj3"></del>

  • <dd id="5sdj3"></dd>
    <dfn id="5sdj3"></dfn>
  • <th id="5sdj3"></th>
    <tfoot id="5sdj3"><menuitem id="5sdj3"></menuitem></tfoot>

  • <td id="5sdj3"><form id="5sdj3"><menu id="5sdj3"></menu></form></td>
  • <kbd id="5sdj3"><form id="5sdj3"></form></kbd>
    亚洲青青草在线视频 | 国产精品乱| 国产精品在线视频免费 | 黄色视频一级 | 亚洲高清视频免费观看 |