基于uni-app的埋点sdk设计

时间:2024-04-11 15:57:05

一、统计app激活状态

在App.vue 中 利用onShow生命周期验证 或者操作

onShow: function () {

uni.showToast({

title: 'onShow'

})

},

二、页面级别的统计 (进入页面、停留时长、手机系统信息、网络状态、页面路径、标题)

需要收集的数据

{

"pageType": "leavePage",

"networkType": "wifi",

"pageInfo": {

"pageUrl": "pages/index/newIndex",

"title": ""

},

"entryTime": "2024-04-10 13:18:50",

"leaveTime": "2024-04-10 13:18:51",

"nowTime": "2024-04-10 13:18:51",

"stayTime": 279,

"sysTemInfo": {

"appName": "某某app",

"appVersion": "2.1.4",

"brand": "apple",

"platform": "ios",

"system": "iOS 17.3.1"

},

"pageLoadTime": 873

}

通过混入mixins 每个页面生命周期埋点统计、编写逻辑方法

三、页面内部事件级别的统计 (各种事件信息集合eventTrack(点击、复制、下载、来源某个特定页面的操作)、 手机系统信息、网络状态、页面路径、标题)

需要收集的数据

{

"networkType": "unknown",

"pageInfo": {

"pageUrl": "pages/order/index",

"title": "订单"

},

"sysTemInfo": {

"appName": "某某app",

"appVersion": "2.1.4",

"brand": "xiaomi",

"platform": "android",

"system": "Android 12"

},

"eventTrack": { // 事件所需要的埋点字段

"eventCode": "B0004"

}

}

通过混入mixins 每个页面生命周期埋点统计、编写逻辑方法

四、具体的设计流程

1、创建 埋点sdk方法 pointCom.js

主要三个方法

myPointPage, 页面级别触发的

toDateDetail, 时间转化函数

myPointEvent, 页面内部事件触发的

详细编码

import { pagesObj } from '@/uni-config/pages.js' // 页面路由和标题的映射map

console.log(pagesObj, 'uni-config')

async function myPointPage(pageType = "", pageUrl = "") {

console.log("埋点", pageType, pageUrl);

let entryTime, leaveTime, stayTime, nowTime;

if (!pageType) return;

if (pageType == "entryPage") {

entryTime = new Date().getTime();

nowTime = new Date().getTime();

leaveTime = null;

uni.setStorageSync("entryTime", entryTime);

} else {

entryTime = uni.getStorageSync("entryTime");

leaveTime = new Date().getTime();

stayTime = leaveTime - entryTime;

nowTime = new Date().getTime();

}

uni.getNetworkType({

success: function (res) {

let networkType = res.networkType;

try {

uni.getSystemInfo({

success: function (res) {

let { appName,

appWgtVersion,

brand,

platform,

system } = res

let data = {

pageType: pageType,

networkType: networkType,

pageInfo: {

pageUrl: pageUrl,

title: pagesObj[pageUrl]

},

entryTime: toDateDetail(entryTime),

leaveTime: toDateDetail(leaveTime),

nowTime: toDateDetail(nowTime),

stayTime: stayTime,

sysTemInfo: {

appName,

appVersion: appWgtVersion,

brand,

platform,

system

},

};

if (pageType === "leavePage") {

data.pageLoadTime = uni.getStorageSync("pageLoadTime");

}

console.log('发送调用埋点接口', data)

},

fail(error) {

sysTemInfo = "null";

},

});

} catch (e) { }

},

});

}

async function myPointEvent(eventTrack = {}, pageUrl = "") {

uni.getNetworkType({

success: function (res) {

let networkType = res.networkType;

try {

uni.getSystemInfo({

success: function (res) {

let { appName,

appWgtVersion,

brand,

platform,

system } = res

let data = {

networkType: networkType,

pageInfo: {

pageUrl: pageUrl,

title: pagesObj[pageUrl]

},

sysTemInfo: {

appName,

appVersion: appWgtVersion,

brand,

platform,

system

},

eventTrack

};

console.log('myPointEvent发送调用埋点接口', data)

},

fail(error) {

sysTemInfo = "null";

},

});

} catch (e) { }

},

});

}

