Community Blog Flutter IM Cross-End Architecture Design and Implementation

Flutter IM Cross-End Architecture Design and Implementation

This article discussed the architecture design and implementation of Flutter IM.

By Qiqing, from Xianyu Technology

1. Xianyu IM Status Quo

The Xianyu IM framework was built in 2016-2017. During this period, many iterations and upgrades led to the accumulation of historical burdens. After the IM interface became Flutter, the architecture became more complex. The development level summarized that the current Xianyu architecture mainly has the following problems:

  • Low Research and Development Efficiency: The current architecture development requirements involve Android/iOS dual-terminal logic code and Flutter UI interface code. Locating problems can only be traced to Native logic vulnerabilities from Flutter UI tables.
  • Poor Architecture Level: The hierarchy is not clear in architecture design, and the business logic is mixed with the core logic layer, resulting in a high risk of code change.
  • Poor Performance Test: The core data source stores Native memory, and the data source needs to be serialized by the Flutter Plugin to throw the Flutter side, which has poor performance in the case of large quantities of data sources.

There is a summary below of the main problems of Xianyu IM's current architecture from the public's perspective:

  • It is difficult to locate the problem: Online public opinion feedback is very strange, and the test cannot reproduce the relevant scenes all the time, so the essence can only be guessed by phenomena in many cases.
  • There are many complicated diseases: Problems caused by architecture instability appear repeatedly. The current complicated diseases mainly include unread red dot counting, iPhone 5C low-end machine architecture, multimedia transmission, and other problems.
  • There are big differences in the problems: The logic codes at both ends of Android and iOS are quite different, including the existing buried point logic. Therefore, when checking the root causes of the problems, both ends will have different root causes and different solutions to the problems.

2. Industry Cross-End Solutions

Xianyu started a special IM architecture upgrade project this year to solve the current IM pain points, focusing on solving the double-end consistency pain points in the client. The preliminary plan is to realize a unified Android/iOS logical architecture across ends. In the current industry, cross-end schemes can be preliminarily classified into the following structure. Cross-end schemes at the GUI level include Weex, ReactNative, H5, and Uni-App. Most of its memory models need to be bridged to Native mode storage. At the logical level, cross-end schemes generally include C/C++ and other virtual machine-independent languages to implement cross-end, but assembly language is also feasible. In addition, there are two architectures independent of the system above, namely Flutter and KMM (Google implements a similar Flutter architecture based on Kotlin), in which Flutter runs a specific DartVM and mounts memory data into its isolate.


Considering that Xianyu is the cutting-edge explorer of Flutter, Flutter is preferred in the scheme. However, Flutter's isolate is more like the concept of a process (the underlying implementation does not use process mode.) Compared with Android, multiple threads of Android's Dalvik virtual machine run to share a memory Heap in the same process scenario, while DartVM's Isolate runs to isolate their respective Heap. Therefore, the communication mode between isolates is relatively complicated. It needs to go through the serialization and deserialization process. The whole model is shown in the following figure:


If the Flutter application is implemented according to the official hybrid architecture and multiple FlutterAcitivty/FlutterController are opened, multiple Engines will be generated at the bottom layer, and there will be multiple isolates corresponding to them. Isolate communication is similar to process communication (similar to socket or AIDL.) Here, drawing on the design concept of FlutterBoost, the FlutterIM architecture shares the Engine of multiple pages, and the memory model will naturally support shared reading. The schematic diagram is listed below:


3. Flutter IM Architecture Design

3.1 A Comparison of Old and New Architectures

The following figure shows an old architecture solution. Its core problems mainly focus on the poor abstraction of Native logic. At the logic level, multi-thread concurrency is also designed to multiply the problems. Android, iOS, and Flutter have complicated interaction, high development and maintenance costs, serious core layer coupling, and no plug-in concept.


Considering the historical architecture, the new architecture design has evolved:


From top to bottom, the architecture consists of the business layer, distribution layer, logic layer, and data source layer. The data source layer originates from push or network requests and is encapsulated in the Native layer. The Flutter plug-in throws the message protocol data to the core logic layer on the Flutter side. After processing, the data source layer becomes the Entity of Flutter DB, and some message protocol entities are attached to the entity. The core logic layer flattens and packages the complicated data, mounts the session memory model data or the message memory model data in the distribution layer, and distributes it to the business logic through the subscription of observer mode. Flutter IM focuses on transforming the logic layer and the distribution layer, encapsulating and isolating the IM core logic and the business-level data model. After the core logic layer interacts with the database, the data is encapsulated into moduleData in the distribution layer. It is distributed to the business layer data model by subscription. DB is also heavily dependent in the IM model. Individuals carry out comprehensive encapsulation and solution of DB database management to realize a lightweight and high-performance Flutter DB management framework.

3.2 DB Storage Model

The DB storage of Flutter IM architecture depends on the database plug-in. The mainstream plug-in is Sqflite. Its storage model is listed below:


According to the DB storage model of the Sqflite plug-in in the figure above, there will be two waiting queues. One is the synchronous execution queue of the Flutter layer, and the other is the thread execution queue of the Native layer. Its Android implementation mechanism is HandlerThread. Therefore Query/Save reads and writes in the same thread queue, resulting in slow response speed. It is easy to cause DB SQL accumulation. In addition, the cache model is missing. Therefore, the following improvement solutions are customized for personal customization:


