@jolibox/implement 1.3.7 → 1.3.9

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.
@@ -12,6 +12,7 @@ export declare class NativeTaskTracker extends TaskTracker {
12
12
  private sessionId;
13
13
  private track;
14
14
  private taskUrl;
15
+ private started;
15
16
  constructor(track: Track, eventEmitter: EventEmitter<{
16
17
  visible: [boolean];
17
18
  }>, interval?: number);
@@ -1,9 +1,9 @@
1
1
  Invoking: npm run clean && npm run build:esm && tsc
2
2
 
3
- > @jolibox/implement@1.3.7 clean
3
+ > @jolibox/implement@1.3.9 clean
4
4
  > rimraf ./dist
5
5
 
6
6
 
7
- > @jolibox/implement@1.3.7 build:esm
7
+ > @jolibox/implement@1.3.9 build:esm
8
8
  > BUILD_VERSION=$(node -p "require('./package.json').version") node esbuild.config.js --format=esm
9
9
 
package/package.json CHANGED
@@ -1,17 +1,17 @@
1
1
  {
2
2
  "name": "@jolibox/implement",
3
3
  "description": "This project is Jolibox JS-SDk implement for Native && H5",
4
- "version": "1.3.7",
4
+ "version": "1.3.9",
5
5
  "main": "dist/index.js",
6
6
  "typings": "dist/index.d.ts",
7
7
  "license": "MIT",
8
8
  "dependencies": {
9
- "@jolibox/common": "1.3.7",
10
- "@jolibox/types": "1.3.7",
11
- "@jolibox/native-bridge": "1.3.7",
12
- "@jolibox/ads": "1.3.7",
9
+ "@jolibox/common": "1.3.9",
10
+ "@jolibox/types": "1.3.9",
11
+ "@jolibox/native-bridge": "1.3.9",
12
+ "@jolibox/ads": "1.3.9",
13
13
  "localforage": "1.10.0",
14
- "@jolibox/ui": "1.3.7",
14
+ "@jolibox/ui": "1.3.9",
15
15
  "web-vitals": "4.2.4"
16
16
  },
17
17
  "devDependencies": {
@@ -12,6 +12,8 @@ type TaskEvent =
12
12
  | 'GAME_TASK_EVENT' // 关卡行为
13
13
  | 'GAME_ENDED' // 游戏结束
14
14
  | 'GAME_LEVEL_UP' // 游戏关卡升级
15
+ | 'GAME_LEVEL_START' // 游戏关卡开始
16
+ | 'GAME_LEVEL_FAIL' // 游戏关卡失败
15
17
  | 'COMPLETE_WATCH_ADS'; // 完成观看广告
16
18
  export type TaskPoint = {
17
19
  event: TaskEvent;
@@ -15,6 +15,7 @@ const JOLIBOX_SUB_EVENT = 'JOLIBOX_SUB_EVENT';
15
15
 
16
16
  const CP_LOAD_FINISH = 'CP_LOAD_FINISH';
17
17
  const CP_LOAD_PROGRESS = 'CP_LOAD_PROGRESS';
18
+ const CP_GAME_TTI = 'CP_GAME_TTI';
18
19
 
19
20
  interface JoliboxCustomEvent {
20
21
  [JOLIBOX_CUSTOM_ADS_EVENT_TYPE]: {
@@ -61,6 +62,9 @@ interface JoliboxCustomEvent {
61
62
  [CP_LOAD_PROGRESS]: {
62
63
  progress: number;
63
64
  };
65
+ [CP_GAME_TTI]: {
66
+ duration?: number;
67
+ };
64
68
  }
65
69
 
66
70
  const notifyCustomEvent = <T extends keyof JoliboxCustomEvent>(eventName: T, data: JoliboxCustomEvent[T]) => {
@@ -7,6 +7,7 @@ import {
7
7
  IPlacementInfo
8
8
  } from '@jolibox/ads';
9
9
  import { IAdsHandler } from '../ads';
10
+ import { track } from '../../report';
10
11
 
11
12
  enum HuaweiQuickAdsEventEnum {
12
13
  INIT = 'huawei_quick_ads_init',
@@ -155,6 +156,11 @@ export default class HuaweiQuickAdsHandler implements IAdsHandler {
155
156
  isBreakDone = false;
156
157
  break;
157
158
  case 'beforeAd':
159
+ track('HuaweiQuickAdsAdBreakBeforeAd', {
160
+ type: 'beforeAd',
161
+ format: callbacks?.breakType === 'reward' ? 'reward' : 'interstitial'
162
+ });
163
+
158
164
  callbacks?.beforeAd?.();
159
165
  isBreakDone = false;
160
166
  break;
@@ -230,6 +236,11 @@ export default class HuaweiQuickAdsHandler implements IAdsHandler {
230
236
 
231
237
  this.callbackMap.set(callbackId, callbacks);
232
238
 
239
+ track('HuaweiQuickAdsAdBreak', {
240
+ type: params.type,
241
+ format: params.type === 'reward' ? 'reward' : 'interstitial'
242
+ });
243
+
233
244
  this.sendPostMessage(HuaweiQuickAdsEventEnum.AD_BREAK, callbackId, params);
234
245
  } catch (e) {
235
246
  params.adBreakDone?.({
@@ -17,3 +17,12 @@ commands.registerCommand('RuntimeSDK.loadProgressEvent', (progress) => {
17
17
  notifyCustomEvent('CP_LOAD_PROGRESS', { progress });
18
18
  console.log('RuntimeSDK.loadProgressEvent', progress);
19
19
  });
20
+
21
+ commands.registerCommand('RuntimeSDK.gameTTIEvent', () => {
22
+ notifyCustomEvent('CP_GAME_TTI', {
23
+ duration: performance.now()
24
+ });
25
+ track('gameTTI', {
26
+ duration: performance.now()
27
+ });
28
+ });
@@ -5,7 +5,9 @@ import { taskTracker } from '../report';
5
5
  enum ECrossFrameEvent {
6
6
  JOLIBOX_GAME_TASK_LEVEL_FINISHED = 'JOLIBOX_GAME_TASK_LEVEL_FINISHED',
7
7
  JOLIBOX_GAME_TASK_GAME_PLAY_ENDED = 'JOLIBOX_GAME_TASK_GAME_PLAY_ENDED',
8
- JOLIBOX_GAME_TASK_LEVEL_UPGRADE = 'JOLIBOX_GAME_TASK_LEVEL_UPGRADE'
8
+ JOLIBOX_GAME_TASK_LEVEL_UPGRADE = 'JOLIBOX_GAME_TASK_LEVEL_UPGRADE',
9
+ JOLIBOX_GAME_TASK_LEVEL_START = 'JOLIBOX_GAME_TASK_LEVEL_START',
10
+ JOLIBOX_GAME_TASK_LEVEL_FAILED = 'JOLIBOX_GAME_TASK_LEVEL_FAILED'
9
11
  }
10
12
 
11
13
  const notifyIframeGameTaskEvent = (eventName: string, data: any) => {
@@ -135,9 +137,60 @@ const onLevelUpgrade = createAPI('levelUpgrade', {
135
137
  }
136
138
  });
137
139
 
140
+ const onLevelStart = createAPI('levelStart', {
141
+ paramsSchema: t.tuple(
142
+ t.object({
143
+ levelId: t.or(t.string(), t.number())
144
+ })
145
+ ),
146
+ implement: async (params) => {
147
+ const { levelId } = params;
148
+ logger.info(`onLevelStart`, levelId);
149
+
150
+ notifyIframeGameTaskEvent(ECrossFrameEvent.JOLIBOX_GAME_TASK_LEVEL_START, {
151
+ levelId
152
+ });
153
+
154
+ await taskTracker.tracker('LevelStart', {
155
+ levelId
156
+ });
157
+ }
158
+ });
159
+
160
+ const onLevelFailed = createAPI('levelFailed', {
161
+ paramsSchema: t.tuple(
162
+ t.object({
163
+ levelId: t.or(t.string(), t.number()),
164
+ score: t.number().optional(),
165
+ rating: t.number().optional(),
166
+ duration: t.number().optional()
167
+ })
168
+ ),
169
+ implement: async (params) => {
170
+ const { levelId, score, rating, duration } = params;
171
+ logger.info(`onLevelFailed`, levelId, score, rating, duration);
172
+
173
+ notifyIframeGameTaskEvent(ECrossFrameEvent.JOLIBOX_GAME_TASK_LEVEL_FAILED, {
174
+ levelId,
175
+ score,
176
+ rating,
177
+ duration
178
+ });
179
+
180
+ await taskTracker.tracker('LevelFailed', {
181
+ levelId,
182
+ score,
183
+ rating,
184
+ duration
185
+ });
186
+ }
187
+ });
188
+
138
189
  commands.registerCommand('TaskTrackerSDK.levelFinished', onLevelFinished);
139
190
  commands.registerCommand('TaskTrackerSDK.gamePlayEnded', onGamePlayEnded);
140
191
  commands.registerCommand('TaskTrackerSDK.levelUpgrade', onLevelUpgrade);
192
+ commands.registerCommand('TaskTrackerSDK.levelStart', onLevelStart);
193
+ commands.registerCommand('TaskTrackerSDK.levelFailed', onLevelFailed);
141
194
 
142
195
  registerCanIUse('TaskTrackerSDK.onLevelFinished', {
143
196
  version: '1.1.25',
@@ -173,3 +226,24 @@ registerCanIUse('TaskTrackerSDK.onLevelUpgrade', {
173
226
  }
174
227
  }
175
228
  });
229
+
230
+ registerCanIUse('TaskTrackerSDK.onLevelStart', {
231
+ version: '1.3.8',
232
+ properties: {
233
+ params: {
234
+ levelId: '1.3.8'
235
+ }
236
+ }
237
+ });
238
+
239
+ registerCanIUse('TaskTrackerSDK.onLevelFailed', {
240
+ version: '1.3.8',
241
+ properties: {
242
+ params: {
243
+ levelId: '1.3.8',
244
+ score: '1.3.8',
245
+ rating: '1.3.8',
246
+ duration: '1.3.8'
247
+ }
248
+ }
249
+ });
@@ -2,6 +2,7 @@ import { createCommands } from '@jolibox/common';
2
2
  import { canIUseNative, createSyncAPI, registerCanIUse } from './base';
3
3
  import { createToast } from '@jolibox/ui';
4
4
  import '../rewards';
5
+ import { notifyCustomEvent } from '@/common/utils';
5
6
 
6
7
  const commands = createCommands();
7
8
 
@@ -195,6 +196,10 @@ const showUnlockSuccessToast = (params: { quantity: number; balance: number }) =
195
196
  warmupRewardCache(httpClient);
196
197
  warmupGemBalanceCache(httpClient);
197
198
 
199
+ adEventEmitter.on('isAdShowing', (isAdShowing) => {
200
+ notifyCustomEvent('JOLIBOX_ADS_EVENT', { isAdShowing });
201
+ });
202
+
198
203
  export const showGemSuccessToast = (params: { quantity: number; balance: number }) => {
199
204
  const { quantity } = params;
200
205
  const toastTemplate = `{slot-correct} ${quantity * -1} {slot-gem}`;
@@ -71,19 +71,14 @@ const flushSubInfoCache = createAPI('flushSubInfoCache', {
71
71
  }
72
72
  });
73
73
 
74
- const subscribe = createAPI('subscribe', {
75
- paramsSchema: t.tuple(
76
- t.object({
77
- productId: t.string()
78
- })
79
- ),
80
- implement: async (params: {
81
- productId: string;
82
- }): Promise<{
83
- subPlanId: string;
84
- errMsg: string;
85
- result: 'SUCCESS' | 'FAILED' | 'FAILURE_SUBSCRIPTED';
86
- }> => {
74
+ // base subscribe
75
+ const internalSubscribe = async (params: { productId: string; appStoreProductId?: string }) => {
76
+ const { productId } = params;
77
+ let basePlanId = params.appStoreProductId;
78
+ let appStoreProductId = params.appStoreProductId;
79
+ let nativeProductId = productId;
80
+
81
+ if (!params.appStoreProductId) {
87
82
  const tier = await subscriptionService.getTierByProductId(params.productId);
88
83
  if (!tier) {
89
84
  throw createAPIError({
@@ -91,20 +86,53 @@ const subscribe = createAPI('subscribe', {
91
86
  msg: '[JoliboxSDK]: product not found'
92
87
  });
93
88
  }
94
- const { basePlanId, appStoreProductId, nativeProductId } = tier;
89
+ basePlanId = tier.basePlanId;
90
+ appStoreProductId = tier.appStoreProductId;
91
+ nativeProductId = tier.nativeProductId;
92
+ }
95
93
 
96
- // Use subscription service with built-in compensation polling
97
- const result = await subscriptionService.subscribe({
98
- basePlanId,
99
- nativeProductId,
100
- appStoreProductId
94
+ if (!basePlanId || !appStoreProductId || !nativeProductId) {
95
+ throw createAPIError({
96
+ code: -1,
97
+ msg: '[JoliboxSDK]: product not found'
101
98
  });
99
+ }
102
100
 
103
- return {
104
- result: result.result,
105
- subPlanId: result.subPlanId,
106
- errMsg: result.message ?? ''
107
- };
101
+ const result = await subscriptionService.subscribe({
102
+ basePlanId,
103
+ nativeProductId,
104
+ appStoreProductId
105
+ });
106
+
107
+ return {
108
+ result: result.result,
109
+ subPlanId: result.subPlanId,
110
+ errMsg: result.message ?? ''
111
+ };
112
+ };
113
+
114
+ // origin subscribe
115
+ const subscribe = createAPI('subscribe', {
116
+ paramsSchema: t.tuple(
117
+ t.object({
118
+ productId: t.string(),
119
+ appStoreProductId: t.string().optional()
120
+ })
121
+ ),
122
+ implement: internalSubscribe // 直接引用
123
+ });
124
+
125
+ const subscribeSpin = createAPI('subscribeSpin', {
126
+ paramsSchema: t.tuple(
127
+ t.object({
128
+ appStoreProductId: t.string().optional()
129
+ })
130
+ ),
131
+ implement: async (params) => {
132
+ return internalSubscribe({
133
+ ...params,
134
+ productId: 'jolibox_app_spin_sub'
135
+ });
108
136
  }
109
137
  });
110
138
 
@@ -113,6 +141,7 @@ commands.registerCommand('PaymentSDK.getGemProducts', getGemProducts);
113
141
 
114
142
  commands.registerCommand('PaymentSDK.getSubscriptionPlans', getSubscriptionPlans);
115
143
  commands.registerCommand('PaymentSDK.subscribe', subscribe);
144
+ commands.registerCommand('PaymentSDK.subscribeSpin', subscribeSpin);
116
145
 
117
146
  commands.registerCommand('PaymentSDK.flushSubInfoCache', flushSubInfoCache);
118
147
 
@@ -135,3 +164,7 @@ registerCanIUse('payment.subscribe', {
135
164
  registerCanIUse('payment.flushSubInfoCache', {
136
165
  version: '1.2.9'
137
166
  });
167
+
168
+ registerCanIUse('payment.subscribeSpin', {
169
+ version: '1.3.7'
170
+ });
@@ -3,12 +3,16 @@ import { t, createSyncAPI } from './base';
3
3
  import { emitNative } from '@jolibox/native-bridge';
4
4
  import { context } from '@/common/context';
5
5
  import { track } from '../report';
6
+ import { notifyCustomEvent } from '@/common/utils';
6
7
 
7
8
  const commands = createCommands();
8
9
 
9
10
  const onLoadFinished = createSyncAPI('onLoadFinished', {
10
11
  implement: () => {
11
12
  emitNative('cpLoadFinishEvent', {}, context.webviewId, true);
13
+ notifyCustomEvent('CP_LOAD_FINISH', {
14
+ duration: performance.now()
15
+ });
12
16
  track('loadFinished', {
13
17
  duration: performance.now()
14
18
  });
@@ -22,6 +26,7 @@ const THROTTLE_INTERVAL = 200;
22
26
 
23
27
  function notifyProgress(progress: number) {
24
28
  emitNative('cpLoadProgressEvent', { progress }, context.webviewId, true);
29
+ notifyCustomEvent('CP_LOAD_PROGRESS', { progress });
25
30
  }
26
31
 
27
32
  const onLoadProgress = createSyncAPI('onLoadProgress', {
@@ -47,6 +52,28 @@ const onLoadProgress = createSyncAPI('onLoadProgress', {
47
52
  }
48
53
  });
49
54
 
55
+ const onGameTTI = createSyncAPI('onGameTTI', {
56
+ paramsSchema: t.tuple(t.number().optional()),
57
+ implement: () => {
58
+ emitNative(
59
+ 'cpGameTTIEvent',
60
+ {
61
+ duration: performance.now()
62
+ },
63
+ context.webviewId,
64
+ true
65
+ );
66
+ notifyCustomEvent('CP_GAME_TTI', {
67
+ duration: performance.now()
68
+ });
69
+ track('gameTTI', {
70
+ duration: performance.now()
71
+ });
72
+ }
73
+ });
74
+
50
75
  commands.registerCommand('RuntimeSDK.loadFinishedEvent', onLoadFinished);
51
76
 
52
77
  commands.registerCommand('RuntimeSDK.loadProgressEvent', onLoadProgress);
78
+
79
+ commands.registerCommand('RuntimeSDK.gameTTIEvent', onGameTTI);
@@ -111,9 +111,47 @@ const onLevelUpgrade = createAPI('levelUpgrade', {
111
111
  }
112
112
  });
113
113
 
114
+ const onLevelStart = createAPI('levelStart', {
115
+ paramsSchema: t.tuple(
116
+ t.object({
117
+ levelId: t.or(t.string(), t.number())
118
+ })
119
+ ),
120
+ implement: async (params) => {
121
+ const { levelId } = params;
122
+
123
+ await taskTracker.tracker('LevelStart', {
124
+ levelId
125
+ });
126
+ }
127
+ });
128
+
129
+ const onLevelFailed = createAPI('levelFailed', {
130
+ paramsSchema: t.tuple(
131
+ t.object({
132
+ levelId: t.or(t.string(), t.number()),
133
+ score: t.number().optional(),
134
+ rating: t.number().optional(),
135
+ duration: t.number().optional()
136
+ })
137
+ ),
138
+ implement: async (params) => {
139
+ const { levelId, score, rating, duration } = params;
140
+
141
+ await taskTracker.tracker('LevelFailed', {
142
+ levelId,
143
+ score,
144
+ rating,
145
+ duration
146
+ });
147
+ }
148
+ });
149
+
114
150
  commands.registerCommand('TaskTrackerSDK.levelFinished', onLevelFinished);
115
151
  commands.registerCommand('TaskTrackerSDK.gamePlayEnded', onGamePlayEnded);
116
152
  commands.registerCommand('TaskTrackerSDK.levelUpgrade', onLevelUpgrade);
153
+ commands.registerCommand('TaskTrackerSDK.levelStart', onLevelStart);
154
+ commands.registerCommand('TaskTrackerSDK.levelFailed', onLevelFailed);
117
155
 
118
156
  registerCanIUse('TaskTrackerSDK.onLevelFinished', {
119
157
  version: '1.1.25',
@@ -149,3 +187,24 @@ registerCanIUse('TaskTrackerSDK.onLevelUpgrade', {
149
187
  }
150
188
  }
151
189
  });
190
+
191
+ registerCanIUse('TaskTrackerSDK.onLevelStart', {
192
+ version: '1.3.8',
193
+ properties: {
194
+ params: {
195
+ levelId: '1.3.8'
196
+ }
197
+ }
198
+ });
199
+
200
+ registerCanIUse('TaskTrackerSDK.onLevelFailed', {
201
+ version: '1.3.8',
202
+ properties: {
203
+ params: {
204
+ levelId: '1.3.8',
205
+ score: '1.3.8',
206
+ rating: '1.3.8',
207
+ duration: '1.3.8'
208
+ }
209
+ }
210
+ });
@@ -10,6 +10,8 @@ import { Env } from '@jolibox/types';
10
10
  import { registerLanguageHandler } from '@jolibox/ui';
11
11
  import { createIframeModal, registerIframeModalToGlobal } from '../ui/modal-iframe';
12
12
  import { onFCP, onLCP, onTTFB } from 'web-vitals';
13
+ import { canIUseNative } from '../utils/can-iuse-native';
14
+
13
15
  interface IBasicMetaConfig {
14
16
  canShowRecommended: boolean;
15
17
  }
@@ -147,8 +149,11 @@ function addGameServiceReadyListener() {
147
149
  timestamp: Date.now()
148
150
  });
149
151
 
150
- // 任务上报
151
- handleTaskTracker(loadDuration);
152
+ // 任务上报,1.7.3 版本以下在onReady时机开始计算埋点
153
+ if (!canIUseNative('onJoliboxHideLoading')) {
154
+ handleTaskTracker(loadDuration);
155
+ }
156
+
152
157
  registerLanguageHandler(() => context.language);
153
158
  });
154
159
 
@@ -156,6 +161,10 @@ function addGameServiceReadyListener() {
156
161
  updateDisableExitRecommendDialog(disableExitRecommendDialog);
157
162
  globalThis.joliboxJSCore?.doExit(uuid);
158
163
  });
164
+
165
+ onNative('onJoliboxHideLoading', ({ duration }) => {
166
+ handleTaskTracker(duration);
167
+ });
159
168
  }
160
169
 
161
170
  function addDoExitLoader() {
@@ -33,6 +33,7 @@ export class NativeTaskTracker extends TaskTracker {
33
33
  private sessionId: string;
34
34
  private track: Track;
35
35
  private taskUrl: string;
36
+ private started = false;
36
37
 
37
38
  constructor(track: Track, eventEmitter: EventEmitter<{ visible: [boolean] }>, interval?: number) {
38
39
  super(eventEmitter, interval);
@@ -76,8 +77,13 @@ export class NativeTaskTracker extends TaskTracker {
76
77
  }
77
78
 
78
79
  start(duration?: number) {
80
+ if (this.started) {
81
+ console.info('[JoliboxSDK] taskTrakcer has started');
82
+ return;
83
+ }
79
84
  super.start(duration);
80
85
  this.tryReportOpenGamePlus();
86
+ this.started = true;
81
87
  }
82
88
 
83
89
  private tryReportOpenGamePlus() {