HarmonyOS鸿蒙Next埋点总结

HarmonyOS鸿蒙Next埋点总结

背景

关于脚本埋点,在上一篇文章有所实践,当时主要是验证一下脚本动态修改源码埋点的可行性,结论是可行的。

本篇是对完善之后的脚本做个总结。

初衷

为实现基本页面生命周期追踪和点击行为追踪,能够快捷的在项目中实现基础数据采集。

可惜HarmonyOS没有对应用开发者提供自定义transformer的功能

在TypeScript语言中,可以采用自定义装饰器和AST(Abstract Syntax Tree)两种方式来提高基础埋点效率。

备注

实践下来,采用AST方式操纵代码修改,暂时能想到的方法就是另外开一个工程,专门用于自动化源码埋点

1. 解析源文件结构

脚本埋点,需要首先要能正确的解析源文件结构

1.1 注释解析

HarmonyOS UI层文件均遵循的是TypeScript语言注释规则

1.1.1 多行注释

/* 开头,以 */ 结尾,两个标识都十分容易通过程序辨识

1.1.2 单行注释

// 开头

1.1.3 数据结构

注释解析完成后,仅仅需要将其位置存储下来。因此可定义一个基础代码通用数据结构

class CodeIndex{
  public startIndex: number = 0
  public endIndex: number = 0

  constructor(s: number, e: number) {
    this.startIndex = s
    this.endIndex = e
  }
}

由于整个解析过程都是在“hvigorfile.ts”文件中完成的,这里直接定义两个注释变量,如下:

//多行注释
let mulCodeIndex: CodeIndex[] = []
//单行注释
let singleCodeIndex: CodeIndex[] = []

对于这两个变量,可以只定义一个

对于多行注释和单行注释,在解析的先后顺序上,没有先后,因为两者的格式都可以相互被包含在对方内容中。

我是优先解析多行注释,原因是它解析起来相对比较简单

1.2 字符串解析

