@dcloudio/uni-stat 2.0.2-5000720260410001 → 2.0.2-5010520260709001
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/uni-cloud-stat.cjs.js +482 -58
- package/dist/uni-cloud-stat.es.js +482 -58
- package/dist/uni-stat-public.cjs.js +6765 -0
- package/dist/uni-stat-public.es.js +6760 -0
- package/dist/uni-stat.cjs.js +476 -55
- package/dist/uni-stat.es.js +476 -55
- package/package.json +2 -2
|
@@ -1,9 +1,18 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
|
-
*
|
|
4
|
+
* 老版本兼容,系统信息
|
|
5
5
|
*/
|
|
6
|
-
const sys = uni.getSystemInfoSync();
|
|
6
|
+
const sys = uni.getSystemInfoSync();
|
|
7
|
+
// /**
|
|
8
|
+
// * app基础信息
|
|
9
|
+
// */
|
|
10
|
+
// export const baseInfo = uni.getAppBaseInfo()
|
|
11
|
+
|
|
12
|
+
// /**
|
|
13
|
+
// * 设备相关
|
|
14
|
+
// */
|
|
15
|
+
// export const deviceInfo = uni.getDeviceInfo()
|
|
7
16
|
|
|
8
17
|
// 访问开始即启动小程序,访问结束结分为:进入后台超过5min、在前台无任何操作超过30min、在新的来源打开小程序;
|
|
9
18
|
const STAT_VERSION = process.env.UNI_COMPILER_VERSION;
|
|
@@ -14,6 +23,409 @@ const APP_PVER_TIME = 300; // 应用在后台结束访问时间 单位s
|
|
|
14
23
|
const OPERATING_TIME = 10; // 数据上报时间 单位s
|
|
15
24
|
const DIFF_TIME = 60 * 1000 * 60 * 24;
|
|
16
25
|
|
|
26
|
+
/**
|
|
27
|
+
* 事件类型与会话创建类型常量。
|
|
28
|
+
*
|
|
29
|
+
* 与私有版 / 文档 `uni统计上报参数.md` 的兼容关系:
|
|
30
|
+
* - 上行参数文档明确:`lt` 仅取 `1 / 3 / 11 / 21 / 31 / 41`,**没有** `lt=0`。
|
|
31
|
+
* - 历史架构文档(03-公有版架构设计.md §3.2)曾设计 `lt=0` 作为"客户端 session 边界"事件,
|
|
32
|
+
* 但与服务端入库口径不一致(会话日志 = lt=1),已**整体移除**:
|
|
33
|
+
* 新会话直接发一条 lt=1,会话字段(`sid / cst / fvts / lvts / tvc`)随 lt=1 上行。
|
|
34
|
+
* - 因此 `LT` 不再包含 `Session`;删除 lt=0 不影响老接收端。
|
|
35
|
+
*/
|
|
36
|
+
/**
|
|
37
|
+
* Log Type(事件类型)。统一在此声明,禁止其他模块裸写字符串。
|
|
38
|
+
*
|
|
39
|
+
* 注:`lt=41`(uni-app x 原生崩溃日志)暂未在公有版实现,详见 `docs/暂未实现字段说明.md`。
|
|
40
|
+
*/
|
|
41
|
+
const LT = {
|
|
42
|
+
Launch: '1',
|
|
43
|
+
Hide: '3',
|
|
44
|
+
Page: '11',
|
|
45
|
+
Event: '21',
|
|
46
|
+
Error: '31',
|
|
47
|
+
Push: '101',
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
/******************************************************************************
|
|
51
|
+
Copyright (c) Microsoft Corporation.
|
|
52
|
+
|
|
53
|
+
Permission to use, copy, modify, and/or distribute this software for any
|
|
54
|
+
purpose with or without fee is hereby granted.
|
|
55
|
+
|
|
56
|
+
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
|
57
|
+
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
|
58
|
+
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
|
59
|
+
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
|
60
|
+
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
|
61
|
+
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
|
62
|
+
PERFORMANCE OF THIS SOFTWARE.
|
|
63
|
+
***************************************************************************** */
|
|
64
|
+
/* global Reflect, Promise, SuppressedError, Symbol, Iterator */
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
|
|
68
|
+
var e = new Error(message);
|
|
69
|
+
return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* 安全工具集:序列化、try 包裹、指数退避重试。
|
|
74
|
+
*
|
|
75
|
+
* 修复缺陷:
|
|
76
|
+
* - #1 `_retry` 未初始化导致重试链路 NaN(公有版直接以参数显式传 `times`)。
|
|
77
|
+
* - #7 取值反向(私有版 `if (data.length > MAX_LENGTH)` 误判)。
|
|
78
|
+
* - #8 循环引用导致 `JSON.stringify` 抛错(用 WeakSet replacer 兜底)。
|
|
79
|
+
*/
|
|
80
|
+
const DEFAULT_MAX_LENGTH = 4096;
|
|
81
|
+
const TRUNCATED_SUFFIX = '…[truncated]';
|
|
82
|
+
/**
|
|
83
|
+
* 序列化任意值为字符串:支持循环引用与最大长度截断。
|
|
84
|
+
*
|
|
85
|
+
* @param value 待序列化的值。`undefined` 返回 '';string 直接返回(仍参与截断)。
|
|
86
|
+
* @param max 字符串最大长度,默认 4096;超长会截断并附 `…[truncated]`。
|
|
87
|
+
*/
|
|
88
|
+
function safeStringify(value, max = DEFAULT_MAX_LENGTH) {
|
|
89
|
+
var _a;
|
|
90
|
+
if (value === undefined)
|
|
91
|
+
return '';
|
|
92
|
+
let raw;
|
|
93
|
+
if (typeof value === 'string') {
|
|
94
|
+
raw = value;
|
|
95
|
+
}
|
|
96
|
+
else {
|
|
97
|
+
const seen = new WeakSet();
|
|
98
|
+
try {
|
|
99
|
+
raw =
|
|
100
|
+
(_a = JSON.stringify(value, (_key, val) => {
|
|
101
|
+
if (typeof val === 'object' && val !== null) {
|
|
102
|
+
if (seen.has(val))
|
|
103
|
+
return '[Circular]';
|
|
104
|
+
seen.add(val);
|
|
105
|
+
}
|
|
106
|
+
if (typeof val === 'bigint')
|
|
107
|
+
return val.toString();
|
|
108
|
+
if (typeof val === 'function')
|
|
109
|
+
return `[Function ${val.name || 'anonymous'}]`;
|
|
110
|
+
return val;
|
|
111
|
+
})) !== null && _a !== void 0 ? _a : '';
|
|
112
|
+
}
|
|
113
|
+
catch (e) {
|
|
114
|
+
raw = `[Unserializable: ${e.message}]`;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
if (raw.length > max) {
|
|
118
|
+
return (raw.slice(0, Math.max(0, max - TRUNCATED_SUFFIX.length)) +
|
|
119
|
+
TRUNCATED_SUFFIX);
|
|
120
|
+
}
|
|
121
|
+
return raw;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* 解析 uni-app 运行时根对象 `uni`。
|
|
126
|
+
*
|
|
127
|
+
* - H5 / App:常见为 `globalThis.uni`。
|
|
128
|
+
* - 微信小程序等:多为 Vite/rollup 向**当前模块**注入的标识符 `uni`,
|
|
129
|
+
* **未必**同步挂到 `globalThis`;仅读 `globalThis.uni` 会导致
|
|
130
|
+
* `bindLifecycle` / `uni.request` / storage 等全部静默失败。
|
|
131
|
+
* - 支付宝等旧版小程序:**无 `globalThis` 标识符**,须用 `getGlobalObject()` 兜底。
|
|
132
|
+
* - H5 发行摇树:`pages.json.js` 会先把 `window.uni = {}` 占位;若仍按「有 object 即用」
|
|
133
|
+
* 会误把空桩当真 uni。须用 `isUsableUniRuntime` 过滤后再择源。
|
|
134
|
+
*
|
|
135
|
+
* 第二路依赖宿主构建对 `uni` 的注入(与业务页面同一套解析规则),
|
|
136
|
+
* 类型兜底见 `packages/uni-stat/src/uni-global.d.ts`。
|
|
137
|
+
*/
|
|
138
|
+
/**
|
|
139
|
+
* 判断候选 `uni` 是否具备统计 SDK 可用的最小 API 集合(排除 H5 摇树空桩 `{}`)。
|
|
140
|
+
*
|
|
141
|
+
* 任一核心 API 存在即视为可用;与具体平台无关,微信/QQ/抖音/支付宝/百度等
|
|
142
|
+
* 完整 runtime 均满足,仅「占位空对象」会被过滤。
|
|
143
|
+
*/
|
|
144
|
+
/**
|
|
145
|
+
* H5 兜底:在 `globalThis` / `self` 不可用时尝试读取 `window`。
|
|
146
|
+
*
|
|
147
|
+
* 通过 `Function` 间接访问,避免 ESLint `no-restricted-globals` 对 `window` 标识符的限制;
|
|
148
|
+
* 小程序等环境执行失败时返回 `undefined`。
|
|
149
|
+
*/
|
|
150
|
+
function getWindowObject() {
|
|
151
|
+
try {
|
|
152
|
+
const w = Function('return typeof window !== "undefined" ? window : undefined')();
|
|
153
|
+
return w != null ? w : undefined;
|
|
154
|
+
}
|
|
155
|
+
catch (_a) {
|
|
156
|
+
return undefined;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* 安全获取全局对象。
|
|
161
|
+
*
|
|
162
|
+
* 支付宝 / 部分旧版小程序运行时未提供 `globalThis`,直接写 `globalThis` 会
|
|
163
|
+
* `ReferenceError: globalThis is not defined`,导致 install 阶段整包崩溃。
|
|
164
|
+
*/
|
|
165
|
+
function getGlobalObject() {
|
|
166
|
+
if (typeof globalThis !== 'undefined' && globalThis != null) {
|
|
167
|
+
return globalThis;
|
|
168
|
+
}
|
|
169
|
+
if (typeof global !== 'undefined' && global != null) {
|
|
170
|
+
return global;
|
|
171
|
+
}
|
|
172
|
+
if (typeof self !== 'undefined' && self != null) {
|
|
173
|
+
return self;
|
|
174
|
+
}
|
|
175
|
+
const win = getWindowObject();
|
|
176
|
+
if (win)
|
|
177
|
+
return win;
|
|
178
|
+
return {};
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* 公有版统一日志出口。
|
|
183
|
+
*
|
|
184
|
+
* 修复的私有版缺陷:
|
|
185
|
+
* - #19 `!!process.env.UNI_STAT_DEBUG` 在构建时若被替换为字符串 `"false"` 仍是 truthy。
|
|
186
|
+
* 公有版严格使用 `=== 'true'` 判定,并允许在运行时通过 `setDebug()` 临时打开
|
|
187
|
+
* (供调试 / 灰度小流量验证)。
|
|
188
|
+
*
|
|
189
|
+
* 行为约定:
|
|
190
|
+
* - `debug` 受调试开关控制;其他 level 始终输出到对应的 `console.*`。
|
|
191
|
+
* - **Android / iOS 真机**:`TAG` 与正文拼成单条字符串,避免桥接丢弃第二参起。
|
|
192
|
+
* - **其它平台**:`console.*(TAG, ...args)`,对象保持原生传递。
|
|
193
|
+
*
|
|
194
|
+
* 兼容性:
|
|
195
|
+
* - 历史版本插件 define 误把 `process.env.UNI_STAT_DEBUG` 替换成布尔字面量
|
|
196
|
+
* (未 `JSON.stringify`),导致 dist 运行时该值为 `true`/`false` 而非 `'true'`/`'false'`。
|
|
197
|
+
* `isDebug()` 同时接受字符串 `'true'` 与布尔字面量 `true`,避免历史构建产物完全失效。
|
|
198
|
+
*/
|
|
199
|
+
const TAG = '[uni统计 2.0]';
|
|
200
|
+
let runtimeDebug;
|
|
201
|
+
/**
|
|
202
|
+
* 是否屏蔽 info / warn / error。
|
|
203
|
+
* `undefined`:自动——`NODE_ENV === 'test'` 时默认屏蔽,避免 Jest 用例预期失败路径刷屏。
|
|
204
|
+
*/
|
|
205
|
+
let muteNonDebug;
|
|
206
|
+
/**
|
|
207
|
+
* 是否将日志合并为单行(Android / iOS 真机侧)。
|
|
208
|
+
*/
|
|
209
|
+
function preferSingleLineConsole() {
|
|
210
|
+
return isAndroidOrIosRuntime();
|
|
211
|
+
}
|
|
212
|
+
/**
|
|
213
|
+
* 是否为 App 或小程序运行在 **Android / iOS** 上(仅此类环境对对象参数做字符串化)。
|
|
214
|
+
*/
|
|
215
|
+
function isAndroidOrIosRuntime() {
|
|
216
|
+
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
217
|
+
const raw = (_a = process.env.UNI_PLATFORM) !== null && _a !== void 0 ? _a : '';
|
|
218
|
+
const g = getGlobalObject();
|
|
219
|
+
if (raw === 'app' || raw === 'app-plus' || raw === 'app-harmony') {
|
|
220
|
+
const n = (_d = (_c = (_b = g.plus) === null || _b === void 0 ? void 0 : _b.os) === null || _c === void 0 ? void 0 : _c.name) === null || _d === void 0 ? void 0 : _d.toLowerCase();
|
|
221
|
+
if (!n)
|
|
222
|
+
return false;
|
|
223
|
+
if (n.includes('android'))
|
|
224
|
+
return true;
|
|
225
|
+
if (n === 'ios' || n.includes('iphone'))
|
|
226
|
+
return true;
|
|
227
|
+
return false;
|
|
228
|
+
}
|
|
229
|
+
if (raw.startsWith('mp-')) {
|
|
230
|
+
try {
|
|
231
|
+
const p = (_h = (_g = (_f = (_e = g.uni) === null || _e === void 0 ? void 0 : _e.getSystemInfoSync) === null || _f === void 0 ? void 0 : _f.call(_e)) === null || _g === void 0 ? void 0 : _g.platform) === null || _h === void 0 ? void 0 : _h.toLowerCase();
|
|
232
|
+
return p === 'android' || p === 'ios';
|
|
233
|
+
}
|
|
234
|
+
catch (_j) {
|
|
235
|
+
return false;
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
return false;
|
|
239
|
+
}
|
|
240
|
+
/**
|
|
241
|
+
* 在 Android/iOS 上将「对象类」参数转为可打印字符串;其余类型原样返回。
|
|
242
|
+
*/
|
|
243
|
+
function stringifyObjectArgForNative(value) {
|
|
244
|
+
if (value === null || value === undefined)
|
|
245
|
+
return value;
|
|
246
|
+
if (typeof value !== 'object')
|
|
247
|
+
return value;
|
|
248
|
+
if (value instanceof Error)
|
|
249
|
+
return `${value.name}: ${value.message}`;
|
|
250
|
+
return safeStringify(value);
|
|
251
|
+
}
|
|
252
|
+
/**
|
|
253
|
+
* 将单段日志参数格式化为可拼进一行文本的片段(Android/iOS 单参输出用)。
|
|
254
|
+
*/
|
|
255
|
+
function formatLogArgForNativeConsole(value) {
|
|
256
|
+
if (value === null)
|
|
257
|
+
return 'null';
|
|
258
|
+
if (value === undefined)
|
|
259
|
+
return 'undefined';
|
|
260
|
+
if (typeof value === 'string')
|
|
261
|
+
return value;
|
|
262
|
+
if (typeof value === 'number' || typeof value === 'boolean') {
|
|
263
|
+
return String(value);
|
|
264
|
+
}
|
|
265
|
+
if (typeof value === 'bigint')
|
|
266
|
+
return String(value);
|
|
267
|
+
if (typeof value === 'symbol') {
|
|
268
|
+
try {
|
|
269
|
+
return value.toString();
|
|
270
|
+
}
|
|
271
|
+
catch (_a) {
|
|
272
|
+
return '?';
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
if (typeof value === 'function') {
|
|
276
|
+
const fn = value;
|
|
277
|
+
return `[Function ${fn.name || 'anonymous'}]`;
|
|
278
|
+
}
|
|
279
|
+
if (typeof value === 'object') {
|
|
280
|
+
if (value instanceof Error)
|
|
281
|
+
return `${value.name}: ${value.message}`;
|
|
282
|
+
return safeStringify(value);
|
|
283
|
+
}
|
|
284
|
+
return String(value);
|
|
285
|
+
}
|
|
286
|
+
/**
|
|
287
|
+
* 当前是否应屏蔽 info / warn / error(debug 仍由 `isDebug()` 单独控制)。
|
|
288
|
+
*/
|
|
289
|
+
function isNonDebugMuted() {
|
|
290
|
+
if (muteNonDebug !== undefined)
|
|
291
|
+
return muteNonDebug;
|
|
292
|
+
return process.env.NODE_ENV === 'test';
|
|
293
|
+
}
|
|
294
|
+
/**
|
|
295
|
+
* 测试 / CI 下临时恢复 warn 等输出(如断言 install 告警文案)。
|
|
296
|
+
*
|
|
297
|
+
* @param value `true` 屏蔽;`false` 允许;`undefined` 恢复为按 NODE_ENV 自动判定。
|
|
298
|
+
*/
|
|
299
|
+
function setMuteNonDebug(value) {
|
|
300
|
+
muteNonDebug = value;
|
|
301
|
+
}
|
|
302
|
+
/**
|
|
303
|
+
* 输出到 console:Android/iOS 真机整行单参;其余平台 `TAG` + 多参。
|
|
304
|
+
*/
|
|
305
|
+
function emitConsole(method, args) {
|
|
306
|
+
if (method !== 'log' && isNonDebugMuted())
|
|
307
|
+
return;
|
|
308
|
+
const fn = console[method];
|
|
309
|
+
if (!preferSingleLineConsole()) {
|
|
310
|
+
fn.call(console, TAG, ...args);
|
|
311
|
+
return;
|
|
312
|
+
}
|
|
313
|
+
const mapped = isAndroidOrIosRuntime()
|
|
314
|
+
? args.map(stringifyObjectArgForNative)
|
|
315
|
+
: args;
|
|
316
|
+
if (mapped.length === 0) {
|
|
317
|
+
fn.call(console, TAG);
|
|
318
|
+
return;
|
|
319
|
+
}
|
|
320
|
+
const body = mapped.map(formatLogArgForNativeConsole).join(' ');
|
|
321
|
+
fn.call(console, `${TAG} ${body}`);
|
|
322
|
+
}
|
|
323
|
+
/**
|
|
324
|
+
* 当前是否启用 debug 输出。优先级:
|
|
325
|
+
* 1. `setDebug(value)` 显式设置过 → 直接返回。
|
|
326
|
+
* 2. `process.env.UNI_STAT_DEBUG === 'true'` 或被构建期替换为布尔字面量 `true`
|
|
327
|
+
* (历史插件兼容路径)。
|
|
328
|
+
*/
|
|
329
|
+
function isDebug() {
|
|
330
|
+
if (runtimeDebug !== undefined)
|
|
331
|
+
return runtimeDebug;
|
|
332
|
+
const v = process.env.UNI_STAT_DEBUG;
|
|
333
|
+
return v === 'true' || v === true;
|
|
334
|
+
}
|
|
335
|
+
/**
|
|
336
|
+
* 运行时切换 debug 开关;传 `undefined` 恢复为「按 process.env 判断」。
|
|
337
|
+
*/
|
|
338
|
+
function setDebug(value) {
|
|
339
|
+
runtimeDebug = value;
|
|
340
|
+
}
|
|
341
|
+
const logger = {
|
|
342
|
+
debug(...args) {
|
|
343
|
+
if (!isDebug())
|
|
344
|
+
return;
|
|
345
|
+
// eslint-disable-next-line no-console
|
|
346
|
+
emitConsole('log', args);
|
|
347
|
+
},
|
|
348
|
+
info(...args) {
|
|
349
|
+
// eslint-disable-next-line no-console
|
|
350
|
+
emitConsole('info', args);
|
|
351
|
+
},
|
|
352
|
+
warn(...args) {
|
|
353
|
+
// eslint-disable-next-line no-console
|
|
354
|
+
emitConsole('warn', args);
|
|
355
|
+
},
|
|
356
|
+
error(...args) {
|
|
357
|
+
// eslint-disable-next-line no-console
|
|
358
|
+
emitConsole('error', args);
|
|
359
|
+
},
|
|
360
|
+
setDebug,
|
|
361
|
+
isDebug,
|
|
362
|
+
setMuteNonDebug,
|
|
363
|
+
};
|
|
364
|
+
|
|
365
|
+
/**
|
|
366
|
+
* 公有版调试日志:面向业务方的"采集 / 上报"过程日志封装。
|
|
367
|
+
*
|
|
368
|
+
* 与 `logger.debug` 的差异:
|
|
369
|
+
* - `logger.debug` 是底层 console.log + 闸门;调用点散落,文案随意。
|
|
370
|
+
* - 本模块提供**统一文案 / 统一格式**的高层包装,覆盖:
|
|
371
|
+
* 1. 采集动作:每个 lt 都有中文动作名 +「采集 → 数据」标记。
|
|
372
|
+
* 2. 上报生命周期:开始 / 成功 / 失败 / 冷启续传。
|
|
373
|
+
* 3. 启动摘要:通道版本、上报间隔、ak 是否就位等。
|
|
374
|
+
* - 所有 helper 都内嵌 `logger.isDebug()` 判断;非 debug 模式下零开销,
|
|
375
|
+
* 调用方无需再写 `if (logger.isDebug()) ...`。
|
|
376
|
+
*
|
|
377
|
+
* 文案风格参考私有版 `utils/pageInfo.js#log`:直接面向业务调试,**中文**为主,
|
|
378
|
+
* 关键字段(lt / 通道 / 用时 / 错误原因)一目了然。
|
|
379
|
+
*
|
|
380
|
+
* 注意:不在此处吞错;任意 console.log 异常仍会冒泡。运行时调用方需要 `tryRun` 兜底
|
|
381
|
+
* 时自行处理(一般 console.log 不会抛错,故未做包装)。
|
|
382
|
+
*/
|
|
383
|
+
/**
|
|
384
|
+
* `lt` → 用户友好的中文动作名映射。
|
|
385
|
+
*
|
|
386
|
+
* 与私有版 `pageInfo.js#log` 的 msg_type 对齐。
|
|
387
|
+
* 注:`lt=0` 已废弃(详见 `domain/eventTypes.ts` 头注释),新会话信息直接随 lt=1 上行。
|
|
388
|
+
*
|
|
389
|
+
* 未知 lt 走默认 "未知事件 (lt=X)",便于排查异常上行。
|
|
390
|
+
*/
|
|
391
|
+
function getActionLabel(lt) {
|
|
392
|
+
switch (lt) {
|
|
393
|
+
case LT.Launch:
|
|
394
|
+
return '应用启动';
|
|
395
|
+
case LT.Hide:
|
|
396
|
+
return '应用进入后台';
|
|
397
|
+
case LT.Page:
|
|
398
|
+
return '页面切换';
|
|
399
|
+
case LT.Event:
|
|
400
|
+
return '事件触发';
|
|
401
|
+
case LT.Error:
|
|
402
|
+
return '应用错误';
|
|
403
|
+
case LT.Push:
|
|
404
|
+
return 'PUSH 设备标识';
|
|
405
|
+
default:
|
|
406
|
+
return `未知事件 (lt=${String(lt !== null && lt !== void 0 ? lt : '?')})`;
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
/**
|
|
410
|
+
* 单次事件采集日志。
|
|
411
|
+
*
|
|
412
|
+
* 文案示意:
|
|
413
|
+
* ```text
|
|
414
|
+
* [uni统计 2.0] === 统计数据采集:应用启动 (lt=1) ===
|
|
415
|
+
* [uni统计 2.0] {lt: '1', t: 1714123456, ut: 'h5', ...}
|
|
416
|
+
* [uni统计 2.0] === 采集结束 ===
|
|
417
|
+
* ```
|
|
418
|
+
*/
|
|
419
|
+
function logCollect(data) {
|
|
420
|
+
if (!logger.isDebug())
|
|
421
|
+
return;
|
|
422
|
+
const lt = data.lt;
|
|
423
|
+
const label = getActionLabel(lt);
|
|
424
|
+
logger.debug(`=== 统计数据采集:${label} (lt=${String(lt !== null && lt !== void 0 ? lt : '?')}) ===`);
|
|
425
|
+
logger.debug(data);
|
|
426
|
+
logger.debug('=== 采集结束 ===');
|
|
427
|
+
}
|
|
428
|
+
|
|
17
429
|
const appid = process.env.UNI_APP_ID; // 做应用隔离
|
|
18
430
|
const dbSet = (name, value) => {
|
|
19
431
|
let data = uni.getStorageSync('$$STAT__DBDATA:'+appid) || {};
|
|
@@ -60,7 +472,9 @@ let statConfig = {
|
|
|
60
472
|
appid: process.env.UNI_APP_ID,
|
|
61
473
|
};
|
|
62
474
|
let titleJsons = {};
|
|
63
|
-
let debug =
|
|
475
|
+
let debug =
|
|
476
|
+
process.env.UNI_STAT_DEBUG === 'true' ||
|
|
477
|
+
process.env.UNI_STAT_DEBUG === true;
|
|
64
478
|
// #ifdef VUE3
|
|
65
479
|
titleJsons = process.env.UNI_STAT_TITLE_JSON;
|
|
66
480
|
// #endif
|
|
@@ -190,6 +604,8 @@ const get_platform_name = () => {
|
|
|
190
604
|
const platformList = {
|
|
191
605
|
app: 'n',
|
|
192
606
|
'app-plus': 'n',
|
|
607
|
+
'app-harmony':'n',
|
|
608
|
+
'mp-harmony':'mhm',
|
|
193
609
|
h5: 'h5',
|
|
194
610
|
'mp-weixin': 'wx',
|
|
195
611
|
[aliArr.reverse().join('')]: 'ali',
|
|
@@ -200,6 +616,7 @@ const get_platform_name = () => {
|
|
|
200
616
|
'mp-kuaishou': 'ks',
|
|
201
617
|
'mp-lark': 'lark',
|
|
202
618
|
'quickapp-webview': 'qw',
|
|
619
|
+
'mp-xhs': 'xhs'
|
|
203
620
|
};
|
|
204
621
|
if (platformList[process.env.VUE_APP_PLATFORM] === 'ali') {
|
|
205
622
|
if (my && my.env) {
|
|
@@ -209,7 +626,7 @@ const get_platform_name = () => {
|
|
|
209
626
|
// TODO 缺少 ali 下的其他平台
|
|
210
627
|
}
|
|
211
628
|
}
|
|
212
|
-
return platformList[process.env.VUE_APP_PLATFORM]
|
|
629
|
+
return platformList[process.env.VUE_APP_PLATFORM] || process.env.VUE_APP_PLATFORM
|
|
213
630
|
};
|
|
214
631
|
|
|
215
632
|
/**
|
|
@@ -265,7 +682,7 @@ const get_scene = (options) => {
|
|
|
265
682
|
/**
|
|
266
683
|
* 获取页面url,不包含参数
|
|
267
684
|
*/
|
|
268
|
-
const get_route
|
|
685
|
+
const get_route = (pageVm) => {
|
|
269
686
|
let _self = pageVm || get_page_vm();
|
|
270
687
|
if (get_platform_name() === 'bd') {
|
|
271
688
|
let mp_route = _self.$mp && _self.$mp.page && _self.$mp.page.is;
|
|
@@ -506,13 +923,16 @@ const uni_cloud_config = () => {
|
|
|
506
923
|
const get_space = (config) => {
|
|
507
924
|
const uniCloudConfig = uni_cloud_config();
|
|
508
925
|
const { spaceId, provider, clientSecret ,secretKey,secretId} = uniCloudConfig;
|
|
509
|
-
const space_type = ['tcb', 'tencent', 'aliyun','alipay'];
|
|
926
|
+
const space_type = ['tcb', 'tencent', 'aliyun','alipay','private','dcloud'];
|
|
510
927
|
const is_provider = space_type.indexOf(provider) !== -1;
|
|
511
928
|
const is_aliyun = provider === 'aliyun' && spaceId && clientSecret;
|
|
512
929
|
const is_tcb = (provider === 'tcb' || provider === 'tencent') && spaceId;
|
|
513
930
|
const is_alipay = provider === 'alipay' && spaceId && secretKey && secretId;
|
|
514
931
|
|
|
515
|
-
|
|
932
|
+
const is_private = provider === 'private' && spaceId && clientSecret;
|
|
933
|
+
const is_dcloud = provider === 'dcloud' && spaceId && clientSecret;
|
|
934
|
+
|
|
935
|
+
if (is_provider && (is_aliyun || is_tcb || is_alipay || is_private || is_dcloud)) {
|
|
516
936
|
return uniCloudConfig
|
|
517
937
|
} else {
|
|
518
938
|
if (config && config.spaceId) {
|
|
@@ -529,52 +949,18 @@ const get_space = (config) => {
|
|
|
529
949
|
const is_debug = debug;
|
|
530
950
|
|
|
531
951
|
/**
|
|
532
|
-
*
|
|
533
|
-
* @param {*} data
|
|
952
|
+
* 日志输出(采集 / 上报过程日志,文案与公有版 `debugLog` 对齐)。
|
|
953
|
+
* @param {*} data 采集事件或上报 payload
|
|
954
|
+
* @param {*} type 为真时表示上报阶段
|
|
534
955
|
*/
|
|
535
956
|
const log = (data, type) => {
|
|
536
|
-
|
|
537
|
-
switch (data.lt) {
|
|
538
|
-
case '1':
|
|
539
|
-
msg_type = '应用启动';
|
|
540
|
-
break
|
|
541
|
-
case '3':
|
|
542
|
-
msg_type = '应用进入后台';
|
|
543
|
-
break
|
|
544
|
-
|
|
545
|
-
case '11':
|
|
546
|
-
msg_type = '页面切换';
|
|
547
|
-
break
|
|
548
|
-
case '21':
|
|
549
|
-
msg_type = '事件触发';
|
|
550
|
-
break
|
|
551
|
-
case '31':
|
|
552
|
-
msg_type = '应用错误';
|
|
553
|
-
break
|
|
554
|
-
case '101':
|
|
555
|
-
msg_type = 'PUSH';
|
|
556
|
-
break
|
|
557
|
-
}
|
|
558
|
-
|
|
559
|
-
// #ifdef APP
|
|
560
|
-
// 在 app 中,日志转为 字符串
|
|
561
|
-
if (typeof data === 'object') {
|
|
562
|
-
data = JSON.stringify(data);
|
|
563
|
-
}
|
|
564
|
-
// #endif
|
|
565
|
-
|
|
957
|
+
if (!logger.isDebug()) return
|
|
566
958
|
if (type) {
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
console.log(`=== 上报结束 ===`);
|
|
959
|
+
logger.debug('=== 准备上报 ===');
|
|
960
|
+
logger.debug(data);
|
|
570
961
|
return
|
|
571
962
|
}
|
|
572
|
-
|
|
573
|
-
if (msg_type) {
|
|
574
|
-
console.log(`=== 统计数据采集:${msg_type} ===`);
|
|
575
|
-
console.log(data);
|
|
576
|
-
console.log(`=== 采集结束 ===`);
|
|
577
|
-
}
|
|
963
|
+
logCollect(data);
|
|
578
964
|
};
|
|
579
965
|
|
|
580
966
|
/**
|
|
@@ -762,11 +1148,12 @@ const get_residence_time = (type) => {
|
|
|
762
1148
|
};
|
|
763
1149
|
|
|
764
1150
|
const eport_Interval = get_report_Interval(OPERATING_TIME);
|
|
1151
|
+
|
|
765
1152
|
// 统计数据默认值
|
|
766
1153
|
let statData = {
|
|
767
1154
|
uuid: get_uuid(), // 设备标识
|
|
768
1155
|
ak: stat_config.appid, // uni-app 应用 Appid
|
|
769
|
-
p:
|
|
1156
|
+
p: '', // 手机系统,客户端平台
|
|
770
1157
|
ut: get_platform_name(), // 平台类型
|
|
771
1158
|
mpn: get_pack_name(), // 原生平台包名、小程序 appid
|
|
772
1159
|
usv: STAT_VERSION, // 统计 sdk 版本
|
|
@@ -779,7 +1166,7 @@ let statData = {
|
|
|
779
1166
|
tt: '',
|
|
780
1167
|
brand: sys.brand || '', // 手机品牌
|
|
781
1168
|
md: sys.model, // 手机型号
|
|
782
|
-
sv:
|
|
1169
|
+
sv: '', // 手机系统版本
|
|
783
1170
|
mpsdk: sys.SDKVersion || '', // x程序 sdk version
|
|
784
1171
|
mpv: sys.version || '', // 小程序平台版本 ,如微信、支付宝
|
|
785
1172
|
lang: sys.language, // 语言
|
|
@@ -789,6 +1176,26 @@ let statData = {
|
|
|
789
1176
|
sw: sys.screenWidth, // screenWidth 屏幕宽度
|
|
790
1177
|
sh: sys.screenHeight, // screenHeight 屏幕高度
|
|
791
1178
|
};
|
|
1179
|
+
|
|
1180
|
+
// 客户端平台,只有app平台平台可以用到
|
|
1181
|
+
if(sys.platform){
|
|
1182
|
+
switch (sys.platform) {
|
|
1183
|
+
case 'android':
|
|
1184
|
+
statData.p = 'a';
|
|
1185
|
+
break
|
|
1186
|
+
case 'ios':
|
|
1187
|
+
statData.p = 'i';
|
|
1188
|
+
break
|
|
1189
|
+
case 'harmonyos':
|
|
1190
|
+
statData.p = 'h';
|
|
1191
|
+
break
|
|
1192
|
+
}
|
|
1193
|
+
}
|
|
1194
|
+
|
|
1195
|
+
// 获取手机版本
|
|
1196
|
+
if (sys.system){
|
|
1197
|
+
statData.sv = sys.system.replace(/(Android|iOS)\s/, '');
|
|
1198
|
+
}
|
|
792
1199
|
class Report {
|
|
793
1200
|
constructor() {
|
|
794
1201
|
// 页面实例
|
|
@@ -910,6 +1317,19 @@ class Report {
|
|
|
910
1317
|
cst: 2,
|
|
911
1318
|
};
|
|
912
1319
|
this.sendReportRequest(options);
|
|
1320
|
+
} else {
|
|
1321
|
+
// 在没有超过时限的时候 ,判断场景值 ,如果是场景值发生了变化,则需要上报应用启动数据
|
|
1322
|
+
// 目前只有微信小程序生效
|
|
1323
|
+
const scene = get_scene();
|
|
1324
|
+
if (scene !== this.statData.sc) {
|
|
1325
|
+
let lastPageRoute = uni.getStorageSync('_STAT_LAST_PAGE_ROUTE');
|
|
1326
|
+
let options = {
|
|
1327
|
+
path: lastPageRoute,
|
|
1328
|
+
scene: scene,
|
|
1329
|
+
cst: 2,
|
|
1330
|
+
};
|
|
1331
|
+
this.sendReportRequest(options);
|
|
1332
|
+
}
|
|
913
1333
|
}
|
|
914
1334
|
// 状态重置
|
|
915
1335
|
this.__licationHide = false;
|
|
@@ -955,7 +1375,7 @@ class Report {
|
|
|
955
1375
|
};
|
|
956
1376
|
|
|
957
1377
|
const route = get_page_route(self);
|
|
958
|
-
const routepath = get_route
|
|
1378
|
+
const routepath = get_route(self);
|
|
959
1379
|
|
|
960
1380
|
this._navigationBarTitle.config = get_page_name(routepath);
|
|
961
1381
|
// 表示应用触发 ,页面切换不触发之后的逻辑
|
|
@@ -1016,14 +1436,14 @@ class Report {
|
|
|
1016
1436
|
let query = is_opt ? '?' + JSON.stringify(options.query) : '';
|
|
1017
1437
|
const last_time = get_last_visit_time();
|
|
1018
1438
|
// 非老用户
|
|
1019
|
-
if(last_time !== 0 || !last_time){
|
|
1439
|
+
if (last_time !== 0 || !last_time) {
|
|
1020
1440
|
const odid = get_odid();
|
|
1021
1441
|
|
|
1022
1442
|
// 2.0 处理规则
|
|
1023
1443
|
{
|
|
1024
1444
|
const have_device = is_handle_device();
|
|
1025
1445
|
// 如果没有上报过设备信息 ,则需要上报设备信息
|
|
1026
|
-
if(!have_device) {
|
|
1446
|
+
if (!have_device) {
|
|
1027
1447
|
this.statData.odid = odid;
|
|
1028
1448
|
}
|
|
1029
1449
|
}
|
|
@@ -1100,7 +1520,7 @@ class Report {
|
|
|
1100
1520
|
let routepath = '';
|
|
1101
1521
|
|
|
1102
1522
|
try {
|
|
1103
|
-
routepath = get_route
|
|
1523
|
+
routepath = get_route();
|
|
1104
1524
|
} catch (error) {
|
|
1105
1525
|
const launch_options = dbGet('__launch_options');
|
|
1106
1526
|
routepath = launch_options.path;
|
|
@@ -1511,9 +1931,8 @@ class Stat extends Report {
|
|
|
1511
1931
|
this.request(options);
|
|
1512
1932
|
}
|
|
1513
1933
|
}
|
|
1514
|
-
var Stat$1 = Stat;
|
|
1515
1934
|
|
|
1516
|
-
const stat = Stat
|
|
1935
|
+
const stat = Stat.getInstance();
|
|
1517
1936
|
|
|
1518
1937
|
// 用于判断是隐藏页面还是卸载页面
|
|
1519
1938
|
let isHide = false;
|
|
@@ -1552,7 +1971,12 @@ const lifecycle = {
|
|
|
1552
1971
|
stat.hide(this);
|
|
1553
1972
|
},
|
|
1554
1973
|
onError(e) {
|
|
1555
|
-
|
|
1974
|
+
// fix by haotian 避免统计内部错误导致堆栈溢出,造成死循环
|
|
1975
|
+
try {
|
|
1976
|
+
stat.error(e);
|
|
1977
|
+
} catch (error) {
|
|
1978
|
+
console.error('uni-stat error:', error);
|
|
1979
|
+
}
|
|
1556
1980
|
},
|
|
1557
1981
|
};
|
|
1558
1982
|
|
|
@@ -1590,7 +2014,7 @@ function main() {
|
|
|
1590
2014
|
if (is_debug) {
|
|
1591
2015
|
{
|
|
1592
2016
|
// #ifndef APP-NVUE
|
|
1593
|
-
|
|
2017
|
+
logger.debug('=== uni统计 2.0(私有版)已启用 ===');
|
|
1594
2018
|
// #endif
|
|
1595
2019
|
}
|
|
1596
2020
|
load_stat();
|