Flutter product analysis and package reduction scheme

airingursb 2021-05-03 13:24:22
flutter product analysis package reduction

In a mixed development scenario ,Flutter The slightly larger package increment has always been criticized by everyone , also Google The official made it clear that Flutter No support for dynamic , And now Flutter SDK The government has not yet provided a customized solution . So I want to lose weight , Then you have to do it yourself .

The so-called package reduction , The premise is that you have to know what the content of the product is ? What parts of the product can be reduced ? How do we add back the subtracted part ? So this article will focus on “ Product analysis ” And “ Package reduction scheme ” Two topics are discussed respectively iOS And Android At both ends Flutter The principle and scheme of packet reduction .

that , First from iOS Let's start .

notes : The data and code fragments in this article are all from a project based on Flutter 1.17.1 Of Flutter Module stay Release(AOT Assembly)Mode Next, the product after construction , Without any compression .

1. iOS piece

1.1 The composition of the product

We know how to use flutter build ios-framework You can put a Flutter Module Build into a Framework for iOS Host integration , This kind of integration is called product integration , So this “ product ” Namely Flutter product , It consists of the following parts :

  1. App.framework
    • App: This is Dart Business code AOT The product of
    • flutter_assets: Flutter Static resource file
  2. Flutter.framework
    • Flutter: Flutter Engine The compiler product of
    • icudtl.dat: Internationalization supports data files

After the production , We can display the volume of each part at the terminal , Finally, tidy up iOS End Flutter The structure of the product is shown in the figure below :

It should be noted that Mac Finder The volume shown in will be too large , The conversion ratio is 1000 Instead of 1024, We need to use the command line to get the displayed volume and then calculate the real volume manually .

Besides ,Engine The volume of the product we choose is profile Pattern (arm64+arm32) The volume at the bottom , because Flutter 1.17.1 release There is bug,bitcode Can't be compressed , The resulting volume has 351.47 MB, The impact analysis . Specific reasons can be seen. :Flutter app size is too big · Issue #45519.

1.2 Package reduction scheme

There are two basic ways to reduce packets :

  1. Delete product : Delete the useless part of the product directly
  2. It's a product : Move the part that can be removed temporarily and change it to remote distribution , At the same time, you need to modify the product loading logic , send Flutter Support dynamic loading of some products distributed by remote end

In view of the product structure summarized in the previous paper, we realize the product packet reduction , First of all App.framework Medium App part .

1.2.1 App.framework/App

Before we talk about the plan , Let's see App.framework Under the App How it was built , As shown in the figure below :

First ,frontend_server Will Dart Source code compiled into an intermediate dill, We can also achieve the compilation effect by running the following command :

app.dill It's binary bytecode , We go through string app.dill You can see that it's actually Dart The product of code merging :

and Dart Provided in development mode Hot Reload In fact, it's just by passing the changed code through frontend_server Compile to get the new kernel(app.dill.incremental.dill), adopt WS Submit to Dart VM Update And then we'll do the whole tree Rebuild, So as to achieve Hot Reload.

After that, it will pass through the two platform sides gen_snapshot Compile to get IL Instruction set and optimization code , Finally, output the assembly product . The assembly product is passed through xcrun Tools get single architecture App product , Last pass lipo Get the last two ARM Architecturally App product . therefore , What we're showing here App.framework Under the App The volume of is dual architecture .

ARMv7: iPhone 5s Previous iOS equipment . ARM64: iPhone 5s And after that iOS equipment .

next , We will explain how to reduce the volume of the product from two aspects of deleting product and removing product .

Delete product

This part of the volume is Dart Code AOT After the product , It's bigger , It's our focus in the process of package reduction .

According to the basic method of packet reduction mentioned before , Let's try it first “ Delete product ”, Let's see what can be deleted directly , Use Flutter The volume analysis tool provided can directly get the volume diagram :

We found that there are two libraries that are not used in the business , Just delete the dependency .

Besides, there are some optimizations , Can help us reduce code size :

  • To configure linter To prohibit unreasonable grammar : Such as display type conversion, etc , A lot of... Will be added before compiling try catch It makes the code larger .
  • confusion Dart Code : 0.75MB (2.5%) ↓

Besides , We can also delete some symbols to achieve packet reduction effect

  • No stack trace symbols :1.8MB (6.2%) ↓
  • Delete dSYM Symbol table information file :5.8MB (20%) ↓

