上一篇:flutter_boost学习1:iOS运行flutter_boost的Sample
下一篇:flutter_boost学习3:iOSNative添加与flutter交互调用

环境:MacOS、Xcode、cocoapods、flutter、flutter_boost

练习GitHub:HybridFlutter

参考:

  • 添加Flutter到现有iOS的项目
  • 中文文档

前言

上一篇体验运行了flutter_boost的sample,现在在一个完整项目中集成flutter_boost,方便一些业务能运行能同时运行在多个端,顺便提供一套flutter与Native方法交互的通用功能

1、创建一个flutter项目
flutter create -t module flutter_module
2.1、flutter添加flutter_boost的依赖,可以参考flutter_boost中文文档

2.2、在pubspec.yaml里添加flutter_boost的依赖,

   git:
     url: 'https://github.com/alibaba/flutter_boost.git'
     ref: '0.0.410'

完整的文件内容如下

name: advance_study
description: A new Flutter application.

# The following defines the version and build number for your application.
# A version number is three numbers separated by dots, like 1.2.43
# followed by an optional build number separated by a +.
# Both the version and the builder number may be overridden in flutter
# build by specifying --build-name and --build-number, respectively.
# In Android, build-name is used as versionName while build-number used as versionCode.
# Read more about Android versioning at https://developer.android.com/studio/publish/versioning
# In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion.
# Read more about iOS versioning at
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
version: 1.0.0+1

environment:
  sdk: ">=2.1.0 

2.3 命令行运行:flutter packages get或在各个IDE里运行相关的packages get
2.4 flutter里添加代码,参考flutter_boost中文文档

3、iOS原生代码里添加对flutter_boost的支持
3.1 在Podfile里添加引用flutter的库

flutter_application_path = "../../Flutter/flutter_module"
   eval(File.read(File.join(flutter_application_path, '.ios', 'Flutter', 'podhelper.rb')), binding)

完整配置如下:

# Uncomment the next line to define a global platform for your project
# platform :ios, '9.0'
use_frameworks!
target 'HybridiOS' do
  # Uncomment the next line if you're using Swift or would like to use dynamic frameworks
  # use_frameworks!

  # Pods for HybridiOS
  # 返回侧滑适配有导航栏和没导航栏的切换
   pod 'FDFullscreenPopGesture', '~> 1.1'
   pod 'ZJScrollPageView'
   pod 'YYModel'
   pod 'Aspects'
   pod 'Masonry', '~> 1.1.0'
   pod 'MJRefresh', '~> 3.1.13'
   
   flutter_application_path = "../../Flutter/flutter_module"
   eval(File.read(File.join(flutter_application_path, '.ios', 'Flutter', 'podhelper.rb')), binding)

  target 'HybridiOSTests' do
    inherit! :search_paths
    # Pods for testing
  end

  target 'HybridiOSUITests' do
    inherit! :search_paths
    # Pods for testing
  end

end

3.2 在AppDelegate.h里设置继承与FLBFlutterAppDelegate
完整代码如下:

//
//  AppDelegate.h
//  HybridiOS
//
//  Created by lonelyflow on 14/05/2019.
//  Copyright © 2019 Lonely traveller. All rights reserved.
//

#import 
#import 
@interface AppDelegate : FLBFlutterAppDelegate 
@property (strong, nonatomic) UIWindow *window;
@end

创建Router,这个Router优化为在第一次调用Router时才会初始化Fluttery Engine,这样能尽量避免在还未使用到Flutter时就创建了先关的消耗
MyFlutterRouter.h

//
//  MyFlutterRouter.h
//  HybridiOS
//
//  Created by loneylyflow on 15/05/2019.
//  Copyright © 2019 Lonely traveller. All rights reserved.
//

#import 
#import 
@interface MyFlutterRouter : NSObject 
@property(nonatomic, weak) FlutterViewController *flutterViewController;
+ (instancetype)sharedRouter;

@end

MyFlutterRouter.m

//
//  MyFlutterRouter.m
//  HybridiOS
//
//  Created by loneylyflow on 15/05/2019.
//  Copyright © 2019 Lonely traveller. All rights reserved.
//

#import "MyFlutterRouter.h"
#import "MyFlutterViewController.h"
#import 

@interface MyFlutterRouter() 
@property(nonatomic, copy) FlutterEventSink eventSink;
@property(nonatomic, strong) UINavigationController *navigationController;
@end

@implementation MyFlutterRouter
  
+ (instancetype)sharedRouter
{
    static MyFlutterRouter *_instance = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        _instance = [[MyFlutterRouter alloc] init];
        // 在这里初始化FlutterViewController
        // 初始化Router
        [FlutterBoostPlugin.sharedInstance startFlutterWithPlatform:_instance onStart:^(FlutterViewController * fvc){
            dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.001 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
                MyFlutterRouter.sharedRouter.flutterViewController = fvc;
          
            });
        }];
    });
    return _instance;
}

#pragma mark - push/pop/close
- (void)openPage:(NSString *)name params:(NSDictionary *)params animated:(BOOL)animated completion:(void (^)(BOOL))completion
{
        if([params[@"present"] boolValue]){
            MyFlutterViewController *vc = MyFlutterViewController.new;
            [vc setName:name params:params];
            vc.hidesBottomBarWhenPushed = YES;
            [self.navigationController presentViewController:vc animated:animated completion:^{}];
        }else{
            MyFlutterViewController *vc = MyFlutterViewController.new;
            vc.hidesBottomBarWhenPushed = YES;
            [vc setName:name params:params];
            [self.navigationController pushViewController:vc animated:animated];
        }
    }
    
    
- (void)closePage:(NSString *)uid animated:(BOOL)animated params:(NSDictionary *)params completion:(void (^)(BOOL))completion
{
    FLBFlutterViewContainer *vc = (id)self.navigationController.presentedViewController;
    if([vc isKindOfClass:FLBFlutterViewContainer.class] && [vc.uniqueIDString isEqual: uid]){
        [vc dismissViewControllerAnimated:animated completion:^{}];
    }else{
        [self.navigationController popViewControllerAnimated:animated];
    }
}
- (UINavigationController *)navigationController
{
    UITabBarController *tabVC = (UITabBarController *)[UIApplication sharedApplication].delegate.window.rootViewController;
    if([tabVC isKindOfClass:[UITabBarController class]]){
        UINavigationController *nav = (UINavigationController *)tabVC.selectedViewController;
        if([nav isKindOfClass:[UINavigationController class]]){
            return nav;
        }else{
            return [[UINavigationController alloc] init];
        }
    }
    return [[UINavigationController alloc] init];
}
@end

3.3 在需要用到Flutter的地方调用flutter

[MyFlutterRouter.sharedRouter openPage:@"first" params:@{} animated:YES completion:^(BOOL isFinish){}];

3.4 在Build Phases里添加运行脚本,好让iOS原生运行时自动打包flutter项目

"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh" build
"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh" embed
frc bce07a06bf5b0d7ae7a2c0d4a65b988b - flutter_boost学习2:iOS集成flutter_boost
tmp693cc5fa.png

flutter_boost学习2:iOS集成flutter_boost