5
头图
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 by child , return , sibling to three pointers FiberNode traversal tree, memoizedProps and memoizedState be used to replace components props and state 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

The author of this article

Shopee local life front-end team


Shopee技术团队
88 声望45 粉丝

如何在海外多元、复杂场景下实践创新探索,解决技术难题?Shopee技术团队将与你一起探讨前沿技术思考与应用。