notes :dSYM Is save 16 Binary function address mapping information transfer file , Including our debugging symbols, Used for analysis crash report file , Parse out the correct error function information .

It's a product

next , Let's see how to achieve “ It's a product ”, Then you need to be right App.framework/App The content of this article is analyzed in detail . We said it was Dart Code AOT After the product , you 're right , Because it's mainly made up of four AOT Snapshot Library (snapshot) form :

  • kDartIsolateSnapshotData: Isolate Snapshot data , This is a Dart The initial state of the heap , And includes isolate Exclusive information .
  • kDartIsolateSnapshotInstructions: Isolate Snapshot instructions , Include by Dart isolate Executive AOT Instructions .
  • kDartVmSnapshotData: Dart VM Snapshot data ,isolate Shared between Dart The initial state of the heap .
  • kDartVmSnapshotInstructions: Dart VM Snapshot instructions , contain VM All in Dart isolate Common routines shared between AOT Instructions .

See the official website for details Wiki In the introduction :github.com/flutter/flu…

There can be many in the same process Isolate, But the two one. Isolate You can't share the heap of .Dart VM The development team has long considered the issue of interaction , So I designed a VM Isolate, It's running on UI In the thread Isolate A bridge of interaction between .Dart VM in isolate The relationship between them is shown in the figure below :

therefore isolate Corresponding AOT Snapshot Namely kDartIsolateSnapshot, It is divided into instruction segment and data segment ;VM Isolate Corresponding AOT Snapshot Namely kDartVmSnapshot, It is also divided into instruction segment and data segment .

Based on the above analysis ,App.framework We can further split it into the following figure :

We know App Store Audit regulations do not allow dynamic distribution of executable binary code , So for the above 4 A snapshot , We can only distribute the content of the data segment (kDartIsolateSnapshotData And kDartVmSnapshotData), And the content of the instruction segment (kDartIsolateSnapshotInstructions And kDartVmSnapshotInstructions) It will remain in the product .

that , Where are we going to separate this snapshot Library ?

stay Dart VM Data loading phase at startup , As shown in the figure below , modify settings The read path of the snapshot library is OK :

The specific implementation after modification is not explained in this paper , stay 《Q Live broadcast Flutter Package clipping scheme (iOS)》 This article has a detailed introduction to code modification .

1.2.2 App.framework/flutter_assets

flutter_assets yes Flutter Module Local static resources used in , For this part, we can't “ Delete ” The only way is “ Norway ”, We have two options to It's a product —— The conventional solution is still Dart VM Start the data loading phase to modify settings Inside flutter_assets route , To do remote loading , Normally we can remove it in this way flutter_assets 了 .

So is there any way not to modify Flutter Engine Code removal flutter_assets? yes , we have , have access to CDN picture + Disk caching + Preloading The same effect can be achieved by the combination scheme of , Steps are as follows :

  1. Encapsulates a Image Components , Choose whether to use this map or network map according to the compilation mode , That is to use this map to develop quickly in the development environment , Use in production environment CDN chart .
  2. reform CI, Remove during continuous integration flutter_assets And post the pictures in the package to CDN On .
  3. Expansion enhancements Image Component capabilities , introduce cached_network_image, Supports disk caching .
  4. Flutter When the module is loaded , Use precacheImage Method pair CDN Images are preloaded .

This scheme is a little troublesome , And we have to distinguish the environment , Therefore, it is suggested to revise Flutter Engine To achieve remote loading flutter_assets.

1.2.3 Flutter.framework/icudtl.dat

icudtl.dat It's an international support data file , It is not recommended to delete it directly , It's the same as the above It's a product The plan is the same , stay Dart VM Data loading phase modification at startup settings Inside icudtl.dat route (icu_data_path) To achieve remote loading :

1.2.4 Flutter.framework/Flutter

Engine modification

This part is Flutter Engine (C++) The compiled binary product of , It's the largest part of the product , At present, we refer to the sharing of byte beating 《 How to reduce proximity 50% Of Flutter Package volume 》, At present, there are two parts that can be optimized :

  1. Compile optimization
  2. Engine tailoring

Flutter Engine Use LLVM Compile , Among them, link optimization (LTO) There is one Clang Optimization Level Compile parameters , As shown in the figure below ( stay buildroot in ):

We will be here iOS Platform Engine Compile parameters from -Os The parameter is changed to use -Oz Parameters , In the end, it can reduce 700 KB Left and right volume .

