gio-miniprogram-sdk 4.2.0 → 4.3.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.
@@ -13,7 +13,6 @@ import {
13
13
  isBoolean,
14
14
  isEmpty,
15
15
  isFunction,
16
- isNil,
17
16
  isString,
18
17
  keys,
19
18
  typeOf,
@@ -94,7 +93,7 @@ class DataStore implements DataStoreType {
94
93
  EMIT_MSG.ON_COMMIT_REQUEST,
95
94
  ({ eventData: event, trackingId }) => {
96
95
  if (event.eventType === 'VISIT') {
97
- this.lastVisitEvent = event;
96
+ this.lastVisitEvent[trackingId] = event;
98
97
  }
99
98
  if (event.eventType === 'PAGE') {
100
99
  this.lastPageEvent[trackingId] = event;
@@ -219,26 +218,25 @@ class DataStore implements DataStoreType {
219
218
  };
220
219
 
221
220
  // 保存初始来源信息
222
- setOriginalSource = (trackingId: string, { path, query }) => {
221
+ setOriginalSource = (trackingId: string, origins: any) => {
223
222
  const { minipInstance } = this.growingIO;
224
- if (isNil(this.getOriginalSource(trackingId))) {
225
- const originalSource = { path, query, title: '' };
226
- minipInstance.setStorageSync(
227
- this.getStorageKey(trackingId, 'originalSource'),
228
- JSON.stringify(originalSource)
229
- );
230
- }
223
+ minipInstance.setStorageSync(
224
+ this.getStorageKey(trackingId, 'originalSource'),
225
+ JSON.stringify(origins)
226
+ );
231
227
  };
232
228
 
233
229
  // 获取初始来源信息
234
230
  getOriginalSource = (trackingId: string) => {
235
231
  const { minipInstance } = this.growingIO;
236
- return niceTry(() =>
237
- JSON.parse(
238
- minipInstance.getStorageSync(
239
- this.getStorageKey(trackingId, 'originalSource')
232
+ return (
233
+ niceTry(() =>
234
+ JSON.parse(
235
+ minipInstance.getStorageSync(
236
+ this.getStorageKey(trackingId, 'originalSource')
237
+ )
240
238
  )
241
- )
239
+ ) ?? {}
242
240
  );
243
241
  };
244
242
 
@@ -263,12 +261,14 @@ class DataStore implements DataStoreType {
263
261
  const { platformConfig, inPlugin, minipInstance, plugins } = this.growingIO;
264
262
  const { uniVue, taro } = vdsConfig;
265
263
  // 如果是使用全量版本时,当前小程序不是框架的,要允许原生的hook
266
- if (!(uniVue || taro)) {
264
+ if (!(uniVue || taro || minipInstance.platform === 'quickapp')) {
267
265
  platformConfig.canHook = true;
268
266
  }
269
267
  // 初始化核心钩子(重写全局)
270
268
  if (!inPlugin || ['tbp', 'jdp'].includes(minipInstance.platform)) {
271
269
  this.eventHooks.initEventHooks();
270
+ } else {
271
+ this.eventHooks.initOriginalValue();
272
272
  }
273
273
  /** 第三方框架重写 */
274
274
  // uniapp
@@ -365,19 +365,11 @@ class DataStore implements DataStoreType {
365
365
  this.updateVdsConfig(trackingId, { ...trakerVds, [k]: v });
366
366
  // 从关闭到打开dataCollect时补发visit和page
367
367
  if (k === 'dataCollect' && prevConfig.dataCollect !== v && v) {
368
+ // 更新session
368
369
  userStore.setSessionId(trackingId);
369
- const { path, query, settedTitle } = this.eventHooks.currentPage;
370
- // 重新获取页面title,防止切换配置前修改了title没取到
371
- this.eventHooks.currentPage.title =
372
- settedTitle[path] ||
373
- this.growingIO.minipInstance.getPageTitle(
374
- this.growingIO.minipInstance.getCurrentPage()
375
- );
376
- // visit取当前页面值
377
- this.sendVisit(trackingId, { path, query });
378
- // 要重设一次页面时间,防止比visit早
379
- this.eventHooks.currentPage.time = Date.now();
380
- this.sendPage(trackingId, { path, query });
370
+ // 重发visit/page
371
+ this.sendVisit(trackingId);
372
+ this.sendPage(trackingId);
381
373
  }
382
374
  // 配置项有变更要全局广播
383
375
  emitter.emit(EMIT_MSG.OPTION_CHANGE, { optionName: k, optionValue: v });
@@ -431,10 +423,7 @@ class DataStore implements DataStoreType {
431
423
 
432
424
  // 手动调用visit事件的方法
433
425
  sendVisit = (trackingId: string, props?: any) => {
434
- (this.eventHooks.appEffects as any).buildVisitEvent(
435
- trackingId,
436
- props ?? this.lastVisitEvent
437
- );
426
+ (this.eventHooks.appEffects as any).buildVisitEvent(trackingId, props);
438
427
  };
439
428
 
440
429
  // 手动调用page事件的方法
@@ -482,6 +471,26 @@ class DataStore implements DataStoreType {
482
471
  }
483
472
  };
484
473
 
474
+ // 事件重组
475
+ eventRefactor = (e: any) => {
476
+ // 有的事件的path和query不能再用页面的值,所以直接使用事件中已有的值
477
+ const ne = {
478
+ ...e,
479
+ ...this.eventContextBuilder(e.trackingId, {
480
+ path: e.path,
481
+ query: e.query,
482
+ // page事件需要使用事件中原有的时间戳,其他事件也要用原来的时间戳保证事件的准确性
483
+ timestamp: e.timestamp
484
+ })
485
+ };
486
+ // 防止事件原有的属性被通用属性直接覆盖
487
+ ne.attributes = {
488
+ ...(ne.attributes ?? {}),
489
+ ...(e.attributes ?? {})
490
+ };
491
+ return ne;
492
+ };
493
+
485
494
  // 事件拦截器(有的通用维度字段需要异步获取,为了防止事件在通用维度还没返回之前就发出去)一般只有最开始的个别事件会被拦住
486
495
  eventInterceptor = (event: any) => {
487
496
  const { systemInfo, network } = this.growingIO.minipInstance;
@@ -491,17 +500,7 @@ class DataStore implements DataStoreType {
491
500
  } else if (!isEmpty(this.interceptEvents)) {
492
501
  // 有通用维度字段了,且有被拦截的事件,放一起重新添加通用维度字段再提交转换
493
502
  [...this.interceptEvents, event].forEach((e: any) => {
494
- // 有的事件的path和query不能再用页面的值,所以直接使用事件中已有的值
495
- const ne = {
496
- ...e,
497
- ...this.eventContextBuilder(event.trackingId, {
498
- path: e.path,
499
- query: e.query,
500
- // page事件需要使用事件中原有的时间戳,其他事件也要用原来的时间戳保证事件的准确性
501
- timestamp: e.timestamp
502
- })
503
- };
504
- this.eventConverter(ne);
503
+ this.eventConverter(this.eventRefactor(e));
505
504
  });
506
505
  this.interceptEvents = [];
507
506
  } else {
@@ -517,17 +516,7 @@ class DataStore implements DataStoreType {
517
516
  } = this.growingIO;
518
517
  if (systemInfo && network && !isEmpty(this.interceptEvents)) {
519
518
  [...this.interceptEvents].forEach((e: any) => {
520
- // 有的事件的path和query不能再用页面的值,所以直接使用事件中已有的值
521
- const ne = {
522
- ...e,
523
- ...this.eventContextBuilder(e.trackingId, {
524
- path: e.path,
525
- query: e.query,
526
- // page事件需要使用事件中原有的时间戳,其他事件也要用原来的时间戳保证事件的准确性
527
- timestamp: e.timestamp
528
- })
529
- };
530
- this.eventConverter(ne);
519
+ this.eventConverter(this.eventRefactor(e));
531
520
  });
532
521
  this.interceptEvents = [];
533
522
  }
@@ -208,22 +208,21 @@ class GrowingIO implements GrowingIOType {
208
208
  setPageAttributes = (trackingId: string, properties: any) => {
209
209
  if (isObject(properties) && !isEmpty(properties)) {
210
210
  const { currentPage } = this.dataStore.eventHooks;
211
+ const path = currentPage.getPagePath();
211
212
  if (isEmpty(currentPage.pageProps[trackingId])) {
212
213
  currentPage.pageProps[trackingId] = {};
213
214
  }
214
- if (isEmpty(currentPage.pageProps[trackingId][currentPage.path])) {
215
- currentPage.pageProps[trackingId][currentPage.path] = {};
215
+ if (isEmpty(currentPage.pageProps[trackingId][path])) {
216
+ currentPage.pageProps[trackingId][path] = {};
216
217
  }
217
218
  // 结果合并,动态属性不作处理
218
219
  if (!isEmpty(properties)) {
219
220
  forEach(properties, (v, k) => {
220
221
  if (
221
- !isFunction(
222
- currentPage.pageProps[trackingId][currentPage.path][k]
223
- ) ||
222
+ !isFunction(currentPage.pageProps[trackingId][path][k]) ||
224
223
  isFunction(v)
225
224
  ) {
226
- currentPage.pageProps[trackingId][currentPage.path][k] = v;
225
+ currentPage.pageProps[trackingId][path][k] = v;
227
226
  }
228
227
  });
229
228
  }
@@ -244,15 +243,13 @@ class GrowingIO implements GrowingIOType {
244
243
  !isEmpty(this.dataStore.eventHooks.currentPage.pageProps[trackingId])
245
244
  ) {
246
245
  const { currentPage } = this.dataStore.eventHooks;
246
+ const path = currentPage.getPagePath();
247
247
  if (isArray(properties) && !isEmpty(properties)) {
248
248
  properties.forEach((propName: string) => {
249
- unset(
250
- currentPage.pageProps[trackingId][currentPage.path],
251
- propName
252
- );
249
+ unset(currentPage.pageProps[trackingId][path], propName);
253
250
  });
254
251
  } else {
255
- currentPage.pageProps[trackingId][currentPage.path] = {};
252
+ currentPage.pageProps[trackingId][path] = {};
256
253
  }
257
254
  }
258
255
  } catch (error) {
@@ -319,9 +316,9 @@ class GrowingIO implements GrowingIOType {
319
316
  // 该方法很可能被放在在app的onShow中的wx.login异步回调中,
320
317
  // 此时页面的path和query可能还没取到,就拿visit事件的path和query补上
321
318
  if (!event.path) {
322
- event.path = lastVisitEvent.path;
323
- event.query = lastVisitEvent.query;
324
- event.title = lastVisitEvent.title;
319
+ event.path = lastVisitEvent[trackingId]?.path;
320
+ event.query = lastVisitEvent[trackingId]?.query;
321
+ event.title = lastVisitEvent[trackingId]?.title;
325
322
  }
326
323
  eventInterceptor(event);
327
324
  } else {
@@ -348,14 +345,7 @@ class GrowingIO implements GrowingIOType {
348
345
  // 切换userId时重置session并补发visit
349
346
  if (prevId && prevId !== userId) {
350
347
  this.userStore.setSessionId(trackingId);
351
- const { path, query, settedTitle } =
352
- this.dataStore.eventHooks.currentPage;
353
- // 重新获取页面title,防止切换配置前修改了title没取到
354
- this.dataStore.eventHooks.currentPage.title =
355
- settedTitle[path] ||
356
- this.minipInstance.getPageTitle(this.minipInstance.getCurrentPage());
357
- // visit取当前页面值
358
- this.dataStore.sendVisit(trackingId, { path, query });
348
+ this.dataStore.sendVisit(trackingId);
359
349
  }
360
350
  } else {
361
351
  callError('setUserId');
@@ -611,7 +601,9 @@ class GrowingIO implements GrowingIOType {
611
601
  if (!isEmpty(extraParams)) {
612
602
  extraParams.forEach((o) => {
613
603
  if (!ignoreFields.includes(o)) {
614
- infos[`gio${o}`] = this.dataStore.lastVisitEvent[o];
604
+ infos[`gio${o}`] = (this.dataStore.lastVisitEvent[trackingId] ?? {})[
605
+ o
606
+ ];
615
607
  }
616
608
  });
617
609
  }
package/src/index.ts CHANGED
@@ -62,16 +62,16 @@ const gdp = function () {
62
62
  getGlobal().gdp = gdp;
63
63
  getGlobal().gioSDKVersion = gioInstance.sdkVersion;
64
64
 
65
- export const GioApp = niceTry(
66
- () => gioInstance.dataStore.eventHooks.growingApp ?? App
67
- );
68
- export const GioPage = niceTry(
69
- () => gioInstance.dataStore.eventHooks.growingPage ?? Page
70
- );
71
- export const GioComponent = niceTry(
72
- () => gioInstance.dataStore.eventHooks.growingComponent ?? Component
73
- );
74
- export const GioBehavior = niceTry(
75
- () => gioInstance.dataStore.eventHooks.growingBehavior ?? Behavior
76
- );
65
+ const {
66
+ growingApp,
67
+ growingPage,
68
+ growingComponent,
69
+ growingBehavior,
70
+ initOriginalValue
71
+ } = gioInstance.dataStore.eventHooks;
72
+ initOriginalValue();
73
+ export const GioApp = niceTry(() => growingApp ?? App);
74
+ export const GioPage = niceTry(() => growingPage ?? Page);
75
+ export const GioComponent = niceTry(() => growingComponent ?? Component);
76
+ export const GioBehavior = niceTry(() => growingBehavior ?? Behavior);
77
77
  export default gdp;
@@ -7,7 +7,14 @@ import {
7
7
  SystemInfo
8
8
  } from '@@/types/minipInstance';
9
9
  import { PLATFORMS } from '@@/types/platforms';
10
- import { isFunction, isObject, isString, last } from '@@/utils/glodash';
10
+ import {
11
+ isFunction,
12
+ isObject,
13
+ isString,
14
+ last,
15
+ typeOf,
16
+ isEmpty
17
+ } from '@@/utils/glodash';
11
18
  import EMIT_MSG from '@@/constants/emitMsg';
12
19
  import {
13
20
  limitString,
@@ -126,38 +133,58 @@ class BaseInstance implements MinipInstanceType {
126
133
 
127
134
  // 获取页面标题
128
135
  getPageTitle = (page) => {
136
+ const platform = getPlainPlatform();
129
137
  let title = '';
130
- const instConfig = getPlainConfig(getPlainPlatform());
131
- try {
132
- // 第一优先级在base中的hook setNavigationBarTitle设置的值
133
- // 第二优先级支持客户自己在页面中设置页面title
134
- const data = page?.data || page.$data || {};
135
- title = isString(data?.gioPageTitle) ? data?.gioPageTitle : '';
136
- // 第三优先级取页面的navigationBarTitleText
137
- if (title.length === 0) {
138
- const pageInfo =
139
- instConfig.page[page.route] || instConfig.page[`${page.route}.html`];
140
- if (pageInfo) {
141
- title = pageInfo.window.navigationBarTitleText;
142
- } else {
143
- title = instConfig.global.window.navigationBarTitleText;
144
- }
138
+ let instConfig = getPlainConfig(platform);
139
+ if (typeOf(instConfig) === 'string') {
140
+ instConfig = niceTry(() => JSON.parse(instConfig)) ?? {};
141
+ }
142
+ // 第一优先级在base中的hook setNavigationBarTitle设置的值(在dataStore page实例中实现)
143
+ // 第二优先级支持客户自己在页面中设置页面title
144
+ const data = page?.data || page.$data || {};
145
+ title = isString(data?.gioPageTitle) ? data?.gioPageTitle : '';
146
+ if (instConfig) {
147
+ // 第三优先级app生命周期中拿不到page对象,拿生命周期的参数来匹配
148
+ const { enterParams } = this.growingIO.dataStore.eventHooks.appEffects;
149
+ if (!page.route && !isEmpty(enterParams)) {
150
+ page.route = enterParams.path || '';
151
+ title = this._getTitleFromTabbar(instConfig, page.route);
145
152
  }
146
- // 第四优先级取tabBar配置
147
- if (title.length === 0) {
148
- const tabPage = instConfig?.tabBar?.list?.find((p) => {
149
- return (
150
- p.pagePath === page.route || p.pagePath === `${page.route}.html`
151
- );
152
- });
153
- title = tabPage?.text || '';
153
+ // 第四优先级取页面的navigationBarTitleText
154
+ niceTry(() => {
155
+ if (!title) {
156
+ const instPage = instConfig.page || {};
157
+ 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
+ }
168
+ }
169
+ });
170
+ // 第五优先级取tabBar配置
171
+ if (!title) {
172
+ title = this._getTitleFromTabbar(instConfig, page.route);
154
173
  }
155
- } catch (e) {
156
- return '';
157
174
  }
158
175
  return limitString(title);
159
176
  };
160
177
 
178
+ private _getTitleFromTabbar = (
179
+ instConfig: any,
180
+ pageRoute: string
181
+ ): string => {
182
+ const tabPage = instConfig?.tabBar?.list?.find((p) => {
183
+ return p.pagePath === pageRoute || p.pagePath === `${pageRoute}.html`;
184
+ });
185
+ return tabPage?.text || '';
186
+ };
187
+
161
188
  /**
162
189
  * 存储相关
163
190
  */
@@ -48,6 +48,11 @@ class Alipay extends BaseImplements {
48
48
  setStorageSync = (key: string, value: any) => {
49
49
  this.minip?.setStorageSync({ key, data: value });
50
50
  };
51
+
52
+ // 同步移除指定数据
53
+ removeStorageSync = (key: string) => {
54
+ this.minip?.removeStorageSync({ key });
55
+ };
51
56
  }
52
57
 
53
58
  export default Alipay;
@@ -48,6 +48,11 @@ class Taobao extends BaseImplements {
48
48
  setStorageSync = (key: string, value: any) => {
49
49
  this.minip?.setStorageSync({ key, data: value });
50
50
  };
51
+
52
+ // 同步移除指定数据
53
+ removeStorageSync = (key: string) => {
54
+ this.minip?.removeStorageSync({ key });
55
+ };
51
56
  }
52
57
 
53
58
  export default Taobao;
@@ -76,16 +76,15 @@ export interface PageShareResult {
76
76
  }
77
77
 
78
78
  export interface MinipPageType {
79
- path: string;
80
- time: number;
81
- query: any;
79
+ queryOption: any;
82
80
  settedTitle: any;
83
- title: string;
84
81
  pageProps: any;
85
82
  lastLifecycle: string;
86
83
  currentLifecycle: string;
87
- parsePage: (page: any, query: any) => void;
88
- getQuery: (query: any) => string;
84
+ getPagePath: () => string;
85
+ getPageQeury: () => string;
86
+ getPageTitle: (trackingId?: string) => string;
87
+ qsQuery: (query: any) => string;
89
88
  getReferralPage: (trackingId: string) => string;
90
89
  buildShareQuery: (result: PageShareResult) => [string, string];
91
90
  updateAppMessageResult: (result: PageShareResult) => PageShareResult;
@@ -110,8 +109,7 @@ export interface EventHooksType {
110
109
  supLifeFcs: (target: any, type: 'app' | 'page') => void;
111
110
  // 对象的遍历
112
111
  objectTraverse: (target: any, fn: any) => any;
113
- // 初始化无埋点
114
- initEventHooks: () => void;
112
+
115
113
  // 生命周期方法effects
116
114
  lifeFcEffects: (eventName: string, method: any, cType: 'App' | 'Page') => any;
117
115
  // 自定义方法effects
@@ -140,4 +138,8 @@ export interface EventHooksType {
140
138
  growingBehavior: (behavior: any) => any;
141
139
  // 对原生的重写方法
142
140
  nativeGrowing: (designated?: string[]) => void;
141
+ // 初始化原始值
142
+ initOriginalValue: () => void;
143
+ // 初始化事件钩子
144
+ initEventHooks: () => void;
143
145
  }
@@ -16,6 +16,7 @@ import {
16
16
  split,
17
17
  startsWith,
18
18
  toString,
19
+ typeOf,
19
20
  unset
20
21
  } from '@@/utils/glodash';
21
22
 
@@ -239,11 +240,15 @@ export const getPlainConfig = (platform?: string) => {
239
240
  case 'swan':
240
241
  return appConfig;
241
242
  case 'tt':
242
- return __ttConfig;
243
+ return (
244
+ niceTry(() => __ttConfig) ||
245
+ global?.TMAConfig ||
246
+ globalThis?.TMAConfig
247
+ ); // 可能会拿不到
243
248
  case 'qq':
244
249
  return __qqConfig;
245
250
  case 'ks':
246
- return __ksConfig;
251
+ return __ksConfig; // 新版快手小程序已经拿不到了
247
252
  case 'jd':
248
253
  return __jdConfig;
249
254
  // 第三方框架下自动获取实例
@@ -296,7 +301,10 @@ export const getAppInst = () => {
296
301
  };
297
302
 
298
303
  export const getGlobal = () => {
299
- return niceTry(() => $global) ?? global;
304
+ return (
305
+ niceTry(() => niceTry(() => niceTry(() => $global) ?? global) ?? window) ??
306
+ globalThis
307
+ );
300
308
  };
301
309
 
302
310
  // Object参数限制
@@ -407,3 +415,14 @@ export const hashCode = (string: string, abs = false) => {
407
415
  }
408
416
  return abs ? Math.abs(hash) : hash;
409
417
  };
418
+
419
+ // 获取额外的启动参数并合并进query
420
+ export const getLaunchQuery = (originQuery: any = {}, extraData: any = {}) => {
421
+ const validData = {};
422
+ keys(extraData).forEach((k: string) => {
423
+ if (['string', 'number', 'boolean'].includes(typeOf(extraData[k]))) {
424
+ validData[k] = extraData[k];
425
+ }
426
+ });
427
+ return Object.assign({}, validData, originQuery);
428
+ };