1. 程式人生 > >iOS原生專案整合 Flutter

iOS原生專案整合 Flutter

前不久,谷歌官方正式釋出了Flutter的首個釋出預覽版(Release Preview 1),這標誌著谷歌進入了Flutter正式版(1.0)釋出前的最後階段,同時作為Google的重量級跨平臺開發方案,此次更新也吸引了多數的移動開發者的關注。使用 Flutter從頭開始寫一個 App是一件非常輕鬆愜意的事情,但在原生APP中接入 Flutter會是什麼效果呢,似乎並不是一件容易的事情,下面就講解在iOS原生應用中如何接入Flutter。

開發環境

  • Flutter:0.5.7
  • Xcode 9.4.1
  • Flutter工程:flutter/examples/hello_world

專案例項

Flutter(engine) 基礎庫

首先,在你的專案裡面拖入Flutter.framework,這個庫是 Flutter的Engine庫,承載了 Dart執行時和繪圖引擎。Flutter.framework和命令列工具版本是一一對應的,如果你不知道從哪裡找這個檔案,可以直接在 Flutter原始碼專案裡面進行一次 flutter run命令,然後你就能在/<project>/ios/Flutter/目錄下面就能找到Flutter.framework了,然後直接將它拖進專案即可。

接下來需要把 Flutter的基礎程式碼引入現有工程,有了基礎的 Flutter ViewController才可以顯示 Flutter檢視。然後,只需要在你現有的 ViewController中 Push過去就可以。例如:

 - (void)jumpToFlutter {
    FlutterViewController *viewController = [FlutterViewController new];
    [self.navigationController pushViewController:viewController animated:YES];
}

需要注意的是,在使用的時候還需要把 AppDelegate裡面的生命週期事件傳遞給 Flutter。實現的思路如下:
直接讓現有的 AppDelegate繼承 FlutterAppDelegate即可,但這帶來的負面影響是 root ViewController會被設定為Flutter ViewController。
改造 AppDelegate實現。例如:

// AppDelegate 或者模組的 Delegate

@interface DemoFlutterBaseAppDelegate : NSObject <ModularApplicationDelegate, FlutterPluginRegistry>

/**
 FlutterBinaryMessenger
 this determines which view controller is the flutter view controller
 nomally, flutter view controller provides the binary messages
 @return root Flutter ViewController
 */
- (NSObject<FlutterBinaryMessenger> *)binaryMessenger;

/**
 FlutterTextureRegistry
 this determines which view controller is the flutter view controller
 nomally, flutter view controller provides the custom textures
 @return root Flutter ViewController
 */
- (NSObject<FlutterTextureRegistry> *)textures;

@end

然後在實現中新增Flutter messenger 和 texture。

// Registrar 宣告和實現

@interface DemoFlutterAppDelegateRegistrar : NSObject<FlutterPluginRegistrar>

@property(nonatomic, copy) NSString *pluginKey;
@property(nonatomic, strong) DemoFlutterBaseAppDelegate *appDelegate;

- (instancetype)initWithPlugin:(NSString*)pluginKey appDelegate:(DemoFlutterBaseAppDelegate*)delegate;

@end

@implementation DemoFlutterAppDelegateRegistrar
- (instancetype)initWithPlugin:(NSString*)pluginKey appDelegate:(DemoFlutterBaseAppDelegate*)appDelegate {
    self = [super init];
    NSAssert(self, @"Super init cannot be nil");
    _pluginKey = [pluginKey copy];
    _appDelegate = appDelegate;
    return self;
}


- (NSObject<FlutterBinaryMessenger>*)messenger {
    return [_appDelegate binaryMessenger];
}

- (NSObject<FlutterTextureRegistry>*)textures {
    return [_appDelegate textures];
}

- (void)publish:(NSObject*)value {
    _appDelegate.pluginPublications[_pluginKey] = value;
}

- (void)addMethodCallDelegate:(NSObject<FlutterPlugin>*)delegate
                      channel:(FlutterMethodChannel*)channel {
    [channel setMethodCallHandler:^(FlutterMethodCall* call, FlutterResult result) {
        [delegate handleMethodCall:call result:result];
    }];
}

- (void)addApplicationDelegate:(NSObject<FlutterPlugin>*)delegate {
    [_appDelegate.pluginDelegates addObject:delegate];
}

- (NSString*)lookupKeyForAsset:(NSString*)asset {
    return [FlutterDartProject lookupKeyForAsset:asset];
}

- (NSString*)lookupKeyForAsset:(NSString*)asset fromPackage:(NSString*)package {
    return [FlutterDartProject lookupKeyForAsset:asset fromPackage:package];
}

@end


// AppDelegate實現

@interface DemoFlutterBaseAppDelegate ()

@property(nonatomic, strong) DemoFlutterBaseViewController *rootController;
@property(readonly, nonatomic) NSMutableArray* pluginDelegates;
@property(readonly, nonatomic) NSMutableDictionary* pluginPublications;

@end

@implementation DemoFlutterBaseAppDelegate