And there are two parts of engine tailoring that can be cropped :

  1. Skia: Remove some parameters , Can reduce... Without affecting performance 200KB Volume .
  2. BoringSSL: If you use a client proxy request , You don't need to Dart HttpClient modular , This part can be completely removed , And the proxy request is better than HttpClient Better performance , This part can be reduced 500KB Volume

attach : stay github.com/flutter/flu… Another aspect of compiler optimization is mentioned in , Function compilation optimization . The same addition function ,Dart After compiling, there are 36 Orders , and Objective-C Only 11 Orders ,36 There is a head in the command 8 Bar and tail 6 The alignment command of the bar , It can be removed , There is 5 The stack overflow check can also be removed ,** namely Dart The compiled 36 Instructions can be optimized to 13 Orders .** We need to wait here Google It's official to optimize .

Engine compilation

After modification, we need to compile the engine , First of all, let's introduce Flutter Engine Tools needed to compile :

  • gclient: Source code library management tools , It was chromium The use of , It can manage the source code and the corresponding dependencies , adopt gclient To get all the source code and dependencies needed for compilation .
  • gn: Responsible for generating ninja What's needed to compile build file , Special like Flutter It's across multiple operating systems, across multiple platforms CPU Architecturally , It needs to pass gn Generate many different sets of ninja build file .
  • ninja: Compiler tools , Responsible for the final compilation .

The compiler tools are described in detail Flutter official Wiki:Setting up the Engine development environment - Flutter wiki

Specific compilation is divided into sa, First create a .gclient file , To pull the source code and all the corresponding dependencies , As shown in the figure below :

The second step , perform gclient sync Download dependency .

It should be noted that the above changes are dependent on ( Such as buildroot,skia etc. ) Not the source code , So we need to fork One copy flutter engine, Then change the dependence first and then , Get the corresponding dependency commit Fill in the number engine Of DEPS In the document , Then submit the code and get engine The latest in the warehouse commit Number , Fill in .gclient In file .

The third step , Use ninja coordination gn Generated configuration file to compile engine, What platform architecture do you want to compile engine Just use gn Generate a configuration , after ninja Just compile . As shown in the figure below :

Final , We're going to get a couple of ( Different platform architectures ) The custom of Engine, And it's easy to use them , Directly replace the local Flutter SDK Medium Engine that will do .

After the above steps for each product content packet reduction processing , Our final product architecture is shown in the figure below :

1.3 Package reduction effect

iOS App The volume of view is divided into the following methods , The sizes we get are all different :

The first way is to look at the local build ipa The following analysis report , Two volumes will be provided in the analysis report , But it's important to note that they are all unencrypted Of :

  1. Package size : That is, unencrypted , Download size
  2. The volume after decompression : That is, unencrypted , Occupied volume

But upload App Store After that, it will be encrypted , So you want to know the last volume that the user sees , Need to upload App Store Check the report , The report here also provides two volumes , As shown in the figure below :

Namely :

  1. Download Size
  2. Install Size

Users end up in App Store To see is Install Size.

notes : But there is an exception , That is to use Web Browser login App Store To view the App Volume , The volume that was shown at that time Download Size, because Apple I don't think what you're focusing on right now is installation footprint .

We use the blank project as the host project to upload App Store see Install Size, Find out App Volume from 18.7MB Reduced to 11.8MB.

2. Android piece

Android The side reduction package is relatively simple , Because no App Store The audit regulations of the company limit , All products can be removed roughly and distributed dynamically . We're still made up of products 、 Package reduction scheme 、 Let's see the effect of package reduction Android On the side Flutter Package reduction .

2.1 The composition of the product

First let's take a look Android End Flutter Module product (Release) Compilation process , and iOS equally , Is still Dart Source code and Engine Two parts of the product make up :

The end product flutter.gradle It includes :

  1. libapp.so
  2. flutter.jar

among ,flutter.jar Also contain libflutter.so,icudtl.dat With some Java file , and libflutter.so It's the product of the engine ,icudtl.dat It's still an international support document , The last ones Java Is exposed to business side calls Flutter The interface of .

The composition of key products is shown in the following table :

2.2 Package reduction scheme

