flutter build做了什么事情(iOS 打包編譯流程)

1健蕊、展示JIT模式 下編譯文件列表沦补,并解釋每個文件的內(nèi)容

1、展示文件:

屏幕快照 2019-10-16 下午3.20.03.png

2住练、單個文件說明:

  • app.dill : 這就是dart代碼通過build的產(chǎn)物地啰,為二進制的字節(jié)碼,可以通過 strings app.dill看到里面的內(nèi)容讲逛,其實就是我們dart代碼的源碼亏吝。
  • Frontend_server.d : 這里面放的是frontend_server.dart.snapshot的絕對路徑,這個.snapshot可執(zhí)行文件其實就是真正把我們dart代碼編程app.dill的真正工具盏混,下面詳細講解蔚鸥。
  • snapshot_blob.bin.d : 這個文件里面是所有參與編譯的dart文件的集合惜论,包括我們自己的業(yè)務代碼、pubspec.yaml中定義的三方庫的代碼止喷、以及我們業(yè)務代碼中import進來的所有flutter或者dart原生package的代碼馆类。
  • snapshot_blob.bin.d.fingerprint : 這里面放的是snapshot_blob.bin.d中的所有文件的絕對路徑以及每個文件內(nèi)容對應的md5值。使用這個md5來判斷該文件是否有修改弹谁。在每次編譯的時候會判斷乾巧,如果沒有文件修改,則直接跳過編譯预愤。

2沟于、flutter build命令執(zhí)行拆分:

流程一:flutter可執(zhí)行文件為FlutterSDK/bin/flutter

其核心代碼為最下面的"$DART" $FLUTTER_TOOL_ARGS "$SNAPSHOT_PATH" "$@"。我們可以分別打印出相關(guān)參數(shù)植康,如下圖修改flutter可執(zhí)行文件:

WechatIMG2.jpeg

然后我們隨便執(zhí)行一條flutter命令旷太,我執(zhí)行的是flutter -h,結(jié)果如下:

WechatIMG3.jpeg

所以最終flutter -h的命令實際上為:

/Users/zhuyaning/.flutter_sdk/bin/cache/dart-sdk/bin/dart /Users/zhuyaning/.flutter_sdk/bin/cache/flutter_tools.snapshot -h

解釋一下的話:就是啟動dart虛擬機销睁,在dart虛擬機上運行:
/Users/zhuyaning/.flutter_sdk/bin/cache/flutter_tools.snapshot供璧,給這個
.snapshot的參數(shù)為-h

因此,我們需要知道flutter_tools.snapshot是什么冻记。

流程二:flutter_tools.snapshot是什么睡毒?我們怎么調(diào)試它呢?

其實flutter_tools.snapshot也是個可執(zhí)行文件冗栗,生成它的工程為FlutterSDK/packages/flutter_tools這個工程是可以debug的吕嘀,下面這個是flutter官方的調(diào)試方法:
flutter官方介紹
總結(jié)一下調(diào)試方法為:

1、使用Android Studio打開FlutterSDK/packages/flutter_tools

2贞瞒、自己設置一下flutter sdk的路徑,入下圖:

屏幕快照 2019-10-16 下午4.00.23.png

3趁曼、配置dart command line如下圖所示:

WechatIMG4.jpeg

WechatIMG5.jpeg

4军浆、斷點調(diào)試結(jié)果展示:這里我就不多BB了,直接告訴大家挡闰,在mac.dart文件里的buildXcodeProject方法中執(zhí)行了runAsync方法打斷點乒融,然后看一下給到runAsync的參數(shù),如下圖:

image.png

說明摄悯,最終執(zhí)行的是我們iOS工程的xcrun xcodebuild + 上圖紅框按順序羅列這條命令赞季。
說白了:就等于,我們用xcode打開iOS工程奢驯,然后點擊run按鈕是一個道理的申钩。