/*
 * ... 這裡寫轉發各種宣告週期事件給 plugin
 */
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    for (id<FlutterPlugin> plugin in _pluginDelegates) {
        if ([plugin respondsToSelector:_cmd]) {
            [plugin application:application didFinishLaunchingWithOptions:launchOptions];
        }
    }
    return YES;
}

#pragma mark - getters for flutter

// 返回 FlutterViewController例項
- (FlutterViewController *)rootController {
    // ...
}

- (NSObject<FlutterBinaryMessenger> *)binaryMessenger
{
    if ([self.rootController conformsToProtocol:@protocol(FlutterBinaryMessenger)]) {
        return (NSObject<FlutterBinaryMessenger> *)self.rootController;
    }
    return nil;
}

- (NSObject<FlutterTextureRegistry> *)textures
{
    if ([self.rootController conformsToProtocol:@protocol(FlutterTextureRegistry)]) {
        return (NSObject<FlutterTextureRegistry> *)self.rootController;
    }
    return nil;
}

- (NSObject<FlutterPluginRegistrar>*)registrarForPlugin:(NSString*)pluginKey {
    NSAssert(self.pluginPublications[pluginKey] == nil, @"Duplicate plugin key: %@", pluginKey);
    self.pluginPublications[pluginKey] = [NSNull null];
    return [[DemoFlutterAppDelegateRegistrar alloc] initWithPlugin:pluginKey appDelegate:self];
}

- (BOOL)hasPlugin:(NSString*)pluginKey {
    return _pluginPublications[pluginKey] != nil;
}

- (NSObject*)valuePublishedByPlugin:(NSString*)pluginKey {
    return _pluginPublications[pluginKey];
}

@end

到此,Flutter的執行環境其實就準備好了,無論是 Hot Restart還是 AOT都可以支援。接下來我們實現 Debug Hot Restart,即Flutter中最重要特性之一:特過載。

首先在你的 Flutter程式碼目錄下執行一遍 Flutter build bundle,這可以幫助我們打包出一個 Flutter Asset,然後把這個 flutter_assets 目錄拖入專案。

對你的專案進行一次 build,確保能夠得到一個 .app 檔案。然後新建一個資料夾叫做 Payload,把 .app檔案放入 Payload資料夾,然後壓縮成 zip檔案。然後執行如下的命令:

flutter run --use-application-binary /path/to/Payload.zip

讓我們來看一下執行的效果:
這裡寫圖片描述

如有要打包到真機上執行,需要做如下的一些替換操作。

  1. 把 Flutter.framework替換成flutter/bin/cache/artifacts/engine/ios-release/Flutter.framework,因為上一步我們用的庫其實是JIT Runtime。
  2. 在 Flutter程式碼專案下面執行 flutter build aot –release –target-platform ios –ios-arch armv7,arm64 然後我們可以在 build目錄下拿到一個打包好的 App.framework,不過別忘記在裡面放一個 Info.plist。並且把這個庫拖到工程裡面。
  3. 刪除工程裡面的 flutter_assets資料夾下的 isolate_snapshot_data、kernel_blob.bin、platform.dill、vm_snapshot_data這幾個檔案。
  4. 編譯打包給真機執行。

其實 Flutter官方有支援現有 App 整合的計劃,並且現在文件也有一部分介紹,但其實整體工具鏈還沒支援上來,目前所支援的程度和上文的方法也大同小異,所以還需要更多的摸索。

相關推薦

iOS原生專案整合 Flutter

前不久,谷歌官方正式釋出了Flutter的首個釋出預覽版(Release Preview 1),這標誌著谷歌進入了Flutter正式版(1.0)釋出前的最後階段,同時作為Google的重量級跨平臺開發方案,此次更新也吸引了多數的移動開發者的關注。使用 Flutt

iOS原生專案整合Cordova混合開發

         對於網上很多人分享的,原生專案整合cordova進行混合開發,很多人說的都很籠統,剛接觸的小白,有時候很容易懵逼。其實整合不同的開發環境,剛開始就一點:從原生進入Cordova和從Cordova返回原生、或者從原生進入ReactNative和ReactNa

最新iOS原生專案整合React-Native

       大樓不是一天所建成,是時間慢慢積累起來滴,原先用原生寫的專案,沒辦法將專案中所有的程式碼都換成RN,而且我也不認為全換成RN就是好的,所以準備先將專案中的一些頁面改成RN開發。由於我們並沒有使用Cocoapods,因為Cocoapods管理第三方依賴的時候會

IOS原生專案整合Unity3D

第1步 unity3D匯出Xcode專案 第2步  將專案匯入到ios原生專案 1.將Classes,Libraries,MapFileParser.sh拖入到專案(選中Copy items if needed,選中Create groups) 2.將Data拖入到

iOS原生專案(Objective-C)整合React Native(0.57.3版本)圖文教程--(3)style的全部有效屬性