在TypeScript中,源码标识字符串的标识总共有三种

  1. '
  2. "
  3. `

例如

let a: string = 'demo'
let b: string = "demo"
let c: string = `demo`

解析字符串的首要准备条件,必须确定字符串是以哪种标识表示的,所以在遍历过程中,遍历下标每移动一次,需要把三个标识全部查找一遍,然后由小到大排序,取最小下标,然后截取字符串。

同时基于注释范围,遍历过程中,需要忽略注释内的字符串。

1.3 类结构解析

每个以".ets"和".ts"结尾的文件,在其内部,可能出现多个类,例如

@Component
struct TestOne{
  build(){
  
  }
}

class TestTwo{

}

@Entry
@Component
struct TestThree{
  build(){
  
  }
}

通过观察上边的Test.ets文件可以发现,如果我们要在Test.ets中对@Component组件进行生命周期代码插入,可能就比较麻烦,因为有两个@Component

为了方便后续代码插入,还需要对文件中的类进行整体的结构化,结构化之前,需要清楚一个文件中,到底会出现哪些样式的类?

根据HarmonyOS SDK common.d.ts文件中的 “ClassDecorator” 类型可知,ArkTS中会出现的类有4种,

  1. @Entry
  2. @Component
  3. @Observed
  4. @CustomDialog

这4种装饰器修饰的类,其对应的关键词为"struct"

根据TypeScript语言规范可知,类的关键词为"class"

结构化文件,这里可以根据类的类型定义一个Map,从而达到能对一个文件中的多个类进行精准分割

let programClassMap: Map<string, CodeIndex[]> = new Map<string, CodeIndex[]>()

结构化之后,如果要在如上Test.ets文件中的@Component装饰类中进行变量定义,就可以使用如下形式进行每个类的代码遍历

let codeIndex: CodeIndex[] = programClassMap.get('@Component')

//开始遍历
......

至此3步,已基本可以确定整个源码结构,并且可以通过脚本对源码进行插入动作

2. 文件过滤

2.1 服务卡片

关于服务卡片的ets文件, 暂时无法引用自定义的埋点文件,因此必须对其过滤

根据HarmonyOS服务卡片开发指南可知,所有的服务卡片的UI配置均在 form_config.json 文件中

2.2 无@Component装饰器

由于这里做的埋点目标是页面生命周期和点击事件,所以在一个文件内,如果没有@Component装饰器,则忽略对文件进行后续操作

3. 埋点信息

3.1 页面生命周期

@Entry 和 @Component对应生命周期函数是不一样的,因此在代码插入时,需要分别处理

注意:一个 struct 类,可能同时被@Entry 和 @Component修饰,所以在插入代码中,需要依次判断

if(funName == 'onPageShow' || funName == 'onPageHide' || funName == 'onBackPress') {
    // @Entry修饰的 struct 类
    ......
}


if(funName == 'aboutToAppear' || funName == 'aboutToDisappear') {
   //@Component修饰的 struct 类
   ......
}

3.1.1 基础信息

这篇文章,针对生命周期,定义了5个基础数据

  1. 行为序列编号(即 每次从主模块主入口进入应用时的标识)
  2. 页面所属模块
  3. 页面所在的容器
  4. 页面所在的文件
  5. 生命周期名称

3.2 点击事件

onClick是HarmonyOS的一个通用API,这篇文章中的代码插入目标就是它。

onClick的参数是一个无返回值的方法

本篇文章仅针对箭头函数做代码插入

3.2.1 常见写法

//箭头函数
Text().onClick(() => console.log('箭头函数,无花括号'))

Text().onClick(() => {
 console.log('箭头函数,带花括号')
})


function clickTest(){
  console.log('测试点击')
}

Text().onClick(this.clickTest)

3.2.2 基础信息

这篇文章中,针对点击事件,定义了3个基础数据

  1. 行为序列编号(即 每次从主模块主入口进入应用时的标识)
  2. 事件被哪个文件消耗
  3. 事件被哪个onClick消耗

3.3 Entry模块入口

应用内的所有埋点信息,应该带有使用次数的概念,对于这个次数的定义,从程序来定义,即经过应用主入口算作一次。对应的文件,可以从entry模块中的module.json5文件中找到

所以,脚本执行开始时,需要在主入口文件中的 onCreate()方法中,插入一个唯一标识,我的脚本采用时间戳

private static startBootTime: number = 0

4. 脚本说明

4.1 API接口

  • copyConfigFile
    复制埋点文件至模块ets文件夹下
  • initAppEntry
    Entry模块主入口初始化埋点行为序号
  • extractCodeIndex
    提取注释,提取字符串,结构化文件中的类
  • insertLifecycleFunction
    插入生命周期埋点
  • insertContentToOnClick
    onClick函数增加埋点

结尾

埋点不是什么重点,“.hvigor/project_caches” 这个隐藏文件夹中的@ohos文件夹文件比较有意思。

当前这种埋点对于测试人员也是比较有利。

祝各位好运!


更多关于HarmonyOS鸿蒙Next埋点总结的实战教程也可以访问 https://www.itying.com/category-93-b0.html

1 回复

更多关于HarmonyOS鸿蒙Next埋点总结的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


在HarmonyOS鸿蒙Next中,埋点主要用于收集用户行为数据,以优化产品体验和功能。以下是埋点总结的关键点:

埋点类型:

  • 页面埋点:记录用户访问的页面和停留时间。
  • 事件埋点:记录用户操作,如点击、滑动等。
  • 曝光埋点:记录内容的曝光次数。

埋点工具:

  • 使用HarmonyOS提供的Analytics Kit,支持自动和手动埋点。
  • 第三方工具如友盟、神策等也可集成。

埋点规范:

  • 统一命名规则,确保数据一致性。
  • 区分开发、测试和生产环境,避免数据污染。

数据安全:

  • 遵守隐私政策,确保用户数据安全。
  • 数据加密传输,防止泄露。

通过合理埋点,可以高效获取用户行为数据,为产品优化提供数据支持。

回到顶部