HarmonyOS 鸿蒙Next基于无感监听实现全局页面埋点

发布于 1周前 作者 songsunli 最后一次编辑是 5天前 来自 鸿蒙OS

场景描述 当前许多应用都需要实现全局页面埋点能力,例如输出用户使用的页面路径、用户在每个页面的停留时间等,但是navigation路由场景会存在首页为page的情况,这时候使用navDestinationUpdate无法监听到首页的变化,想要在HarmonyOS上实现一个监听navigation所有页面的方法。

此demo暂不支持navigation嵌套场景,复杂场景推荐使用HMRouter。

显示效果 使用navgation路由:

1. 首页pushPath到pageOne

2. pushPath到pageTwo

3. remove PageOne

4. 返回首页

5. 退出应用

image.png

使用router路由:

1. Index push到page1

2. replaceUrl到page3

3. 返回Index

4. 锁屏

核心代码 1. 自定义页面对象,统一routerInfo和navInfo,保证每个页面的唯一性。

class PageInfo { 
  //PageID或NavDestinationID 
  id: string = '' 
  name: ResourceStr = '' 
  //navigationID或'RouterPage' 
  uniqueId: string = '' 
} 
 
//统一navDestinationInfo与RouterPageInfo 
function routerInfo(info: RouterPageInfo): PageInfo { 
  let pageinfo = new PageInfo() 
  pageinfo.id = info.pageId 
  pageinfo.name = info.name 
  pageinfo.uniqueId = 'RouterPage' 
  return pageinfo 
 
} 
 
function navInfo(info: NavDestinationInfo): PageInfo { 
  let pageinfo = new PageInfo() 
  pageinfo.id = info.navDestinationId 
  pageinfo.name = info.name 
  pageinfo.uniqueId = info.navigationId as string 
  return pageinfo 
}
  1. 定义一个方法来监听页面。

stack用来存页面栈,其中页面信息的顺序与页面栈一致allInfo存页面以及对应的开始展示的时间。

export function observerAll(context: UIContext) { 
  // key用info.id + info.name + info.navigationId做拼接,保证唯一性,value为开始展示的时间点 
  let allInfo: HashMap<string, number> = new HashMap(); 
  // 存栈信息 
  let stack: ArrayList<PageInfo> = new ArrayList() 
  ...... 
}
  1. 声明全局的页面栈实例,用于缓存不同页面的状态和区分不同窗口的页面。

(1) navDestinationUpdate监听。

注意:navDestinationUpdate此监听是监听navDestination组件的生命周期变化,若存在单独使用navDestination组件的场景(不推荐),或者子窗的场景,这里请绑定NavigationID:

observer.on('navDestinationUpdate', { navigationId: "testId" }, (info) => { 
  ...... 
});
onAppear:将页面信息存入栈中,打印栈中页面路径。
onDisappear:页面退栈,删除页面信息,并打印当前栈中的页面路径。
onShown:将onShown页面移入栈顶,并更新开始展示时间。
onHidden:计算页面展示时间。
observer.on('navDestinationUpdate', (info) => { 
  let nPageInfo = navInfo(info); 
  let allString = infoSplice(nPageInfo); 
  //onAppear入栈 
  if (info.state == 2) { 
    stack.add(nPageInfo); 
    //当前时间就是开始展示时间 
    allInfo.set(allString, Date.now()); 
    let stackInfo = '' 
    for (let i = 0; i < stack.length; i++) { 
      let pageName = (stack[i] as PageInfo).name; 
      stackInfo += pageName + ' -> '; 
    } 
    console.log('当前页面栈:' + stackInfo); 
  } 
 
  //onDisappear出栈,删除栈中信息,并打印之后的栈 
  if (info.state == 3) { 
    allInfo.remove(allString); 
    let stackInfo = '' 
    for (let i = 0; i < stack.length; i++) { 
      if (isObjectChanged(stack[i], nPageInfo)) { 
        stack.removeByIndex(i); 
      } 
    } 
    for (let i = 0; i < stack.length; i++) { 
      let pageName = (stack[i] as PageInfo).name; 
      stackInfo += pageName + ' -> '; 
    } 
    console.log('当前页面栈:' + stackInfo); 
  } 
  //onShown更新页面出现时间,更新栈中顺序 
  if (info.state == 0) { 
    allInfo.set(allString, Date.now()); 
  } 
 
  //onHidden计算页面展示时间 
  if (info.state == 1) { 
    let stateTime = Date.now() - allInfo.get(allString); 
    console.log(nPageInfo.name + '显示时间为:' + stateTime); 
  } 
})
  (2) navDestinationSwitch监听。

  navDestinationUpdate监听无法监听到首页page的变化,navDestinationSwitch可以监听到首页page的变化,首页信息为NavBar

  这里只需要补充跳转NavBar以及返回NavBar的场景:

  (3) routerPageUpdate监听。

  特别说明:navDestinationUpdate与navDestinationSwitch监听无法兼顾到应用后台回到前台以及锁屏解锁的场景(若此时栈中存在navBar+navDestination,同时会触发navBar以及navDestination两个页面的回调),这时候就需要用routerPageUpdate补充,并增加监听使用router路由场景的功能。

  大部分逻辑与navDestinationUpdate监听相同,但是在onPageHide展示时间前需要判断此页面是否为栈中最后一个,若为最后一个,则打印。
