gio-miniprogram-sdk 4.3.1 → 4.4.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 (52) hide show
  1. package/.github/workflows/publish.yml +3 -3
  2. package/dist/alipay.js +1 -1
  3. package/dist/baidu.js +1 -1
  4. package/dist/bytedance.js +1 -1
  5. package/dist/jingdong.js +1 -1
  6. package/dist/kuaishou.js +1 -1
  7. package/dist/plugins/gioABTest.js +1 -1
  8. package/dist/plugins/gioCompress.js +1 -1
  9. package/dist/plugins/gioEventAutoTracking.js +1 -1
  10. package/dist/plugins/gioImpressionTracking.js +1 -1
  11. package/dist/plugins/gioMultipleInstances.js +1 -1
  12. package/dist/plugins/gioPerformance.js +1 -0
  13. package/dist/qq.js +1 -1
  14. package/dist/quickapp.js +1 -1
  15. package/dist/taobao.js +1 -1
  16. package/dist/taro.js +1 -1
  17. package/dist/uniapp.js +1 -1
  18. package/dist/wechat.js +1 -1
  19. package/dist/xiaohongshu.js +1 -0
  20. package/package.json +12 -6
  21. package/rollup.config.js +9 -6
  22. package/rollup.plugins.config.js +1 -1
  23. package/src/constants/emitMsg.ts +1 -0
  24. package/src/core/dataStore/eventHooks/appEffects.ts +3 -0
  25. package/src/core/dataStore/eventHooks/index.ts +4 -2
  26. package/src/core/dataStore/eventHooks/pageEffects.ts +1 -0
  27. package/src/core/growingIO.ts +27 -3
  28. package/src/core/uploader.ts +12 -3
  29. package/src/core/userStore.ts +1 -2
  30. package/src/minipInstance/base.ts +62 -25
  31. package/src/minipInstance/framework.ts +3 -1
  32. package/src/minipInstance/my.ts +40 -0
  33. package/src/minipInstance/quickapp.ts +23 -6
  34. package/src/minipInstance/wx.ts +15 -0
  35. package/src/minipInstance/xhs.ts +20 -0
  36. package/src/platformConfig/base.ts +1 -0
  37. package/src/platformConfig/xhs.ts +20 -0
  38. package/src/plugins/gioABTest.ts +32 -3
  39. package/src/plugins/gioEventAutoTracking.ts +99 -1
  40. package/src/plugins/gioImpressionTracking.ts +3 -1
  41. package/src/plugins/gioPerformance/exception.ts +152 -0
  42. package/src/plugins/gioPerformance/monitor.ts +284 -0
  43. package/src/plugins/gioPerformance/network.ts +197 -0
  44. package/src/plugins/gioPerformance.ts +131 -0
  45. package/src/types/base.ts +5 -1
  46. package/src/types/minipInstance.ts +3 -1
  47. package/src/types/platforms.ts +3 -0
  48. package/src/utils/tools.ts +46 -3
  49. package/src/utils/verifiers.ts +4 -3
  50. package/tsconfig.json +1 -1
  51. package/typings/global.d.ts +8 -0
  52. package/bin/build.sh +0 -38
package/rollup.config.js CHANGED
@@ -19,7 +19,8 @@ const platform = processENV[0];
19
19
  // 框架平台
20
20
  const frameName = processENV[1];
21
21
  // 插件实例的入口名
22
- const pluginInstanceName = frameName || platform === 'tb' ? frameName || platform : 'base';
22
+ const pluginInstanceName =
23
+ frameName || platform === 'tb' ? frameName || platform : 'base';
23
24
  // 小程序平台文件名枚举
