This article was first published on the WeChat public "161d653931481c Shopee Technical Team ".
1. Background
The author’s team is Shopee’s local life front-end team. Users can buy coupons on our platform and use them in offline stores. As the number of users continues to increase, researching user behavior data can better guide product function design and provide a better user experience. The research on user behavior data first involves how to collect it, which is what we often call "buying points".
For a long time, the buried points in our project are code buried points. Each new buried point is often some repetitive work, and the code needs to be re-released to take effect. For this reason, our developers are complaining. In order to achieve new embedding points without modifying the code, we have investigated two methods: visual embedding and no embedding. Among them, the no-buying point (also known as the full-buying point) will collect all the user's behavior in the application and report all the relevant data, resulting in a large amount of useless data, so it was excluded by us.
The way to visualize the buried points is: the page elements of the required buried points through the buried point platform, configure and publish the buried point reporting attributes, synchronize the buried point configuration by the collection SDK, and automatically perform user behavior data according to the configuration. Capture and send . It just solved our problem, so we decided to use the visual tracking solution.
Before we start to introduce our system, let's take a look at the basic idea of visual embedding on the web: take click events as an example (if there is no special description below, click events are used as an example), web visualization embedding generally provides An SDK, the SDK will monitor the click
document
. With the help of the event delegation feature, the click
event and element information of any element on the page can be captured. Buried while Web Visualization provides a platform by iframe
required Buried configuration page embedded, then postMessage
to communicate with the target internet page.
Since our front-end technology stack is React Native, it is difficult to implement in many places. For example, we cannot iframe
embedded page and postMessage
, and we cannot use the feature of event delegation to implement our SDK. So, how did it come about in the end? It will be introduced in detail below.
2. System introduction
The following is an introduction to our system according to the usage process. First, we need to access our SDK on the React Native client.
2.1 Client access SDK
As shown below, we TouchableComponent
initGoblin
method of the SDK, and this object exported some click-related components for the business side to use. We directly use the exported click-related components and specify trackId
(about trackId
It will be introduced later):
import { initGoblin } from '@dp/goblin-sdk-react-native'
export const { TouchableComponent } = initGoblin({ ... })
const {
GButton,
GTouchableHighlight,
GTouchableNativeFeedback,
GTouchableOpacity,
GTouchableWithoutFeedback
} = TouchableComponent
<GButton trackId="button">Click Me</GButton>
These exported components use the idea of high-order components to rewrite the original components, and add the logic related to buried points.
2.2 Connecting the Client and the Visual Embedding Platform
After accessing the SDK, you can configure the buried point next. Before configuring the tracking point, we must first connect our React Native client with the visual tracking point platform.
As shown in the figure above, the burying point configurator first needs to start a burying point task on the visual burying point platform. The front end of the visual burying point platform will WebSocket
, and the server will generate a sessionId
send it to the front end:
And will register WebSocket
client connected to the server:
{
25089: {
creator: adminWSClient
}
}
At this time, the burying point configuration personnel enter the connection page through the tools provided by the SDK on the React Native client, enter sessionId
then connect to the burying point visualization platform server WebSocket
The server will also register the WebSocket
{
25089: {
creator: adminWSClient,
connector: rnWSClient
}
}
In this way, the React Native client can be indirectly connected with the front end of the visual tracking platform through the server side of the visual tracking platform. At this point, the visual tracking server will notify the front end and the React Native client that the connection is successful. After getting the message, the front end will enter the configuration page, and the React Native client will enter the configuration mode. After that, whenever the configuration personnel circle the page elements on the React Native client, the SDK will send the relevant data to the front end of the visual tracking platform for configuration personnel to configure.
2.3 Buried point configuration
The following is the corresponding effect of the React Native client and the front end of the visual embedded point after the connection is successful:
As shown in the figure, when the embedded point configurator clicks and selects the element that needs to be embedded in the React Native client, the SDK will highlight the element. At the same time, the SDK will also send the currently selected element's trackId
and buried point attribute data source collection to the platform server, where the buried point attribute data source collection consists of the React component corresponding to the element itself and the props
and state
attributes of its ancestor components. .
Buried case arranged on a platform in the art can add fields need to be reported and specified field names, field values sources, such figures added named title
field, and specify a value derived from Item
this component props
under title
attribute .
trackId
mentioned above is the unique identifier of the currently selected element, similar to the id or XPath of the page element in the Web. The advantage of id is that it is more accurate and will not fail due to changes in page structure. The disadvantage is that it needs to be set by developers in advance. The advantage of XPath is that it can be automatically generated, but it is more sensitive to changes in page structure.
We know that behind each React application actually corresponds to a FiberNode
nodes, and in the React class component, FiberNode
node corresponding to the current component this._reactInternals
FiberNode
of the current component, a path similar to XPath can be obtained as trackId
the component. However, during the implementation, it was found that the trackId
generated by the same code on the Android and iOS platforms are different, which means that if this scheme is adopted, the buried point configuration needs to be configured separately for the two platforms, which obviously will Greatly increase the workload. So in the end, we had to give up this solution, and temporarily adopted the solution of manually setting trackId
for the component.
While traversed, we can get all the components of the ancestors FiberNode
on memoizedProps
and memoizedState
, which correspond to components props
and state
, so that we can get a set of points embedded component of the attribute data sources, like the following figure Show:
After the buried point configuration is completed, it will be published as a file in JSON format. For example, the above example will be published as follows:
{
...
"item-button": {
"constant": {
"operation": "click"
},
"variable": {
"title": "props.Item.title"
}
}
...
}
Each configuration is trackId
as the key. The constant
attribute in the object indicates that the value of the field to be reported is fixed. For example, operation
is click
indicates that the current user's operation is a click, and variable
indicates the value of the field that needs to be reported. It is dynamic, the path whose value is a value, here represented title
the value of the field need from Item
assembly props
in title
to obtain attribute.
However, another problem was encountered in actual use: after our code was packaged in the production environment, the names of the components were obfuscated, which made the configuration personnel unable to recognize it when configuring.
In order to solve this problem, we referenced the babel-plugin-add-react-displayname library to write a babel plug-in, which automatically added displayName
to the component during packaging. The embedded SDK no longer takes the name of the component when collecting the embedded data. is to take the displayName
attribute on the component.
After the embedded configuration is released, when the user uses our product, the SDK will synchronize the configuration file and report the data according to the user's behavior matching the configuration file.
2.4 Buried point reporting
When the user opens the page, the SDK will first go to the remote to pull the latest buried point configuration file. At this time, there is another problem: it takes time to pull the buried point configuration file, which leads to all user behavior events in this process. lost.
As shown in the figure above, to solve this problem, we design a queue that continuously receives and stores all user behavior events. Then, we process it in requestIdleCallback
. requestIdleCallback
is that it can be executed when idle, so it does not affect key events such as animation and user input.
When it is found that the configuration file is successfully pulled, it will start to consume the user behavior events in the queue. If the component corresponding to the user behavior event cannot be found in the configuration file, it will be discarded directly; otherwise, it will be processed. The processing method is similar to the buried point configuration process. First, a collection of buried point attribute data sources is collected FiberNode
variable
in the buried point configuration are assigned values through this collection, and finally the data in constant
For example, the following buried point configuration:
{
"item-button": {
"constant": {
"operation": "click"
},
"variable": {
"title": "props.Item.title"
}
}
}
Finally, the following report data will be generated:
{
"operation": "click",
"title": "Second Item"
}
3. Summary
This article introduces a set of solutions for implementing visual embedding in React Native applications. The implementation of this set of solutions involves the following knowledge:
- The idea of React high-order components, by rewriting the React Native components, adds the logic related to our buried points;
FiberNode
node can be obtained_reactInternals
class component;FiberNode
related properties, such as bychild
,return
,sibling
to three pointersFiberNode
traversal tree,memoizedProps
andmemoizedState
be used to replace componentsprops
andstate
the like;- Use the babel plugin to rewrite the code to solve the problem of confusing component names.
Some of these knowledge are relatively mature solutions in the industry and can be reused directly, and some are not mentioned in the official documents, which require a deep understanding of the internal mechanism to achieve. It can be seen that when conducting business development, it is essential to maintain an in-depth exploration of the frameworks and tools used on a daily basis.
At present, we have successfully accessed some new buried point requirements. From the perspective of development feedback, it is indeed a great boon to not have to write a lot of repetitive buried points to report the code. At the same time, it can also support the modification or increase of buried points without modifying the code, which significantly improves the efficiency of the online tracking requirements. We are also constantly improving this system, such as the inspection and monitoring of buried points. The purpose of inspection is to ensure the accuracy of the reported data, and the purpose of monitoring is to detect and repair buried point problems in a timely manner.
Reference link
- Web Visualization Full Embedding User Guide,
- babel-plugin-add-react-displayname
- Higher-Order Components
- _reactInternals
- FiberNode
The author of this article
Shopee local life front-end team
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。