Flutter will preferentially obtain the query from the Entity Cache layer when designing queries through the primary key of the table. If the cache does not exist, the Sqflite plug-in is used to query and transform the Sqflite plug-in to support sync/Async synchronous and asynchronous operations. There will also be synchronous thread queues and asynchronous thread queues corresponding to the Native side to ensure the data throughput rate.

3.3 ORM Database Solution

The IM architecture relies heavily on DB databases, and the industry does not have a complete database ORM management solution currently. Referring to Android's OrmLite/GreenDao, I designed a Flutter ORM database management solution. Its core idea is listed below:


Flutter does not support reflection, so it cannot operate like Android's open-source database mode, but it can use APT mode to bind Entity and Orm Entity together. Operation OrmEntity is Operation Entity, and the entire code style design is very similar to OrmLite. The reference code is listed below:


3.4 IM Memory Data Model

FlutterIM architecture is mainly divided into two granularities: session and message in the memory data model. The session memory data model is entrusted to the SessionModuleData, and the message memory data model is entrusted to the MessageModuleData. Session memory data has a root node RootNotice. Then, its mount PSessionMessageNotice child node set (here PSessionMessageNotice is the ORM mapped session DB table model.) Message memory data will be managed by a MessageConatiner container. The PMMessage (PMMessage is the message DB table model mapped by ORM) message collection in this session is mounted internally.

According to the previous chapter, PSessionMessageNotice designed an OrmEntity Cache. Considering that the number of sessions in IM is limited, PSessionMessageNotice are all directly cached in the Cache. The advantage of this approach is that the session data elements are the same object in the cache, which is easy to ensure the data consistency of repeated reading and writing. However, considering the particularity that its number can be unlimited, PSessionMessageNotice is mounted here in the memory management of the MessageContainer. The number of PMessages in the container is verified at the time of exiting the session. Proper scale-out can reduce the memory overhead. The following figure shows the model:


3.5 State Management Solution

Flutter IM state management scheme is relatively simple. The session/message dimension of the data source is implemented by the subscription distribution method of observer mode. The architecture is similar to EventBus mode. No matter you use fish-reduxscopeModel or provider, they have little impact on the page-level state management. It is more important to keep a plug-in abstraction at the core. The architecture is listed below:


3.6 IM Synchronization Model Solution

The following is the current message synchronization model. There are multi-thread concurrency scenarios in the model, such as ACCS Thread, Main Thread, Region Thread, which leads to the problem of high concurrency of multi-threads. The isolation scheme of native push and network request synchronization is handled through the Lock mechanism and queue frequency reduction, which is complicated and error-prone. The overall Region Version Gap determines whether there is a domain hole and then performs domain synchronization to supplement data. The improved synchronization model is listed below:


There is no multi-thread scenario on the Flutter side. The Handler MSMQ is implemented synchronously and asynchronously through a kind of tag bit conversion. The architecture is much clearer and simpler, avoiding the overhead and synchronization problems caused by locks.


4. Progress and Performance Comparison

  • Aiming at the Architecture Level: In FlutterIM architecture, the focus is on unifying the double-ended logic differences into the same Dart code, completely smoothing out the problems caused by Android/iOS code differences, reducing half the cost of development and maintenance, test regression, and visual acceptance and improving the research and development efficiency significantly. The architecture is reconstructed and layered to realize a decoupled and pluggable IM architecture. At the same time, it natives to the large amount of data on the flutter side and transforms into the flutter reference transfer through serialization process to solve the problem of private chat blocking in extreme test scenarios.
  • For Online Public Opinion: The group log method of filling UT and TLog can be traced and checked. In addition, the focus is on special solutions for many existing complicated diseases, such as the unified planning of the iPhone 5C architecture on the Flutter side. The counting of unread red dots and other problems are also fixed in the upgrading of the architecture model, and the multimedia audio and video sending module is upgraded.
  • Performance Data Comparison: When the logic layer and UI layer of IM architecture are switched to Flutter, the overall memory water level is the same as the original architecture mode. Compared with the old architecture, the memory data of the new architecture in the extreme test scenario has more improvements, mainly because both interfaces use Flutter. The cost of page switching is much lower.

5. Outlook

JS cross-end is not safe, and C++ cross-end cost is a bit high, so Flutter will be a better choice. At that time, the fundamental purpose of upgrading FlutterIM architecture was never because of Flutter. It was due to the heavy historical burden, high maintenance cost at the code level, poor extensibility of new services, uncoordinated workforce ratio, and continuous feedback of public opinion on difficult and miscellaneous diseases that caused us to explore new solutions. After verifying the logical cross-end feasibility of the Flutter mode in the ultra-complex business scenario of Xianyu IM, Xianyu will always keep the cutting-edge exploration on the Flutter road and finally be able to feedback to the ecosystem. To sum up, the exploration process lies in the courage to take the first step. Then, you will be surprised and discovered.

0 0 0
Share on

XianYu Tech

56 posts | 4 followers

You may also like