gio-miniprogram-sdk 4.0.0 → 4.1.0

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.
Files changed (78) hide show
  1. package/dist/alipay.js +1 -1
  2. package/dist/baidu.js +1 -1
  3. package/dist/bytedance.js +1 -1
  4. package/dist/jingdong.js +1 -1
  5. package/dist/kuaishou.js +1 -1
  6. package/dist/plugins/gioABTest.js +1 -1
  7. package/dist/plugins/gioCompress.js +1 -1
  8. package/dist/plugins/gioEventAutoTracking.js +1 -1
  9. package/dist/plugins/gioImpressionTracking.js +1 -1
  10. package/dist/plugins/gioMultipleInstances.js +1 -0
  11. package/dist/qq.js +1 -1
  12. package/dist/quickapp.js +1 -1
  13. package/dist/taobao.js +1 -1
  14. package/dist/taro.js +1 -1
  15. package/dist/uniapp.js +1 -1
  16. package/dist/wechat.js +1 -1
  17. package/package.json +39 -42
  18. package/rollup.config.js +11 -6
  19. package/rollup.plugins.config.js +13 -10
  20. package/src/{pluginsOut/frameworks → adapters}/gioTaobaoAdapter.ts +47 -44
  21. package/src/adapters/gioTaroAdapter.ts +459 -0
  22. package/src/{pluginsOut/frameworks → adapters}/gioUniAppAdapter.ts +35 -6
  23. package/src/constants/config.ts +49 -20
  24. package/src/constants/emitMsg.ts +23 -0
  25. package/src/constants/regex.ts +14 -0
  26. package/src/core/dataStore/eventContextBuilder.ts +28 -17
  27. package/src/core/dataStore/eventHooks/appEffects.ts +50 -31
  28. package/src/core/dataStore/eventHooks/index.ts +7 -5
  29. package/src/core/dataStore/eventHooks/minipPage.ts +2 -11
  30. package/src/core/dataStore/eventHooks/pageEffects.ts +61 -27
  31. package/src/core/dataStore/index.ts +266 -181
  32. package/src/core/growingIO.ts +312 -179
  33. package/src/core/pluginsInstance/base.ts +157 -0
  34. package/src/core/pluginsInstance/taro.ts +15 -0
  35. package/src/core/pluginsInstance/tb.ts +15 -0
  36. package/src/core/pluginsInstance/uniapp.ts +15 -0
  37. package/src/core/uploader.ts +131 -87
  38. package/src/core/userStore.ts +160 -121
  39. package/src/index.ts +37 -28
  40. package/src/minipInstance/base.ts +2 -1
  41. package/src/minipInstance/quickapp.ts +5 -19
  42. package/src/platformConfig/base.ts +0 -4
  43. package/src/{pluginsOut/ordinary → plugins}/gioABTest.ts +74 -37
  44. package/src/{pluginsOut/ordinary → plugins}/gioEventAutoTracking.ts +25 -18
  45. package/src/{pluginsOut/ordinary → plugins}/gioImpressionTracking.ts +109 -41
  46. package/src/plugins/gioMultipleInstances.ts +176 -0
  47. package/src/types/base.ts +12 -3
  48. package/src/types/dataStore.ts +31 -16
  49. package/src/types/eventHooks.ts +8 -9
  50. package/src/types/growingIO.ts +30 -14
  51. package/src/types/platforms.ts +0 -4
  52. package/src/types/plugins.ts +1 -1
  53. package/src/types/uploader.ts +16 -12
  54. package/src/types/userStore.ts +21 -17
  55. package/src/utils/glodash.ts +10 -3
  56. package/src/utils/tools.ts +27 -6
  57. package/src/utils/verifiers.ts +25 -50
  58. package/typings/global.d.ts +5 -0
  59. package/.babelrc +0 -4
  60. package/bin/build/full.sh +0 -32
  61. package/bin/build/jd.sh +0 -14
  62. package/bin/build/ks.sh +0 -14
  63. package/bin/build/my.sh +0 -14
  64. package/bin/build/plugins.sh +0 -5
  65. package/bin/build/qq.sh +0 -14
  66. package/bin/build/quickapp.sh +0 -14
  67. package/bin/build/swan.sh +0 -14
  68. package/bin/build/taro.sh +0 -18
  69. package/bin/build/tb.sh +0 -18
  70. package/bin/build/tt.sh +0 -14
  71. package/bin/build/uniapp.sh +0 -18
  72. package/bin/build/wx.sh +0 -14
  73. package/src/core/plugins.ts +0 -152
  74. package/src/pluginsOut/README.md +0 -50
  75. package/src/pluginsOut/frameworks/gioTaroAdapter.ts +0 -358
  76. package/src/pluginsOut/ordinary/gioCustomTracking.ts +0 -71
  77. package/bin/{build/all.sh → build.sh} +3 -3
  78. /package/src/{pluginsOut/ordinary → plugins}/gioCompress.ts +0 -0
