本文翻譯自:Flutter’s iOS Application Bundle
本文檔描述了Flutter的構(gòu)建系統(tǒng)如何將您的Flutter項(xiàng)目(及其資產(chǎn))轉(zhuǎn)換為iOS應(yīng)用程序包。我希望能描述清楚一些構(gòu)建步驟,并解釋生成相應(yīng)產(chǎn)物的目的(PS:這里的產(chǎn)物我覺得可以理解為構(gòu)建時(shí)生成的一些中間文件或者最終生成的可執(zhí)行文件等),這樣您就可以將相同的過程集成到你自己的構(gòu)建環(huán)境中。
關(guān)于工作流程的注意事項(xiàng):在構(gòu)建要發(fā)布的應(yīng)用程序時(shí),您可能會使用Flutter工具,這會使構(gòu)建過程容易一些。但是,一些開發(fā)人員可能會發(fā)現(xiàn)這個(gè)過程不是可配置的,或者不適合他們自定義的構(gòu)建持續(xù)集成(CI)配置。
如果您有自定義的Xcode構(gòu)建或Gradle設(shè)置,那么Flutter工具添加的所有“魔法”功能都是可選的,您可以配置構(gòu)建方式以適應(yīng)您自己的工作流程。
本文檔中的所有信息均適用于準(zhǔn)備發(fā)布到App Store的iOS應(yīng)用程序包。也就是說項(xiàng)目構(gòu)建的是Flutter的發(fā)布模式。Debug或者Prifile的編譯方式使用了不同的運(yùn)行時(shí)和打包模式,以便于支持熱重載(Hot Reload)和監(jiān)控(observatory)。
Flutter應(yīng)用程序?qū)⒂脩艚缑驿秩緸樵晥D樹(圖層)中的單個(gè)視圖。如下

