鸿蒙原生APP性能监控之应用埋点开发实践


📚往期笔录记录📔:


概述

埋点是指将信息采集程序和原本的功能代码结合起来,针对特定用户行为收集、处理和发送一些信息,用来跟踪应用使用情况。包括访问数、访客数、停留时长、页面浏览数和跳出率。以下是几种常见业务场景:

  • 页面中可视区域或者组件的点击量,统计点击频率,分析用户的偏好行为。
  • 监听页面中组件滑动的开始与结束,计算滑动偏移量以及曝光比例。
  • 监听页面切换,统计页面的停留时间以及切换的来源页和目标页,分析页面浏览数和跳出率。
  • 分析页面加载性能,计算加载过程各个节点的耗时,可针对某个关键点进行优化。

埋点分类

按照用户行为不同,埋点可以分为点击埋点、曝光埋点以及页面埋点等。

  • 点击埋点:用户在任意区域的一次点击,比如一个icon或一张图片。区别于被动的用户曝光行为,点击属于主动行为。
  • 曝光埋点:统计页面局部区域是否被用户有效浏览,比如瀑布流中的每一个卡片的曝光比例以及曝光时长,属于被动行为。
  • 页面埋点:统计用户在固定页面的停留时间,页面加载性能以及页面跳转时的来源页和去向页信息。

方案介绍

接下来会从:
(1)组件动态绑定埋点数据;(2)点击埋点方案;
(3)曝光埋点方案;
(4)页面埋点方案四部分介绍。整体方案使用全局无感监听能力 UIObserver 和 setOnVisibleAreaApproximateChange 属性实现埋点功能。

绑定埋点数据

首先针对需要埋点的组件指定对应的ID值以及埋点数据。比如Text组件可以指定ID为“text-1”,并且通过customProperty自定义属性设置key和value,key为组件ID,value为埋点数据。为方便拿取,可以将埋点数据统一定义在DataResource中。

import { DataResource } from '../common/DataResource';
import { router } from '@kit.ArkUI';

@Entry
@Component
struct Index {
  onPageShow(): void {
    const uiContext: UIContext = this.getUIContext();
    console.log('text-1', JSON.stringify(uiContext.getFrameNodeById('text-1')?.getCustomProperty('text-1')));
  }

  build() {
    Column() {
      Text('text-1')
        .id('text-1')
        .fontSize(50)
        .fontWeight(FontWeight.Bold)
        .customProperty('text-1', DataResource['Index']['text-1'])
        .onClick(() => {
          console.log('111111');
        })

      Text('text-2')
        .id('text-2')
        .fontSize(50)
        .fontWeight(FontWeight.Bold)
        .customProperty('text-2', DataResource['Index']['text-2'])
        .onClick(() => {
        })

      Button('Navigation')
        .onClick(() => {
          router.pushUrl({ url: 'pages/NavigationPage' })
        })

      Button('WaterFlow')
        .onClick(()=>{
          router.pushUrl({url: 'pages/WaterFlowPage'})
        })
    }
    .height('100%')
    .width('100%')
  }
}

其中DataResource在本示例中是根据Page名、组件名以及索引进行封装,以Page名作为最外层key层,以组件名+索引为里层key值。value值(埋点数据)可以根据实际业务进行配置。

export const DataResource: Record<string, Record<string, DataResourceType>> = {
  'Index': {
    'text-1': { id: 'text-1' },
    'text-2': { id: 'text-2' },
  },
  'Page2': {
    'component-1': {id: 'text-2' },
    // ...
  }
}

export interface DataResourceType {
  id: string
}

点击埋点

配置完埋点数据以及成功绑定组件后,可以在EntryAbility里统一注册点击事件监听,在事件回调中获取点击的触发节点。 UIObserver 一共提供了两种监听事件:

  • on(“willClick”):用于监听点击事件指令下发情况,所注册回调将于点击事件触发前触发。
  • on(“didClick”):用于监听点击事件指令下发情况,所注册回调将于点击事件触发后触发。

这两种方式均可以实现用户点击组件时触发回调,但要注意必须在组件上添加onClick属性。本示例中以willClick监听为例,下面介绍具体方案实现。

实现步骤

  1. 首先实现一个简单页面,并且在组件上绑定ID以及埋点数据,ID可以根据组件名-索引来命名;比如下面代码示例中有两个Text组件,ID值分别为“text-1”与“text-2”。
import { DataResource } from '../common/DataResource';
import { router } from '@kit.ArkUI';

@Entry
@Component
struct Index {
  onPageShow(): void {
    const uiContext: UIContext = this.getUIContext();
    console.log('text-1', JSON.stringify(uiContext.getFrameNodeById('text-1')?.getCustomProperty('text-1')));
  }

  build() {
    Column() {
      Text('text-1')
        .id('text-1')
        .fontSize(50)
        .fontWeight(FontWeight.Bold)
        .customProperty('text-1', DataResource['Index']['text-1'])
        .onClick(() => {
          console.log('111111');
        })

      Text('text-2')
        .id('text-2')
        .fontSize(50)
        .fontWeight(FontWeight.Bold)
        .customProperty('text-2', DataResource['Index']['text-2'])
        .onClick(() => {
        })

      Button('Navigation')
        .onClick(() => {
          router.pushUrl({ url: 'pages/NavigationPage' })
        })

      Button('WaterFlow')
        .onClick(()=>{
          router.pushUrl({url: 'pages/WaterFlowPage'})
        })
    }
    .height('100%')
    .width('100%')
  }
}

2.在EntryAbility中统一注册UIObserver的wilClick事件监听,并且在事件回调中获取触发的组件节点FrameNode。

import { AbilityConstant, UIAbility, Want } from '@kit.AbilityKit';
import { FrameNode, window } from '@kit.ArkUI';
import { hiAppEvent } from '@kit.PerformanceAnalysisKit';
import CallbackManager from '../common/CallBackManager';

export default class EntryAbility extends UIAbility {
  onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
    console.info('testTag', '%{public}s', 'Ability onCreate');
  }

  onDestroy(): void {
    console.info('testTag', '%{public}s', 'Ability onDestroy');
  }

  onWindowStageCreate(windowStage: window.WindowStage): void {
    // Main window is created, set main page for this ability
    console.info('testTag', '%{public}s', 'Ability onWindowStageCreate');
    windowStage.loadContent('pages/Index', (err) => {
      const uiContext: UIContext = windowStage.getMainWindowSync().getUIContext();
      AppStorage.setOrCreate('uiContext', uiContext);
      uiContext.getUIObserver()?.on('willClick', (_event: ClickEvent, node?: FrameNode) => {
        const clickCallback = CallbackManager.getInstance().getClickCallback();
        clickCallback(node, uiContext);
      })
      uiContext.getUIObserver()
        .on('scrollEvent', (info) => CallbackManager.getInstance().getScrollEvent(info))
      uiContext.getUIObserver().on('navDestinationSwitc
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值