如何自己在小程序内做埋点数据统计

小程序后台已经有了较为完善的数据统计和基础的分析,但是功能还是比较基础的,通常我们对数据分析有较高的要求时,就需要自己做数据收集了。那小程序内如何做自动的数据埋点和手动埋点呢。

自动埋点
启动时间 (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
})
}

// 手动埋点的部分,自己在需要收集的地方调用相关方法收集数据

# 回答此问题

后才能回答