應(yīng)用程序包
使用flutter build ios --release 命令(或者使用Flutter IDE如Android Studio)創(chuàng)建的應(yīng)用程序與典型的iOS應(yīng)用程序包非常相似,后者包含了應(yīng)用程序可執(zhí)行文件及其引用的框架和資源。
Flutter生成的Runner.app包結(jié)構(gòu):
Runner.app
├── AppFrameworkInfo.plist
├── Assets.car
├── Base.lproj
│ ├── LaunchScreen.storyboardc
│ └── Main.storyboardc
├── Debug.xcconfig
├── Frameworks
│ ├── App.framework # See “App framework bundle”
│ │ ├── App
│ │ ├── Info.plist
│ └── Flutter.framework # See “Flutter framework bundle”
│ ├── Flutter
│ ├── Info.plist
│ └── icudtl.dat
├── Info.plist
├── Runner
└── flutter_assets
├── AssetManifest.json
├── FontManifest.json
├── LICENSE
├── fonts
└── packages
└── cupertino_icons
└── assets
└── CupertinoIcons.ttf
編譯應(yīng)用程序
在編譯應(yīng)用程序的發(fā)布版本(而不是Profile或debug版本)時(shí),需要來自構(gòu)建程序和主機(jī)的產(chǎn)品。(有關(guān)構(gòu)建機(jī)器人(構(gòu)建引擎的一部分,使用GN和Ninja)的更多信息,請參見《為Flutter引擎做貢獻(xiàn)》。)
當(dāng)您安裝SDK時(shí),F(xiàn)lutter工具將緩存在您的機(jī)器上。您可以在你的Flutter SDK副本中的bin/cache目錄中看到它們。如果您決定將此過程的任何步驟集成到您自己的構(gòu)建系統(tǒng)中,那么該文件夾包含處理Flutter所需的所有版本化工具。
以下部分描述了Flutter的iOS應(yīng)用程序包特有的一些文件。
Flutter 引擎框架包
Flutter.framework 文件夾是被打包成iOS框架的包,包含
-
Flutter 引擎
包含核心庫(例如,圖形、文件和網(wǎng)絡(luò)I/O、可訪問性支持、插件架構(gòu))、DartVM和Skia渲染引擎。 - Flutter引擎引用的資源文件集(assets)
目前這只是ICU的數(shù)據(jù)。
構(gòu)建機(jī)器人生成Flutter引擎框架包,然后Flutter工具下載并緩存到您的機(jī)器上。
AOT框架包
App.framework 包含用戶編寫的所有Dart應(yīng)用程序代碼的AOT快照以及 armv7 和 aarch64 格式的Flutter框架和插件的Dart代碼。
在版本構(gòu)建過程中,編譯器對Dart代碼執(zhí)行精簡,因此只有實(shí)際使用的代碼才會出現(xiàn)在bundle中。設(shè)備上緩存的gen_snapshot工具生成創(chuàng)建App.framework包所需的組件。
AOT 快照
AOT快照包含了由Dart向設(shè)備相關(guān)編譯而成的靜態(tài)碼。gen_snapshot 生成的快照庫包含四個(gè)主要符號。這些符號可以由nm命令解包,如:
$ nm -gU Runner.app/Frameworks/App.framework/App
Runner.app/Frameworks/App.framework/App (for architecture armv7):
003c6f60 S _kDartIsolateSnapshotData
00007000 T _kDartIsolateSnapshotInstructions
003c16a0 S _kDartVmSnapshotData
00004000 T _kDartVmSnapshotInstructions
Runner.app/Frameworks/App.framework/App (for architecture arm64):
00000000004041a0 S _kDartIsolateSnapshotData
0000000000009000 T _kDartIsolateSnapshotInstructions
00000000003fc740 S _kDartVmSnapshotData
0000000000005000 T _kDartVmSnapshotInstructions
其目的如下:
Dart VM快照(kDartVmSnapshotData):
表示孤立體之間共享的Dart堆的初始狀態(tài)。這有助于更快地啟動(dòng)Dart isolates,但不包含任何特定于分離的信息。但不包含任何特定isolates的信息。Dart VM指令(kDartVmSnapshotInstructions):
包含VM中所有Dart隔離器之間共享的通用例程的AOT指令。這個(gè)快照通常非常小,并且主要包含存根。隔離快照(kDartIsolateSnapshotData):
表示Dart堆的初始狀態(tài),并包含特定于隔離的信息。分離指令(kDartIsolateSnapshotInstructions):
包含Dart分離器執(zhí)行的AOT代碼。
調(diào)用gen_snapshot很簡單。您將其指向Dart源代碼,它將為這四個(gè)符號中的每一個(gè)輸出一點(diǎn)東西。然后,Xcode將這些符號打包成一個(gè)iOS framework,就像用C、c++、Objective-C或Swift編寫的框架一樣。了解更多關(guān)于如何在Flutter engine 中配置快照和引擎請查看: Flutter engine wiki。
除了大量的代碼之外,F(xiàn)lutter工具還確保應(yīng)用程序(及其插件)引用的資產(chǎn)最終位于應(yīng)用程序包中。它通過閱讀項(xiàng)目的pubspec.yaml文件中列出的資產(chǎn)來實(shí)現(xiàn)這一點(diǎn)。
關(guān)于安卓
構(gòu)建Android APK包(使用`flutter build apk - release 命令或IDE)的過程會生成以下文件結(jié)構(gòu):
$ Runner.apk.unzipped
├── AndroidManifest.xml
├── assets
│ ├── flutter_assets
│ │ ├── fonts
│ │ │ └── MaterialIcons-Regular.ttf
│ │ └── packages
│ │ └── cupertino_icons
│ │ └── assets
│ │ └── CupertinoIcons.ttf
│ ├── icudtl.dat
│ ├── isolate_snapshot_data
│ ├── isolate_snapshot_instr
│ ├── vm_snapshot_data
│ └── vm_snapshot_instr
├── classes.dex
├── lib
│ └── armeabi-v7a
│ └── libflutter.so
├── output.json
├── res
└── resources.arsc
它與iOS發(fā)布包基本相同,除了:
- Flutter引擎被打包為ELF庫(libflutter.so)。
- 上一節(jié)中詳細(xì)介紹的4個(gè)符號現(xiàn)在只是assets目錄中的二進(jìn)制blob。
第二點(diǎn)可能有點(diǎn)出乎意料,需要解釋一下:構(gòu)建發(fā)行版APK并不需要下載NDK。這是因?yàn)?,在機(jī)器上沒有NDK時(shí),F(xiàn)lutter工具會將blob添加為資產(chǎn)。在Android上,F(xiàn)lutter引擎可以將頁面標(biāo)記為可執(zhí)行文件。因此,當(dāng)它檢測到AOT資產(chǎn)被打包為二進(jìn)制blob時(shí),它將這些blob映射到內(nèi)存中,并將相應(yīng)的頁面標(biāo)記為可執(zhí)行文件。如果您可以訪問機(jī)器上的NDK,那么您可以指定它的位置,并使用這些符號生成一個(gè)動(dòng)態(tài)庫。在這種情況下,F(xiàn)lutter引擎使用動(dòng)態(tài)庫中的4個(gè)符號。
總結(jié)
構(gòu)建iOS應(yīng)用程序包的關(guān)鍵在于:
您可以在原生視圖層次結(jié)構(gòu)的任何位置放置Flutter視圖。Flutter呈現(xiàn)的所有內(nèi)容都將被合成到這個(gè)視圖中。
Dart代碼被編譯成原生機(jī)器碼,并像其他c++ /Objective/Swift庫一樣打包成庫或框架包。這意味著所有崩潰報(bào)告和符號化工具對Dart AOT代碼的工作方式是相同的。
您可以將Flutter集成到您自己的定制構(gòu)建系統(tǒng)中,而不依賴于開發(fā)機(jī)器上的Flutter工具(盡管使用它會使您的工作更輕松)。所有這些工具都可以在Flutter SDK的bin/cache目錄中找到。