5、探究flutter create出來的iOS工程瘪阁,發(fā)現(xiàn)如下圖撒遣,有個run Script

image.png

此腳本為:

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

1邮偎、/bin/sh 表示環(huán)境為shell
2、在shell環(huán)境下執(zhí)行xcode_backend.sh build命令义黎。

6禾进、xcode_backend.sh是什么?

FlutterSDK/packages/flutter_tools/bin/xcode_backend.sh目錄下,打開xcode_backend.sh廉涕。
這里我也找到了關(guān)鍵的地方泻云,發(fā)現(xiàn)最終又執(zhí)行flutter build bundle命令,然后我打印出了這個命令的參數(shù)狐蜕,如何打印和打印結(jié)果如下:

image.png

屏幕快照 2019-10-16 下午4.46.09.png

所以這個xcode_backend.sh執(zhí)行的真正命令為:

FlutterSDK/bin/flutter --suppress-analytics build bundle --target-platform=ios --target=lib/main.dart --debug --depfile=build/snapshot_blob.bin.d --asset-dir=/Users/zhuyaning/Desktop/test/abc/ios/Flutter/App.framework/flutter_assets

仔細一看其實就是 flutter build bundle + 參數(shù)
1宠纯、--target-platform=ios 表示iOS的工程
2、--target=lib/main.dart 入口文件是誰
3馏鹤、--debug 編譯模式是啥
4征椒、--depfile=build/snapshot_blob.bin.d目標文件有哪些,開頭也說過snapshot_blob.bin.d這個文件里面是啥
5湃累、--asset dir=/Users/zhuyaning/Desktop/test/abc/ios/Flutter/App.framework/flutter_assets 編譯出來的東西放在那里

所以勃救,我們需要調(diào)試一下 flutter build bundle這個命令

7、flutter build bundle做了什么

我們把--suppress-analytics build bundle --target-platform=ios --target=lib/main.dart --debug --depfile=build/snapshot_blob.bin.d --asset-dir=/Users/zhuyaning/Desktop/test/abc/ios/Flutter/App.framework/flutter_assets這一大串復制到我們剛剛用Android Studio打開的dart command line里面治力,如圖:

image.png

8蒙秒、調(diào)試flutter build bundle的結(jié)論

我不多啰嗦了:直接在compile.dart中有一個classKernelCompiler,在這個class的compile方法中processManager .start的地方打斷點,看看傳入的commands:如圖:

image.png

通過看上圖紅框里的command宵统,得到結(jié)論:
1晕讲、開啟dart虛擬機
2、利用dart虛擬機運行一個叫FlutterSDK/bin/cache/artifacts/engine/darwin-x64/frontend_server.dart.snapshot的腳本
3马澈、后面還是參數(shù)瓢省,包括需要傳入的文件路徑、需要編譯的模式痊班、編譯好了的東西輸出到哪里勤婚。

因此需要看看這個frontend_server.dart.snapshot是個什么東西。

9涤伐、frontend_server.dart.snapshot是什么馒胆?

直接說結(jié)論:frontend_server.dart.snapshot和其他可執(zhí)行文件一樣,都是一個工程的產(chǎn)物凝果,這個工程沒有像flutter toolsflutterSDK中祝迂,而是在engine中,所以需要自己下載flutter engine
flutter engine的下載地址
下載完成之后器净,同樣用Android Studio打開你下載的engine/src/flutter/frontend_server型雳。按剛剛調(diào)試flutter tools的方式自己配置dart command line,如圖:

image.png

我把中間那一大串貼出來,大家可以參考:

--sdk-root /Users/zhuyaning/.flutter_sdk/bin/cache/artifacts/engine/common/flutter_patched_sdk/ --strong --target=flutter --no-link-platform --incremental --packages /Users/zhuyaning/Desktop/test/abc/.packages --output-dill build/app.dill --depfile build/snapshot_blob.bin.d --filesystem-scheme org-dartlang-root package:abc/main.dart

