preface
Hello everyone, following the practice of Flutter cross-process hybrid stack rendering — the subprocess WebView, WE have done some basic testing on the whole plugin in our spare time. Although there is still some way to go into production, we can finally reach the beta stage (the warehouse address is at the end of this article).
This plug-in has been developed intermittently for about half a year. Initially, it was just to isolate webView, but with practice, it was found that app containerization, applets and other aspects may also have good application and performance. Therefore, here to make a record and share, hope to help friends in need, at the same time for the lack of place, also hope big man can give advice.
Due to limited space, this article only gives a comprehensive introduction to the plug-in, and the specific sub-modules will be introduced in detail later.Copy the code
introduce
Currently, only Android is supported. The following is based on the Android platformCopy the code
Flutter_hybird_webview aims to isolate the Webview from the subprocess to avoid its influence on the main process. Meanwhile, in order not to increase the complexity of stack management, the subprocess rendering and the main process displaying are adopted to keep the uniqueness of the flutter stack.
Demo (multiple pictures)
GIF converted to WebP. A total of about 10 m +Copy the code
The technology principle
Organization Chart
The old architecture drawing has the same structure with minor details changes.Copy the code
The principle is introduced
The main modules of the plug-in are described belowCopy the code
Rendering module
The Flutter side uses the Texture Widget, which can be displayed with the platform surface.
When we build a page with widgets on the Flutter side, we end up with a Layer tree on the Engine side. Skia will draw (the basic drawing method of SKia is determined by the platform, such as OpengL, Vulkan, Metal, etc.) to the memory buffer pointed by the surface through the recorded drawing instructions.
Rasterizer Runner is a thread that the engine starts in the app process and is responsible for drawing dependencies. There are also runners like Platform, IO, UI, etc.Copy the code
If you understand the drawing principle, you should know that the surface is provided by the platform side, and the surface on the platform side corresponds to the Layer of the Surface Flinger service process (one-to-one correspondence). It contains a BufferQueue that can request a memory buffer as needed and share it with other processes (such as app) through mapping. Basically, the surface contains a pointer that points to a memory region where the data we draw will end up.
Here do not do too much introduction, interested can baiduCopy the code
Since surface is cross-process capable, we can create the surface in the main process and share it with the child process (or even vice versa), which provides the drawing instructions.
This ensures stack uniqueness and reduces the additional cost of managing stacks.
Touch the event module
Touch events are generated by hardware sensors and eventually transmitted to app, while Input events are generated by Input processes (including the soft keyboard window) and transmitted to APP. In other words, these events naturally have cross-process transmission.Copy the code
Flutter Touch events are passed from the platform side and distributed. See Flutter — native View’s Touch event distribution process and earlier articles.
At first, I planned to intercept and distribute the view on the platform side, but considering that the environment of view might be very complicated when it is used, such as partial display, floating layer on the surface, visible but unable to consume events, etc., I gave up this solution, and referred to The implementation of Google to process the view on the flutter side and send it back to the platform layer. And then distributed to the child process.
The event Coordinator module is added here because the view does not fill the entire page when it is displayed in detail, and the click coordinates need to be converted into relative coordinates and distributed to the remote View of the child process.
The Input event module
Since the soft keyboard is pulled up, the view needs to get the match of focus and display ID, and the official TRICK cannot solve the problem that the soft keyboard cannot be pulled up in multi-process.
After thinking, we get two plans:
Plan a
Through the analysis of the source code, it can be known that APP communicates with IMS through binder to realize the input function. Then, binder of IMS: IInputMethodManager proxies to listen for show requests from the soft keyboard, notifies the main process through the app’s binder, and distributes input events to child processes to do this.
A theoretical analysis, then full of confidence to open dry, the result was reality hit a black eye…… Newer versions of Android have caches for both binder and IMM, and cannot hook properly due to API limitations of older versions. After further research and guidance from the boss, it is found that the limitation can be bypassed by hook or anonymous call of native layer.
Due to the large amount of engineering, so the implementation of the plug-in temporarily did not adopt scheme 1, but temporarily adopt scheme 2.
Scheme 2
After carefully analyzing the communication process and source code of the Android and Chromium input module, the method of getSystemService is rewritten, and then the call stack is analyzed to determine whether the WebView requests the pop-up operation of the soft keyboard.
The specific operation effect is ok, but my personal goal is still plan 1, and I will seize the time to realize this plan later.
Communication module
The whole plug-in can be divided into three parts according to the communication terminal:
Flutter end Platform end child process endCopy the code
Plug-in management and widget/view communication are based on this communication architecture, which is implemented by Channel and binder. In order to reduce the complexity of communication channels, channels are divided into management channels and private channels.
Administration channel: Responsible for plug-in lifecycle management and distribution of maintenance commands. Private channel: The private channel inside the View that handles the distribution of custom commands.Copy the code
The specific communication process is shown below:
After the language
This is the end of the basic introduction of the plug-in, because some sub-modules involve more things, so will do a detailed introduction in the subsequent article, thank you for reading, if there is a mistake also hope to point out.
The warehouse address
Cannot be used in production at this time. See readme for details on branch meanings.Copy the code
flutter_hybird_webview
Other articles
Flutter – the Touch event distribution process of native View
What does the Native layer do when Flutter launches on Android?
Flutter version of imitation. Parallax effect of Zhihu list
Flutter — Realize progressive card switching for NetEase Cloud Music
Flutter imitates flush list of self-selected stocks