HarmonyOS 鸿蒙Next基于无感监听实现全局页面埋点
场景描述 当前许多应用都需要实现全局页面埋点能力,例如输出用户使用的页面路径、用户在每个页面的停留时间等,但是navigation路由场景会存在首页为page的情况,这时候使用navDestinationUpdate无法监听到首页的变化,想要在HarmonyOS上实现一个监听navigation所有页面的方法。
此demo暂不支持navigation嵌套场景,复杂场景推荐使用HMRouter。
显示效果 使用navgation路由:
1. 首页pushPath到pageOne
2. pushPath到pageTwo
3. remove PageOne
4. 返回首页
5. 退出应用
使用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
}
- 定义一个方法来监听页面。
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) 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
更多关于HarmonyOS 鸿蒙Next基于无感监听实现全局页面埋点的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html
HarmonyOS 鸿蒙Next通过无感监听技术实现全局页面埋点,主要依赖于其先进的系统架构和事件分发机制。具体而言,该系统能够在不干扰用户正常操作的前提下,自动捕获页面切换、用户交互等关键事件,并将这些事件数据记录下来,用于后续的数据分析和业务优化。
实现这一功能的关键在于鸿蒙系统的底层能力,包括事件监听、数据收集与传输等模块。这些模块协同工作,能够实时捕获全局范围内的页面变化,确保数据的准确性和完整性。同时,鸿蒙系统还提供了丰富的API接口,使得开发者可以轻松地接入这一功能,实现自定义的数据收集和分析需求。
值得注意的是,无感监听并不意味着对用户隐私的侵犯。鸿蒙系统在实现全局页面埋点时,严格遵守相关法律法规和隐私政策,确保用户数据的安全和合规性。所有收集的数据都经过加密处理,并在用户授权的前提下进行传输和使用。
总之,HarmonyOS 鸿蒙Next通过无感监听技术实现全局页面埋点,为开发者提供了强大的数据收集和分析能力,有助于提升应用的用户体验和业务效果。如果问题依旧没法解决请联系官网客服,官网地址是:https://www.itying.com/category-93-b0.html 。