AboutToAppear:page入栈,打印此时栈中页面信息。
AboutToDisappear:页面出栈,删除页面信息,并打印当前栈中的页面路径。
onPageShow:将onPageShow页面移入栈顶,并更新开始展示时间。
onPageHide:计算页面展示时间。
//监听page生命周期变化 
observer.on('routerPageUpdate', context, (info) => { 
  let rPageInfo = routerInfo(info); 
  let allString = infoSplice(rPageInfo); 
 
  //aboutToAppear入栈,打印栈信息 
  if (info.state == 0) { 
    stack.add(rPageInfo); 
    //当前时间就是开始展示时间 
    allInfo.set(allString, Date.now()); 
 
    let stackInfo = '' 
    for (let i = 0; i < stack.length; i++) { 
      let pageName = (stack[i] as PageInfo).name; 
      stackInfo += pageName + ' -> '; 
    } 
    console.log('当前页面栈:' + stackInfo); 
  } 
 
  //aboutToDisappear出栈,删除栈中信息,并打印栈信息 
  if (info.state == 1) { 
    allInfo.remove(allString) 
    let stackInfo = ''; 
    for (let i = 0; i < stack.length; i++) { 
      if (isObjectChanged(stack[i], rPageInfo)) { 
        stack.removeByIndex(i); 
      } 
    } 
    for (let i = 0; i < stack.length; i++) { 
      let pageName = (stack[i] as PageInfo).name 
      stackInfo += pageName + ' -> '; 
    } 
    console.log('当前页面栈:' + stackInfo); 
  } 
 
  //onPageShow更新页面出现时间 
  if (info.state === 2) { 
    allInfo.set(allString, Date.now()); 
  } 
 
  //onPageHide计算页面展示时间 
  if (info.state === 3) { 
    //需要判断此page后是否存在navDestination,若存在,则不打印 
    for (let i = 0; i < stack.length; i++) { 
      if (isObjectChanged(stack[i], rPageInfo)) { 
        if (i == stack.length - 1 || (stack[i+1] as PageInfo).uniqueId == 'RouterPage') { 
          let stateTime = Date.now() - allInfo.get(allString); 
          console.log(rPageInfo.name + '显示时间为:' + stateTime); 
        } 
      } 
    } 
  } 
})
4. 在主窗口创建后开启页面监听(推荐在ability.onWindowStageCreate()中进行)。
onWindowStageCreate(windowStage: window.WindowStage): void { 
  windowStage.loadContent('pages/Index', (err) => { 
    // 开始监听(不能早于该时机) 
    observerAll(uiContext) 
  }); 
}
5. 在子窗口创建后开启页面监听。
windowStage.createSubWindow('subWindow').then(subWin=>{ 
  subWin.setUIContent('pages/Index').then((err)=>{ 
    // 开始监听(不能早于该时机) 
  }) 
})

常见问题 Q1:如果router与navigation混用能监听到吗? ​​​​​​​A1:可以,但是更推荐使用navigation作为路由框架,如果使用navigation路由,一个Page+多个NavDestination即可满足路由需求。

Q2:如果一个应用内有多个窗口,对应的页面栈该是否共用? ​​​​​​​​​​​​​​ A2:可以区分开,每个窗口都有自己的页面栈信息。

Q3:navigation嵌套场景能使用吗? ​A3:复杂场景推荐使用HMRouter。


更多关于HarmonyOS 鸿蒙Next基于无感监听实现全局页面埋点的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html

1 回复

更多关于HarmonyOS 鸿蒙Next基于无感监听实现全局页面埋点的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


HarmonyOS 鸿蒙Next通过无感监听技术实现全局页面埋点,主要依赖于其先进的系统架构和事件分发机制。具体而言,该系统能够在不干扰用户正常操作的前提下,自动捕获页面切换、用户交互等关键事件,并将这些事件数据记录下来,用于后续的数据分析和业务优化。

实现这一功能的关键在于鸿蒙系统的底层能力,包括事件监听、数据收集与传输等模块。这些模块协同工作,能够实时捕获全局范围内的页面变化,确保数据的准确性和完整性。同时,鸿蒙系统还提供了丰富的API接口,使得开发者可以轻松地接入这一功能,实现自定义的数据收集和分析需求。

值得注意的是,无感监听并不意味着对用户隐私的侵犯。鸿蒙系统在实现全局页面埋点时,严格遵守相关法律法规和隐私政策,确保用户数据的安全和合规性。所有收集的数据都经过加密处理,并在用户授权的前提下进行传输和使用。

总之,HarmonyOS 鸿蒙Next通过无感监听技术实现全局页面埋点,为开发者提供了强大的数据收集和分析能力,有助于提升应用的用户体验和业务效果。如果问题依旧没法解决请联系官网客服,官网地址是:https://www.itying.com/category-93-b0.html

回到顶部