Author: Idle fish technology — Hao An
After nearly two months of development, internal testing and online grayscale, The Preview version of FlutterBoost3.0 is finally available. Compared with the beta version, this version does not change the main structure, but adds the following capabilities:
1. Reconstruct the life cycle to ensure the semantic accuracy of the life cycle. 2. Add customized startup parameters 4. Implement the page return parameter transmission scheme 5. Support page transparency 6. Add custom event sending mechanism 7. Add pre-interceptor 8. Provide more perfect documentation and examples
Due to the lack of space, I will not expand on the above abilities. If you’re interested in the implementation, you can look at the source code and documentation to see what the functionality is. Today we’ll start by talking about design and implementation of the lifecycle part, documentation and use cases, and community building.
1. Page life cycle design
FlutterBoost3.0 has two concepts related to pages, BoostContainer and BoostPage. Each BoostContainer has a corresponding container in the Native layer. For example, on Android, this container may be FlutterBoostActivity or FlutterBoostFragment, while on iOS, This container refers to the FBFlutterViewContainer. Each BoostContainer has a Navigator corresponding to it, so a BoostContainer can contain multiple BoostPages. This design is also called double stack. As you may have noticed, when a Flutter page is opened, there is an extra withContainer parameter. If this parameter is set to false, a new container does not need to be opened when the page is opened. If this parameter is set to true, the Flutter page will be opened at the same time. Go open a new container.
When developing a business, we often need to know the visibility of a Flutter page. For example, if we write a Flutter page that contains a VideoWidget, we want the VideoWidget to play when the page is visible and pause when the page is not. Listening for changes in page visibility is one of the core capabilities that FlutterBoost needs to provide, so we provide an API called PageVisibilityObserver that specifically listens for changes in page visibility.
In our initial design, we controlled the page life cycle through the upper-level Dart code. We maintain a List in The FlutterBoostAppState and a List in each BoostContainer, so the page displayed is actually the top BoostPage in the top BoostContainer. So every time the top BoostContainer changes, or the top BoostPage in the top BoostContainer changes, we consider a page visibility change and distribute the event accordingly.
However, some problems were found in the practice of this solution. The Dart side is only aware of the double stack of Flutter, while the Native side is not aware of the page stack. Therefore, even if a page is the top BoostPage in the top BoostContainer, The page is not necessarily in the display state. For example, if A Flutter page A opens A Native page B, then the Flutter page A is still at the top of the double stack after opening the Native page B, so if nothing is done, FlutterBoost still considers Flutter page A to be visible. We also tried some methods to realize these Bad cases, such as maintaining a stack of Flutter pages in the Native layer to sense page display hiding, etc. However, in the subsequent verification process, we found that the maintainability of this scheme was not high, and finally gave up.
After that, we decided to adopt a more secure solution. The display and hiding of BoostContainer should be controlled by The Native container itself. When the Native container is displayed, the onContainerShow event will be sent to notify the corresponding BoostContainer display. When the Native container is hidden, the onContainerHide event is issued to notify the corresponding BoostContainer to hide. In this way, the problem that the life cycle is difficult to maintain is solved. Compared with the previous solution, the maintainability of this solution is more stable, but there is also a problem that has to be solved. The first onContainerShow may not receive. Taking Android as an example, the first onResume emitted after FlutterBoostActivity was created emits an onContainerShow event. However, this event is not necessarily received because the Widget for the page has not yet been created. Stable life cycle events are a strong proposition, so this issue needs to be addressed completely in FlutterBoost3.0. So how can this problem be solved? To solve this problem, we will receive the onContainerShow event separately for the first time, with the following logic
void containerDidShow(BoostContainer container) { final id = container.pageInfo.uniqueId; assert(id ! = null); if (! hasShownPageIds.contains(id)) { hasShownPageIds.add(id); // This case indicates it is the first time that this container show // So we should dispatch event using // PageVisibilityBinding.dispatchPageShowEventOnPageShowFirstTime // to ensure the page will receive callback PageVisibilityBinding.instance .dispatchPageShowEventOnPageShowFirstTime(container.topPage.route); } else { PageVisibilityBinding.instance .dispatchPageShowEvent(container.topPage.route); }}Copy the code
In PageVisibilityBinding. DispatchPageShowEventOnPageShowFirstTime we will events distribution delay to the end of the rendering
///When page show first time,we should dispatch event in [FrameCallback]
///to avoid the page can't receive the show event
void dispatchPageShowEventOnPageShowFirstTime(Route<dynamic> route) {
WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
dispatchPageShowEvent(route);
});
}
Copy the code
This ensures that the first onContainerShow event is received. From the final code point of view, this is a trivial change, but from a design point of view, this change clearly defines the page life cycle events and ensures that life cycle events are called.
2. Flutter application lifecycle design
For pure Flutter applications, a Flutter application actually runs on an Activity or ViewController, so the lifecycle of the Flutter application is actually tied to the lifecycle of the Activity or ViewController. This is also the current implementation of Flutter. However, for a single-engine, multi-page hybrid stack scenario, this is definitely not applicable. If we don’t do anything with the Flutter application life cycle, there is a risk that the Flutter application life cycle will become chaotic and the interface will not brush. Our previous approach to solve this problem is to start from the Native layer and correct the lifecycle of the Flutter application by controlling the sending of lifecycle events. For example, Android uses a resume event every time a Flutter application is paused, while iOS uses the FlutterViewController lifecycle method to manage its own lifecycle events. This corrects the lifecycle of the Flutter application, but ultimately results in a messy lifecycle for the upper application, with pause and resume being called multiple times in a row.
In order for the upper users to have a stable Flutter application life cycle, we decided to take over these capabilities. We provide a BoostFlutterBinding to take over the lifecycle as follows
mixin BoostFlutterBinding on WidgetsFlutterBinding { bool _appLifecycleStateLocked = true; @override void initInstances() { super.initInstances(); _instance = this; changeAppLifecycleState(AppLifecycleState.resumed); } static BoostFlutterBinding get instance => _instance; static BoostFlutterBinding _instance; @override void handleAppLifecycleStateChanged(AppLifecycleState state) { if (_appLifecycleStateLocked) { return; } Logger.log('boost_flutter_binding: handleAppLifecycleStateChanged ${state.toString()}'); super.handleAppLifecycleStateChanged(state); } void changeAppLifecycleState(AppLifecycleState state) { if (SchedulerBinding.instance.lifecycleState == state) { return; } _appLifecycleStateLocked = false; handleAppLifecycleStateChanged(state); _appLifecycleStateLocked = true; }}Copy the code
Code is very simple, is to hook handleAppLifecycleStateChanged method, so that no matter how to invoke Native layer Flutter set the life cycle of events, will not affect the upper Flutter application lifecycle. In addition, we provide a changeAppLifecycleState method, which can really change the life cycle of the upper Flutter application. At present, the call time of this method is related to the number of Flutter containers. When the container is greater than or equal to 1, The lifecycle state of a Flutter application is resumed, and that of a Flutter application is paused when the number of containers is 0.
3. Complete documentation and use cases
FlutterBoost previously had only one access document, which was not user-friendly. So we decided to provide better documentation. We’ve combed through some of the themes you care most about:
• Integration details • Basic routing API• Page lifecycle monitoring related API• Custom send cross-end event API
We’ve provided documentation for each of these topics this time, making it easier for users to access FlutterBoost and troubleshoot problems when they encounter them. We are also working on a new Example3.0 to be used with documentation, in which we will present all of the documentation as use cases, hopefully that will help.
4. Community building
All of Boost’s planned development work will now be displayed on the Project Kanban at github.com/alibaba/flu… . Students who are interested in our work can see our work plan on the board, welcome to discuss with us. In addition, if there are any features that you want us to support, you can also issue them to us. If our evaluation is reasonable, they will also be added to the kanban.
At the same time, we added an AUTHORS file (github.com/alibaba/flu… , recording all FlutterBoost Contributors (fCN3). For those of you who give us your PR, you can add your name to the file along with your PR and thank you for contributing to Boost.
5. Future outlook
As the core infrastructure of AliFlutter, FlutterBoost3.0 is mainly developed and maintained by Xianyu team and UC Hummer team. The main developers include Noborder, 0xZOne, Christyuj, ColdPaleLight and LuckySmg. In addition, I would like to thank seedotlee, CheungSKei, Bktoky, JK and other students for their contributions to FlutterBoost3.0. At present, several apps in the group have access to FlutterBoost3.0, including Quack, Taobao Union, Foogonote, etc.
After that, in principle, Breaking Change will not be done in the Preview version of FlutterBoost3.0. Students who have already used the beta version can also switch to the Preview version one after another. In the next stage, we will focus on issue convergence and document use case completion.
As an open source project, FlutterBoost still has a long way to go. Thank you for your support and tolerance along the way, and we hope that more students will get involved in this project.