10、到這里四啰,當你看到這里的時候宁玫,才真正到如何生成dill的時候。

3柑晒、調(diào)試frontend_server

經(jīng)過一系列的方法調(diào)用欧瘪,最終走到:

  @override
  Future<bool> compile(
    String entryPoint,
    ArgResults options, {
    IncrementalCompiler generator,
  }) async {
....
....
....
    Component component;
    if (options['incremental']) {
      _compilerOptions = compilerOptions;
      setVMEnvironmentDefines(environmentDefines, _compilerOptions);

      _compilerOptions.omitPlatform = false;
      _generator =
          generator ?? _createGenerator(new Uri.file(_initializeFromDill));
      await invalidateIfInitializingFromDill();
      component = await _runWithPrintRedirection(() => _generator.compile());
    } else {
      if (options['link-platform']) {
        // TODO(aam): Remove linkedDependencies once platform is directly embedded
        // into VM snapshot and http://dartbug.com/30111 is fixed.
        compilerOptions.linkedDependencies = <Uri>[
          sdkRoot.resolve(platformKernelDill)
        ];
      }
      component = await _runWithPrintRedirection(() => compileToKernel(
          _mainSource, compilerOptions,
          aot: options['aot'],
          useGlobalTypeFlowAnalysis: options['tfa'],
          environmentDefines: environmentDefines,
          useProtobufTreeShaker: options['protobuf-tree-shaker']));
    }
....
....
....
  }

到此上面我省去的代碼,是做一些校驗工作匙赞,重點在if (options['incremental'])后面佛掖,這里判斷是否為增量編譯,由于我們在編譯參數(shù)中攜帶了--incremental涌庭,所以最終會進入if中芥被。無論if還是else都為下面省去的代碼提供一個component

這個component是什么坐榆?

/// A way to bundle up libraries in a component.
class Component extends TreeNode {
  final CanonicalName root;

  /// Problems in this [Component] encoded as json objects.
  ///
  /// Note that this field can be null, and by convention should be null if the
  /// list is empty.
  List<String> problemsAsJson;

  final List<Library> libraries;

  /// Map from a source file URI to a line-starts table and source code.
  /// Given a source file URI and a offset in that file one can translate
  /// it to a line:column position in that file.
  final Map<Uri, Source> uriToSource;

  /// Mapping between string tags and [MetadataRepository] corresponding to
  /// those tags.
  final Map<String, MetadataRepository<dynamic>> metadata =
      <String, MetadataRepository<dynamic>>{};

  /// Reference to the main method in one of the libraries.
  Reference mainMethodName;
...這里同樣省略了一些代碼
}

通過對源碼component 這個class的查看拴魄,它主要包含:
1、List<Library> libraries
2席镀、Map<Uri, Source> uriToSource;

我們看一下Libraries和uriToSource是什么

Libriaries

image.png

每一個Library代表一個參與編譯的文件匹中,而且Library中包含文件的絕對路徑、引用關(guān)系豪诲、定義的class顶捷、method、文件偏移量等等等等屎篱,所有和該文件相關(guān)的信息都定于于此服赎,有點像ios中clang生成的抽象語法樹 AST。

uriToSource

屏幕快照 2019-10-16 下午7.36.28.png

uriToSource是uri為key source為value的map交播,作為一個工具重虑,通過uri來找尋對應的文件。

結(jié)論:

component其實就是所有參與編譯的文件生成的抽象語法樹的包裝類秦士,就像我們MVC架構(gòu)中的model一樣嚎尤。
值得一提的是,在生成component的過程中伍宦,執(zhí)行了一個方法:

image.png

