在已有iOS項(xiàng)目中添加flutter模塊

前提

前提是你已經(jīng)配置好flutter環(huán)境了,如果沒有配置好,可以參考我上一篇文章,先把環(huán)境配好.查看是否已經(jīng)配好環(huán)境,在終端輸入命令: flutter doctor

一,項(xiàng)目準(zhǔn)備

1. 先拿出你已有的iOS項(xiàng)目
2. 打開終端cd 到你的項(xiàng)目路徑
3. 創(chuàng)建module (flutter 模塊),輸入以下命令

flutter_library是flutter模塊的名字,可以自己命名,最好帶有flutter字樣,這樣好區(qū)分,命令執(zhí)行完之后,就會生成一個(gè)flutter_library文件夾,這文件夾就是你將來寫flutter代碼的地方

flutter create -t module flutter_library

如圖:


WeChat2ea5948994b8559845ff499d75acfd07.png

在這個(gè)文件夾里面有個(gè)配置文件很重要在隱藏文件.iOS中,先留意一下,待會有用,如圖:


WeChatac214b2cda7e747f8a4fef770056b960.png
4. 創(chuàng)建三個(gè)配置文件,Flutter文件夾是自己創(chuàng)建的,你可以自己想一個(gè)其他名字,Flutter.xcconfig, Debug.xcconfig,Release.xcconfig,創(chuàng)建方法如圖:
WeChatadc0ddc91ba5f240e79a3c3322ff4868.png

在Flutter.xcconfig文件中寫入:

#include "../flutter_library/.ios/Flutter/Generated.xcconfig"
ENABLE_BITCODE=NO

在Debug.xcconfig文件中寫入

#include "../Flutter/Flutter.xcconfig"
// 如果項(xiàng)目中引入pods可以不加以下代碼
#include "Pods/Target Support Files/Pods-FlutterMixed/Pods-FlutterMixed.debug.xcconfig"

在Release.xconfig文件中寫入

#include "../Flutter/Flutter.xcconfig"
FLUTTER_BUILD_MODE=release
// 如果項(xiàng)目中引入pods可以不加以下代碼
#include "Pods/Target Support Files/Pods-FlutterMixed/Pods-FlutterMixed.debug.xcconfig"
5. Xcode project環(huán)境配置(如圖)
WeChat57bd2851bdfd8c24caeccdf83a7836fe.png

第四步和第五步的目的是讓iOS項(xiàng)目與flutter模塊關(guān)聯(lián)上.

6. 添加腳本(如圖)
WeChatdf2579ac418ebfc9a7c232310b0b20ae.png

腳本代碼是:

"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh" build
"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh" embed

進(jìn)展到這一步,run一下項(xiàng)目正常來說,在你的Flutter文件夾中會新出來幾個(gè)文件,如果項(xiàng)目編譯通過之后,并沒有出現(xiàn)新的文件,你可以找到你配置環(huán)境的時(shí)候下載的flutter文件,找到這個(gè)文件(如圖)

WeChat2a3fe2c31153c52ef68027309fb2181b.png

打開它找到如下代碼,再注釋掉,再重新run,build也行

  if [[ -e "${project_path}/.ios" ]]; then
    derived_dir="${project_path}/.ios/Flutter"
  fi

這時(shí)候,新生成的文件就會出來了,如圖:


WeChate35219153ae3e6eb7fe5360f0178d603.png

也許你會納悶,為啥其他很多博客上寫著,還會出來flutter_assets這個(gè)文件夾,還教你如何導(dǎo)入項(xiàng)目,說實(shí)話,為了這事我折騰了兩天,也搞不懂,我這里為啥沒有出來,如果哪位大牛知道,歡迎賜教,盡管沒有出來flutter_assets這個(gè)文件,但是后來我發(fā)現(xiàn)并不影響我后面的步驟.

7. 把App.framework和engin引入到xcode中

這時(shí)候,就可以在你的iOS舊項(xiàng)目中引入#import <Flutter/Flutter.h>不會報(bào)錯(cuò)了.

8. 上代碼

iOS ViewController中代碼如下

#import <Flutter/Flutter.h>
@interface SpaceBookingViewController ()<FlutterStreamHandler>
@end

@implementation SpaceBookingViewController
- (void)viewDidLoad {
    [super viewDidLoad];
    [self initNavigationView];
    [self initSubView];
}
- (void)initNavigationView{
    self.navigationItem.title = @"flutter測試";
    self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"跳轉(zhuǎn)到flutter" style:UIBarButtonItemStylePlain target:self action:@selector(onRightItemClickAction)];
}

- (void)initSubView{
    [self.view addSubview:self.tableView];
    [self.view addSubview:self.titleView];
}

- (void)onRightItemClickAction{
    [self pushFlutterViewController_EventChannel];
}

