现有iOS工程引入Flutter

作者: alanwangmodify | 来源:发表于2018-10-31 19:59 被阅读91次

    前言

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

    Flutter 环境搭建

    首先是要搭建Flutter环境,之前也写了一篇相关文章搭建Flutter-iOS开发环境,可以参考一下
    可以去官网查看:https://github.com/flutter/flutter/wiki/Add-Flutter-to-existing-apps
    比较简单,这里不做赘述。

    现有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.xcconfigDebug.xcconfigRelease.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.xcconfigRelease.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,不然会报错。

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

    在工程的Build Phase中新建一个Run Script,用于编译时运行脚本,
    建立方法如图:

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

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

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

    如图:


    四、生成和添加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.frameworkFlutter.framework

    五、AppDelegate改造

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

    AppDelegate.h文件中:

    #import <Flutter/Flutter.h>
    
    @interface AppDelegate : FlutterAppDelegate <UIApplicationDelegate, FlutterAppLifeCycleProvider>
    
    @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<UIApplicationOpenURLOptionsKey, id>*)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<FlutterPlugin>*)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的数据通信等。

    相关文章

      网友评论

        本文标题:现有iOS工程引入Flutter

        本文链接:https://www.haomeiwen.com/subject/cfugaftx.html