iOS原生專案(Objective-C)整合React Native(0.57.3版本)圖文教程–(3)style的全部有效屬性 Valid style props: [ "alignContent", "alignItems", "alignSelf", "aspe

iOS原生專案(Objective-C)整合React Native(0.57.3版本)圖文教程--(2)整合過程

iOS原生專案(Objective-C)整合React Native(0.57.3版本)圖文教程–(1)基本環境 iOS原生專案(Objective-C)整合React Native(0.57.3版本)圖文教程–(2)整合過程 文章目錄 iOS原生

iOS原生專案(Objective-C)整合React Native(0.57.3版本)圖文教程--(1)基本環境

文章目錄 iOS原生專案(Objective-C)整合React Native(0.57.3版本)圖文教程--(1)基本環境 1. Homebrew 2. Node 3. Yarn 4. react-nat

React Native整合IOS原生專案

這裡預設電腦上已經安裝了cocoapods和React-Native,如果沒有RN開發環境,可以點選這裡按照步驟配置。 0、新建專案 首先,先使用xcode新建一個專案,然後在專案的根目錄下新建一個資料夾,用於存放RN的元件庫還有其他一些檔案。這

iOS Xcode原生專案整合Unity匯出的工程

Xcode原生專案整合Unity匯出的工程 注:成功的前提:Unity匯出的Xcode工程可以編譯。 1、 建立好工程之後,將Unity匯出的Xcode工程的以下資料夾複製到我們新建的工程中。 Unity匯出: 新建工程: 複製到我們新建的

Xcode原生專案整合Unity匯出的工程

注:成功的前提:Unity匯出的Xcode工程可以編譯。 1、 建立好工程之後,將Unity匯出的Xcode工程的以下資料夾複製到我們新建的工程中。 Unity匯出:  新建工程: 複製到我們新建的工程中(Command + C

解決IOS 原生專案載入html上下可滑動

初入前端,在IOS上載入一個html專案,發現前端頁面總是上下滑動,導航和下面的tabbar 在上拉和滑動時總是跟著滑動,如圖: 不明原因,以為是前端頁面的問題,一直改,可是無論如何都不行,決定換個思路,在原生專案上做更改,因為是用UIWebView載入的,想著是否可以用它來控制滑動!

React-Native與iOS原生整合步驟

需求:     最近準備在公司專案中使用RN,但羅馬不是一天建成的,沒辦法將專案中所有的程式碼都換成RN,而且我也不認為全換成RN就是好的,所以準備先將專案中的一些頁面改成RN開發。這篇文章就是與iOS原生整合的步驟。 我將專案更新到了github上,裡面有很多我自己的

Android原生專案整合React Native

剛建立的React Native 微信公眾號,歡迎微信掃描關注訂閱號,每天定期會分享react native 技術文章,移動技術乾貨,精彩文章技術推送。同時可以掃描我的微信加入react-native技術交流微信群。歡迎各位大牛,React Native技術愛好者加入

Android原生專案整合React Native踩坑記

最近在學習React Native,將Android原生專案整合React Native實現混合開發。參考官網和其他一些相關資料,自己動手一步一步操作,發現真的是一步步踩坑再填坑的過程,此文章記錄整合React Native的步驟和出現的問題,方便以後查閱。

iOS原生專案嵌入Cordova

MAC OS  High Sierra系統版本10.13Xcode版本Version 9.0.1 (9A1004)對於iOS原生專案嵌入cordova的一些記錄,廢話不說,開始正題!嵌入cordova,網上一頓搜,搜到的都很詳細,但是執行出問題,自己總結後記錄下來,方便以後查

iOS 開發之現有老專案引入整合 Flutter

  【Flutter 環境配置傳送門】   1、在工程目錄執行如下命令引入 flutter 配置 flutter create -t module flutter_module 補充:新增 flutter 依賴庫流程: cd flutter_modul

iOS 開發之老專案整合引入 Flutter

1、在工程目錄執行如下命令引入 flutter 配置 flutter create -t module flutter_module 補充:新增 flutter 依賴庫流程: cd flutter_module vim pubspec.yaml // (編

React Native整合原生專案(IOS)

React Native整合到原生專案 iOS端 一、準備工作 Mac 安裝了node.js 安裝React Native (檢視ReactNative官網) 安裝CocoaPods 二、整合React Native 1.新建packa

ios 原生整合ReactNative錯誤總結2之TransformError

TransformError:/xx/xx/Desktop/RNDemo/RN/index.ios.js: /xx/xx/Desktop/package.json: Error while parsing JSON - Unexpected token \\ in JSON at position

cocos2d-lua整合ios工程,即在ios原生應用中可以直接玩cocoslua開發的遊戲

前段時間配合其他部門把cocostudio做的動畫拿到ios原生引用中播放,把cocos2d-x做成靜態庫並保留了一個頭檔案給ios那邊呼叫,可以實現ios呼叫cocos2d-x,最近又要實現cocos2d-lua版本的,思路差不多,不過最後是呼叫的指令碼,可以把指令碼直接看做資源,坑也有幾看踩踩填