- (void)pushFlutterViewController_EventChannel {
    FlutterViewController* flutterViewController = [[FlutterViewController alloc] initWithProject:nil nibName:nil bundle:nil];
    
    [flutterViewController.view setBackgroundColor:[UIColor whiteColor]];
    flutterViewController.navigationItem.title = @"Demo";
    [flutterViewController setInitialRoute:@"myApp"];
    // 要與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>
// // 這個(gè)onListen是Flutter端開始監(jiān)聽這個(gè)channel時(shí)的回調(diào),第二個(gè)參數(shù) EventSink是用來傳數(shù)據(jù)的載體。
- (FlutterError* _Nullable)onListenWithArguments:(id _Nullable)arguments
                                       eventSink:(FlutterEventSink)events {
    // arguments flutter給native的參數(shù)
    // 回調(diào)給flutter潜秋, 建議使用實(shí)例指向捆昏,因?yàn)樵揵lock可以使用多次
    if (events) {
        events(@"push傳值給flutter的vc");
    }
    return nil;
}

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

在flutter中main.dart代碼如下

import 'dart:ui' as ui; // 調(diào)用window拿到route判斷跳轉(zhuǎn)哪個(gè)界面
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import './pages/HomePage.dart';


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

// 根據(jù)iOS端傳來的route跳轉(zhuǎn)不同界面
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',
      debugShowCheckedModeBanner:false,
      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> {

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

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

  _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("跳轉(zhuǎn)ios新界面究驴,參數(shù)是字符串")),
            new FlatButton(onPressed: () {
              _iOSPushToVC1();
            }, child: new Text("傳參吹艇,參數(shù)是map诱建,看log")),
            new FlatButton(onPressed: () {
              _iOSPushToVC2();
            }, child: new Text("接收客戶端相關(guān)內(nèi)容")),
          ],
        ),
      ),
    );
  }
}

這個(gè)時(shí)候,點(diǎn)擊按鈕,就能跳轉(zhuǎn)到flutter的頁面

9. 熱更新
  1. cd到 flutter模塊目錄, 輸入flutter attach命令
  2. 打開xcode,運(yùn)行,之后就可以正常熱更新
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市仅颇,隨后出現(xiàn)的幾起案子单默,更是在濱河造成了極大的恐慌,老刑警劉巖忘瓦,帶你破解...
    沈念sama閱讀 211,123評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件搁廓,死亡現(xiàn)場離奇詭異,居然都是意外死亡耕皮,警方通過查閱死者的電腦和手機(jī)境蜕,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,031評論 2 384
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來凌停,“玉大人粱年,你說我怎么就攤上這事》D猓” “怎么了台诗?”我有些...
    開封第一講書人閱讀 156,723評論 0 345
  • 文/不壞的土叔 我叫張陵,是天一觀的道長赐俗。 經(jīng)常有香客問我拉队,道長,這世上最難降的妖魔是什么阻逮? 我笑而不...
    開封第一講書人閱讀 56,357評論 1 283
  • 正文 為了忘掉前任粱快,我火速辦了婚禮,結(jié)果婚禮上叔扼,老公的妹妹穿的比我還像新娘皆尔。我一直安慰自己,他們只是感情好币励,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,412評論 5 384
  • 文/花漫 我一把揭開白布慷蠕。 她就那樣靜靜地躺著,像睡著了一般食呻。 火紅的嫁衣襯著肌膚如雪流炕。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,760評論 1 289
  • 那天仅胞,我揣著相機(jī)與錄音每辟,去河邊找鬼。 笑死干旧,一個(gè)胖子當(dāng)著我的面吹牛渠欺,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播椎眯,決...
    沈念sama閱讀 38,904評論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼挠将,長吁一口氣:“原來是場噩夢啊……” “哼胳岂!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起舔稀,我...
    開封第一講書人閱讀 37,672評論 0 266
  • 序言:老撾萬榮一對情侶失蹤乳丰,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后内贮,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體产园,經(jīng)...
    沈念sama閱讀 44,118評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,456評論 2 325
  • 正文 我和宋清朗相戀三年夜郁,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了什燕。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,599評論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡竞端,死狀恐怖秋冰,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情婶熬,我是刑警寧澤,帶...
    沈念sama閱讀 34,264評論 4 328
  • 正文 年R本政府宣布埃撵,位于F島的核電站赵颅,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏暂刘。R本人自食惡果不足惜饺谬,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,857評論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望谣拣。 院中可真熱鬧募寨,春花似錦、人聲如沸森缠。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,731評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽贵涵。三九已至列肢,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間宾茂,已是汗流浹背瓷马。 一陣腳步聲響...
    開封第一講書人閱讀 31,956評論 1 264
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留跨晴,地道東北人欧聘。 一個(gè)月前我還...
    沈念sama閱讀 46,286評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像端盆,于是被迫代替她去往敵國和親怀骤。 傳聞我的和親對象是個(gè)殘疾皇子费封,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,465評論 2 348

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