現(xiàn)有iOS工程引入Flutter

前言

Flutter 是一個(gè)很有潛力的框架,但是目前使用Flutter的APP并不算很多,相關(guān)資料并不豐富,介紹現(xiàn)有工程引入Flutter的相關(guān)文章也比較少。項(xiàng)目從零開始,引入Flutter操作比較簡(jiǎn)單,但是現(xiàn)有工程引入Flutter 需要費(fèi)很多精力和時(shí)間,這里是我在完成現(xiàn)有iOS工程引入Flutter后寫的一次總結(jié)文章。

Flutter 環(huán)境搭建

首先是要搭建Flutter環(huán)境,之前也寫了一篇相關(guān)文章搭建Flutter-iOS開發(fā)環(huán)境,可以參考一下
可以去官網(wǎng)查看:https://github.com/flutter/flutter/wiki/Add-Flutter-to-existing-apps
比較簡(jiǎn)單,這里不做贅述。

現(xiàn)有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

二、新建配置文件

根據(jù)官網(wǎng),需要在工程中建立三個(gè)配置文件:
Flutter.xcconfig 、Debug.xcconfig、Release.xcconfig
在XCode工程對(duì)應(yīng)目錄,右擊,選擇新建文件(New File),選中創(chuàng)建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"http://pod路徑
FLUTTER_BUILD_MODE=release

在準(zhǔn)備好這些xcconfig文件后,需要到XCode工程PROJECT(注意是PROJECT,不是Target)中的Configuration選項(xiàng)里,將對(duì)應(yīng)的target選擇成前面的xcconfig文件,Debug用Debug.xcconfig, Release用 Release.xcconfig

注意:進(jìn)行Archive打包的時(shí)候,無(wú)論是Debug包還是Release包,需要切換到Release.xcconfig,不然會(huì)報(bào)錯(cuò)。

三、為編譯Dart引入相關(guān)build phase

在工程的Build Phase中新建一個(gè)Run Script,用于編譯時(shí)運(yùn)行腳本,
建立方法如圖:

建立Run Script后,需要移動(dòng)其對(duì)應(yīng)的位置,需要在Target dependencies之后,如果用cocoapods管理工程需要在,Check Pods Manifest.lock之后:

在腳本框中,填入以下代碼,用于引進(jìn)Flutter中的xcode_backend腳本:

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

如圖:


四、生成和添加Framework

完成前面的配置后,便可以在XCode對(duì)工程進(jìn)行編譯build (Command+B),在提示“ Build Success ” 后,在iOS工程文件夾中會(huì)生成一個(gè)Flutter文件夾,將其加入工程目錄中,建議和剛才xcconfig所在目錄并列,

右鍵項(xiàng)目目錄 ,選擇 Add Files to 'xxx' ,Options選Create groups,添加編譯生成的Flutter文件夾。需要注意但是:Flutter目錄下有個(gè)flutter_assets文件,不能使用Create groups的方式添加,只能用Creat folder references的Options, 否則Flutter頁(yè)面會(huì)空白渲染不出來(lái)。可以刪了flutter_assets在用Creat folder references重新添加。

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

五、AppDelegate改造

Flutter需要和APP進(jìn)行交互,需要對(duì)AppDelegate 進(jìn)行改造:

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

主要配置基本上已經(jīng)完成,只要在main.dart實(shí)現(xiàn)Flutter的業(yè)務(wù)代碼即可


在原有工程中 ,建立FlutterViewController來(lái)承載main.dart實(shí)現(xiàn)的Flutter頁(yè)面,如:

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

后語(yǔ)

到這里現(xiàn)有iOS工程引入Flutter的工作就完成了,一些細(xì)節(jié)上的修改需要根據(jù)場(chǎng)景進(jìn)行修改,例如Flutter和Native的數(shù)據(jù)通信等。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容