Flutter踩坑日记:接入现有iOS项目

之前搞的Flutter版工具链已经弄完了,感兴趣的朋友可以围观下,Android版本dio库(v2.0.14)发送网络请求老是报错,去官方提了issue还没回,于是今天搞一下把Flutter模块接入到已有项目中。

首先Flutter官方已经出了wiki,教大家怎么接入。懒得看官方原文的可以看看这个简易版快速集成,先来看看效果。

一、创建Flutter模块

一般用Flutter或者React Native的团队大部分原因都是因为需要跨平台,所以在已有项目目录的上一级创建Flutter模块,譬如你的工作目录在some/path/MyApp,那么你需要在some/path下执行,这样Flutter可以单独交给一个虚拟团队维护,各自独立。

$ cd some/path/

$ flutter create -t module my_flutter

文件结构如下:

some/path/

  my_flutter/

    lib/main.dart

    .ios/

  MyApp/

      MyApp.xcodeproj

      Podfile

    MyApp/

      AppDelegate.h

      AppDelegate.m (or swift)

二、利用Cocoapods添加依赖

没用过Cocoapods的童鞋可以google搜一下,之前写过很多Cocoapods的文章由于博客主机商跑路都没了,说多了都是泪

1.在Podfile文件加入以下代码:

flutter_application_path = '../my_flutter/'

eval(File.read(File.join(flutter_application_path, '.ios', 'Flutter', 'podhelper.rb')), binding)

注意my_flutter的路径,因为我们是以xcodeproj文件的上一级创建的,所以需要加../,这个和React Native引入依赖路径是一样的,都需要注意这个问题。

2.执行pod install

注:如果报错

[!] InvalidPodfilefile: No such file or directory @ rb_sysopen - ./my_flutter/.ios/Flutter/podhelper.rb.

需要在my_flutter文件夹下执行以下flutter run,把.ios.androidflutter配置生成出来。

3.禁用bitcode,设置环境变量

找到你的targetBuild Settings->Build Options->Enable Bitcode设置为NO,另外在Preprocessor Macros添加FLUTTER_BUILD_MODE=DebugFLUTTER_BUILD_MODE=Release,如果还有其他环境需要根据情况选择DebugRelease

image

4.添加run script

找到你的targetBuild Phases -> + -> New Run Script Phase,并且在bashzsh配置FLUTTER_ROOT,否则打包会出错找不到flutter。涉及多人开发还需要安装路径位置,否则团队小伙伴每个人的路径不一样。

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

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

注:把这个script放到Target Dependencies phasescript的后面。

5.添加assets资源

官网说需要添加Flutter.framework资源,但是这个Cocoapods已经帮忙引入了,所以就不需要了,如果没有被引入进去那就手动引入下。这里只需要添加flutter_assets就行了,记得选Creat folder references引入方式。Flutter 1.0.0版本路径是my_flutter->build->flutter_assets

6.修改AppDelegate

Objective-C:

AppDelegate.h

#import <UIKit/UIKit.h>

#import <Flutter/Flutter.h>

@interface AppDelegate : FlutterAppDelegate

@property (nonatomic,strong) FlutterEngine *flutterEngine;

@end

AppDelegate.m

#import <FlutterPluginRegistrant/GeneratedPluginRegistrant.h> // Only if you have Flutter Plugins

#include "AppDelegate.h"

@implementation AppDelegate

// This override can be omitted if you do not have any Flutter Plugins.

- (BOOL)application:(UIApplication *)application

    didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {

  self.flutterEngine = [[FlutterEngine alloc] initWithName:@"io.flutter" project:nil];

  [self.flutterEngine runWithEntrypoint:nil];

  [GeneratedPluginRegistrant registerWithRegistry:self.flutterEngine];

  return [super application:application didFinishLaunchingWithOptions:launchOptions];

}

@end

Swift:

AppDelegate.swift

import UIKit

import Flutter

import FlutterPluginRegistrant // Only if you have Flutter Plugins.

@UIApplicationMain

class AppDelegate: FlutterAppDelegate {

  var flutterEngine : FlutterEngine?;

  // Only if you have Flutter plugins.

  override func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {

    self.flutterEngine = FlutterEngine(name: "io.flutter", project: nil);

    self.flutterEngine?.run(withEntrypoint: nil);

    GeneratedPluginRegistrant.register(with: self.flutterEngine);

    return super.application(application, didFinishLaunchingWithOptions: launchOptions);

  }

}

到这里,我们的Flutter就算已经引入工程了

三、跳转Flutter页面

Objective-C:

ViewController.m

#import <Flutter/Flutter.h>

#import "AppDelegate.h"

#import "ViewController.h"

@implementation ViewController

- (void)viewDidLoad {

    [super viewDidLoad];

    UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];

    [button addTarget:self

              action:@selector(handleButtonAction)

    forControlEvents:UIControlEventTouchUpInside];

    [button setTitle:@"Press me" forState:UIControlStateNormal];

    [button setBackgroundColor:[UIColor blueColor]];

    button.frame = CGRectMake(80.0, 210.0, 160.0, 40.0);

    [self.view addSubview:button];

}

- (void)handleButtonAction {

    FlutterEngine *flutterEngine = [(AppDelegate *)[[UIApplication sharedApplication] delegate] flutterEngine];

    FlutterViewController *flutterViewController = [[FlutterViewController alloc] initWithEngine:flutterEngine nibName:nil bundle:nil];

    [self presentViewController:flutterViewController animated:false completion:nil];

}

@end

Swift:

ViewController.swift

import UIKit

import Flutter

class ViewController: UIViewController {

  override func viewDidLoad() {

    super.viewDidLoad()

    let button = UIButton(type:UIButtonType.custom)

    button.addTarget(self, action: #selector(handleButtonAction), for: .touchUpInside)

    button.setTitle("Press me", for: UIControlState.normal)

    button.frame = CGRect(x: 80.0, y: 210.0, width: 160.0, height: 40.0)

    button.backgroundColor = UIColor.blue

    self.view.addSubview(button)

  }

  @objc func handleButtonAction() {

    let flutterEngine = (UIApplication.shared.delegate as? AppDelegate)?.flutterEngine;

    let flutterViewController = FlutterViewController(engine: flutterEngine, nibName: nil, bundle: nil)!;

    self.present(flutterViewController, animated: false, completion: nil)

  }

}

剩下的就是写Flutter页面逻辑了以及Flutter模块需要调用Native API(后面专门写一篇文章)。

写完Flutter页面,如果要跳转到指定页面使用Flutter的路由就可以了

Objective-C:

[flutterViewController setInitialRoute:@"route1"];

Swift:

flutterViewController.setInitialRoute("route1")

四、运行

my_flutter手动flutter run一下,或者直接开启热加载,然后就可以在原有的iOS项目中用Xcoderun起来了。

$ flutter attach --isolate-filter='debug'

Waiting for a connection from Flutter...

Done.

Syncing files to device...      1.1s

🔥  To hot reload changes while running, press "r". To hot restart (and rebuild state), press "R".

An Observatory debugger and profiler is available at: http://127.0.0.1:43343/

For a more detailed help message, press "h". To detach, press "d"; to quit, press "q".

Connected view:

  debug isolate (isolates/642101161)

五、发布

执行flutter build ios以创建release版本(flutter build默认为--release

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,185评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,445评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,684评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,564评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,681评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,874评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,025评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,761评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,217评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,545评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,694评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,351评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,988评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,778评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,007评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,427评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,580评论 2 349

推荐阅读更多精彩内容