Flutter-现有iOS工程引入Flutter

Posted Cocoa开发者社区

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Flutter-现有iOS工程引入Flutter相关的知识,希望对你有一定的参考价值。


前言


Flutter 是一个很有潜力的框架,但是目前使用Flutter的APP并不算很多,相关资料并不丰富,介绍现有工程引入Flutter的相关文章也比较少。项目从零开始,引入Flutter操作比较简单,但是现有工程引入Flutter 需要费很多精力和时间,这里是我在完成现有ios工程引入Flutter后写的一次总结文章。


Flutter 环境搭建


首先是要搭建Flutter环境,之前也写了一篇相关文章,可以参考一下

可以去官网查看:比较简单,这里不做赘述。


现有iOS工程引入Flutter


一、建立Flutter module


首先建立flutter module,主要是用于获取改flutter app中的Generated.xcconfig和framework


cd some/path/
$ flutter create -t module my_flutter


也可以用


flutter create app


建立flutter app,flutter app中也有Generated.xcconfig和framework


二、新建配置文件


根据官网,需要在工程中建立三个配置文件:


Flutter.xcconfig 、Debug.xcconfig、Release.xcconfig


在XCode工程对应目录,右击,选择新建文件(New File),选中创建xcconfig文件,如图:



在Flutter.xcconfig中填写:


 //这里填写前面建立的flutter module 的Generated.xcconfig的路径
#include "../../my_flutter/.ios/Flutter/Generated.xcconfig"
ENABLE_BITCODE=NO


在 Debug.xcconfig中填写:


#include "../Flutter/Flutter.xcconfig"


在 Release.xcconfig中填写:


#include "../Flutter/Flutter.xcconfig"
FLUTTER_BUILD_MODE=release


如果工程中用cocoapods管理,需要在 Debug.xcconfig和Release.xcconfig添加pod的路径:


例如 Release.xcconfig中


#include "Flutter.xcconfig"
#include "工程路径/Pods/Target Support Files/******.release.xcconfig"//pod路径
FLUTTER_BUILD_MODE=release


在准备好这些xcconfig文件后,需要到XCode工程PROJECT(注意是PROJECT,不是Target)中的Configuration选项里,将对应的target选择成前面的xcconfig文件,Debug用Debug.xcconfig, Release用 Release.xcconfig


注意:进行Archive打包的时候,无论是Debug包还是Release包,需要切换到Release.xcconfig,不然会报错。


Flutter-现有iOS工程引入Flutter


三、为编译Dart引入相关build phase


在工程的Build Phase中新建一个Run Script,用于编译时运行脚本,

建立方法如图:


Flutter-现有iOS工程引入Flutter

建立Run Script后,需要移动其对应的位置,需要在Target dependencies之后,如果用cocoapods管理工程需要在,Check Pods Manifest.lock之后:


Flutter-现有iOS工程引入Flutter


在脚本框中,填入以下代码,用于引进Flutter中的xcode_backend脚本:


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


如图:

Flutter-现有iOS工程引入Flutter


四、生成和添加Framework


完成前面的配置后,便可以在XCode对工程进行编译build (Command+B),在提示“ Build Success ” 后,在iOS工程文件夹中会生成一个Flutter文件夹,将其加入工程目录中,建议和刚才xcconfig所在目录并列,


右键项目目录 ,选择 Add Files to 'xxx' ,Options选Create groups,添加编译生成的Flutter文件夹。需要注意但是:Flutter目录下有个flutter_assets文件,不能使用Create groups的方式添加,只能用Creat folder references的Options, 否则Flutter页面会空白渲染不出来。可以删了flutter_assets在用Creat folder references重新添加。


在添加完Flutter 文件夹之后,去Embeded Binaries中添加App.framework和Flutter.framework


Flutter-现有iOS工程引入Flutter

五、AppDelegate改造


Flutter需要和APP进行交互,需要对AppDelegate 进行改造:


AppDelegate.h文件中:


#import  
     

@interface AppDelegate : FlutterAppDelegate <UIApplicationDelegateFlutterAppLifeCycleProvider>

@end


AppDelegate.m 文件中:


#import "AppDelegate.h"

@interface AppDelegate ()

@end

@implementation AppDelegate
{
  FlutterPluginAppLifeCycleDelegate *_lifeCycleDelegate;
}

- (instancetype)init {
    if (self = [super init]) {
        _lifeCycleDelegate = [[FlutterPluginAppLifeCycleDelegate alloc] init];
    }
    return self;
}