libflutter.so It's an engine product , We can still do tailoring , But it's no longer necessary , because Flutter The product is in Android The end can be distributed completely dynamically . Steps are as follows :

  1. Move away libapp.so,libflutter.so,flutter_assets Wait for the documents , Publish to the cloud
  2. Through customization flutter.jar Medium FlutterLoader.java Logic , To load the library path of the custom location , So as to realize dynamic loading

The specific code will not be demonstrated .

2.3 Package reduction effect

Using blank project as host , Measure before and after package reduction APK The size of , You can find 6.2MB Of Flutter The volume of the product can be completely subtracted .

That's double ended Flutter Package reduction scheme , The content is relatively simple , All of them refer to the steps of predecessors and the effects obtained from practice step by step , Therefore, it is strongly recommended that readers extend their reading to the two articles at the end of this article , As a further study to deepen the understanding of .

Reference article :

  1. 《Q Live broadcast Flutter Package clipping scheme (iOS)》
  2. 《 How to reduce proximity 50% Of Flutter Package volume 》

  1. Why did gitlab choose vue.js?
  2. HTTP-RPC: 轻量跨平台REST服务
  3. 继全面采用Node.js以后,PayPal分享大幅度踩坑GraphQL心得 - Mark Stuart
  4. vue组件化开发实战之滚动/轮播的实现
  5. Http-rpc: lightweight cross platform rest Service
  6. Following the full adoption of node.js, PayPal shares a great deal of graphql experience mark Stuart
  7. Implementation of rolling / carousel in Vue component development
  8. CSS是什么?这一篇全解,绝对有你想要的
  9. What is CSS? This is a complete solution, there is absolutely what you want
  10. 04-HTML5常用标签-HTML5极速入门
  11. 04-html5 common tags
  12. WEB前端全套零基础视频教程+软件2021最新编程视频
  13. Web front end full set of zero basic video tutorial + software 2021 latest programming video
  14. 使用Node, Mongo, React, Redux实现Token认证
  15. Using node, Mongo, react and Redux to realize token authentication
  16. 体面编码之CSS和HTML
  17. CSS and HTML for decent coding
  18. 使用Playwright基于多浏览器进行javascript自动化测试的简单教程- Applitools
  19. A simple tutorial for JavaScript automatic testing based on multi browser using playwright - applitools
  20. Minimum distance to target element
  21. 浅谈 React 中的 XSS 攻击
  22. XSS attack in react
  23. 自学前端教程整理,附不容错过的前端100篇文章合集
  24. Self taught front-end tutorial collation, with a collection of 100 front-end articles that can not be missed
  25. 使用OpenTracing跟踪Go中的HTTP请求延迟
  26. Using opentracing to track HTTP request latency in go
  27. Encapsulating databinding allows you to write less than 10000 lines of code
  28. 03-HTML5标签-HTML5极速入门
  29. 03-html5 tag-html5 quick start
  30. LayUI - 极易上手拿来即用的前端 UI 框架
  31. Layui - easy to use front end UI framework
  32. Interpretation of lodash source code (1)
  33. Why is the first parameter of node family callback error?
  34. 报告:JavaScript 开发者达1380 万,C#超越 PHP,Rust 增长最快
  35. Report: Javascript developers reach 13.8 million, C surpasses PHP, and rust grows fastest
  36. 小白前端入门笔记(10),怎么设置网站内部的超链接?
  37. How to set up hyperlinks inside the website?
  38. Using node and socket to realize online chat room
  39. The core competitiveness of Vue: data bidirectional binding
  40. React configuration agent
  41. CSS layout
  42. Application scenario explanation of Vue dynamic component
  43. Redux learning notes 04 -- using multiple reducers to manage data
  44. After three months of typescript writing, what have I learned?
  45. Node family - what is a callback?
  46. React -- a simple implementation of render & create element
  47. JS learning simple usage of jquery
  48. Seamless love
  49. 小白前端入门笔记(12),设置哑链接
  50. Small white front-end entry notes (12), set dumb links
  51. Vue2. X opens composition API and TSX
  52. Interview record and thinking of social recruitment for one and a half years (Alibaba, Tencent, baidu offer)
  53. Flex learning notes
  54. The most essential closure article in the eastern hemisphere
  55. 2021-05-03 hot news
  56. Sword finger offer -- reverse order pair in array (JS Implementation)
  57. Working process of scaffold
  58. Use decorator mode to strengthen your fetch
  59. [JS] scope (Introduction)
  60. Employment information statistics network (interface document)