Thoughts and Practice on Flutter dynamic thermal renewal (II) —-Dart code conversion AST

Thoughts and Practice on Flutter dynamic thermal renewal (iii) —- analysis of AST Runtime

Thoughts and Practice on Flutter dynamic thermal renewal (IV) —- analysis of AST widgets

Thinking and practice of Flutter dynamic thermal update (v) —- call AST dynamic code

When Flutter first appeared, the first reaction was whether there was support for dynamic thermal update. However, Flutter thermal update is currently only supported during the Debug phase. This feature is not supported during production packaging, mainly due to the build mode of Flutter. Flutter runs in JIT (just-in-time compilation) mode during Debug and AOT (pre-compilation) mode after production packaging.

JIT and AOT

A typical example of JIT is the BROWSER V8 engine, which can dynamically execute Javascript code. The JIT of Flutter runs in the same mode as V8. In this mode, it can achieve the same “WYSIWYG” development mode as the Web front-end, greatly improving the development efficiency. This mode is also limited to the development phase because it requires a lot of extra code to run, resulting in significant performance degradation. AOT mode is similar to C/C++. It needs to be compiled into binary code before running. It has obvious advantages and high running efficiency.

The scheme idea of Flutter dynamic

Knowing the JIT and AOT compilation modes of Flutter, it is not feasible to support dynamic behavior in a production environment unless the JIT engine of the Flutter is well optimized for use in a production environment. But until then, if we want to implement this feature, we’ll have to take a different approach.

Firstly, I searched relevant materials on the Internet and did some research. At present, HyBrid and ReactNative are mobile terminal solutions that support dynamic development. However, Javascript is the development language used by both technologies, and the dynamic characteristics of Javascript are also utilized. As mentioned earlier, the Flutter production environment runs in AOT mode, so HyBrid and RN solutions are not suitable for us.

The other solution is to implement hot update on Flutter Android by replacing aoT-compiled binaries. This solution meets our requirements in principle, but has two drawbacks:

  1. This solution works only if the AOT-compiled files of Flutter are readable and writable. There is a risk that this solution will be completely scrapped if Google later limits the permissions of aoT-compiled files to Hack replacements. For security reasons, this restriction is likely to come up.
  2. One of the main reasons we chose Flutter is that it supports multiple devices, Android & iOS, and later Windows, MacOS, etc. If this solution only runs on Android, it is not very valuable to us.

I came across an article from the Idle Fish Technology team, which mentioned the third solution, “Comparison and Best Implementation of Flutter Dynamic Solutions”. The idea is to take advantage of the declarative programming features of Dart language and the construction way of Flutter UI. By compiling template code into AST description files, This AST description file is then dynamically parsed at run time on the App side, constructed into Widget objects, and the UI is then re-rendered via setState(). By comparison, this solution is currently the most suitable, without platform differences, common to all platforms, and does not change the compilation mode of AOT, but implements a lightweight dynamic execution engine that simulates JIT on top of AOT.

Our Flutter business code will include both the Flutter AOT and the AST Runtime. In fact, the AST Runtime solution is not perfect either. First of all, we need to consider performance. Before use, we need to organize the standard packaged components according to the situation of the company’s products. This can be directly defined in the AST, which can reduce the stress of AST parsing, do not have to worry too much about multiple layout combinations, and can reduce the cost of writing DSL template code.

How to implement

In theory, our solution to analyze the AST Runtime works both technically and in scenarios. Then we need to consider how to implement the solution and dismantle the solution. We need to complete the following four phases:

  1. The implementation DSL template code is compiled into an AST description file
  2. Implement AST Runtime lightweight engine on App side
  3. Realize AST management background and store AST description files
  4. Implement AST cache management on App side and design synchronization strategy with background

In the first and second stages, it is difficult to combine DSL template with AST Runtime. In this regard, we need to further analyze our product. Take our company’s product as an example, our product is called New Core Cloud, which is a MES&ERP system focusing on manufacturing industry. The main function of the App terminal is to interact with various Back-End apis, which is also a prominent feature of ToB apps. In this way, the main functional form of App is much simpler. We used the officially recommended BLoC mode when constructing Flutter to decouple UI from business. For AST dynamic, we follow the same idea:

This allows us to further differentiate the work to be done:

  • The AST Widget is responsible for parsing the AST and constructing the Widget
  • AST BLoC dynamically parses the business logic

To further refine the image:

In the figure above, we can see that the AST Widget really interacts with the AST Runtime. That is, the business logic is executed dynamically, and the corresponding business logic needs to be executed dynamically through the interface opened by the AST Runtime.

Finally, through the flow chart to sort out our ideas:

This is the general idea of the dynamic scenario, written here first, and then updated with the specific technical implementation of each phase.