@@ -12,12 +12,14 @@ import {
12
12
  callError,
13
13
  consoleText,
14
14
  eventNameValidate,
15
- getAppInst,
15
+ getDynamicAttributes,
16
+ getGlobal,
16
17
  getPlainPlatform,
17
18
  guid,
18
- limitObject
19
+ limitObject,
20
+ niceCallback
19
21
  } from '@@/utils/tools';
20
- import { ALLOWED_MODIFY_OPTIONS } from '@@/constants/config';
22
+ import { ALLOW_SET_OPTIONS, DEFAULT_SETTINGS } from '@@/constants/config';
21
23
  import { DataStoreType, OriginOptions } from '@@/types/dataStore';
22
24
  import { FRAMEWORKS, PLATFORMTYPES } from '@@/types/platforms';
23
25
  import { GrowingIOType } from '@@/types/growingIO';
@@ -32,10 +34,11 @@ import DataStore from './dataStore';
32
34
  import mitt from 'mitt';
33
35
  import platformConfig from '__GIO_PLATFORM_CONFIG__';
34
36
  import PlatformInstance from '__GIO_PLATFORM_INSTANCE__';
35
- import Plugins from '@@/core/plugins';
37
+ import Plugins from '__GIO_PLUGIN_INSTANCE__';
36
38
  import qs from 'querystringify';
37
39
  import Uploader from './uploader';
38
40
  import UserStore from '@@/core/userStore';
41
+ import EMIT_MSG from '@@/constants/emitMsg';
39
42
 
40
43
  // SDK全局参数 版本号、小程序平台、框架名称、运行环境 均由打包工具替换写入
41
44
  const sdkVersion: any = '__SDK_VERSION__';
