如何在自己小程序内做数据埋点
小程序后台已经有了较为完善的数据统计和基础的分析,但是功能还是比较基础的,通常我们对数据分析有较高的要求时,就需要自己做数据收集了。那小程序内如何做自动的数据埋点和手动埋点呢。
自动埋点
- 启动时间 (onLaunch)
- 系统信息 (systemInfo)
- 停留时长 (Page onHide - Page onShow)
- 来源 (query 参数)
- PV (Page onShow)
- UV (结合用户筛选PV)
- 预设点击数据收集 (onTap 等)
手动埋点
- 自定义点击收集数据
改造小程序生命周期
自动埋点是需要集成到底层内,不能对业务进行侵入,所以,我们需要改造小程序生命周期,在不同的生命周期内进行预设收集数据的功能。
- 对
App
进行重写
const oldApp = App;
// 我们需要重写的方法
const appFn = ['onLaunch', 'onShow', 'onHide'];
App = function (options) {
let oldFuncs = {};
appFn.forEach((item) => {
oldFuncs[item] = options[item]
})
appFn.forEach((item) => {
options[item] = function (options) {
// todo 做各类数据收集
oldFuncs[item].apply(this, arguments)
}
})
oldApp.apply(this, arguments);
};
- 对
Page
重写
const oldPage = Page;
const pageFn = ['onLoad', 'onShow', 'onHide', 'onUnload', 'onShareAppMessage', 'onAddToFavorites']
Page = function (options) {
let oldFuncs = {};
pageFn.forEach((item) => {
if (options[item]) {
oldFuncs[item] = options[item]
}
})
pageFn.forEach((item) => {
if (options[item]) {
options[item] = function () {
console.log('Page', item, ); // 收集各类数据
oldFuncs[item].apply(this, arguments)
}
}
})
// 以下代码则是对除生命周期类的方法进行重写,做预设点击事件收集数据
const methods = getMethods(options);
if (!!methods) {
for (var i = 0, len = methods.length; i < len; i++) {
clickProxy(options, methods[i]);
}
}
oldPage.apply(this, arguments);
}
- 对
Component
重写
const oldComponent = Component;
Component = function (options) {
// 对组建内 methods 进行重写预设点击事件埋点收集
Object.keys(options.methods).forEach((method) => {
clickProxy(options.methods, method)
})
oldComponent.apply(this, arguments);
}
以上对 App
Page
Component
进行重写之后,在必要的地方,加入自己的上报代码.
以下完整代码
const mpHook = {
data: 1,
onLoad: 1,
onShow: 1,
onReady: 1,
onPullDownRefresh: 1,
onReachBottom: 1,
onShareAppMessage: 1,
onPageScroll: 1,
onResize: 1,
onTabItemTap: 1,
onHide: 1,
onUnload: 1,
};
const oldApp = App;
const oldPage = Page;
const oldComponent = Component;
const appFn = ['onLaunch', 'onShow', 'onHide']
App = function (options) {
let oldFuncs = {};
appFn.forEach((item) => {
oldFuncs[item] = options[item]
})
appFn.forEach((item) => {
options[item] = function (options) {
console.log('App', item); // 收集各类数据
oldFuncs[item].apply(this, arguments)
}
})
oldApp.apply(this, arguments);
};
const pageFn = ['onLoad', 'onShow', 'onHide', 'onUnload', 'onShareAppMessage', 'onAddToFavorites']
Page = function (options) {
let oldFuncs = {};
pageFn.forEach((item) => {
if (options[item]) {
oldFuncs[item] = options[item]
}
})
pageFn.forEach((item) => {
if (options[item]) {
options[item] = function () {
console.log('Page', item, ); // 收集各类数据
oldFuncs[item].apply(this, arguments)
}
}
})
const methods = getMethods(options);
if (!!methods) {
for (var i = 0, len = methods.length; i < len; i++) {
clickProxy(options, methods[i]);
}
}
oldPage.apply(this, arguments);
}
Component = function (options) {
Object.keys(options.methods).forEach((method) => {
clickProxy(options.methods, method)
})
oldComponent.apply(this, arguments);
}
function clickProxy(options, method) {
const oldFunc = options[method];
options[method] = function () {
const pages = getCurrentPages();
const currentPage = pages[pages.length - 1];
const pageQuery = currentPage.options || {};
const pagePath = currentPage.route;
const res = oldFunc.apply(this, arguments);
let prop = {},
type = "";
if (isObject(arguments[0])) {
const current_target = arguments[0].currentTarget || {};
const dataset = current_target.dataset || {};
type = arguments[0]["type"];
prop["$event_type"] = type;
prop["$event_timestamp"] = Date.now();
prop["$element_id"] = current_target.id;
prop["$element_type"] = dataset["type"];
prop["$element_content"] = dataset["content"];
prop["$element_name"] = dataset["name"];
prop["$page_path"] = pagePath;
prop["$page_quey"] = pageQuery;
if (isObject(arguments[0].event_prop)) {
prop = Object.assign(prop, arguments[0].event_prop);
}
}
console.log('type', type)
if (type) { // 可以对不同事件类型进行筛选是否需要收集
post(prop)
}
console.log(res);
return res;
};
}
const getMethods = function (options) {
let methods = [];
for (let m in options) {
if (typeof options[m] === "function" && !mpHook[m]) {
methods.push(m);
}
}
return methods;
};
const isObject = function (obj) {
if (obj === undefined || obj === null) {
return false;
} else {
return toString.call(obj) == "[object Object]";
}
};
const post = function (data) {
console.log('data', data)
// 提交数据时,可以在组合下 systeminfo 用户信息等相关信息
wx.request({
url: 'https://www.example.php',
method: 'post',
data
})
}
// 手动埋点的部分,自己在需要收集的地方调用相关方法收集数据
Component重写后,自定义组件里的点击事件可以上报了。但是Page页面里的的view的点击事件怎么办呢?没有处理吗?
怎么使用这个埋点方法呢,
支持对小程序直播互动行为做监测吗