本文翻譯自:Flutter’s iOS Application Bundle
本文檔描述了Flutter的構建系統如何將您的Flutter項目(及其資產)轉換爲iOS應用程序包。我希望能描述清楚一些構建步驟,並解釋生成相應產物的目的(PS:這裏的產物我覺得可以理解爲構建時生成的一些中間文件或者最終生成的可執行文件等),這樣您就可以將相同的過程集成到你自己的構建環境中。
關於工作流程的注意事項:在構建要發佈的應用程序時,您可能會使用Flutter工具,這會使構建過程容易一些。但是,一些開發人員可能會發現這個過程不是可配置的,或者不適合他們自定義的構建持續集成(CI)配置。
如果您有自定義的Xcode構建或Gradle設置,那麼Flutter工具添加的所有“魔法”功能都是可選的,您可以配置構建方式以適應您自己的工作流程。
本文檔中的所有信息均適用於準備發佈到App Store的iOS應用程序包。也就是說項目構建的是Flutter的發佈模式。Debug或者Prifile的編譯方式使用了不同的運行時和打包模式,以便於支持熱重載(Hot Reload)和監控(observatory)。
Flutter應用程序將用戶界面渲染爲原生視圖樹(圖層)中的單個視圖。如下
應用程序包
使用flutter build ios --release
命令(或者使用Flutter IDE如Android Studio)創建的應用程序與典型的iOS應用程序包非常相似,後者包含了應用程序可執行文件及其引用的框架和資源。
Flutter生成的Runner.app包結構:
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
編譯應用程序
在編譯應用程序的發佈版本(而不是Profile或debug版本)時,需要來自構建程序和主機的產品。(有關構建機器人(構建引擎的一部分,使用GN和Ninja)的更多信息,請參見《爲Flutter引擎做貢獻》。)
當您安裝SDK時,Flutter工具將緩存在您的機器上。您可以在你的Flutter SDK副本中的bin/cache目錄中看到它們。如果您決定將此過程的任何步驟集成到您自己的構建系統中,那麼該文件夾包含處理Flutter所需的所有版本化工具。
以下部分描述了Flutter的iOS應用程序包特有的一些文件。
Flutter 引擎框架包
Flutter.framework 文件夾是被打包成iOS框架的包,包含
- Flutter 引擎
包含核心庫(例如,圖形、文件和網絡I/O、可訪問性支持、插件架構)、DartVM和Skia渲染引擎。 - Flutter引擎引用的資源文件集(assets)
目前這只是ICU的數據。
構建機器人生成Flutter引擎框架包,然後Flutter工具下載並緩存到您的機器上。
AOT框架包
App.framework
包含用戶編寫的所有Dart應用程序代碼的AOT快照以及 armv7
和 aarch64
格式的Flutter框架和插件的Dart代碼。
在版本構建過程中,編譯器對Dart代碼執行精簡,因此只有實際使用的代碼纔會出現在bundle中。設備上緩存的gen_snapshot工具生成創建App.framework包所需的組件。
AOT 快照
AOT快照包含了由Dart向設備相關編譯而成的靜態碼。gen_snapshot
生成的快照庫包含四個主要符號。這些符號可以由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堆的初始狀態。這有助於更快地啓動Dart isolates
,但不包含任何特定於分離的信息。但不包含任何特定isolates
的信息。 -
Dart VM指令(kDartVmSnapshotInstructions):
包含VM中所有Dart隔離器之間共享的通用例程的AOT指令。這個快照通常非常小,並且主要包含存根。 -
隔離快照(kDartIsolateSnapshotData):
表示Dart堆的初始狀態,幷包含特定於隔離的信息。 -
分離指令(kDartIsolateSnapshotInstructions):
包含Dart分離器執行的AOT代碼。
調用gen_snapshot很簡單。您將其指向Dart源代碼,它將爲這四個符號中的每一個輸出一點東西。然後,Xcode將這些符號打包成一個iOS framework,就像用C、c++、Objective-C或Swift編寫的框架一樣。瞭解更多關於如何在Flutter engine 中配置快照和引擎請查看: Flutter engine wiki。
除了大量的代碼之外,Flutter工具還確保應用程序(及其插件)引用的資產最終位於應用程序包中。它通過閱讀項目的pubspec.yaml
文件中列出的資產來實現這一點。
關於安卓
構建Android APK包(使用`flutter build apk - release 命令或IDE)的過程會生成以下文件結構:
$ 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發佈包基本相同,除了:
- Flutter引擎被打包爲ELF庫(libflutter.so)。
- 上一節中詳細介紹的4個符號現在只是assets目錄中的二進制blob。
第二點可能有點出乎意料,需要解釋一下:構建發行版APK並不需要下載NDK。這是因爲,在機器上沒有NDK時,Flutter工具會將blob添加爲資產。在Android上,Flutter引擎可以將頁面標記爲可執行文件。因此,當它檢測到AOT資產被打包爲二進制blob時,它將這些blob映射到內存中,並將相應的頁面標記爲可執行文件。如果您可以訪問機器上的NDK,那麼您可以指定它的位置,並使用這些符號生成一個動態庫。在這種情況下,Flutter引擎使用動態庫中的4個符號。
總結
構建iOS應用程序包的關鍵在於:
-
您可以在原生視圖層次結構的任何位置放置Flutter視圖。Flutter呈現的所有內容都將被合成到這個視圖中。
-
Dart代碼被編譯成原生機器碼,並像其他c++ /Objective/Swift庫一樣打包成庫或框架包。這意味着所有崩潰報告和符號化工具對Dart AOT代碼的工作方式是相同的。
-
您可以將Flutter集成到您自己的定製構建系統中,而不依賴於開發機器上的Flutter工具(儘管使用它會使您的工作更輕鬆)。所有這些工具都可以在Flutter SDK的bin/cache目錄中找到。