這個方法遍歷了每一個Libriary,并對其中每一個類、方法等解析成了Token(Token中定義的都是class乏梁、method的偏移量)次洼,并且通過parser.parseUnit(tokens);經(jīng)過詞法及語法分析,生成剛才我們看到的抽象語法樹遇骑。
component 得到之后卖毁,我們回到Future<bool> compile(下面省略的代碼:

if (component != null) {
      if (transformer != null) {
        transformer.transform(component);
      }

      await writeDillFile(component, _kernelBinaryFilename,
          filterExternal: importDill != null);

      _outputStream.writeln(boundaryKey);
      await _outputDependenciesDelta(component);
      _outputStream
          .writeln('$boundaryKey $_kernelBinaryFilename ${errors.length}');
      final String depfile = options['depfile'];
      if (depfile != null) {
        await writeDepfile(compilerOptions.fileSystem, component,
            _kernelBinaryFilename, depfile);
      }

      _kernelBinaryFilename = _kernelBinaryFilenameIncremental;
    }

調(diào)用await writeDillFile(component, _kernelBinaryFilename, filterExternal: importDill != null);方法,把剛才生成的component,通過BinaryFile輸出到定義的產(chǎn)物文件夾亥啦。

到此炭剪,dill文件的生成過程就結(jié)束了,其實debug模式下app.framework中的kernel_blob.bin和剛才講解的app.dill是同一個文件翔脱,都可以直接被dartVM直接執(zhí)行奴拦。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市届吁,隨后出現(xiàn)的幾起案子错妖,更是在濱河造成了極大的恐慌,老刑警劉巖疚沐,帶你破解...
    沈念sama閱讀 216,997評論 6 502
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件暂氯,死亡現(xiàn)場離奇詭異,居然都是意外死亡亮蛔,警方通過查閱死者的電腦和手機痴施,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,603評論 3 392
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來究流,“玉大人辣吃,你說我怎么就攤上這事√菟裕” “怎么了齿尽?”我有些...
    開封第一講書人閱讀 163,359評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長灯节。 經(jīng)常有香客問我循头,道長,這世上最難降的妖魔是什么炎疆? 我笑而不...
    開封第一講書人閱讀 58,309評論 1 292
  • 正文 為了忘掉前任卡骂,我火速辦了婚禮,結(jié)果婚禮上形入,老公的妹妹穿的比我還像新娘全跨。我一直安慰自己,他們只是感情好亿遂,可當我...
    茶點故事閱讀 67,346評論 6 390
  • 文/花漫 我一把揭開白布浓若。 她就那樣靜靜地躺著,像睡著了一般蛇数。 火紅的嫁衣襯著肌膚如雪挪钓。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,258評論 1 300
  • 那天耳舅,我揣著相機與錄音碌上,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播绞惦,決...
    沈念sama閱讀 40,122評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼创葡,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,970評論 0 275
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎敷燎,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體箩言,經(jīng)...
    沈念sama閱讀 45,403評論 1 313
  • 正文 獨居荒郊野嶺守林人離奇死亡硬贯,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,596評論 3 334
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了陨收。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片饭豹。...
    茶點故事閱讀 39,769評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖务漩,靈堂內(nèi)的尸體忽然破棺而出拄衰,到底是詐尸還是另有隱情,我是刑警寧澤饵骨,帶...
    沈念sama閱讀 35,464評論 5 344
  • 正文 年R本政府宣布翘悉,位于F島的核電站,受9級特大地震影響居触,放射性物質(zhì)發(fā)生泄漏妖混。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,075評論 3 327
  • 文/蒙蒙 一轮洋、第九天 我趴在偏房一處隱蔽的房頂上張望制市。 院中可真熱鬧,春花似錦弊予、人聲如沸祥楣。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,705評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽误褪。三九已至,卻和暖如春碾褂,著一層夾襖步出監(jiān)牢的瞬間兽间,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,848評論 1 269
  • 我被黑心中介騙來泰國打工斋扰, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 47,831評論 2 370
  • 正文 我出身青樓传货,卻偏偏與公主長得像屎鳍,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子问裕,可洞房花燭夜當晚...
    茶點故事閱讀 44,678評論 2 354

推薦閱讀更多精彩內(nèi)容