- (BOOL)application:(UIApplication*)application
didFinishLaunchingWithOptions:(NSDictionary*)launchOptions {
    return [_lifeCycleDelegate application:application didFinishLaunchingWithOptions:launchOptions];
}

- (void)applicationDidEnterBackground:(UIApplication*)application {
    [_lifeCycleDelegate applicationDidEnterBackground:application];
}

- (void)applicationWillEnterForeground:(UIApplication*)application {
    [_lifeCycleDelegate applicationWillEnterForeground:application];
}

- (void)applicationWillResignActive:(UIApplication*)application {
    [_lifeCycleDelegate applicationWillResignActive:application];
}

- (void)applicationDidBecomeActive:(UIApplication*)application {
    [_lifeCycleDelegate applicationDidBecomeActive:application];
}

- (void)applicationWillTerminate:(UIApplication*)application {
    [_lifeCycleDelegate applicationWillTerminate:application];
}

- (void)application:(UIApplication*)application
didRegisterUserNotificationSettings:(UIUserNotificationSettings*)notificationSettings {
    [_lifeCycleDelegate application:application
didRegisterUserNotificationSettings:notificationSettings];
}

- (void)application:(UIApplication*)application
didRegisterForRemoteNotificationsWithDeviceToken:(NSData*)deviceToken {
    [_lifeCycleDelegate application:application
didRegisterForRemoteNotificationsWithDeviceToken:deviceToken];
}

- (void)application:(UIApplication*)application
didReceiveRemoteNotification:(NSDictionary*)userInfo
fetchCompletionHandler:(void (^)(UIBackgroundFetchResult result))completionHandler {
    [_lifeCycleDelegate application:application
       didReceiveRemoteNotification:userInfo
             fetchCompletionHandler:completionHandler];
}

- (BOOL)application:(UIApplication*)application
            openURL:(NSURL*)url
            options:(NSDictionary<UIApplicationOpenURLOptionsKeyid>*)options {
    return [_lifeCycleDelegate application:application openURL:url options:options];
}

- (BOOL)application:(UIApplication*)application handleOpenURL:(NSURL*)url {
    return [_lifeCycleDelegate application:application handleOpenURL:url];
}

- (BOOL)application:(UIApplication*)application
            openURL:(NSURL*)url
  sourceApplication:(NSString*)sourceApplication
         annotation:(id)annotation {
    return [_lifeCycleDelegate application:application
                                   openURL:url
                         sourceApplication:sourceApplication
                                annotation:annotation];
}

- (void)application:(UIApplication*)application
performActionForShortcutItem:(UIApplicationShortcutItem*)shortcutItem
  completionHandler:(void (^)(BOOL succeeded))completionHandler NS_AVAILABLE_IOS(9_0) {
    [_lifeCycleDelegate application:application
       performActionForShortcutItem:shortcutItem
                  completionHandler:completionHandler];
}

- (void)application:(UIApplication*)application
handleEventsForBackgroundURLSession:(nonnull NSString*)identifier
  completionHandler:(nonnull void (^)(void))completionHandler {
    [_lifeCycleDelegate application:application
handleEventsForBackgroundURLSession:identifier
                  completionHandler:completionHandler];
}

- (void)application:(UIApplication*)application
performFetchWithCompletionHandler:(void (^)(UIBackgroundFetchResult result))completionHandler {
    [_lifeCycleDelegate application:application performFetchWithCompletionHandler:completionHandler];
}

- (void)addApplicationLifeCycleDelegate:(NSObject *)delegate {
    [_lifeCycleDelegate addDelegate:delegate];
}


六、新建FlutterViewController


主要配置基本上已经完成,只要在main.dart实现Flutter的业务代码即可



在原有工程中 ,建立FlutterViewController来承载main.dart实现的Flutter页面,如:


    self.flutterViewController = [[FlutterViewController alloc] initWithProject:nil nibName:nil bundle:nil];
    [self.navigationController pushViewController:self.flutterViewController animated:YES];


后语


到这里现有iOS工程引入Flutter的工作就完成了,一些细节上的修改需要根据场景进行修改,例如Flutter和Native的数据通信等。


链接:https://juejin.im/post/5bda622f6fb9a022523c4da8


以上是关于Flutter-现有iOS工程引入Flutter的主要内容,如果未能解决你的问题,请参考以下文章

iOS现有工程 集成 flutter App.framework 找不到问题

flutter setInitialRoute: 不生效

Flutter混合工程改造实践

Flutter - 将 Flutter 集成到现有项目(iOS - Framework篇)

iOS与Flutter混合开发的姿势

Flutter:现有应用程序无法在 ios 中运行