@@ -58,7 +61,9 @@ class GrowingIO implements GrowingIOType {
58
61
  public dataStore: DataStoreType;
59
62
  public plugins: PluginsType;
60
63
  public uploader: UploaderType;
61
-
64
+ // 当前主SDK的trackingId,用于区分事件归属。
65
+ public trackingId: string;
66
+ public subInstance: any;
62
67
  constructor() {
63
68
  this.utils = { ...glodash, ...tools, qs };
64
69
  this.emitter = mitt();
@@ -94,84 +99,143 @@ class GrowingIO implements GrowingIOType {
94
99
  this.dataStore = new DataStore(this);
95
100
  // 用户实例
96
101
  this.userStore = new UserStore(this);
102
+ // 初始化请求逻辑
103
+ this.uploader = new Uploader(this);
97
104
  // 插件管理实例
98
105
  this.plugins = new Plugins(this);
99
106
  // 加载内置插件
100
107
  this.plugins.innerPluginInit();
101
- // 数据管理实例和上传实例均在各自环境中继承实现
102
108
  }
103
109
 
110
+ // SDK初始化方法
111
+ init = (options: any) => {
112
+ // 初始化实例之前
113
+ this.emitter.emit(EMIT_MSG.ON_SDK_INITIALIZE_BEFORE, { options });
114
+ try {
115
+ consoleText('Gio小程序SDK 初始化中...', 'info');
116
+ if (
117
+ options.trackingId &&
118
+ this.dataStore.initializedTrackingIds.includes(options.trackingId)
119
+ ) {
120
+ throw new Error(`已存在实例 ${options.trackingId},请勿重复初始化!`);
121
+ }
122
+ if (this.trackingId && !this.plugins.gioMultipleInstances) {
123
+ throw new Error('您正在尝试初始化另一个实例,请集成多实例插件后重试!');
124
+ }
125
+ // 初始化实例配置
126
+ const vdsConfig = this.dataStore.initTrackerOptions(options);
127
+ // 广播基础配置初始化完成
128
+ this.emitter?.emit(EMIT_MSG.OPTION_INITIALIZED, vdsConfig);
129
+ // 标记SDK已初始化完成
130
+ this.gioSDKInitialized = true;
131
+ // 初始化实例hooker
132
+ this.dataStore.initTrackerHooker(vdsConfig);
133
+ // 手动初始化用户信息
134
+ if (this.gioPlatform !== 'quickapp') {
135
+ this.userStore.initUserInfo(options.trackingId);
136
+ }
137
+ // 广播SDK初始化完成
138
+ this.emitter.emit(EMIT_MSG.SDK_INITIALIZED, vdsConfig);
139
+ // 初始化完成后把实例注入到小程序全局
140
+ if (!this.trackingId || this.trackingId === options.trackingId) {
141
+ // ?直接挂载对象,存在问题:Page.data 触发深拷贝 存在循环引用会导致死循环
142
+ getGlobal().__gio__ = () => this;
143
+ }
144
+ consoleText('Gio小程序SDK 初始化完成!', 'success');
145
+ // 在插件中手动触发visit
146
+ if (this.inPlugin && this.minipInstance.platform !== 'tbp') {
147
+ this.dataStore.sendVisit(vdsConfig.trackingId);
148
+ }
149
+ if (this.vdsConfig.forceLogin) {
150
+ consoleText(
151
+ 'forceLogin已开启,请调用 identify 方法设置 openId 以继续上报!',
152
+ 'info'
153
+ );
154
+ }
155
+ return true;
156
+ } catch (error) {
157
+ consoleText(error, 'error');
158
+ return false;
159
+ }
160
+ };
161
+
162
+ // 需要校验实例的方法执行
163
+ handlerDistribute = (trackingId: string, handler: string, args: any) => {
164
+ const { initializedTrackingIds, getTrackerVds } = this.dataStore;
165
+ const trakerVds = getTrackerVds(trackingId);
166
+ if (trakerVds && initializedTrackingIds.includes(trackingId)) {
167
+ return this[handler](trackingId, ...args);
168
+ } else {
169
+ consoleText(`不存在实例:${trackingId},请检查!`, 'warn');
170
+ }
171
+ };
172
+
104
173
  // 手动注册插件
105
174
  registerPlugins = (plugins: any) => {
106
175
  this.plugins.pluginItems = [...this.plugins.pluginItems, ...plugins];
107
176
  this.plugins.installAll(plugins);
108
177
  };
109
178
 
110
- // SDK初始化方法
111
- init = (args: any) => {
112
- consoleText('Gio小程序SDK 初始化中...', 'info');
113
- // 初始化全局配置
114
- this.dataStore.initOptions(args);
115
- // 广播基础配置初始化完成
116
- this.emitter?.emit('OPTION_INITIALIZED', this);
117
- // 标记SDK已初始化完成
118
- this.gioSDKInitialized = true;
119
- // 初始化完成后把实例注入到小程序全局
120
- // ?注意不要轻易修改实例挂载的地方(这里指app),会影响分包插件和运营SDK的实例取值
121
- if (!this.vdsConfig.subpackage) {
122
- const app = getAppInst();
123
- // 直接挂载对象,存在问题:Page.data 触发深拷贝 存在循环引用会导致死循环
124
- app.__gio__ = () => {
125
- return this;
126
- };
127
- }
128
- // 初始化请求逻辑
129
- this.uploader = new Uploader(this);
130
- // 没有开启IDMapping的时候要把userKey清掉,防止之前有数被带到上报数据里
131
- if (!this.vdsConfig.idMapping) {
132
- this.userStore.userKey = '';
133
- }
134
- // 广播SDK初始化完成
135
- this.emitter.emit('SDK_INITIALIZED', this);
136
- consoleText('Gio小程序SDK 初始化完成!', 'success');
137
- if (this.vdsConfig.forceLogin) {
138
- consoleText(
139
- 'forceLogin已开启,请调用 identify 方法设置 openId 以继续上报!',
140
- 'info'
141
- );
142
- }
143
- // 在插件中手动触发visit
144
- if (this.inPlugin && this.minipInstance.platform !== 'tbp') {
145
- this.dataStore.sendVisit();
146
- }
147
- return true;
148
- };
179
+ // 获取所有已注册插件
180
+ getPlugins = () => this.plugins.pluginItems;
181
+
182
+ // 获取设备ID(匿名用户ID)
183
+ getDeviceId = () => this.userStore.getUid();
149
184
 
150
185
  // 运行中获取配置
151
- getOption = (k?: string) => this.dataStore.getOption(k);
186
+ getOption = (trackingId: string, k?: string) =>
187
+ this.dataStore.getOption(trackingId, k);
152
188
 
153
189
  // 运行中修改配置
154
- setOption = (k: string, v: any) => {
155
- if (keys(ALLOWED_MODIFY_OPTIONS).includes(k)) {
156
- const r = this.dataStore.setOption(k, v);
157
- if (r && ALLOWED_MODIFY_OPTIONS[k]) {
158
- consoleText(
159
- `已${v ? '开启' : '关闭'}${ALLOWED_MODIFY_OPTIONS[k]}`,
160
- 'info'
161
- );
190
+ setOption = (trackingId: string, k: string, v: any) => {
191
+ if (keys(ALLOW_SET_OPTIONS).includes(k)) {
192
+ if (typeof v === DEFAULT_SETTINGS[k]?.type) {
193
+ this.dataStore.setOption(trackingId, k, v);
194
+ consoleText(`已修改${ALLOW_SET_OPTIONS[k]}: ${v}`, 'info');
195
+ return true;
196
+ } else {
197
+ consoleText(`参数格式不正确:${v},请检查后重试!`, 'error');
198
+ return false;
162
199
  }
163
- return r;
164
200
  } else {
165
- consoleText(`不存在可修改的配置项:${k},请检查后重试!`, 'warn');
201
+ consoleText(`不存在可修改的配置项:${k},请检查后重试!`, 'error');
166
202
  return false;
167
203
  }
168
204
  };
169
205
 
170
- // 获取设备ID(匿名用户ID)
171
- getDeviceId = () => this.userStore.uid;
206
+ // 设置页面属性
207
+ setPageAttributes = (trackingId: string, properties: any) => {
208
+ const { currentPage } = this.dataStore.eventHooks;
209
+ if (isEmpty(currentPage.pageProps[trackingId])) {
210
+ currentPage.pageProps[trackingId] = {};
211
+ }
212
+ if (!isEmpty(properties)) {
213
+ currentPage.pageProps[trackingId] = {
214
+ ...currentPage.pageProps[trackingId],
215
+ ...limitObject(properties)
216
+ };
217
+ }
218
+ };
219
+
220
+ // 手动发page
221
+ sendPage = (trackingId: string, props?: any) => {
222
+ const { trackPage } = this.dataStore.getTrackerVds(trackingId);
223
+ if (!trackPage) {
224
+ this.dataStore.sendPage(trackingId, props);
225
+ } else {
226
+ consoleText(
227
+ '仅在关闭trackPage时允许调用sendPage,请确认后修改初始化配置项!',
228
+ 'error'
229
+ );
230
+ }
231
+ };
172
232
 
173
233
  // 设置设备ID,一般为openId
174
- identify = (assignmentId: string | number) => {
234
+ identify = (trackingId: string, assignmentId: string | number) => {
235
+ if (trackingId !== this.trackingId) {
236
+ callError('identify', !1, '子实例不允许调用identify');
237
+ return;
238
+ }
175
239
  if (this.vdsConfig.forceLogin) {
176
240
  if (!verifyId(assignmentId)) {
177
241
  callError('identify');
@@ -180,33 +244,63 @@ class GrowingIO implements GrowingIOType {
180
244
  // 截取长度
181
245
  const asId = toString(assignmentId).slice(0, 1000);
182
246
  // 在之后的请求中使用assignmentId作为uid(deviceId)使用
183
- this.userStore.uid = asId;
247
+ this.userStore.setUid(asId);
248
+ // 修改forceLogin配置项
249
+ this.dataStore.setOption(this.trackingId, 'forceLogin', false);
184
250
  // 为已积压的请求使用assignmentId全部赋值deviceId
185
- this.uploader.hoardingQueue.forEach(
186
- (o, i) => (this.uploader.hoardingQueue[i].deviceId = asId)
187
- );
188
- this.dataStore.setOption('forceLogin', false);
189
- // 发送积压队列中的请求
190
- this.uploader.initiateRequest(true);
251
+ this.dataStore.trackersExecute((tid: string) => {
252
+ const hq = this.uploader.getHoardingQueue(tid);
253
+ hq.forEach((o, i) => (hq[i].deviceId = asId));
254
+ // 发送积压队列中的请求
255
+ this.uploader.initiateRequest(tid, true);
256
+ });
191
257
  } else {
192
258
  callError('identify', !1, 'forceLogin未开启');
193
259
  }
194
260
  };
195
261
 
262
+ // 发送用户属性
263
+ setUserAttributes = (trackingId: string, userAttributes: any) => {
264
+ if (!isEmpty(userAttributes) && isObject(userAttributes)) {
265
+ const { eventContextBuilder, eventInterceptor, lastVisitEvent } =
266
+ this.dataStore;
267
+ const event = {
268
+ eventType: 'LOGIN_USER_ATTRIBUTES',
269
+ attributes: limitObject(userAttributes),
270
+ ...eventContextBuilder(trackingId)
271
+ };
272
+ // 该方法很可能被放在在app的onShow中的wx.login异步回调中,
273
+ // 此时页面的path和query可能还没取到,就拿visit事件的path和query补上
274
+ if (!event.path) {
275
+ event.path = lastVisitEvent.path;
276
+ event.query = lastVisitEvent.query;
277
+ event.title = lastVisitEvent.title;
278
+ }
279
+ eventInterceptor(event);
280
+ } else {
281
+ callError('setUserAttributes');
282
+ }
283
+ };
284
+
196
285
  // 设置登录用户Id
197
- setUserId = (userId: string | number, userKey?: string) => {
286
+ setUserId = (
287
+ trackingId: string,
288
+ userId: string | number,
289
+ userKey?: string
290
+ ) => {
198
291
  if (verifyId(userId)) {
199
292
  // 切换userId要重设session补发visit
200
- const prevId = this.userStore.gioId;
293
+ const prevId = this.userStore.getGioId(trackingId);
201
294
  userId = toString(userId).slice(0, 1000);
202
295
  userKey = toString(userKey).slice(0, 1000);
203
- this.userStore.userId = userId;
204
- if (this.vdsConfig.idMapping) {
205
- this.userStore.userKey = isNil(userKey) ? '' : userKey;
296
+ this.userStore.setUserId(trackingId, userId);
297
+ const { idMapping } = this.dataStore.getTrackerVds(trackingId);
298
+ if (idMapping) {
299
+ this.userStore.setUserKey(trackingId, isNil(userKey) ? '' : userKey);
206
300
  }
207
301
  // 切换userId时重置session并补发visit
208
302
  if (prevId && prevId !== userId) {
209
- this.userStore.sessionId = '';
303
+ this.userStore.setSessionId(trackingId);
210
304
  const { path, query, settedTitle } =
211
305
  this.dataStore.eventHooks.currentPage;
212
306
  // 重新获取页面title,防止切换配置前修改了title没取到
@@ -214,7 +308,7 @@ class GrowingIO implements GrowingIOType {
214
308
  settedTitle[path] ||
215
309
  this.minipInstance.getPageTitle(this.minipInstance.getCurrentPage());
216
310
  // visit取当前页面值
217
- this.dataStore.sendVisit({ path, query });
311
+ this.dataStore.sendVisit(trackingId, { path, query });
218
312
  }
219
313
  } else {
220
314
  callError('setUserId');
@@ -222,65 +316,121 @@ class GrowingIO implements GrowingIOType {
222
316
  };
223
317
 
224
318
  // 清除登录用户Id
225
- clearUserId = () => {
226
- this.userStore.userId = undefined;
227
- this.userStore.userKey = undefined;
319
+ clearUserId = (trackingId: string) => {
320
+ this.userStore.setUserId(trackingId, undefined);
321
+ this.userStore.setUserKey(trackingId, undefined);
228
322
  };
229
323
 
230
- // 发送用户属性
231
- setUserAttributes = (userAttributes: any) => {
232
- if (!isEmpty(userAttributes) && isObject(userAttributes)) {
233
- this.plugins?.gioCustomTracking?.buildUserAttributesEvent(userAttributes);
324
+ // 设置埋点事件的通用属性(即每个埋点事件都会带上的属性值)
325
+ setGeneralProps = (trackingId: string, properties: any) => {
326
+ if (!isEmpty(properties)) {
327
+ this.dataStore.generalProps[trackingId] = {
328
+ ...(this.dataStore.generalProps[trackingId] ?? {}),
329
+ ...properties
330
+ };
331
+ return true;
234
332
  } else {
235
- callError('setUserAttributes');
333
+ callError('setGeneralProps');
334
+ return false;
335
+ }
336
+ };
337
+
338
+ // 清空已设置的埋点事件的通用属性
339
+ clearGeneralProps = (
340
+ trackingId: string,
341
+ properties: string[] | undefined
342
+ ) => {
343
+ try {
344
+ if (!isEmpty(this.dataStore.generalProps[trackingId])) {
345
+ // 获取目标tracker的引用
346
+ if (isArray(properties) && !isEmpty(properties)) {
347
+ properties.forEach((propName: string) => {
348
+ unset(this.dataStore.generalProps[trackingId], propName);
349
+ });
350
+ } else {
351
+ this.dataStore.generalProps[trackingId] = {};
352
+ }
353
+ }
354
+ } catch (error) {
355
+ callError('setGeneralProps');
356
+ return false;
236
357
  }
237
358
  };
238
359
 
239
360
  // 自定义埋点事件
240
- track = (name: string, properties: { [key: string]: string | string[] }) => {
241
- const customEvent =
242
- this.plugins?.gioCustomTracking?.buildCustomEvent || function () {};
243
- customEvent(name, {
244
- ...this.dataStore.generalProps,
245
- ...(isObject(properties) && !isEmpty(properties) ? properties : {})
361
+ track = (
362
+ trackingId: string,
363
+ name: string,
364
+ properties: { [key: string]: string | string[] }
365
+ ) => {
366
+ eventNameValidate(name, () => {
367
+ const { eventContextBuilder, eventInterceptor, generalProps } =
368
+ this.dataStore;
369
+ const mergedProperties = {
370
+ ...(generalProps[trackingId] ?? {}),
371
+ ...(isObject(properties) && !isEmpty(properties) ? properties : {})
372
+ };
373
+ const event = {
374
+ eventType: 'CUSTOM',
375
+ eventName: name,
376
+ attributes: limitObject(getDynamicAttributes(mergedProperties)),
377
+ ...eventContextBuilder(trackingId)
378
+ };
379
+ // 埋点事件要保留'&&sendTo'字段用于多实例复制发送
380
+ if (
381
+ this.plugins.gioMultipleInstances &&
382
+ properties &&
383
+ properties['&&sendTo']
384
+ ) {
385
+ event['&&sendTo'] = properties['&&sendTo'];
386
+ }
387
+ eventInterceptor(event);
246
388
  });
247
389
  };
248
390
 
249
391
  // 初始化事件计时器
250
- trackTimerStart = (eventName: string) => {
251
- if (this.vdsConfig.dataCollect) {
392
+ trackTimerStart = (trackingId: string, eventName: string) => {
393
+ const { dataCollect } = this.dataStore.getTrackerVds(trackingId);
394
+ if (dataCollect) {
252
395
  return eventNameValidate(eventName, () => {
253
396
  const timerId = guid();
254
- this.dataStore.trackTimers[timerId] = {
397
+ if (!this.dataStore.trackTimers[trackingId]) {
398
+ this.dataStore.trackTimers[trackingId] = {};
399
+ }
400
+ this.dataStore.trackTimers[trackingId][timerId] = {
255
401
  eventName,
256
402
  leng: 0,
257
403
  start: +Date.now()
258
404
  };
259
405
  return timerId;
260
406
  });
407
+ } else {
408
+ consoleText('指定实例未开启数据采集,请检查!', 'error');
261
409
  }
262
410
  return false;
263
411
  };
264
412
 
265
413
  // 暂停事件计时器
266
- trackTimerPause = (timerId: string) => {
267
- if (timerId && this.dataStore.trackTimers[timerId]) {
268
- const tracker = this.dataStore.trackTimers[timerId];
269
- if (tracker.start) {
270
- tracker.leng = tracker.leng + (+Date.now() - tracker.start);
414
+ trackTimerPause = (trackingId: string, timerId: string) => {
415
+ const timers = this.dataStore.trackTimers[trackingId];
416
+ if (timerId && timers && timers[timerId]) {
417
+ const timer = timers[timerId];
418
+ if (timer.start) {
419
+ timer.leng = timer.leng + (+Date.now() - timer.start);
271
420
  }
272
- tracker.start = 0;
421
+ timer.start = 0;
273
422
  return true;
274
423
  }
275
424
  return false;
276
425
  };
277
426
 
278
427
  // 恢复事件计时器
279
- trackTimerResume = (timerId: string) => {
280
- if (timerId && this.dataStore.trackTimers[timerId]) {
281
- const tracker = this.dataStore.trackTimers[timerId];
282
- if (tracker.start === 0) {
283
- tracker.start = +Date.now();
428
+ trackTimerResume = (trackingId: string, timerId: string) => {
429
+ const timers = this.dataStore.trackTimers[trackingId];
430
+ if (timerId && timers && timers[timerId]) {
431
+ const timer = timers[timerId];
432
+ if (timer.start === 0) {
433
+ timer.start = +Date.now();
284
434
  }
285
435
  return true;
286
436
  }
@@ -288,115 +438,98 @@ class GrowingIO implements GrowingIOType {
288
438
  };
289
439
 
290
440
  // 停止事件计时器并上报事件
291
- trackTimerEnd = (timerId: string, attributes: any) => {
292
- if (this.vdsConfig.dataCollect) {
293
- const maxEnd = 60 * 60 * 24 * 1000;
294
- if (timerId && this.dataStore.trackTimers[timerId]) {
295
- const tracker = this.dataStore.trackTimers[timerId];
296
- if (tracker.start !== 0) {
297
- const shortCut = +Date.now() - tracker.start;
298
- tracker.leng = shortCut > 0 ? tracker.leng + shortCut : 0;
441
+ trackTimerEnd = (trackingId: string, timerId: string, properties: any) => {
442
+ const { dataCollect } = this.dataStore.getTrackerVds(trackingId);
443
+ const timers = this.dataStore.trackTimers[trackingId];
444
+ if (timerId && timers && timers[timerId]) {
445
+ if (dataCollect) {
446
+ const maxEnd = 60 * 60 * 24 * 1000;
447
+ const timer = timers[timerId];
448
+ if (timer.start !== 0) {
449
+ const shortCut = +Date.now() - timer.start;
450
+ timer.leng = shortCut > 0 ? timer.leng + shortCut : 0;
299
451
  }
300
- // 要直接构建custom事件,不要去调用埋点插件的方法,万一插件没有加载就发不出去了
301
452
  const { eventContextBuilder, eventInterceptor } = this.dataStore;
302
453
  const event = {
303
454
  eventType: 'CUSTOM',
304
- eventName: tracker.eventName,
455
+ eventName: timer.eventName,
305
456
  attributes: limitObject({
306
- ...attributes,
307
- event_duration: tracker.leng > maxEnd ? 0 : tracker.leng / 1000
457
+ ...properties,
458
+ event_duration: timer.leng > maxEnd ? 0 : timer.leng / 1000
308
459
  }),
309
- ...eventContextBuilder(),
310
- customEventType: 0
460
+ ...eventContextBuilder(trackingId)
311
461
  };
462
+ // 埋点事件要保留'&&sendTo'字段用于多实例复制发送
463
+ if (
464
+ this.plugins.gioMultipleInstances &&
465
+ properties &&
466
+ properties['&&sendTo']
467
+ ) {
468
+ event['&&sendTo'] = properties['&&sendTo'];
469
+ }
312
470
  eventInterceptor(event);
313
- this.removeTimer(timerId);
314
471
  return true;
315
472
  } else {
316
- consoleText('未查找到对应的计时器,请检查!', 'error');
473
+ consoleText('指定实例未开启数据采集,计时器已移除,请检查!', 'error');
317
474
  return false;
318
475
  }
476
+ this.removeTimer(trackingId, timerId);
477
+ } else {
478
+ consoleText('未查询到指定计时器,请检查!', 'error');
479
+ return false;
319
480
  }
320
- return false;
321
481
  };
322
482
 
323
483
  // 移除事件计时器
324
- removeTimer = (timerId: string) => {
325
- if (timerId && this.dataStore.trackTimers[timerId]) {
326
- delete this.dataStore.trackTimers[timerId];
484
+ removeTimer = (trackingId: string, timerId: string) => {
485
+ const timers = this.dataStore.trackTimers[trackingId];
486
+ if (timerId && timers && timers[timerId]) {
487
+ delete timers[timerId];
327
488
  return true;
489
+ } else {
490
+ consoleText('未查询到指定计时器,请检查!', 'error');
491
+ return false;
328
492
  }
329
- return false;
330
493
  };
331
494
 
332
495
  // 清除所有事件计时器
333
- clearTrackTimer = () => {
334
- this.dataStore.trackTimers = {};
496
+ clearTrackTimer = (trackingId: string) => {
497
+ this.dataStore.trackTimers[trackingId] = {};
335
498
  };
336
499
 
337
- // 设置埋点事件的通用属性(即每个埋点事件都会带上的属性值)
338
- setGeneralProps = (properties: any) => {
339
- if (isObject(properties) && !isEmpty(properties)) {
340
- this.dataStore.generalProps = {
341
- ...this.dataStore.generalProps,
342
- ...properties
343
- };
344
- keys(this.dataStore.generalProps).forEach((k: string) => {
345
- if ([undefined, null].includes(this.dataStore.generalProps[k])) {
346
- this.dataStore.generalProps[k] = '';
347
- }
348
- });
349
- } else {
350
- callError('setGeneralProps');
351
- }
352
- };
353
-
354
- // 清空已设置的埋点事件的通用属性
355
- clearGeneralProps = (properties: string[] | undefined) => {
356
- if (isArray(properties) && !isEmpty(properties)) {
357
- properties.forEach((prop: string) => {
358
- unset(this.dataStore.generalProps, prop);
359
- });
360
- } else {
361
- this.dataStore.generalProps = {};
500
+ // 手动获取位置信息补发visit上报
501
+ setLocation = (trackingId: string, latitude: number, longitude: number) => {
502
+ if (isEmpty(this.dataStore.locationData[trackingId])) {
503
+ this.dataStore.locationData[trackingId] = {};
362
504
  }
363
- };
364
-
365
- // 设置页面属性
366
- setPageAttributes = (properties: any) => {
367
- const { currentPage } = this.dataStore.eventHooks;
368
- // 这个currentPath一般认为是在onLoad中获取的当前小程序页面的path,此时SDK还没有parse,保存的还是上一个页面的信息
369
- const currentPath = this.minipInstance.getCurrentPath();
370
- if (['onLoad', 'attached'].includes(currentPage.currentLifecycle)) {
371
- currentPage.pageProps[currentPath] = limitObject(properties);
505
+ const ld = this.dataStore.locationData[trackingId];
506
+ const verifyLT = (o: number) => o >= -180 && o <= 180;
507
+ if (
508
+ verifyLT(latitude) &&
509
+ verifyLT(longitude) &&
510
+ (ld.latitude !== latitude || ld.longitude !== longitude)
511
+ ) {
512
+ this.dataStore.locationData[trackingId] = { latitude, longitude };
372
513
  }
373
514
  };
374
515
 
375
516
  // 手动更新曝光监听(该方法会在曝光插件加载时被重写)
376
517
  updateImpression = () => {
377
518
  consoleText(
378
- '当前未集成半自动浏览插件,请集成插件后再调用 updateImpression!',
379
- 'warn'
519
+ 'updateImpression 错误! 请集成半自动埋点浏览插件后重试!',
520
+ 'error'
380
521
  );
381
522
  };
382
523
 
383
- // 手动获取位置信息补发visit上报
384
- setLocation = (latitude: number, longitude: number) => {
385
- const nld = { latitude, longitude };
386
- const ld = this.dataStore.locationData;
387
- const verifyLT = (o: number) => o >= -180 && o <= 180;
388
- if (
389
- verifyLT(latitude) &&
390
- verifyLT(longitude) &&
391
- (ld.latitude !== latitude || ld.longitude !== longitude)
392
- ) {
393
- this.dataStore.locationData = nld;
394
- }
524
+ // 获取A/B实验数据
525
+ getABTest = (trackingId: string, layerId: string | number, callback: any) => {
526
+ consoleText('获取ABTest数据错误! 请集成ABTest插件后重试!', 'error');
527
+ niceCallback(callback, {});
395
528
  };
396
529
 
397
530
  // 获取打通信息
398
- getGioInfo = () => {
399
- const { uid, userId, userKey, sessionId } = this.userStore;
531
+ getGioInfo = (trackingId: string) => {
532
+ const { getUid, getUserId, getUserKey, getSessionId } = this.userStore;
400
533
  const {
401
534
  projectId,
402
535
  appId,
@@ -405,19 +538,19 @@ class GrowingIO implements GrowingIOType {
405
538
  idMapping,
406
539
  extraParams,
407
540
  ignoreFields
408
- } = this.vdsConfig;
541
+ } = this.dataStore.getTrackerVds(trackingId);
409
542
  const infos: any = {
410
543
  gioappid: appId,
411
- giocs1: userId || '',
544
+ giocs1: getUserId(trackingId) || '',
412
545
  gioplatform: this.platformConfig.platform,
413
546
  gioprojectid: projectId,
414
- gios: sessionId,
415
- giou: uid
547
+ gios: getSessionId(trackingId),
548
+ giou: getUid()
416
549
  };
417
550
  infos.giodatacollect = dataCollect;
418
551
  infos.giodatasourceid = dataSourceId;
419
552
  if (idMapping) {
420
- infos.giouserkey = userKey;
553
+ infos.giouserkey = getUserKey(trackingId);
421
554
  }
422
555
  if (!isEmpty(extraParams)) {
423
556
  extraParams.forEach((o) => {