Good article to share!!
Introduction:
Dynamism is a topic that Flutter cannot avoid. Starting from the characteristics of Flutter, this paper describes the process of meituan takeout team’s exploration of Flutter dynamics, as well as the design concept, core principles and business application experience. The perspective of this paper is not limited to the framework itself, but more about what the technical team needs to do in the process of problem solving, hoping to inspire and help you.
Author: Shang Xian Yang Chao Song Tao
Original link: https://mp.weixin.qq.com/s?__biz=MjM5NjQ5MTI5OA==&mid=2651752194&idx=1&sn=33f4373e84acea878614a8fa44b5f617&chksm=bd125e4 f8a65d75908902b1bd208c9416a7a902896c8c12780d2ee6340fccda24498ee4309ed&mpshare=1&scene=23&srcid=0716lU6os6Q2SqE2FEOgvZjd& sharer_sharetime=1594901135056&sharer_shareid=5215d443920b86d04cceaaa42defb091#rd
One, foreword
Flutter cross-terminal technology has been well received in the industry since its launch. Its advantages of “multi-terminal consistency” and “rendering performance” make it difficult to compare with other cross-terminal solutions. Although The growth curve and future prospects of Flutter look good, there is no denying that Flutter is still in its development stage, and many large Internet companies cannot provide full App access without any concerns. The main concerns are package size and dynamics.
Dynamic represents a shorter path to online demand, a greatly reduced size of the original package, thus obtaining a higher user intent to download, and a more sound online quality maintenance system. After understanding these meanings, it is not difficult for us to understand that when the application and adaptation of Flutter is approaching perfection, dynamic will naturally become an unavoidable topic. Mature technologies such as RN and Weex have even led to the idea that dynamics is standard for cross-terminal technologies.
The MTFlutter team of Meituan Takeaways has been conducting research on dynamics since September 2019, and it is now online in multiple business modules with an internal project code-named “Flap”.
Second, Flap features and advantages
Flap was developed to provide a complete solution, not an interim solution. The project team thought about the most painful points and listed them one by one, and then made specific selection according to the target. In the early stage, the more thoroughly the requirements are considered, the clearer the subsequent architecture and development will be. In the process of r&d, the team should stick to the bottom line, stick to the original intention, constantly overcome difficulties, and achieve the goals set in the past.
2.1 Core Objectives
- Universality, preserving Flutter’s ability to support multiple platforms without platform differences.
- Low-cost, dynamic alignment of Flutter ecology and common development practices, and low-cost conversion of existing Flutter pages.
- Applicability, avoid package too large, unstable and other defects that are not conducive to application.
- High performance, preserving Flutter’s excellent rendering performance.
2.2 Dynamic selection
A. Product substitution
The first consideration in the selection is product replacement. The official has also launched Code Push program, which can even support Diff differential download, but it was suspended in April 2019. Here is the official statement of Flutter/issues/14330:
To comply with our understanding of store policies on Android and iOS, any solution would be limited to JIT code on Android and interpreted code on iOS. We are not confident that the performance characteristics of such a solution on iOS would reach the quality that we demand of our product. (In other words, “it would be too slow”.)
There are some serious security concerns. Since these patches would essentially allow arbitrary code execution, they would be extremely attractive malware vectors. We could mitigate this by requiring that patches be signed using the same key as the original package, but this is error prone and any mistake would have serious consequences. This is, fundamentally, the same problem that has plagued platforms that allow execution of code from third-party sources. This problem could be mitigated by integrating with a platform update mechanism, but this defeats the purpose of an out-of-band patching mechanism.
In short, officials are not confident about dynamic performance and have security concerns. Previously, the limits of the official offer were also apparent. For example, the support of Native-Flutter hybrid App is not friendly, and gray scale and other business customization operations cannot be carried out, so the core goals of universality and high performance cannot be met.
B. AOT equipped with JIT
Flutter builds AOT compilations in Release mode. IOS is AOT Assembly and Android is AOTBlob by default. Flutter also supports JIT Release mode, which can dynamically load Kernel snapshot or app-JIT snapshot. Dynamic capability can be achieved if JIT is supported on AOT. The problem, however, is that AOT relies on a different Dart VM than JIT. AOT requires a compiled “Dart VM” (more accurately, Precompiled Runtime), while JIT relies on the Dart VM (a virtual machine that provides the language execution environment); JIT releases don’t support iOS devices, and built apps can’t be distributed in the AppStore.
Implementing this solution required a separate compilation of DartVM and introducing it into the project as a dynamic library. Through preliminary tests, it is found that the package volume will increase by 20MB+, which is more than the sum of the package volume optimization done before MTFlutter. Further, the volume of Flutter package becomes a huge obstacle to the promotion and access of business parties, which does not meet our requirements for applicability.
C. Dynamic production DSL
Native side has its own JS dynamic execution environment, which can be used to dynamically generate DSLS containing pages and logical event bindings, and then parse them into Flutter pages or components. Dynamic demands can also be realized. The technical idea is similar to RN, but differs by utilizing the Flutter rendering engine and framework. This method of executing the code and then capturing the DSL is called dynamic production DSL for short.
This scheme can support logic dynamics well, but its disadvantages are also obvious. Align the Flutter framework first, the development of JS side is heavy and the development experience is impaired. In addition, there is a heavy dependence on JS, and the JS framework itself has some overhead for interpretation and execution. For page logic and events, frequent cross-platform communication between Flutter and JS will also have some overhead. This did not meet the high performance requirements of the MTFlutter team. More seriously, this scheme is not friendly to the development habits of the developers. By changing Dart to JS, the existing Flutter development tools cannot be used directly, which runs counter to the appeal of low cost.
D. Static production DSL
Before said “the code to execute and then obtain DSL means, we referred to as dynamic production DSL”, so the code does not execute direct conversion DSL, called static production DSL scheme.
Static production is characterized by smoothing out platform differences because input is the Dart source and is platform-independent. The complete information in the Dart source is directly converted into DSL through a layer converter, and then through Native and Dart static mapping and basic logic support environment. Allows it to render and interact with pure Dart.
As an implementation, you can build DSLS using the Analyzer analysis library provided by DarT-Lang, which is used in Dartfmt, Dart Doc, and Dart Analyzer Server. The library provides a set of apis to analyze Dart Sources and generate AST objects at file granularity. The AST object contains all the information from the Dart file in a neat data structure that makes it easy to generate the desired DSL. All of this analysis + transformation process takes place offline. Next, DSL-JSON is delivered as a Zip. The AOT side of Flutter uses this data source to render and interact with the entire Flutter project.
This solution preserves the Flutter/Dart development experience without platform differences. Logic dynamics rely on static mapping and base logic support rather than JScore, effectively avoiding performance overhead. In conclusion, the static production DSL ultimately became the solution chosen by the MTFlutter team.
2.3 Project Architecture
Figure 1 Flap architecture
As shown in FIG. 1, the three green parts are the products of a stage and play a connecting role. Bounded by the green part, the architecture is naturally divided into three areas:
- The first underlying part is the empowerment of the development phase, and the product is the correct and canonical Dart source code (which also meets the Flap specification).
- The second part is the DSL converter, resulting in a JSON-formatted DSL that describes the page hierarchy and logic in a standardized way.
- The third part of the upper layer is the runtime environment, which prepares all the notations needed to build the Dart object and logic, resulting in a dynamic App or module.
Principles and challenges of Flap
The core modules in Figure 1 are the converter part and the runtime part, and the principles and partial implementations of these two parts are described below.
3.1 Principle of converter
AST & DSL
AST stands for Abstract Syntax Tree. Dart’s AST is similar in basic concepts to AST in other languages. ‘package: front_end/SRC/scanner/token. The dart’ defined in all of the token, AST is through lexical analysis, syntax analysis, solutions nested hierarchy. ASTNode objects serve as basic data structures to store important information in compilation units. Derived classes are basically divided into Declaration, Expression, Literal, and Statement.
DSL stands for domain-specific Language. Represents a programming language or specification language that is specific to a particular problem domain. Programming languages are less flexible than natural languages, and their syntactic and semantic design often depends on their execution environment and specific purposes. In the past, people invented new programming languages all the time. In recent years, new languages have become more and more similar, so DSLS have become popular.
So what exactly is the Flap DSL? For developers, that DSL is Dart Code. For a machine or App, that DSL is JSON.
As mentioned in the previous technical selection:
Dart provides a set of apis for analyzing Dart sources and generating AST objects at file granularity. This data structure contains all the information for the input Dart file.
The rationale for our DSL is a description of the data in the AST, along with some other operations.
Figure 2. Dsl-json conversion steps
Because the AST that is run from the Analyzer’s API is called CompilationUnit, it is actually a CompilationUnit with many compile-related properties such as lineInfo and beginToken. However, the DSL approach does not rely on compilation, so many unwanted attributes are pruned or ignored.
The large class (identifier, statementImpl, literal, methodInvocation, etc.) is distributed at the converter entry. The data structure of each large class is transmitted using Dart model, an intermediate structure. Then, for the subdivided types (IfStatement, AssignmentStatement, DoStatement, SwitchStatement, etc.) in the categories, there are enough fine-grained conversion interfaces with AST structures as inputs and Map nodes as outputs. Ten standard Map structures (class, Method, variable, STMT, and so on) were eventually defined and refined to host all types.
For example
A simple Widget node is transformed to get this DSL-JSON, and you can see that the READability of the DSL is OK (the default delivery is a compressed single-line encrypted binary file, shown here with the Format wrapped after decryption). In the conversion, we distinguish between ordinary string, variable name reference, system enumeration, and so on, and give them different symbols.
Figure 3 shows the source code and AN example DSL for a generic Widget component
About the logic
Taking a simple example of four operations, we can see that our DSL can automatically follow the rule that multiplication should be calculated first. The mystery is that Analyzer helps us determine the priority of such operations, which is ultimately a job of describing AST. We don’t do our own analysis based on static code.
Figure 4 shows the code and DSL example of simple logic
About Grammar sugar
Syntactic sugar tends to have a unique style and unusual structure, but in AST it is honest and the structure is what it is. So the syntactic sugar should be expanded on the converter side into a general structure and then converted into a DSL, rather than having a special DSL for a particular format passed to the runtime for parsing.
Figure 5 shows the expansion of syntactic sugar
Here are just some simple examples, just a fragment of THE DSL system, in fact, there are a lot of more complex logic in the project landing, such as the loop inside the loop for collection operations or asynchronous callback inside the multiple ternary logic and so on. The principle is the same. Some special processing is added in the process of describing AST. Finally, Map nodes of transformation products will be assembled according to the hierarchy of the original AST, and then converted into JSON through JSONEncode.
Figure 6. DSL internal structure hierarchy
The converter side can completely describe all the information in a Dart file, as shown in Figure 6. It is worth mentioning that different nodes can have arbitrary structures. The Argument of method can be a global variable, and the right side of conditional expression can be a method. Even if the same structure appears in different locations, a set of processing logic should be used to transform, so the converter is mainly iterative plus small range recursion design idea.
Divide the fine-grained transformation interfaces into specific categories in different files (statement_factory, class_Factory, function_Factory) and wait for calls to parse the production bus. In practice, there are almost net-like calls between classes, so all calls should be Static and isolated internally, without reference or modification of external variables, and without side effects.
The DSL converter is a command line program, so it can be deployed seamlessly to an automated machine. After the new code is merged into the main trunk, the subsequent Bundle generation and distribution logic can be manipulated using various graphical publishing systems.
3.2 Runtime Principles
Prepare & Running
Runtime operations occur within the App, including initialization, pulling DSL, parsing, and usage. In short, it can be divided into Prepare and Running stages. Prepare is used to Prepare various run-time symbols, including system class symbols and custom symbols, property symbols and method symbols (the symbols in question are actually objects within Dart). Only after the Prepare stage is completed can subsequent operations related to Running be carried out, including page construction, event binding, interaction and normal operation of logic.
Figure 7 shows the two major phases of the runtime principle
Function. Apply ()
Flutter expects online products to be “fully reflected” after compilation, and does not support Dart:Mirror to avoid generating large packages. “Flutter apps are pre-compiled for production, and binary size is always a concern with mobile apps, We disabled dart:mirrors. “How do you convert an external symbol into an internal symbol? The Function() object provides such a universal method.
// function.dart
external static apply(Function function, List positionalArguments,
[Map<Symbol, dynamic> namedArguments]);Copy the code
The first argument is of type Function, and the last two are the parameters required by the Function (positional and named parameters, both of which are available in the DSL), so you can call a Function anytime you can get it.
If this Function is a Constructor Function the return value is the type of the constructed object.
Proxy-Mirror
After DSL, we can only get String identifiers, so we need to establish a mapping between String and Function. Considering the class name and method name, the data structure should be {String:{String:Function}}, Function() = className (); functionName () = functionName ();
{
'EdgeInsets':
{
'fromLTRB': (left, top, right, bottom) => EdgeInsets.fromLTRB(left, top, right, bottom), // ... otherfunction
},
// ...other class
};Copy the code
For instance methods, getters, and setters of the system class, you need to pass an instance parameter externally. Instance is created by the func constructor of the class and passed in.
// instance method
"inflateSize": (instance, size) => instance.inflateSize(size),
// getter
"horizontal": (instance) => instance.horizontal,
// setter
"last": (List instance, dynamic value) => instance.last = value,Copy the code
Custom Class’s meta
For custom classes, we need to build a mock metaclass system that holds all the symbolic information and converts all JSON nodes into processable objects at parsing time. All property declarations are built as FlapVariable, and all method declarations are built as FlapFunction.
As shown in Figure 8, the parent class and metaclass also have corresponding Pointers. The member variables of the parent class will also be filled into the subclass, and the class-related attributes will be injected into the derived class type through mixins, such as FlapState, which inherits from state. This allows the system class’s lifecycle methods to leave an opening in the call chain, as well as the use of injected runtime class properties.
Figure 8 The metaclass system simulated at runtime
Evaluate
As shown in the following code example, the JSON node of an if statement is delivered and passed through the Parser to get an IfStatement object. Each of these objects has several properties and a runtime entry method evaluate (Scope Scope). This method is in the Evaluative abstract class, which all statement and expression classes inherit from, automatically obtaining the Evaluate method, where the attribute part is passed in as a constructor parameter after being parsed into the Dart object during parsing.
class IfStatement extends Statement {
dynamic condition = undefined;
Body thenBody;
Body elseBody; IfStatement(this.condition, this.thenBody, [this.elseBody]); ProcessResult evaluate(Scope Scope) {bool conditionValue = condition.evaluate(Scope)if (conditionValue){
return thenBody(Scope);
}else{
return elseBody(Scope); }}}Copy the code
The condition object and statement object in the property are not triggered during parsing. The real trigger is to enter evaluate when the method is called. The condition is then determined by Scope to be true or false. Then call the other Dart object that needs evaluate, as shown in Figure 9 below:
Figure 9 Evaluate triggers the link at runtime
The expression is stacked to implement the statement, the statement is stacked to implement the body, and then the parameter and return value are added to form our custom method FlapFunction in the runtime. FlapFunction implements the call method, so that when called externally, it really does look like Function.
Flap maintains a system of scopes when dynamic pages run. The structure of Scope is equivalent to a bidirectional linked list. Each Scope has two Pointers, outer and inner. Outer in the global scope is null, inner in the class scope; Inner of the class scope is the local scope; The inner of the local scope may be null or it may be another local scope; If you follow outer all the way up to any scope, you’ll find the global scope.
Scope
Scope acts as a Context in the execution of logic, because each method or expression evalute requires a Scope input that is passed in from the outside. And the Scope is passed as an input parameter to the next line of statements after this line of statement object is executed. For example, if the first statement declares a variable of “code” and the second statement modifies the “code”, the value of “code” needs to be retrieved from Scope by reference. Not only the declared attribute can be retrieved from Scope, but also the declared method can be retrieved. Methods can also be called inside a method. This explains why we can handle logic in custom methods.
Figure 10 Search and construction of Scope
Figure 10 describes two scenarios in the actual application of Scope. On the left, click the button to trigger the onTap callback. If you need to find the confirm method, you will search the list of methods in the local scope. If you do not find the confirm method, you will search the outer layer in the class scope.
The right half shows how the Scope that is passed in when executing the method’s body is built. First, global variables and global attributes are obtained from the symbol base camp to form the global scope. Then, attributes and methods are extracted from the metaclass of this class to form the class scope, and then the local scope is constructed. Of course, parameters will also be placed in the local scope. The evaluate method that builds the entire Scope passed in to the body supports the subsequent logical execution.
3.3 Challenges encountered
It’s a lot of work and requires patience
First of all, I don’t mean a lot of manual work like system method mapping, which is automatically generated and generated on demand (mentioned in the ecology section). By “heavy workload,” we mean converters, runtime development, and ecologically related construction. We need to meet all the Dart syntax possible so that the business code can be converted cheaply, supported by numerous scripts and tools.
Projects are complex and require a well-designed architecture to support scaling
In the module development of the project, each module (Parser, Intermediate, Runtime, etc.) strictly follows the principle of single responsibility and the principle of least knowledge, which maximizes the elimination of coupling between modules. Module to module communication is carried out by some standard data structures (maps or structures inherited from ASTNode). In this way, the major reconfiguration of any module will not affect other modules, and the single-side coverage of several classes of the underlying core is close to 100%, with special personnel responsible for optimization. And you can abstract classes, interface classes, mixin classes, etc., all over the project, so that as the supported capabilities become more complex, the readability of the project does not become inversely proportional and the code does not become “disgusting”, but rather expands in a neat way, with more files than clutter.
There are many difficult and complicated cases, so keep enough confidence in the problem
Sometimes we encounter some bugs such as overwriting the scope of a static method call constructor, stopping the outer statement after the inner continue of a loop statement when nested, and executing the Function after the Function of a method argument is referenced, etc. Bug solving is an essential part of development. Sometimes the easy way can be solved quickly by adding an if else, but we don’t do that. The fun of exploring the elegant Right way is an important part of the development process.
We’d rather spend a lot of time thinking about making code as silky as the packaging on a Mac Pro console than having to go to bed every night with the “soul” of the code. Such a working atmosphere cultivates the confidence of each student, as long as the necessary problems can be solved gracefully.
4. Ecological support
Flap’s design philosophy makes it efficient in development and execution, but it is not enough to quickly spread across the business. So we built a complete Flap ecosystem, covering development, release, testing, operation and maintenance.
Figure 11 Flap in Meituan Intranet ecology
As shown in Figure 11, Flap can be expressed by four words: steady, fast, precise, and ruthless.
4.1 steady
Stable means reliable quality management system. We have strategies for IDE development, beta testing, online monitoring, and DISASTER recovery degradation. Among them, ② and ③ are basically similar to Native PR check, QA, log, report and so on, which will not be repeated here. ① and ④ are mainly mentioned below.
IDE syntax detection plug-in
The point of this feature is to expose unsupported syntax as compilation errors as early as possible so that students can find them during development and fix them. Imagine that when you finish writing the Code, the Code Review has escaped the eyes of your classmates, the PR Dart test has been passed, and you are happy to leave work. Suddenly, you get a phone call saying that you made a mistake in sending the Bundle, and some grammar Flap is not supported, so you need to rework to correct it. At this moment, your heart will be full of horses and horses.
Therefore, we will expose the syntax that is not currently supported in advance and recommend how to replace it so as to effectively reduce rework and obtain a code that meets THE Dart and Flap specifications. In the same way that Lint checks for rules that are later configured for the PR phase, it will also be blocked in the PR phase if the plugin rules are not updated in a timely manner.
Figure 12. IDE syntax checking plug-in
However, currently there are few syntax not supported by Flap. Currently, Flap basically consists of await, AS and more than 2 with scenarios. Among them, await and multiple with can also be supported theoretically, but it will cause a large reconstruction of the project and separate treatment of multiple places, which is not conducive to later maintenance. Considering that await can be completely replaced with future.then, this syntax is forbidden. For mixins, the Dart side itself is permutation and combination. More than two with’s will result in multiple derived classes, and dynamic implementations are similar, so to not complicate simple problems, we also disable more than two with’s. There are also some restrictions on writing, such as import without full path will also report an error.
Currently, Flap and AOT share the same business code in development. In order to prevent Flap rules from affecting the pages that are not covered by Flap and filling the screen with errors, we use the @FLAP annotation as the switch for whether to turn on the Flap specification detection on the current page. This makes sense. If there is no @Flap on the page, it must be an AOT module and the Dart rule is still the default. If @Flap(‘pageID’) is added, the page will be dynamically published and the Flap rule will be automatically enabled.
Disaster downgrade
Flap is connected to the unified dynamic release platform DD within Meituan, and uses the capabilities of DD platform to implement fine-grained distribution rule control of App version, platform type, UUID, Flutter SDK version and so on. A service can choose a policy grayscale publishing scheme based on actual conditions. Flap also supports packet removal if a serious exception occurs.
Figure 13. Boundary controls for the Bundle publishing system
After a page is marked to support dynamic, AOT compilation will continue and transition to two versions. Click to jump to AOT page or Flap page is completely controlled by the PARAMETERS in THE URL. The URL is not completely issued by the cloud, but the default URL is written in the code first. If you need to modify the CONFIGURATION platform, the delivered configuration information will replace the URL on the route side. Even if the configuration platform is down, at best you lose the ability to replace urls rather than fail to go to the landing page.
Figure 14 dynamic URL replacement and conditional configuration
There is an even more sharp feature for Flap. During the interim period (when Flap is online and the AOT code has not been deleted), if there is a Flap abnormality, when the user exits the page and enters the Page again, he will automatically enter the Flutter AOT page under that pageID. Minimize user interference.
4.2 fast
Quick, meaning fast edition, fast update. Flap dynamic transformation enables the application to be dynamically released at the minute level, and the client business iteration process has been adjusted to fully release this capability.
Once the package release is up and running, Flap’s main issue becomes balancing agility and quality: how to ensure that dynamic code takes effect as quickly as possible while maintaining load performance and stability.
For this problem, Flap is a combination of two-level cache and real-time update. In the online environment, memory and disk two-level cache are used. After entering the page, the update package is pre-pulled to balance the loading performance and real-time update performance. The offline environment forces the loading of remote packages to achieve fast delivery of test code.
Figure 15 Flap level-2 cache policy
Thanks to this mechanism, Flap Online achieves web-like access efficiency: The application initiates an update request at startup and at the entry point of a specific service, and when a service is dynamically published, a new version of the page can be reached the next time the user opens it. In terms of load performance, the page load time with level 2 caching is only tens of milliseconds, while the remote load time is only about 1 second.
4.3 the accurate
Fine grain size dynamic
It can be dynamic at the page level or fine-grained dynamic at the local Widget level. In fact, in the world of Flutter, the “page” itself is also a Widget. In the actual development of Flutter, the business side only needs to add a line of annotations to make the corresponding Widget or page dynamic.
@Flap('close_protect') class CloseProtectWidget extends StatelessWidget { // ... UI and logical implementation of widgets}Copy the code
When FLAPPING is distributed, the parsing engine starts with the annotated Widget, recursively parses all dependent files, converts them into the corresponding DSL, and packages them. When the App runs online, each dynamic page or component will be restored to the corresponding UI through FlapWidgetContainer according to the annotation’s FlapId.
Figure 16 Annotation scanning and Widget building
When actually called, simply pass in the FlapId of the tag in the annotation to load and render the dynamic region or page.
// Local widget-level dynamics, loading Column(children: <Widget>[MyAOTWidget(), // Native Flutter AOTWidget FlapWidgetContainer(widgetId:'kangaroo_card'), // Flap widget ], ); // Dynamic at the page level, via MTFlutterRoute route jump: routeutils.open ('scheme://host/mtf? mtf_page=flap&flap_id=close_protect');Copy the code
Accurate Debug capability
Add a @FLAP (‘ pageId ‘) annotation in the Debug phase and you will automatically attempt to transfer to DSL. If the page is very self-contained and the syntax is not too fancy, you can see the converted words directly. This shows that the syntax used on this page supports both Dart and Flap and does not need to be changed. If an error occurs, the exact location of the error will be printed in the terminal. Before this function is supported, the basic is “a collapse collapse” to the system class of a certain method, the development of students can only through their own experience to find the stack up. The current precise Debug capability realizes the comprehensive coverage of converter, run time Parser and run time EVALUATE.
Figure 17 Debug location in three phases
The location of the error reported in the converter phase can be directly retrieved from the LINEInfo of the AST object in the Exception to obtain the column and line number information. Error location in the Parser and EVALUATE phases is achieved layer by layer based on the trycatch and set common Exception types for core methods. Because DSL-JSON is compressed and can be formatted, row numbers and column numbers are meaningless, errors at runtime are all down to a method in a class.
4.4 malicious
Ruthless, all kinds of automatic generation, the actual conversion step operation mode is simple and rough. Flap provides easy automation tools throughout the iterative process.
Imports auto loading
Converting an old Flutter AOT page to a Flap page based on Flap is simple, annotated, and can be “flapped” with one terminal command. However, a business page is often divided into multiple files for rational design. If you have 10 files, do you have to repeat the same work 10 times? The answer is no. Flap does the recursive loading of imports, either on the DSL converter side or at run time when the DSL is loaded.
One limitation of IDE language detection plug-ins is that imports must use the package full path, not just a class name. Because the location of multiple files to be imported is calculated according to the relative path intercepted from the full path.
Proxy-mirror is generated on demand
Proxy-mirror is a bridge between external symbols and internal symbols. Which classes or methods in the Dart file need to have Proxy built in, and which don’t? The boundary of this division is whether declarations of this class or method can be seen in the transformed code. The system method declaration is definitely not in the business file, so Proxy is needed. The declaration of the business Model is in the My Business file, so Proxy is not required. The code uses the official Pub or the Pub of other business lines, such as the method in the Pub of Meituan Finance. The declaration is not in the “my Business” file, so the Proxy is needed.
The problem that often requires manual intervention at the initial stage of the dynamic migration of the Flutter AOT is that the loss of proxy-mirror in the project interrupts the converter and requires manual replenishment to continue the conversion.
For this kind of problem, the tool that Proxy automatically generates on demand is developed in the later stage. The main principle is to scan the AST Tree of the code first, press the level to obtain the Value wrapped by all identifer nodes in the project structure, and make a series of decision rules. Then implement automatic Proxy generation based on the Reflectable function.
The link one-stop service is published
After continuous refining and simplification, developers can now focus on the development phase. Once the code is integrated into the main process, a complete Flap publishing and hosting system will be available to assist developers in the packaging, distribution, operation and maintenance process. All of the details described earlier are automated by these tools, making it easy to publish. Flap also connects to the common operation and maintenance tools in the group at the routing level, enabling developers to monitor load time, FPS, anomaly rate and other basic indicators without any additional operations. In case of index fluctuation and abnormal increase, alarm items will be automatically registered and associated with the current packer.
Five, business practice experience
Business landing is only one of our goals, but more importantly, in the process of business practice, we should find out the problems of the framework, improve the support of various syntax features, improve the compatibility in complex mixed scenarios, and promote the improvement of the framework. Continuous polishing while improving workflow, thinking and precipitation of best practices, gradually summed up reasonable debugging scheme, operation steps and cooperation mode, and constantly improve development efficiency and experience. Improve dynamic infrastructure and tool chain construction, complete the automation and engineering of dynamic processes, and further reduce conversion and development costs.
5.1 Application Scenarios
There are two application scenarios for Flap in business.
Scenario 1. The original Flutter page needs to be transformed into a dynamic page
What would a good dynamic framework ideally look like? The dynamic framework rewrites the original Flutter into a page supporting dynamic? Then an @flap annotation would be nice. Then you can submit your code and go toolchain automatically.
Right now, it’s not ideal, but we’re in infinite proximity, so we’ll just have to debug it locally. Most of these require steps like URL routing and Mock environments, and we’ve provided a template debugging project that allows one-click comparisons between AOT and dynamic execution, as shown in Figure 18. Basically, you annotate, and the IDE plug-in says something wrong about syntax that’s not supported, you need to write it in a different way, and then you run, and then you commit.
Figure 18. The R&D process supports different operating modes
Scenario 2. Develop a new page using Flap stack
Redeveloping the scenario is obviously easier than the first one because there is no historical baggage. What would a good dynamic framework look like? Flutter uses the same IDE and development mode as Flutter AOT, but the IDE will report several syntax errors and will be prompted to write differently. When you’re done, add comments, and then commit the code.
5.2 Practical Experience
At present, our team has implemented Flutter dynamic capability in some business scenarios. Of course, the industry will also have similar or different dynamic solutions. No matter what the solution itself is, the steps in the landing are basically the same, and we have also summarized some experiences.
Bypass the problem and document it
The initial capabilities of any framework are not perfect and will have problems. When students on the business side encounter simple problems such as missing Proxy class, they can solve them directly. When there are deep problems in the runtime environment and some syntax exceptions occur in complex superimposed scenarios, they usually try to bypass them with other syntax first, record documents, and then transfer the problems to students on the Flap team.
Add IDE Plugin Rules regularly
Syntax, keywords, etc. that are explicitly not supported are added to IDE Plugin Rules and provided with alternatives to the relevant syntax. Rules also periodically add and delete syntax.
Be aware of all resources in advance
Make sure the Android launch tempo, QA testing tempo, and known PM dynamic coverage ratio are well established.
Tighten management of key rights
Compared with SOP and FAQ on the line of sorting permissions, gray scale, downgrade, disaster recovery, etc., it seems more reliable to directly appoint 2 or 3 super administrators, and it is better for the online environment to be controlled by “old drivers”.
5.3 Landing Result
The business application covers multiple pages including the first-level page of the App, and the scene has both dynamic pages and local dynamic scenes, which has withstood the flow verification of first-level and second-level pages.
Figure 19 partial dynamic landing page
Figure 20 partial DYNAMIC page FPS data
Figure 21 part of dynamic page rendering time
Figure 21 is a Mosaic for PV. Flap team calculated 11 metrics including FPS, load time, Bundle download time, and render time. The average FPS was over 58 and the render time ranged from 7 to 96ms depending on page complexity.
In general, the performance of all parameters of Flutter is close to the original performance of Flutter. In addition, there is still room for improvement in the data in the figure. The current average value is also affected by the local poor value. In the future, hierarchical optimization schemes will be used according to different TP fractions.
Flutter
Meituan, for example, shows that Flutter has great potential in the future, and that Flutter has become the basis for judging an Android developer’s ability in interviews with big companies like BAT.
- Dart’s “..” What does it mean?
- Dart scope
- The life cycle of StatefulWidget
- How does Flutter communicate with Android iOS?
- What are Widgets, RenderObjects, and Elements?
- What is state management and why is it needed?
- BLoC pattern?
- How to uniformly manage error pages?
In order to solve the problem of this series, I give you the Internet to collect, organize some learning materials about the Flutter and video, are free of charge, because I in the above through some detours, so I hope everyone can with the information I help, shorten learning Flutter time, feel the remember to give me help, of course, thumb up, Comments + attention oh!
In order to facilitate you to view my included in my [GithubRecently there is a need to learn this knowledge of their own!
This study document is divided into three aspects:
- Flutter knowledge system
- Flutter Learning Manual
- Flutter Learning Video
Android Senior Engineer Flutter system learning knowledge system
Complete manual for Advanced Flutter Learning (corresponding to mind Maps)
Learn the full set of Flutter advanced videos
Practical application of FLutter Project
Sixth, summary and prospect
Based on the idea of static production DSL+Runtime interpretation and operation, we realized the dynamic Flutter scheme integrating dynamic delivery and logical pages of interpretation, and built a Flap ecological system covering various stages of development, release, test, operation and maintenance. Flap has been implemented in multiple meituan business scenarios, greatly shortening the distribution path and enhancing the online problem repair capability. Flap made up for the two shortcomings of Flutter dynamics and package size to some extent, and promoted the development of Flutter ecology. In addition, multiple technical teams have shown great interest in Flap, and more scenes are being built and connected to Flap.
In the future, we will further improve the support capacity and ecological construction of complex grammar, reduce the cost of development and Flap conversion, improve development experience, strive to cover more business scenarios, and actively explore cooperation with business parties. Then, based on the big front-end fusion, explore the possibility of bridging other technology stacks and smoothing terminal differences based on Flap DSL.