24
25
  const PLATFORMS = {
25
26
  wx: 'wechat',
@@ -30,20 +31,22 @@ const PLATFORMS = {
30
31
  ks: 'kuaishou',
31
32
  tb: 'taobao',
32
33
  jd: 'jingdong',
33
- quickapp: 'quickapp'
34
+ quickapp: 'quickapp',
35
+ xhs: 'xiaohongshu'
34
36
  };
35
37
 
36
38
  // 控制台打印当前打包的环境和小程序平台
37
39
  console.log(
38
- `Packaging ${PLATFORMS[platform]
39
- ? 'platform:' + PLATFORMS[platform]
40
- : 'framework:' + frameName
40
+ `Packaging ${
41
+ PLATFORMS[platform]
42
+ ? 'platform:' + PLATFORMS[platform]
43
+ : 'framework:' + frameName
41
44
  }`
42
45
  );
43
46
 
44
47
  const fileName = () => {
45
48
  let n = 'dist/';
46
- n += (PLATFORMS[platform] || frameName);
49
+ n += PLATFORMS[platform] ? PLATFORMS[platform] : frameName;
47
50
  n += '.js';
48
51
  return n;
49
52
  };
@@ -16,7 +16,7 @@ const processENV = process.argv[process.argv.length - 1]
16
16
  .split('-')
17
17
  .filter((o) => o);
18
18
  // 获取是否打包全量插件
19
- const folder = processENV[0] || 'plugins';
19
+ const folder = processENV[0] ? processENV[0] : 'plugins';
20
20
 
21
21
  // 获取外置插件的目录
22
22
  const plugInFolder = fs
@@ -9,6 +9,7 @@ export default {
9
9
  ON_SDK_INITIALIZE_BEFORE: 'ON_SDK_INITIALIZE_BEFORE', // SDK开始初始化之前
10
10
  ON_SEND_AFTER: 'ON_SEND_AFTER', // 插件生命周期:发送事件后
11
11
  ON_SEND_BEFORE: 'ON_SEND_BEFORE', // 插件生命周期:发送事件前
12
+ ON_SEND_ERROR: 'ON_SEND_ERROR', // 插件生命周期:发送事件错误
12
13
  OPTION_CHANGE: 'OPTION_CHANGE', // 设置变更事件
13
14
  OPTION_INITIALIZED: 'OPTION_INITIALIZED', // 配置项初始化完成
14
15
  SCENE_UPDATE: 'SCENE_UPDATE', // scene变更事件
@@ -17,6 +17,7 @@ class AppEffects {
17
17
  platformConfig,
18
18
  uploader,
19
19
  dataStore,
20
+ minipInstance,
20
21
  dataStore: {
21
22
  trackersExecute,
22
23
  shareOut,
@@ -81,6 +82,8 @@ class AppEffects {
81
82
  userStore.setSessionId(trackingId);
82
83
  });
83
84
  }
85
+ // 添加网络状态变更监听
86
+ minipInstance.setNetworkStatusListener();
84
87
  break;
85
88
  }
86
89
  case appListeners.appClose: {
@@ -17,6 +17,7 @@ class EventHooks implements EventHooksType {
17
17
  public defPageCbs: any;
18
18
  public appHandlers: string[];
19
19
  public pageHandlers: string[];
20
+ public shareEventTypes: string[];
20
21
  public actionEventTypes: string[];
21
22
  public originalApp: (any: any) => any;
22
23
  public originalPage: (any: any) => any;
@@ -33,6 +34,7 @@ class EventHooks implements EventHooksType {
33
34
  this.defPageCbs = {};
34
35
  this.appHandlers = config.appHandlers;
35
36
  this.pageHandlers = config.pageHandlers;
37
+ this.shareEventTypes = config.shareEventTypes;
36
38
  this.actionEventTypes = config.actionEventTypes;
37
39
  this.appEffects = new AppEffects(this.growingIO);
38
40
  this.pageEffects = new PageEffects(this.growingIO);
@@ -115,7 +117,7 @@ class EventHooks implements EventHooksType {
115
117
  let result;
116
118
  try {
117
119
  // 分享处理
118
- if (eventName === 'onShareAppMessage') {
120
+ if (self.shareEventTypes.includes(eventName)) {
119
121
  // 先执行分享的生命周期拿到分享数据
120
122
  // 与基础库保持一致,没有返回值时默认使用{}
121
123
  result = method.apply(this, args) ?? {};
@@ -160,7 +162,7 @@ class EventHooks implements EventHooksType {
160
162
  consoleText(error, 'error');
161
163
  }
162
164
  // 执行分享之外的生命周期函数
163
- if (eventName !== 'onShareAppMessage') {
165
+ if (!self.shareEventTypes.includes(eventName)) {
164
166
  result = method.apply(this, args);
165
167
  }
166
168
  self.growingIO.emitter.emit(EMIT_MSG.MINIP_LIFECYCLE, {
@@ -102,6 +102,7 @@ class PageEffects {
102
102
  case pageListeners.pageUnload: {
103
103
  break;
104
104
  }
105
+ case pageListeners.shareChat: // 小红书特有事件
105
106
  case pageListeners.shareApp: {
106
107
  toggleShareOut(true);
107
108
  trackersExecute((trackingId: string) => {
@@ -18,7 +18,8 @@ import {
18
18
  getPlainPlatform,
19
19
  guid,
20
20
  limitObject,
21
- niceCallback
21
+ niceCallback,
22
+ qsParse
22
23
  } from '@@/utils/tools';
23
24
  import { ALLOW_SET_OPTIONS, DEFAULT_SETTINGS } from '@@/constants/config';
24
25
  import { DataStoreType, OriginOptions } from '@@/types/dataStore';
@@ -65,6 +66,7 @@ class GrowingIO implements GrowingIOType {
65
66
  // 当前主SDK的trackingId,用于区分事件归属。
66
67
  public trackingId: string;
67
68
  public subInstance: any;
69
+ private _identified: boolean;
68
70
  constructor() {
69
71
  this.utils = { ...glodash, ...tools, qs };
70
72
  this.emitter = mitt();
@@ -288,6 +290,8 @@ class GrowingIO implements GrowingIOType {
288
290
  this.userStore.setUid(asId);
289
291
  // 修改forceLogin配置项
290
292
  this.dataStore.setOption(this.trackingId, 'forceLogin', false);
293
+ // 标记当前已被identify过
294
+ this._identified = true;
291
295
  // 为已积压的请求使用assignmentId全部赋值deviceId
292
296
  this.dataStore.trackersExecute((tid: string) => {
293
297
  const hq = this.uploader.getHoardingQueue(tid);
@@ -295,6 +299,8 @@ class GrowingIO implements GrowingIOType {
295
299
  // 发送积压队列中的请求
296
300
  this.uploader.initiateRequest(tid, true);
297
301
  });
302
+ } else if (this._identified) {
303
+ callError('identify', !1, '请勿重复调用');
298
304
  } else {
299
305
  callError('identify', !1, 'forceLogin未开启');
300
306
  }
@@ -338,9 +344,14 @@ class GrowingIO implements GrowingIOType {
338
344
  userId = toString(userId).slice(0, 1000);
339
345
  userKey = toString(userKey).slice(0, 1000);
340
346
  this.userStore.setUserId(trackingId, userId);
347
+ const processedUserKey =
348
+ !isNil(userKey) && toString(userKey).length > 0
349
+ ? toString(userKey).slice(0, 1000)
350
+ : '';
351
+ this.userStore.setUserKey(trackingId, processedUserKey);
341
352
  const { idMapping } = this.dataStore.getTrackerVds(trackingId);
342
- if (idMapping) {
343
- this.userStore.setUserKey(trackingId, isNil(userKey) ? '' : userKey);
353
+ if (!idMapping && processedUserKey) {
354
+ consoleText('您设置了 userKey ,请初始化开启 idMapping!', 'warn');
344
355
  }
345
356
  // 切换userId时重置session
346
357
  if (prevId && prevId !== userId) {
@@ -606,6 +617,19 @@ class GrowingIO implements GrowingIOType {
606
617
  }
607
618
  });
608
619
  }
620
+ // 只有主实例有可能会带圈选的字段
621
+ if (trackingId === this.trackingId) {
622
+ // 小程序处于圈选状态时,把圈选上报地址带给web
623
+ const { circleServerUrl, circleOpen } =
624
+ this.plugins?.gioEventAutoTracking ?? {};
625
+ if (circleServerUrl && circleOpen) {
626
+ // infos.giocircleserverurl = encodeURIComponent(circleServerUrl);
627
+ const circleParam: any = qsParse(circleServerUrl.split('?')[1]);
628
+ if (circleParam.roomId) {
629
+ infos.giocircleroomid = circleParam.roomId;
630
+ }
631
+ }
632
+ }
609
633
  return qs.stringify(infos);
610
634
  };
611
635
  }
@@ -33,10 +33,10 @@ class Uploader implements UploaderType {
33
33
  this.retryLimit = 2;
34
34
  this.retryIds = {};
35
35
  this.requestingNum = 0;
36
- const { emitter, vdsConfig, plugins } = this.growingIO;
37
- emitter.on(
36
+ this.growingIO.emitter.on(
38
37
  EMIT_MSG.ON_SEND_BEFORE,
39
38
  ({ eventsQueue, requestData, trackingId }) => {
39
+ const { vdsConfig, plugins } = this.growingIO;
40
40
  // 核心逻辑中只发送主实例的事件
41
41
  if (trackingId === this.growingIO.trackingId) {
42
42
  if (vdsConfig?.tbConfig?.cloudAppId) {
@@ -223,11 +223,20 @@ class Uploader implements UploaderType {
223
223
  this.requestFailFn(o);
224
224
  });
225
225
  consoleText(`请求失败!${JSON.stringify(result)}`, 'error');
226
+ emitter.emit(EMIT_MSG.ON_SEND_ERROR, {
227
+ eventsQueue,
228
+ requestData,
229
+ trackingId
230
+ });
226
231
  }
227
232
  },
228
233
  complete: (args: any) => {
229
234
  this.requestingNum -= 1;
230
- emitter.emit(EMIT_MSG.ON_SEND_AFTER, { result: args, requestData });
235
+ emitter.emit(EMIT_MSG.ON_SEND_AFTER, {
236
+ result: args,
237
+ requestData,
238
+ trackingId
239
+ });
231
240
  this.initiateRequest(trackingId);
232
241
  }
233
242
  });
@@ -50,8 +50,7 @@ class UserStore implements UserStoreType {
50
50
  }
51
51
  // 存储中拿不到尝试设新值
52
52
  if (!this._uid) {
53
- this._uid = guid();
54
- minipInstance.setStorage(this._getUidKey(), this._uid);
53
+ this.setUid(guid());
55
54
  }
56
55
  return this._uid;
57
56
  };
@@ -13,7 +13,8 @@ import {
13
13
  isString,
14
14
  last,
15
15
  typeOf,
16
- isEmpty
16
+ isEmpty,
17
+ isArray
17
18
  } from '@@/utils/glodash';
18
19
  import EMIT_MSG from '@@/constants/emitMsg';
19
20
  import {
@@ -21,7 +22,8 @@ import {
21
22
  niceTry,
22
23
  getPlainMinip,
23
24
  getPlainPlatform,
24
- getPlainConfig
25
+ getPlainConfig,
26
+ getPlainAppCode
25
27
  } from '@@/utils/tools';
26
28
 
27
29
  // 此基础实现类仅包含所有小程序,快应用所有方法全部单独实现
@@ -139,39 +141,67 @@ class BaseInstance implements MinipInstanceType {
139
141
  if (typeOf(instConfig) === 'string') {
140
142
  instConfig = niceTry(() => JSON.parse(instConfig)) ?? {};
141
143
  }
142
- // 第一优先级在base中的hook setNavigationBarTitle设置的值(在dataStore page实例中实现)
143
- // 第二优先级支持客户自己在页面中设置页面title
144
+ // 第一优先级在base中的hook setNavigationBarTitle设置的值(在dataStore page实例中实现,准确率最高)
145
+ // 第二优先级支持客户自己在页面中设置页面title(保持3.8的向下兼容,不准确但优先级高)
144
146
  const data = page?.data || page.$data || {};
145
147
  title = isString(data?.gioPageTitle) ? data?.gioPageTitle : '';
146
- if (instConfig) {
147
- // 第三优先级app生命周期中拿不到page对象,拿生命周期的参数来匹配
148
+
149
+ let instPage;
150
+ // 第三优先级取页面的配置json的navigationBarTitleText(仅部分支持)
151
+ if (!title) {
152
+ // 存在__[wx]AppCode__时尝试从__[wx]AppCode__中匹配
153
+ niceTry(() => {
154
+ const instAppCode = getPlainAppCode(platform);
155
+ if (instAppCode) {
156
+ instPage = instAppCode[`${page.route}.json`] || {};
157
+ title =
158
+ instPage?.navigationBarTitleText || // wx/qq/jd
159
+ instPage?.mod?.exports?.navigationBarTitleText; // ks
160
+ }
161
+ });
162
+ }
163
+ if (!title && instConfig) {
164
+ // 第四优先级在app生命周期中拿不到page对象,拿生命周期的参数来匹配
148
165
  const { enterParams } = this.growingIO.dataStore.eventHooks.appEffects;
149
166
  if (!page.route && !isEmpty(enterParams)) {
150
167
  page.route = enterParams.path || '';
151
- title = this._getTitleFromTabBar(instConfig, page.route);
168
+ title = page.route
169
+ ? this._getTitleFromTabBar(instConfig, page.route)
170
+ : '';
152
171
  }
153
- // 第四优先级取页面的navigationBarTitleText
154
- niceTry(() => {
155
- if (!title) {
156
- const instPage = instConfig.page || {};
172
+
173
+ // 第五优先级存在pages数组或page对象时尝试从page中匹配(大概率匹配不到,跟框架有关)
174
+ if (!title) {
175
+ if (isArray(instConfig.pages)) {
176
+ instPage = instConfig.pages.find((o) => o.path === page.route) ?? {};
177
+ } else {
178
+ instPage = instConfig.page || {};
179
+ }
180
+ if (instPage) {
157
181
  const pageInfo =
158
- instPage[page.route] || instPage[`${page.route}.html`];
159
- if (pageInfo) {
160
- title = pageInfo?.window?.navigationBarTitleText;
161
- } else if (['wx', 'tt'].includes(platform)) {
162
- title = (instConfig || global || $global)?.global?.window
163
- ?.navigationBarTitleText;
164
- } else {
165
- title = (instConfig || global || $global)?.window
166
- ?.navigationBarTitleText;
167
- }
182
+ instPage[page.route] || instPage[`${page.route}.html`] || instPage;
183
+ title =
184
+ pageInfo?.navigationBarTitleText ||
185
+ pageInfo?.window?.navigationBarTitleText;
168
186
  }
169
- });
170
- // 第五优先级取tabBar配置
187
+ }
188
+
189
+ // 第六优先级取tabBar配置匹配(只有tabbar的4个页面有机会)
171
190
  if (!title) {
172
191
  title = this._getTitleFromTabBar(instConfig, page.route);
173
192
  }
174
193
  }
194
+
195
+ // 第七优先级兜底取全局window的navigationBarTitleText
196
+ if (!title) {
197
+ if (['wx', 'tt'].includes(platform)) {
198
+ title = (instConfig || global || $global)?.global?.window
199
+ ?.navigationBarTitleText;
200
+ } else {
201
+ title = (instConfig || global || $global)?.window
202
+ ?.navigationBarTitleText;
203
+ }
204
+ }
175
205
  return limitString(title);
176
206
  };
177
207
 
@@ -268,8 +298,6 @@ class BaseInstance implements MinipInstanceType {
268
298
  data,
269
299
  // 微信小程序和其他小程序里叫header
270
300
  header,
271
- // 支付宝小程序里叫headers
272
- headers: header,
273
301
  timeout,
274
302
  method,
275
303
  success,
@@ -310,6 +338,15 @@ class BaseInstance implements MinipInstanceType {
310
338
  this.minip?.getSetting({ success: resolve, fail: resolve });
311
339
  });
312
340
  };
341
+
342
+ // 监听网络变更
343
+ setNetworkStatusListener = () => {
344
+ this.minip?.onNetworkStatusChange(({ networkType }) => {
345
+ if (networkType) {
346
+ this.network.networkType = networkType;
347
+ }
348
+ });
349
+ };
313
350
  }
314
351
 
315
352
  export default BaseInstance;
@@ -1,5 +1,6 @@
1
1
  import { getPlainPlatform } from '@@/utils/tools';
2
2
 
3
+ import XiaoHongShu from './xhs';
3
4
  import JingDong from './jd';
4
5
  import KuaiShou from './ks';
5
6
  import Alipay from './my';
@@ -16,7 +17,8 @@ const INST = {
16
17
  qq: QQ,
17
18
  tt: Bytedance,
18
19
  ks: KuaiShou,
19
- jd: JingDong
20
+ jd: JingDong,
21
+ xhs: XiaoHongShu
20
22
  };
21
23
 
22
24
  export default INST[plainPlatform];
@@ -1,4 +1,6 @@
1
+ import { compareVersion } from '@@/utils/tools';
1
2
  import { GrowingIOType } from '@@/types/growingIO';
3
+ import { isFunction } from '@@/utils/glodash';
2
4
  import BaseImplements from './base';
3
5
 
4
6
  class Alipay extends BaseImplements {
@@ -53,6 +55,44 @@ class Alipay extends BaseImplements {
53
55
  removeStorageSync = (key: string) => {
54
56
  this.minip?.removeStorageSync({ key });
55
57
  };
58
+
59
+ // 支付宝和mpass单独处理
60
+ request = ({
61
+ url,
62
+ data,
63
+ header,
64
+ timeout,
65
+ method,
66
+ success,
67
+ fail,
68
+ complete
69
+ }) => {
70
+ const requestTask = this.minip?.request({
71
+ url,
72
+ data,
73
+ // 支付宝小程序里叫headers
74
+ headers: header,
75
+ timeout,
76
+ method,
77
+ success,
78
+ fail,
79
+ complete
80
+ });
81
+ const myVersion = this.minip.SDKVersion;
82
+ // 支付宝小程序2.0.0版本及以上才超时中断请求
83
+ // https://github.com/growingio/growingio-sdk-miniprogram-autotracker/issues/3
84
+ if (compareVersion(myVersion, '2.0.0') >= 0) {
85
+ // 设置超时中断请求
86
+ let t = setTimeout(() => {
87
+ if (requestTask?.abort && isFunction(requestTask?.abort)) {
88
+ requestTask?.abort();
89
+ }
90
+ clearTimeout(t);
91
+ t = null;
92
+ }, (timeout || 10000) + 10);
93
+ }
94
+ return requestTask;
95
+ };
56
96
  }
57
97
 
58
98
  export default Alipay;
@@ -1,6 +1,6 @@
1
1
  import { GrowingIOType } from '@@/types/growingIO';
2
2
  import { isString, last } from '@@/utils/glodash';
3
- import { limitString } from '@@/utils/tools';
3
+ import { limitString, niceTry } from '@@/utils/tools';
4
4
  import { SystemInfo } from '@@/types/minipInstance';
5
5
  import app from '@system.app';
6
6
  import BaseImplements from './base';
@@ -97,16 +97,22 @@ class QuickApp extends BaseImplements {
97
97
  */
98
98
  // 获取当前页面栈
99
99
  getCurrentPage = () => {
100
- if (router?.getPages) {
101
- return last(router?.getPages());
102
- }
100
+ niceTry(() => {
101
+ if (router?.getPages) {
102
+ return last(router?.getPages()) || {};
103
+ }
104
+ });
103
105
  return {};
104
106
  };
105
107
 
106
108
  // 获取当前页面路由
107
109
  getCurrentPath = () => {
108
- const route = router?.getState();
109
- return route?.path;
110
+ niceTry(() => {
111
+ if (router?.getState) {
112
+ return router?.getState()?.path || '';
113
+ }
114
+ });
115
+ return '';
110
116
  };
111
117
 
112
118
  // 获取页面标题(除wx以外其他平台)
@@ -211,6 +217,17 @@ class QuickApp extends BaseImplements {
211
217
  });
212
218
  });
213
219
  };
220
+
221
+ // 监听网络变更
222
+ setNetworkStatusListener = () => {
223
+ network.subscribe({
224
+ callback: (data) => {
225
+ if (data.type) {
226
+ this.network.networkType = data.type;
227
+ }
228
+ }
229
+ });
230
+ };
214
231
  }
215
232
 
216
233
  export default QuickApp;
@@ -1,4 +1,5 @@
1
1
  import { GrowingIOType } from '@@/types/growingIO';
2
+ import { SystemInfo } from '@@/types/minipInstance';
2
3
 
3
4
  import BaseImplements from './base';
4
5
 
@@ -7,6 +8,20 @@ class Weixin extends BaseImplements {
7
8
  super(growingIO);
8
9
  this.hookSetTitle();
9
10
  }
11
+
12
+ // 获取小程序系统信息
13
+ getSystemInfo = (): Promise<SystemInfo> => {
14
+ const self = this;
15
+ return new Promise((resolve) => {
16
+ const systemInfo = {
17
+ ...this.minip?.getDeviceInfo(),
18
+ ...this.minip?.getWindowInfo(),
19
+ ...this.minip?.getAppBaseInfo()
20
+ };
21
+ self.systemInfo = systemInfo;
22
+ resolve(systemInfo);
23
+ });
24
+ };
10
25
  }
11
26
 
12
27
  export default Weixin;
@@ -0,0 +1,20 @@
1
+ import { GrowingIOType } from '@@/types/growingIO';
2
+
3
+ import BaseImplements from './base';
4
+
5
+ class XiaoHongShu extends BaseImplements {
6
+ constructor(public growingIO: GrowingIOType) {
7
+ super(growingIO);
8
+ this.hookSetTitle();
9
+ }
10
+
11
+ // 采集曝光事件
12
+ initImpression = (collectPage: any) => {
13
+ this.growingIO.plugins?.gioImpressionTracking?.main(
14
+ collectPage,
15
+ 'selectAll'
16
+ );
17
+ };
18
+ }
19
+
20
+ export default XiaoHongShu;
@@ -23,6 +23,7 @@ const Config: PlatformConfigType = {
23
23
  'onReachBottom', // 实际sdk不会执行,但需要写在hook里,防止被归为自定义事件
24
24
  'onResize' // 实际sdk不会执行,但需要写在hook里,防止被归为自定义事件
25
25
  ],
26
+ shareEventTypes: ['onShareAppMessage'],
26
27
  actionEventTypes: [
27
28
  'onclick',
28
29
  'tap',
@@ -0,0 +1,20 @@
1
+ import BaseConfig from './base';
2
+
3
+ const XHSConfig = {
4
+ ...BaseConfig,
5
+ pageHandlers: [...BaseConfig.pageHandlers, 'onShareChat', 'onCopyUrl'],
6
+ shareEventTypes: ['onShareAppMessage', 'onShareChat'],
7
+ listeners: {
8
+ ...BaseConfig.listeners,
9
+ page: {
10
+ ...BaseConfig.listeners.page,
11
+ shareChat: 'onShareChat',
12
+ copyUrl: 'onCopyUrl'
13
+ }
14
+ },
15
+ name: 'XiaoHongShu',
16
+ platform: 'xhsp',
17
+ scnPrefix: 'xhs_'
18
+ };
19
+
20
+ export default XHSConfig;
@@ -33,6 +33,10 @@ class GioABTest {
33
33
  public url: any;
34
34
  // 接口重试计数
35
35
  public retryCount: number;
36
+ // 标记当前是否为新访问设备
37
+ public newDevice: boolean;
38
+ // 各个实例新设备进入时的sessionId;小程序没有刷新页面保持session的问题,所以存在内存里就可以
39
+ public visitSids: any;
36
40
  constructor(public growingIO: GrowingIOType, options: any) {
37
41
  this.pluginVersion = '__PLUGIN_VERSION__';
38
42
  const {
@@ -41,8 +45,9 @@ class GioABTest {
41
45
  requestTimeout
42
46
  } = options ?? {};
43
47
  this.timeoutCheck(requestInterval, requestTimeout);
44
- const { emitter } = this.growingIO;
48
+ const { emitter, userStore } = this.growingIO;
45
49
  this.growingIO.getABTest = this.getABTest;
50
+ this.visitSids = {};
46
51
  emitter.on(EMIT_MSG.OPTION_INITIALIZED, () => {
47
52
  if (!isEmpty(abServerUrl)) {
48
53
  this.abtStorageCheck();
@@ -61,6 +66,21 @@ class GioABTest {
61
66
  );
62
67
  }
63
68
  });
69
+ emitter.on(EMIT_MSG.UID_UPDATE, ({ newUId, oldUId }) => {
70
+ // 没有旧deviceId说明是第一次进入的新设备
71
+ if (!oldUId && newUId) {
72
+ if (isString(abServerUrl)) {
73
+ const trackingId = this.growingIO.trackingId;
74
+ const sId = userStore.getSessionId(trackingId);
75
+ this.visitSids[trackingId] = sId;
76
+ } else if (isObject(abServerUrl)) {
77
+ keys(abServerUrl).forEach((trackingId: string) => {
78
+ const sId = userStore.getSessionId(trackingId);
79
+ this.visitSids[trackingId] = sId;
80
+ });
81
+ }
82
+ }
83
+ });
64
84
  this.retryCount = 0;
65
85
  }
66
86
 
@@ -121,6 +141,14 @@ class GioABTest {
121
141
 
122
142
  // 生成数据接口地址
123
143
  generateUrl = (trackingId: string, abServerUrl: string) => {
144
+ // 如果是延迟初始化的实例,当前又是首次进入设备,要补充把session存起来
145
+ if (this.newDevice && !this.visitSids[trackingId]) {
146
+ // 这里要用userStore中的getSessionId,调用这个方法的时候实例肯定已经初始化了
147
+ // 如果是新初始化可以通过getSessionId准确获取sessionExpires来生成准确的session值;
148
+ // 如果是旧实例则直接用存储中的sessionId
149
+ this.visitSids[trackingId] =
150
+ this.growingIO.userStore.getSessionId(trackingId);
151
+ }
124
152
  if (!startsWith(abServerUrl, 'http')) {
125
153
  this.url[
126
154
  trackingId
@@ -169,7 +197,7 @@ class GioABTest {
169
197
  callback: any
170
198
  ) => {
171
199
  const {
172
- userStore: { getUid },
200
+ userStore: { getUid, getSessionId },
173
201
  dataStore,
174
202
  minipInstance
175
203
  } = this.growingIO;
@@ -182,7 +210,8 @@ class GioABTest {
182
210
  accountId: projectId,
183
211
  datasourceId: dataSourceId,
184
212
  distinctId: getUid(),
185
- layerId
213
+ layerId,
214
+ newDevice: this.visitSids[trackingId] === getSessionId(trackingId)
186
215
  },
187
216
  timeout: this.requestTimeout,
188
217
  success: ({ data }: any) => {