With the booming development of mobile smart devices, a mobile multi-terminal development framework has become a general trend. Download the Flutter Analysis and Practice: Evolution and Innovation of Xianyu Technologies eBook for step-by-step analyses based on real-life problems, as well as clear explanations of the important concepts of Flutter.
First, we will discuss how user behavior tracking is defined. On the user timeline shown in Figure 4-1, after entering page A, the user sees button X and taps it. Then, the new page B appears.
Figure 4-1
The following five tracking events occurred on this timeline:
Here, the most important thing is the tracking time, or to be more precise, the time for triggering the tracking of a specific event. The following describes Xianyu's implementation solution in Flutter.
In native development, an Android client listens to the onResume
and onPause
events of an activity as the events of entering and leaving a page. Similarly, an iOS client listens to the viewWillAppear
and viewDidDisappear
events of the UIViewController
as the events of entering and leaving a page. The entire page stack is maintained by the Android and iOS operating systems.
In Flutter, Android and iOS clients use FlutterActivity
and FlutterViewController
as the containers for carrying Flutter pages. Through these containers, native Flutter page switching can be implemented on a native page. In other words, Flutter maintains its own page stack. This means that the native solution we are most familiar with cannot directly work in Flutter.
To solve this problem, many people may register a NavigatorObserver
that can listen to Flutter to detect the push and pop events on Flutter pages. However, two problems may occur in this case:
BottomSheet
pops up on page A. Although the push operation is performed, page A does not exit.Fortunately, the page stack of Flutter is not as complex as the Android native. The first problem can be solved by maintaining an index list that matches the page stack. When a push event for page A is received, an index of page A is inserted into the queue. When a push event for page B is received, the system checks whether the list contains pages. If yes, the system records a pop event for the last page in the list, records a push event for page B, and inserts an index of page B into the queue. When a pop event on page B is received, the system records a pop event for page B and determines whether the page (assuming it is page A) corresponding to the last index in the queue is on the top of the stack (ModalRoute.of(context).isCurrent)
. If it is, the system records a push event for page A.
To solve the second problem, the Route class provides the member variable overlayEntries
, which can be used to obtain the OverlayEntry
of all layers corresponding to the current route. The OverlayEntry
object provides the member variable opaque, which can be used to determine whether the current layer covers the full screen so the Dialog and BottomSheet
can be excluded. In combination with the first problem, an operation must be added to the preceding solution to determine whether a newly pushed page is valid. If the newly pushed page is valid, the pop event is recorded for the previous page in the index list and the valid page is added to the index list. If the newly pushed page is invalid, no operation is performed on the index list.
The preceding solution was not provided by Xianyu. It came as a recommendation from the author. When implementing the Flutter framework, Xianyu used the in-house hybrid solution FlutterBoost instead of the native page stack management solution of Flutter. Therefore, we will introduce Xianyu's solution based on this hybrid solution. However, as the number of Flutter pages on the Xianyu application increases, Flutter native solutions will be implemented in the future.
Figure 4-2 and Figure 4-3 show the Xianyu solution. For this description, we use Android as an example, but this also applies to iOS.
Figure 4-2
Figure 4-3
A page opened for the first time is a new page that is opened based on the hybrid stack. If a page is not opened for the first time, the page is moved from the backend to the frontend through page rollback.
It seems that Flutter can be used to determine when to trigger the push and pop events. The page stack management in native remains. The tracking time in native is sent to Flutter and Flutter immediately calls the tracking method in native through a channel. You may ask why we do not have native directly complete all management operations. Direct management by native is suitable when a page is not opened for the first time but is not applicable when a page is opened for the first time. When a page is opened for the first time, Flutter does not initialize the page or know the page information when onResume
is called. In this case, the push tracking API in native must be called upon initialization (init) of the Flutter page. We directly trigger the push and pop events in Flutter so developers do not have to check whether a Flutter page is opened for the first time.
We think that images and text need to be exposed, but what users cannot see does not need to be exposed. Therefore, valid exposure occurs when a placement meets the following two conditions:
Based on this, we can quickly design a scenario like that shown in Figure 4-4. A scrolling page contains placements A, B, C, and D. Among the four placements:
Figure 4-4
Then, we need to calculate the proportion of the exposed area of a placement on the screen. To calculate this proportion, we need to know the following values:
It is easy to obtain and calculate the widths and heights of the placement and container. Details are omitted here.
1) Obtain the offset of the container from the screen
//监听容器滚动,得到容器的偏移量
double _scrollContainerOffset = scrollNotification.metrics.pixels;
2) Obtain the offset of the placement from the container
//曝光坑位Widget的context
final RenderObject childRenderObject = context.findRenderObject();
final RenderAbstractViewport viewport = RenderAbstractViewport.of (childRenderObject);
if (viewport == null) {
return;
}
if (!childRenderObject.attached) {
return;
}
//曝光坑位在容器内的偏移量
final RevealedOffset offsetToRevealTop = viewport.getOffsetToReveal (childRenderObject, 0.0);
3) Perform logical judgment
if (当前坑位是invisible && 曝光比例 >= 0.5) {
// 记录当前坑位是visible状态
// 记录出现时间
} else if (当前坑位是visible && 曝光比例 < 0.5) {
// 记录当前坑位是invisible状态
if (当前时间-出现时间 > 500ms) {
// 调用曝光埋点接口
}
}
4) Tap placements
It is easy to tap tracking placements by using the solution shown in Figure 4-5.
Figure 4-5
Flutter Analysis and Practice: Practices of High-Performance Dynamic Template Rendering
Flutter Analysis and Practice: Design of the Performance Stability Monitoring Solution
56 posts | 4 followers
FollowAlibaba Clouder - September 21, 2020
XianYu Tech - September 2, 2020
XianYu Tech - September 8, 2020
XianYu Tech - September 10, 2020
XianYu Tech - September 10, 2020
XianYu Tech - September 7, 2020
56 posts | 4 followers
FollowHelp enterprises build high-quality, stable mobile apps
Learn MoreAn enterprise-level continuous delivery tool.
Learn MoreProvides comprehensive quality assurance for the release of your apps.
Learn MoreAlibaba Cloud (in partnership with Whale Cloud) helps telcos build an all-in-one telecommunication and digital lifestyle platform based on DingTalk.
Learn MoreMore Posts by XianYu Tech