function toDateDetail(number) {

if (!number) return undefined;

// var n = number * 1000

var date = new Date(number);

var Y = date.getFullYear() + "-";

var M =

(date.getMonth() + 1 < 10

? "0" + (date.getMonth() + 1)

: date.getMonth() + 1) + "-";

var D = date.getDate() < 10 ? "0" + date.getDate() : date.getDate();

var h = date.getHours() < 10 ? "0" + date.getHours() : date.getHours();

var mm = date.getMinutes() < 10 ? "0" + date.getMinutes() : date.getMinutes();

var s = date.getSeconds() < 10 ? "0" + date.getSeconds() : date.getSeconds();

return Y + "" + M + "" + D + " " + h + ":" + mm + ":" + s;

}

export default {

myPointPage,

toDateDetail,

myPointEvent,

};

2、创建 埋点混入的方法和生命周期 pointMixin.js

主要四个方法

eventTrack, 页面事件调用的函数

entryTrack, 页面进入调用的函数

leaveTrack, 页面离开调用的函数

pageLoadTime 页面onReady调用的函数

详细编码

import pointCom from "@/utils/pointCom.js";

export default {

data() {

return {

pointPageUrl: "", //跳转url

pageType: "", //事件类型 进入、离开

loadStartTime: "", //页面加载开始时间

};

},

onLoad() {

this.entryTrack();

},

onReady() {

this.pageLoadTime();

},

onHide() {

this.leaveTrack();

},

onUnload() {

this.leaveTrack();

},

methods: {

eventTrack(eventTrack = {}) {

console.log('eventTrack', eventTrack, this.pointPageUrl)

let pointPageUrl = getCurrentPages()[getCurrentPages().length - 1].route;

this.pointPageUrl = pointPageUrl;

pointCom.myPointEvent(eventTrack, this.pointPageUrl);

},

entryTrack() {

let loadStartTime = pointCom.toDateDetail(Number(new Date()));

let pointPageUrl = getCurrentPages()[getCurrentPages().length - 1].route;

this.pointPageUrl = pointPageUrl;

this.pageType = "entryPage";

this.loadStartTime = loadStartTime;

pointCom.myPointPage("entryPage", this.pointPageUrl);

},

pageLoadTime() {

let pageLoadTime = Number(new Date()) - new Date(this.loadStartTime).getTime()

console.log("pageLoadTime", pageLoadTime, this.loadStartTime)

uni.setStorageSync("pageLoadTime", pageLoadTime);

},

leaveTrack() {

if (this.pageType === "leavePage") return;

this.pageType = "leavePage";

pointCom.myPointPage("leavePage", this.pointPageUrl);

},

},

};

3、main.js 引入 pointMixin.js

详细编码

import pointMixin from "@/utils/pointMixin"; //配合埋点的mixin

Vue.mixin(pointMixin);

4、得到页面路由和标题的映射map

h5中可以得到标题等数据,但是app中无法获取

// 获取当前页面链接和参数

function getCurrentPageUrlWithArgs() {

const pages = getCurrentPages();

const currentPage = pages[pages.length - 1];

const route = currentPage?.route;

const options = currentPage?.options || {};

const title = currentPage?.$holder?.navigationBarTitleText || ''

console.log(title)

let urlWithArgs = /${route}?;

for (let key in options) {

const value = options[key];

urlWithArgs += ${key}=${value}&;

}

urlWithArgs = urlWithArgs.substring(0, urlWithArgs.length - 1);

return {

options, //当前页面的参数

urlWithArgs, //当前页面的参数

route,

title,

};

}

app获取相关数据需要另辟蹊径

通过文件的读取和写入来实现
具体编码

const fs = require("fs-extra")

let path = require("path")

let Hjson = require("hjson")

const chokidar = require("chokidar")

let rootPath = (function () {

let e = path.resolve(__dirname, "./")

return e

})()

function creatPagesJs() {

try {

const fileContent = fs.readFileSync('./pages.json', 'utf8');

const jsonObj = Hjson.rt.parse(fileContent);

let pages = jsonObj.pages

let pagesObj = {}

pages.map(item => {

let path = item.path

let title = item?.style?.navigationBarTitleText || ''

pagesObj[path] = title

})

console.log(pagesObj, 'pagesObj')

let pstr = "export const pagesObj = " + JSON.stringify(pagesObj, null, 2);

fs.outputFileSync(

path.resolve(rootPath, "uni-config", "pages.js"),

pstr

);

} catch (err) {

console.log(err);

}

}

const watcherPagesJson = chokidar

.watch(path.resolve(__dirname, "./pages.json"))

watcherPagesJson.on("all", (event, path) => {

console.log(event, path, 'pages.json')

if (event == "change") {

creatPagesJs()

}

})

creatPagesJs();

如何调用 package.json 配置调用命令

"scripts": {

"getPages": "node getPages.js"

},