drgame-cc 1.0.48 → 1.0.50
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/drscript/Define.ts +10 -1
- package/drscript/PlatformAdapter.ts +80 -49
- package/drscript/ad-sdk/ad-sdk.js +20 -4
- package/drscript/ad-sdk/adapters/xiaomi-adapter.js +4 -1
- package/drscript/ad-sdk/reporters/reporter.d.ts +48 -3
- package/drscript/ad-sdk/reporters/reporter.js +312 -29
- package/drscript/ad-sdk/reporters/superset-lewo.js +1 -1
- package/drscript/ad-sdk/types/enums.d.ts +2 -1
- package/drscript/ad-sdk/types/enums.js +3 -1
- package/drscript/ad-sdk/types/interfaces.d.ts +60 -18
- package/drscript/component/ExitWin.ts +7 -5
- package/package.json +1 -1
- package/drscript/BtnExtra.ts +0 -17
- package/drscript/GameAnalytics.ts +0 -150
package/drscript/Define.ts
CHANGED
|
@@ -39,4 +39,13 @@ export enum AnalyticsEvent {
|
|
|
39
39
|
export enum AnalyticsAction {
|
|
40
40
|
Exposure = "exposure",
|
|
41
41
|
Click = "click",
|
|
42
|
-
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/** 事件定义映射(element_position + 曝光/点击事件名) */
|
|
45
|
+
export const AnalyticsEventMap: Record<AnalyticsEvent, { ep: string; expose: string; click?: string }> = {
|
|
46
|
+
[AnalyticsEvent.GameLoading]: { ep: "game_loading", expose: "game_loading_expose" },
|
|
47
|
+
[AnalyticsEvent.StartGameButton]: { ep: "start_game_button", expose: "start_game_expose", click: "start_game_click" },
|
|
48
|
+
[AnalyticsEvent.WatchVideoContinueButton]: { ep: "watch_video_continue_button", expose: "watch_video_continue_expose", click: "watch_video_continue_click" },
|
|
49
|
+
[AnalyticsEvent.ReplayButton]: { ep: "replay_button", expose: "replay_expose", click: "replay_click" },
|
|
50
|
+
[AnalyticsEvent.RewardVideoAd]: { ep: "reward_video_ad", expose: "ad_expose" },
|
|
51
|
+
};
|
|
@@ -1,9 +1,8 @@
|
|
|
1
|
-
import { AdEvent, AdPlatform, AdSdk, AdType } from "./ad-sdk/ad-sdk";
|
|
1
|
+
import { AdEvent, AdPlatform, AdSdk, AdType, ActionType, Reporter } from "./ad-sdk/ad-sdk";
|
|
2
2
|
import { BtnExtra } from "./component/BtnExtra";
|
|
3
3
|
import HelperWin from "./component/HelperWin";
|
|
4
|
-
import { AnalyticsAction, AnalyticsEvent, EVideoScene, FingerStyle } from "./Define";
|
|
4
|
+
import { AnalyticsAction, AnalyticsEvent, AnalyticsEventMap, EVideoScene, FingerStyle } from "./Define";
|
|
5
5
|
import FocusVisualLayer from "./focus/FocusVisualLayer";
|
|
6
|
-
import GameAnalytics from "./GameAnalytics";
|
|
7
6
|
import { Loader } from "./Loader";
|
|
8
7
|
import { UIAdapter } from "./UIAdapter";
|
|
9
8
|
import { WebBridge } from "./WebBridge";
|
|
@@ -26,51 +25,66 @@ export class PlatformAdapter {
|
|
|
26
25
|
/** 初始化
|
|
27
26
|
* @param cnName 中文名称
|
|
28
27
|
* @param minigameID 小游戏ID
|
|
28
|
+
* @param focusIcon 焦点的样式
|
|
29
29
|
*/
|
|
30
30
|
public static async init(cnName: string, minigameID: number, focusIcon: FingerStyle) {
|
|
31
|
+
// ── UI 初始化 ──
|
|
31
32
|
FocusVisualLayer.setStyle(focusIcon);
|
|
32
33
|
UIAdapter._zhName = cnName;
|
|
33
|
-
var platform: AdPlatform = AdPlatform.None;
|
|
34
34
|
UIAdapter.webBridge = new WebBridge();
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
platform = AdPlatform.Xiaomi;
|
|
38
|
-
}
|
|
35
|
+
UIAdapter.init({ focusEnabled: true });
|
|
36
|
+
|
|
39
37
|
this.contentId = minigameID.toString();
|
|
40
38
|
console.log(`[sdk-version] ${UIAdapter.version}`);
|
|
41
|
-
UIAdapter.init({ focusEnabled: true });
|
|
42
39
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
content_type: "游戏",
|
|
46
|
-
content_id: this.contentId,
|
|
47
|
-
content_title: cnName,
|
|
48
|
-
});
|
|
49
|
-
if (PlatformAdapter.isCocos) {
|
|
40
|
+
// ── Cocos 环境初始化 ──
|
|
41
|
+
if (this.isCocos) {
|
|
50
42
|
UIAdapter.toastPool = new cc.NodePool();
|
|
51
43
|
UIAdapter.prefab = await UIAdapter.loadPrefab('drres/prefab/Toast');
|
|
52
44
|
}
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
await AdSdk.init({
|
|
56
|
-
|
|
45
|
+
|
|
46
|
+
// ── 初始化广告 SDK ──
|
|
47
|
+
await AdSdk.init({
|
|
48
|
+
platform: AdPlatform.Xiaomi,
|
|
49
|
+
adapters: { [AdPlatform.Xiaomi]: { cpId: this.contentId } },
|
|
50
|
+
reporter: {
|
|
51
|
+
app_item: "25",
|
|
52
|
+
content_type: "游戏",
|
|
53
|
+
content_id: this.contentId,
|
|
54
|
+
content_title: cnName,
|
|
55
|
+
},
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
// ── 注册广告事件 ──
|
|
57
59
|
if (this.canWatchVideo) {
|
|
58
60
|
AdSdk.on(AdEvent.Closed, (data: any) => {
|
|
59
|
-
if (!data.isCompleted)
|
|
60
|
-
PlatformAdapter.showTip("必须看完视频,才能获取奖励");
|
|
61
|
-
}
|
|
61
|
+
if (!data.isCompleted) this.showTip("必须看完视频,才能获取奖励");
|
|
62
62
|
});
|
|
63
|
-
// 监听失败
|
|
64
63
|
AdSdk.on(AdEvent.Error, (data: any) => {
|
|
65
|
-
|
|
64
|
+
this.showTip(`广告暂不可用,请稍后再试(${data.message})`);
|
|
66
65
|
});
|
|
67
66
|
}
|
|
68
|
-
|
|
67
|
+
|
|
68
|
+
// ── 生命周期收尾 ──
|
|
69
|
+
AdSdk.onGameReady(UIAdapter.version);
|
|
69
70
|
UIAdapter.hookLoadScene();
|
|
70
71
|
UIAdapter.back.setFallback(() => UIAdapter.backHandler());
|
|
71
72
|
}
|
|
72
73
|
|
|
73
|
-
|
|
74
|
+
// ========================================================================
|
|
75
|
+
// 属性
|
|
76
|
+
// ========================================================================
|
|
77
|
+
|
|
78
|
+
/** 是否 Cocos 环境 */
|
|
79
|
+
public static get isCocos() { return window['cc'] != undefined; }
|
|
80
|
+
/** 是否基座环境 */
|
|
81
|
+
public static get isWebBridge() { return UIAdapter.webBridge.isAvailable(); }
|
|
82
|
+
/** 是否可以观看视频 */
|
|
83
|
+
public static get canWatchVideo() { return this.isXiaomi; }
|
|
84
|
+
/** 是否 VIP 用户 */
|
|
85
|
+
public static get isVIP() { return UIAdapter._isVIP; }
|
|
86
|
+
/** 是否小米平台 */
|
|
87
|
+
public static get isXiaomi() {
|
|
74
88
|
if (typeof window === 'undefined') return null;
|
|
75
89
|
return window['AppBridge'] || null;
|
|
76
90
|
}
|
|
@@ -102,14 +116,14 @@ export class PlatformAdapter {
|
|
|
102
116
|
};
|
|
103
117
|
let onSuccess = () => {
|
|
104
118
|
try {
|
|
105
|
-
|
|
119
|
+
this.report(AnalyticsEvent.RewardVideoAd, AnalyticsAction.Exposure);
|
|
106
120
|
callback && callback.call(target);
|
|
107
121
|
} finally {
|
|
108
122
|
fireFinish();
|
|
109
123
|
}
|
|
110
124
|
};
|
|
111
125
|
|
|
112
|
-
if (
|
|
126
|
+
if (this.canWatchVideo) {
|
|
113
127
|
// 监听奖励(用户完整看完广告触发)
|
|
114
128
|
try {
|
|
115
129
|
const result = await AdSdk.requestAd({
|
|
@@ -156,8 +170,8 @@ export class PlatformAdapter {
|
|
|
156
170
|
*/
|
|
157
171
|
public static registerButtonByName(name: string, parent: cc.Node = null) {
|
|
158
172
|
if (!parent) parent = cc.director.getScene();
|
|
159
|
-
let button =
|
|
160
|
-
|
|
173
|
+
let button = this.findChildByName(parent, name);
|
|
174
|
+
this.registerButton(button);
|
|
161
175
|
}
|
|
162
176
|
|
|
163
177
|
/**
|
|
@@ -167,7 +181,7 @@ export class PlatformAdapter {
|
|
|
167
181
|
*/
|
|
168
182
|
public static focusButtonByName(name: string, parent: cc.Node = null) {
|
|
169
183
|
if (!parent) parent = cc.director.getScene();
|
|
170
|
-
let button =
|
|
184
|
+
let button = this.findChildByName(parent, name);
|
|
171
185
|
UIAdapter.focus.focus(button);
|
|
172
186
|
}
|
|
173
187
|
|
|
@@ -184,7 +198,7 @@ export class PlatformAdapter {
|
|
|
184
198
|
public static findChildByName(parent: cc.Node, name: string): cc.Node | null {
|
|
185
199
|
if (parent.name === name) return parent;
|
|
186
200
|
for (let i = 0; i < parent.children.length; i++) {
|
|
187
|
-
let result =
|
|
201
|
+
let result = this.findChildByName(parent.children[i], name);
|
|
188
202
|
if (result) return result;
|
|
189
203
|
}
|
|
190
204
|
return null;
|
|
@@ -228,33 +242,50 @@ export class PlatformAdapter {
|
|
|
228
242
|
// ========================================================================
|
|
229
243
|
|
|
230
244
|
/**
|
|
231
|
-
*
|
|
245
|
+
* 上报事件
|
|
232
246
|
* @param event 事件类型
|
|
233
247
|
* @param action 操作类型,默认点击
|
|
234
248
|
* @param adRequestId 广告请求ID
|
|
235
249
|
*/
|
|
236
250
|
public static report(event: AnalyticsEvent, action: AnalyticsAction = AnalyticsAction.Click, adRequestId?: string) {
|
|
237
|
-
|
|
251
|
+
const def = AnalyticsEventMap[event];
|
|
252
|
+
if (!def) {
|
|
253
|
+
console.warn("[PlatformAdapter] unsupported event", event);
|
|
254
|
+
return;
|
|
255
|
+
}
|
|
256
|
+
const eventName = action === AnalyticsAction.Exposure ? def.expose : def.click;
|
|
257
|
+
if (!eventName) {
|
|
258
|
+
console.warn("[PlatformAdapter] unsupported action", action, "for event", event);
|
|
259
|
+
return;
|
|
260
|
+
}
|
|
261
|
+
const reportItem: any = {
|
|
262
|
+
element_position: def.ep,
|
|
263
|
+
action_type: action === AnalyticsAction.Exposure ? ActionType.Exposure : ActionType.Click,
|
|
264
|
+
event_name: eventName,
|
|
265
|
+
};
|
|
266
|
+
if (event === AnalyticsEvent.RewardVideoAd && adRequestId) {
|
|
267
|
+
reportItem.ad_request_id = adRequestId;
|
|
268
|
+
}
|
|
269
|
+
// 由 Reporter 内部队列批量上报
|
|
270
|
+
Reporter.report(reportItem);
|
|
238
271
|
}
|
|
239
272
|
|
|
240
273
|
/** 批量上报事件 */
|
|
241
274
|
public static reportBatch(events: AnalyticsEvent[]) {
|
|
242
|
-
|
|
275
|
+
if (events.length === 0) return;
|
|
276
|
+
const items: any[] = [];
|
|
277
|
+
for (const e of events) {
|
|
278
|
+
const def = AnalyticsEventMap[e];
|
|
279
|
+
if (!def) continue;
|
|
280
|
+
items.push({
|
|
281
|
+
element_position: def.ep,
|
|
282
|
+
action_type: ActionType.Exposure,
|
|
283
|
+
event_name: def.expose,
|
|
284
|
+
});
|
|
285
|
+
}
|
|
286
|
+
if (items.length > 0) Reporter.reportBatch(items);
|
|
243
287
|
}
|
|
244
288
|
|
|
245
|
-
// ========================================================================
|
|
246
|
-
// 属性
|
|
247
|
-
// ========================================================================
|
|
248
|
-
|
|
249
|
-
/** 是否 Cocos 环境 */
|
|
250
|
-
public static get isCocos() { return window['cc'] != undefined; }
|
|
251
|
-
/** 是否基座环境 */
|
|
252
|
-
public static get isWebBridge() { return UIAdapter.webBridge.isAvailable(); }
|
|
253
|
-
/** 是否可以观看视频 */
|
|
254
|
-
public static get canWatchVideo() { return this.isXiaomi; }
|
|
255
|
-
/** 是否 VIP 用户 */
|
|
256
|
-
public static get isVIP() { return UIAdapter._isVIP; }
|
|
257
|
-
|
|
258
289
|
/** 显示帮助窗口 */
|
|
259
290
|
public static async showHelperWin(url: string, cb: () => void) {
|
|
260
291
|
var key = `${UIAdapter._zhName}-isFirst`;
|
|
@@ -98,6 +98,11 @@ class AdSdkImpl {
|
|
|
98
98
|
});
|
|
99
99
|
}
|
|
100
100
|
|
|
101
|
+
// 桥接适配器的退出事件 → 调用 reporter 上报退出
|
|
102
|
+
adapter.on(AdEvent.Exit, function () {
|
|
103
|
+
Reporter.reportAppExit();
|
|
104
|
+
});
|
|
105
|
+
|
|
101
106
|
// 桥接适配器的按键事件
|
|
102
107
|
if (adapter.onKeyEvent) {
|
|
103
108
|
self._adapterKeyHandler = function (keyEvent) {
|
|
@@ -112,8 +117,16 @@ class AdSdkImpl {
|
|
|
112
117
|
adapter.onKeyEvent(self._adapterKeyHandler);
|
|
113
118
|
}
|
|
114
119
|
|
|
120
|
+
// 自动初始化数据上报模块(传入 reporter 配置,无配置时使用空对象默认初始化)
|
|
121
|
+
Reporter.init(config.reporter || {});
|
|
122
|
+
|
|
115
123
|
this._initialized = true;
|
|
116
124
|
console.log('[AdSdk] Initialized with platform: ' + config.platform);
|
|
125
|
+
|
|
126
|
+
// 上报「启动」事件
|
|
127
|
+
Reporter.reportAppStart();
|
|
128
|
+
|
|
129
|
+
console.log('[AdSdk] Lifecycle reporting bound.');
|
|
117
130
|
}
|
|
118
131
|
|
|
119
132
|
/**
|
|
@@ -164,18 +177,20 @@ class AdSdkImpl {
|
|
|
164
177
|
}
|
|
165
178
|
}
|
|
166
179
|
|
|
167
|
-
/**
|
|
180
|
+
/** 通知游戏暂停(自动上报切后台) */
|
|
168
181
|
onGamePause() {
|
|
169
182
|
this._ensureInit();
|
|
183
|
+
Reporter.reportSwitchBackground();
|
|
170
184
|
const adapter = this._getAdapter();
|
|
171
185
|
if (adapter.onGamePause) {
|
|
172
186
|
adapter.onGamePause();
|
|
173
187
|
}
|
|
174
188
|
}
|
|
175
189
|
|
|
176
|
-
/**
|
|
190
|
+
/** 通知游戏恢复(自动上报切回) */
|
|
177
191
|
onGameResume() {
|
|
178
192
|
this._ensureInit();
|
|
193
|
+
Reporter.reportSwitchBack();
|
|
179
194
|
const adapter = this._getAdapter();
|
|
180
195
|
if (adapter.onGameResume) {
|
|
181
196
|
adapter.onGameResume();
|
|
@@ -183,11 +198,12 @@ class AdSdkImpl {
|
|
|
183
198
|
}
|
|
184
199
|
|
|
185
200
|
/**
|
|
186
|
-
*
|
|
201
|
+
* 退出游戏(自动上报退出事件后执行实际退出)
|
|
187
202
|
* @returns {Promise<void>}
|
|
188
203
|
*/
|
|
189
204
|
async exitGame() {
|
|
190
205
|
this._ensureInit();
|
|
206
|
+
// 通知适配器执行退出,适配器的 onExitConfirmed 回调会触发上报
|
|
191
207
|
const adapter = this._getAdapter();
|
|
192
208
|
if (adapter.exitGame) {
|
|
193
209
|
return adapter.exitGame();
|
|
@@ -319,4 +335,4 @@ module.exports = {
|
|
|
319
335
|
// 类
|
|
320
336
|
XiaomiAdapter,
|
|
321
337
|
EventEmitter,
|
|
322
|
-
};
|
|
338
|
+
};
|
|
@@ -420,6 +420,9 @@ class XiaomiAdapter {
|
|
|
420
420
|
|
|
421
421
|
// ── 退出确认 ──
|
|
422
422
|
case 'onExitConfirmed': {
|
|
423
|
+
// 触发退出回调事件,供 SDK 层调用 reporter 上报
|
|
424
|
+
this._emitter.emit(AdEvent.Exit, {});
|
|
425
|
+
|
|
423
426
|
if (this._exitResolve) {
|
|
424
427
|
this._exitResolve();
|
|
425
428
|
this._exitResolve = null;
|
|
@@ -446,4 +449,4 @@ class XiaomiAdapter {
|
|
|
446
449
|
}
|
|
447
450
|
}
|
|
448
451
|
|
|
449
|
-
module.exports = { XiaomiAdapter };
|
|
452
|
+
module.exports = { XiaomiAdapter };
|
|
@@ -10,18 +10,48 @@ export declare const ActionType: {
|
|
|
10
10
|
Exposure: '曝光';
|
|
11
11
|
/** 点击 */
|
|
12
12
|
Click: '点击';
|
|
13
|
+
/** 开始播放 */
|
|
14
|
+
StartPlay: '开始播放';
|
|
15
|
+
/** 结束播放(需上报时长 action_value) */
|
|
16
|
+
EndPlay: '结束播放';
|
|
17
|
+
/** 分享 */
|
|
18
|
+
Share: '分享';
|
|
19
|
+
/** 订购(需上报成功订购金额) */
|
|
20
|
+
Order: '订购';
|
|
21
|
+
/** 启动 */
|
|
22
|
+
Start: '启动';
|
|
23
|
+
/** 退出 */
|
|
24
|
+
Exit: '退出';
|
|
25
|
+
/** 切后台 */
|
|
26
|
+
SwitchBackground: '切后台';
|
|
27
|
+
/** 切回 */
|
|
28
|
+
SwitchBack: '切回';
|
|
13
29
|
};
|
|
14
30
|
|
|
31
|
+
/** 批量上报配置 */
|
|
32
|
+
export interface IBatchConfig {
|
|
33
|
+
/** 每批最大条数 */
|
|
34
|
+
perNum: number;
|
|
35
|
+
/** 发送间隔(秒) */
|
|
36
|
+
spaceSec: number;
|
|
37
|
+
}
|
|
38
|
+
|
|
15
39
|
/** 数据上报模块(单例) */
|
|
16
40
|
export declare const Reporter: {
|
|
17
41
|
/** 初始化上报模块 */
|
|
18
42
|
init(config: IReporterConfig): void;
|
|
19
43
|
|
|
44
|
+
/** 从后端获取批量上报配置 */
|
|
45
|
+
fetchReportConfig(callback?: (config: IBatchConfig) => void): void;
|
|
46
|
+
|
|
20
47
|
/** 单次上报 */
|
|
21
|
-
report(data: IReportItem): void;
|
|
48
|
+
report(data: IReportItem, immediate?: boolean): void;
|
|
22
49
|
|
|
23
50
|
/** 批量上报 */
|
|
24
|
-
reportBatch(dataList: IReportItem[], commonInfo?: IReportItem): void;
|
|
51
|
+
reportBatch(dataList: IReportItem[], commonInfo?: IReportItem, immediate?: boolean): void;
|
|
52
|
+
|
|
53
|
+
/** 立即刷新队列,将队列中所有事件立即发送 */
|
|
54
|
+
flushQueue(): void;
|
|
25
55
|
|
|
26
56
|
/** 获取或创建设备唯一ID */
|
|
27
57
|
createDeviceId(): string;
|
|
@@ -35,6 +65,21 @@ export declare const Reporter: {
|
|
|
35
65
|
/** 获取当前公共字段 */
|
|
36
66
|
getCommonInfo(): Partial<IReportItem>;
|
|
37
67
|
|
|
68
|
+
/** 更新用户信息(登录后调用,传入memberId) */
|
|
69
|
+
updateUserInfo(userInfo: Record<string, string>): void;
|
|
70
|
+
|
|
71
|
+
/** 上报「启动」事件 */
|
|
72
|
+
reportAppStart(): void;
|
|
73
|
+
|
|
74
|
+
/** 上报「切后台」事件 */
|
|
75
|
+
reportSwitchBackground(): void;
|
|
76
|
+
|
|
77
|
+
/** 上报「切回」事件 */
|
|
78
|
+
reportSwitchBack(): void;
|
|
79
|
+
|
|
80
|
+
/** 上报「退出」事件 */
|
|
81
|
+
reportAppExit(): void;
|
|
82
|
+
|
|
38
83
|
/** 获取底层上报实例(高级用法) */
|
|
39
84
|
readonly instance: any;
|
|
40
|
-
};
|
|
85
|
+
};
|
|
@@ -2,11 +2,15 @@
|
|
|
2
2
|
* 数据上报模块 - 统一封装层
|
|
3
3
|
*
|
|
4
4
|
* 内部使用 supersetLewo 上报脚本,对外提供简洁的调用接口:
|
|
5
|
-
* Reporter.init(config)
|
|
6
|
-
* Reporter.report(data)
|
|
7
|
-
* Reporter.reportBatch(list)
|
|
8
|
-
* Reporter.
|
|
9
|
-
* Reporter.
|
|
5
|
+
* Reporter.init(config) — 初始化
|
|
6
|
+
* Reporter.report(data, immediate) — 单次上报(默认加入队列批量发送)
|
|
7
|
+
* Reporter.reportBatch(list) — 批量上报
|
|
8
|
+
* Reporter.flushQueue() — 立即刷新队列
|
|
9
|
+
* Reporter.reportAppStart() — 启动事件
|
|
10
|
+
* Reporter.reportSwitchBackground() — 切后台事件
|
|
11
|
+
* Reporter.reportSwitchBack() — 切回事件
|
|
12
|
+
* Reporter.reportAppExit() — 退出事件(自动计算游戏时长)
|
|
13
|
+
* Reporter.updateUserInfo(info) — 登录后更新用户信息
|
|
10
14
|
*/
|
|
11
15
|
|
|
12
16
|
var supersetLewo = require('./superset-lewo');
|
|
@@ -20,8 +24,118 @@ var ActionType = {
|
|
|
20
24
|
Exposure: '曝光',
|
|
21
25
|
/** 点击 */
|
|
22
26
|
Click: '点击',
|
|
27
|
+
/** 开始播放 */
|
|
28
|
+
StartPlay: '开始播放',
|
|
29
|
+
/** 结束播放(需上报时长 action_value) */
|
|
30
|
+
EndPlay: '结束播放',
|
|
31
|
+
/** 分享 */
|
|
32
|
+
Share: '分享',
|
|
33
|
+
/** 订购(需上报成功订购金额) */
|
|
34
|
+
Order: '订购',
|
|
35
|
+
/** 启动 */
|
|
36
|
+
Start: '启动',
|
|
37
|
+
/** 退出 */
|
|
38
|
+
Exit: '退出',
|
|
39
|
+
/** 切后台 */
|
|
40
|
+
SwitchBackground: '切后台',
|
|
41
|
+
/** 切回 */
|
|
42
|
+
SwitchBack: '切回',
|
|
23
43
|
};
|
|
24
44
|
|
|
45
|
+
// ────────────────────────────────────────
|
|
46
|
+
// 内部队列管理(无需修改 supersetLewo)
|
|
47
|
+
// ────────────────────────────────────────
|
|
48
|
+
|
|
49
|
+
/** 配置接口地址 */
|
|
50
|
+
var CONFIG_URL = 'http://sup.daoran.tv/bi-api/api/config/get';
|
|
51
|
+
|
|
52
|
+
/** 事件队列 */
|
|
53
|
+
var _eventQueue = [];
|
|
54
|
+
/** 定时器句柄 */
|
|
55
|
+
var _batchTimer = null;
|
|
56
|
+
/** 每批最大条数 */
|
|
57
|
+
var _perNum = 10;
|
|
58
|
+
/** 发送间隔(秒) */
|
|
59
|
+
var _spaceSec = 30;
|
|
60
|
+
/** 队列模式是否已启用 */
|
|
61
|
+
var _queueEnabled = false;
|
|
62
|
+
|
|
63
|
+
/** 会话启动时间戳(毫秒),用于计算游戏时长 */
|
|
64
|
+
var _sessionStartTime = 0;
|
|
65
|
+
|
|
66
|
+
/** 额外用户信息(登录后填充,合并到上报 user 对象) */
|
|
67
|
+
var _extraUserInfo = {};
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* 修补 supersetLewo.getUserInfo,使登录后的额外字段能合并到 user 对象
|
|
71
|
+
* 避免修改 superset-lewo.js 源文件
|
|
72
|
+
*/
|
|
73
|
+
(function _patchGetUserInfo() {
|
|
74
|
+
var originalGetUserInfo = supersetLewo.getUserInfo;
|
|
75
|
+
supersetLewo.getUserInfo = function () {
|
|
76
|
+
var info = originalGetUserInfo();
|
|
77
|
+
// 合并额外字段(如 user_id、user_type 等)
|
|
78
|
+
for (var key in _extraUserInfo) {
|
|
79
|
+
if (_extraUserInfo.hasOwnProperty(key)) {
|
|
80
|
+
info[key] = _extraUserInfo[key];
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
return info;
|
|
84
|
+
};
|
|
85
|
+
})();
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* 刷新队列 —— 将队列中所有事件打包发送
|
|
89
|
+
*/
|
|
90
|
+
function _flushQueue() {
|
|
91
|
+
if (_eventQueue.length === 0) return;
|
|
92
|
+
var batch = _eventQueue.splice(0, _perNum);
|
|
93
|
+
supersetLewo.batchReporting(batch);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* 添加单条事件到队列
|
|
98
|
+
*/
|
|
99
|
+
function _addToQueue(eventItem) {
|
|
100
|
+
_eventQueue.push(eventItem);
|
|
101
|
+
if (_eventQueue.length >= _perNum) {
|
|
102
|
+
_flushQueue();
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* 批量添加事件到队列
|
|
108
|
+
*/
|
|
109
|
+
function _addBatchToQueue(eventList) {
|
|
110
|
+
if (!Array.isArray(eventList) || eventList.length === 0) return;
|
|
111
|
+
for (var i = 0; i < eventList.length; i++) {
|
|
112
|
+
_eventQueue.push(eventList[i]);
|
|
113
|
+
}
|
|
114
|
+
if (_eventQueue.length >= _perNum) {
|
|
115
|
+
_flushQueue();
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* 启用队列定时刷新
|
|
121
|
+
*/
|
|
122
|
+
function _startQueueTimer() {
|
|
123
|
+
if (_queueEnabled) return;
|
|
124
|
+
_queueEnabled = true;
|
|
125
|
+
_batchTimer = setInterval(_flushQueue, _spaceSec * 1000);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* 停止队列定时刷新
|
|
130
|
+
*/
|
|
131
|
+
function _stopQueueTimer() {
|
|
132
|
+
_queueEnabled = false;
|
|
133
|
+
if (_batchTimer) {
|
|
134
|
+
clearInterval(_batchTimer);
|
|
135
|
+
_batchTimer = null;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
25
139
|
// ────────────────────────────────────────
|
|
26
140
|
// Reporter 实现
|
|
27
141
|
// ────────────────────────────────────────
|
|
@@ -33,6 +147,40 @@ var Reporter = {
|
|
|
33
147
|
/** 公共字段缓存(初始化时设置,每次上报自动合并) */
|
|
34
148
|
_commonInfo: {},
|
|
35
149
|
|
|
150
|
+
/**
|
|
151
|
+
* 从后端获取批量上报配置
|
|
152
|
+
* @param {Function} [callback] - 回调函数,接收 { perNum, spaceSec }
|
|
153
|
+
*/
|
|
154
|
+
fetchReportConfig: function (callback) {
|
|
155
|
+
var self = this;
|
|
156
|
+
supersetLewo.ajax({
|
|
157
|
+
url: CONFIG_URL,
|
|
158
|
+
type: 'get',
|
|
159
|
+
dataType: 'json',
|
|
160
|
+
data: {},
|
|
161
|
+
success: function (xhr, rsp) {
|
|
162
|
+
if (rsp && rsp.code === 200 && rsp.data) {
|
|
163
|
+
var cfg = rsp.data;
|
|
164
|
+
_perNum = cfg.perNum || 10;
|
|
165
|
+
_spaceSec = cfg.spaceSec || 30;
|
|
166
|
+
if (typeof callback === 'function') {
|
|
167
|
+
callback({ perNum: _perNum, spaceSec: _spaceSec });
|
|
168
|
+
}
|
|
169
|
+
} else {
|
|
170
|
+
if (typeof callback === 'function') {
|
|
171
|
+
callback({ perNum: 10, spaceSec: 30 });
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
},
|
|
175
|
+
error: function (xhr, rsp) {
|
|
176
|
+
console.warn('[Reporter] fetchReportConfig failed, use defaults');
|
|
177
|
+
if (typeof callback === 'function') {
|
|
178
|
+
callback({ perNum: 10, spaceSec: 30 });
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
});
|
|
182
|
+
},
|
|
183
|
+
|
|
36
184
|
/**
|
|
37
185
|
* 初始化上报模块
|
|
38
186
|
* @param {import('../types/interfaces').IReporterConfig} config
|
|
@@ -69,33 +217,46 @@ var Reporter = {
|
|
|
69
217
|
}
|
|
70
218
|
|
|
71
219
|
supersetLewo.initUserInfo({
|
|
72
|
-
os_type: "",
|
|
73
|
-
os_version: "",
|
|
74
|
-
app_version: "1.0.0",
|
|
75
|
-
app_item: config.app_item, //
|
|
76
|
-
app_name: config.content_title,
|
|
77
|
-
app_project: config.content_id,
|
|
78
|
-
province: "",
|
|
79
|
-
city: "",
|
|
80
|
-
uid: "",
|
|
81
|
-
user_id: "",
|
|
82
|
-
device_id: this._commonInfo.device_id,
|
|
83
|
-
device_brand: "", //
|
|
84
|
-
device_model: "",
|
|
85
|
-
network_type: "",
|
|
86
|
-
carrier: ""
|
|
87
|
-
//
|
|
220
|
+
os_type: config.os_type || "", // 操作系统类型 android/ios
|
|
221
|
+
os_version: config.os_version || "", // 操作系统版本号
|
|
222
|
+
app_version: config.app_version || "1.0.0", // APP版本号
|
|
223
|
+
app_item: config.app_item || "", // 渠道编码(项目编码)
|
|
224
|
+
app_name: config.app_name || config.content_title || "", // APP名称
|
|
225
|
+
app_project: config.app_project || config.content_id || "", // 产品编码
|
|
226
|
+
province: config.province || "", // 省份编码
|
|
227
|
+
city: config.city || "", // 城市编码
|
|
228
|
+
uid: config.uid || "", // 注册登录用户全局UID;游客/未登录填空字符串
|
|
229
|
+
user_id: config.user_id || "", // 会员ID(memberId),无则填空字符串,不用uid填充
|
|
230
|
+
device_id: this._commonInfo.device_id, // 设备唯一ID
|
|
231
|
+
device_brand: config.device_brand || "", // 设备品牌,小写
|
|
232
|
+
device_model: config.device_model || "", // 设备型号
|
|
233
|
+
network_type: config.network_type || "", // 网络类型:wifi/cellular
|
|
234
|
+
carrier: config.carrier || "", // 运营商
|
|
235
|
+
promotion_flag: config.promotion_flag || "0", // 推广标识(ubp接口获取,1推广/0自然)
|
|
236
|
+
user_type: config.user_type || "0" // 用户身份类型(0游客/1注册用户/2付费用户)
|
|
88
237
|
});
|
|
89
238
|
|
|
90
239
|
this._initialized = true;
|
|
240
|
+
|
|
241
|
+
// 记录启动时间
|
|
242
|
+
_sessionStartTime = Date.now();
|
|
243
|
+
|
|
244
|
+
// 异步拉取批量配置,拉取成功后启动队列
|
|
245
|
+
var self = this;
|
|
246
|
+
this.fetchReportConfig(function (batchCfg) {
|
|
247
|
+
_startQueueTimer();
|
|
248
|
+
console.log('[Reporter] Batch config:', batchCfg, '- Queue mode enabled');
|
|
249
|
+
});
|
|
250
|
+
|
|
91
251
|
console.log('[Reporter] Initialized, reportUrl:', supersetLewo.config.reportUrl);
|
|
92
252
|
},
|
|
93
253
|
|
|
94
254
|
/**
|
|
95
255
|
* 单次上报
|
|
96
|
-
* @param {import('../types/interfaces').IReportItem} data -
|
|
256
|
+
* @param {import('../types/interfaces').IReportItem} data - 上报数据
|
|
257
|
+
* @param {boolean} [immediate=false] - 是否立即发送(不经过队列)
|
|
97
258
|
*/
|
|
98
|
-
report: function (data) {
|
|
259
|
+
report: function (data, immediate) {
|
|
99
260
|
if (!this._initialized) {
|
|
100
261
|
console.warn('[Reporter] Not initialized. Call Reporter.init() first.');
|
|
101
262
|
return;
|
|
@@ -120,15 +281,22 @@ var Reporter = {
|
|
|
120
281
|
merged.device_id = supersetLewo.createDeviceId();
|
|
121
282
|
}
|
|
122
283
|
|
|
123
|
-
|
|
284
|
+
if (immediate) {
|
|
285
|
+
// 立即发送(生命周期事件等需要及时上报的场景)
|
|
286
|
+
supersetLewo.superBatchReport(merged);
|
|
287
|
+
} else {
|
|
288
|
+
// 加入队列,凑批次后批量发送
|
|
289
|
+
_addToQueue(merged);
|
|
290
|
+
}
|
|
124
291
|
},
|
|
125
292
|
|
|
126
293
|
/**
|
|
127
294
|
* 批量上报
|
|
128
|
-
* @param {Array<import('../types/interfaces').IReportItem>} dataList -
|
|
129
|
-
* @param {import('../types/interfaces').IReportItem} [commonInfo] -
|
|
295
|
+
* @param {Array<import('../types/interfaces').IReportItem>} dataList - 上报数据列表
|
|
296
|
+
* @param {import('../types/interfaces').IReportItem} [commonInfo] - 可选公共字段
|
|
297
|
+
* @param {boolean} [immediate=false] - 是否立即发送(不经过队列)
|
|
130
298
|
*/
|
|
131
|
-
reportBatch: function (dataList, commonInfo) {
|
|
299
|
+
reportBatch: function (dataList, commonInfo, immediate) {
|
|
132
300
|
if (!this._initialized) {
|
|
133
301
|
console.warn('[Reporter] Not initialized. Call Reporter.init() first.');
|
|
134
302
|
return;
|
|
@@ -158,7 +326,122 @@ var Reporter = {
|
|
|
158
326
|
mergedCommon.device_id = supersetLewo.createDeviceId();
|
|
159
327
|
}
|
|
160
328
|
|
|
161
|
-
|
|
329
|
+
// 合并公共字段到各事件中
|
|
330
|
+
var items = [];
|
|
331
|
+
for (var i = 0; i < dataList.length; i++) {
|
|
332
|
+
var item = {};
|
|
333
|
+
for (key in mergedCommon) {
|
|
334
|
+
if (mergedCommon.hasOwnProperty(key)) {
|
|
335
|
+
item[key] = mergedCommon[key];
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
for (key in dataList[i]) {
|
|
339
|
+
if (dataList[i].hasOwnProperty(key)) {
|
|
340
|
+
item[key] = dataList[i][key];
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
items.push(item);
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
if (immediate) {
|
|
347
|
+
// 立即发送
|
|
348
|
+
supersetLewo.batchReporting(items);
|
|
349
|
+
} else {
|
|
350
|
+
// 加入队列
|
|
351
|
+
_addBatchToQueue(items);
|
|
352
|
+
}
|
|
353
|
+
},
|
|
354
|
+
|
|
355
|
+
/**
|
|
356
|
+
* 立即刷新队列,将队列中所有事件立即发送
|
|
357
|
+
*/
|
|
358
|
+
flushQueue: function () {
|
|
359
|
+
_flushQueue();
|
|
360
|
+
},
|
|
361
|
+
|
|
362
|
+
/**
|
|
363
|
+
* 上报「启动」事件 - APP启动成功后调用,记录启动时间
|
|
364
|
+
*/
|
|
365
|
+
reportAppStart: function () {
|
|
366
|
+
_sessionStartTime = Date.now();
|
|
367
|
+
this.report({
|
|
368
|
+
element_position: "AppLaunch",
|
|
369
|
+
position_name: "应用启动",
|
|
370
|
+
element_type: "page",
|
|
371
|
+
element_name: "app_start",
|
|
372
|
+
action_type: ActionType.Start,
|
|
373
|
+
action_value: ""
|
|
374
|
+
}, true);
|
|
375
|
+
},
|
|
376
|
+
|
|
377
|
+
/**
|
|
378
|
+
* 上报「切后台」事件 - APP切到后台时调用
|
|
379
|
+
* 计算当前时间与启动时间差,action_value传时间差(秒)
|
|
380
|
+
*/
|
|
381
|
+
reportSwitchBackground: function () {
|
|
382
|
+
var duration = Math.floor((Date.now() - _sessionStartTime) / 1000);
|
|
383
|
+
this.report({
|
|
384
|
+
element_position: "AppBackground",
|
|
385
|
+
position_name: "应用切后台",
|
|
386
|
+
element_type: "page",
|
|
387
|
+
element_name: "app_switch_background",
|
|
388
|
+
action_type: ActionType.SwitchBackground,
|
|
389
|
+
action_value: String(duration)
|
|
390
|
+
}, true);
|
|
391
|
+
},
|
|
392
|
+
|
|
393
|
+
/**
|
|
394
|
+
* 上报「切回」事件 - APP从后台切回时调用,上报后更新启动时间
|
|
395
|
+
*/
|
|
396
|
+
reportSwitchBack: function () {
|
|
397
|
+
this.report({
|
|
398
|
+
element_position: "AppForeground",
|
|
399
|
+
position_name: "应用切前台",
|
|
400
|
+
element_type: "page",
|
|
401
|
+
element_name: "app_switch_back",
|
|
402
|
+
action_type: ActionType.SwitchBack,
|
|
403
|
+
action_value: ""
|
|
404
|
+
}, true);
|
|
405
|
+
// 更新启动时间
|
|
406
|
+
_sessionStartTime = Date.now();
|
|
407
|
+
},
|
|
408
|
+
|
|
409
|
+
/**
|
|
410
|
+
* 上报「退出」事件 - APP退出前调用
|
|
411
|
+
* 计算当前时间与启动时间差,action_value传时间差(秒),给后台上传游戏时长
|
|
412
|
+
*/
|
|
413
|
+
reportAppExit: function () {
|
|
414
|
+
// 先刷新队列中剩余事件
|
|
415
|
+
_flushQueue();
|
|
416
|
+
|
|
417
|
+
var duration = Math.floor((Date.now() - _sessionStartTime) / 1000);
|
|
418
|
+
this.report({
|
|
419
|
+
element_position: "AppExit",
|
|
420
|
+
position_name: "应用退出",
|
|
421
|
+
element_type: "page",
|
|
422
|
+
element_name: "app_exit",
|
|
423
|
+
action_type: ActionType.Exit,
|
|
424
|
+
action_value: String(duration)
|
|
425
|
+
}, true);
|
|
426
|
+
// 重置启动时间
|
|
427
|
+
_sessionStartTime = 0;
|
|
428
|
+
},
|
|
429
|
+
|
|
430
|
+
/**
|
|
431
|
+
* 更新用户信息(登录后调用,传入memberId等)
|
|
432
|
+
* @param {Object} userInfo - 用户信息,如 { user_id: 'nC650471', user_type: '1' }
|
|
433
|
+
*/
|
|
434
|
+
updateUserInfo: function (userInfo) {
|
|
435
|
+
if (!userInfo) return;
|
|
436
|
+
// 更新公共字段(合并到 data 事件中)
|
|
437
|
+
this.setCommonInfo(userInfo);
|
|
438
|
+
// 更新额外用户信息(合并到上报的 user 对象中)
|
|
439
|
+
for (var key in userInfo) {
|
|
440
|
+
if (userInfo.hasOwnProperty(key)) {
|
|
441
|
+
_extraUserInfo[key] = userInfo[key];
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
console.log('[Reporter] updateUserInfo:', userInfo);
|
|
162
445
|
},
|
|
163
446
|
|
|
164
447
|
/**
|
|
@@ -214,4 +497,4 @@ var Reporter = {
|
|
|
214
497
|
module.exports = {
|
|
215
498
|
Reporter: Reporter,
|
|
216
499
|
ActionType: ActionType,
|
|
217
|
-
};
|
|
500
|
+
};
|
|
@@ -23,6 +23,7 @@ export declare enum AdEvent {
|
|
|
23
23
|
Closed = 'closed',
|
|
24
24
|
Reward = 'reward',
|
|
25
25
|
Error = 'error',
|
|
26
|
+
Exit = 'exit',
|
|
26
27
|
}
|
|
27
28
|
|
|
28
29
|
/** 广告错误码(聚合层统一) */
|
|
@@ -62,4 +63,4 @@ export declare enum KeyCode {
|
|
|
62
63
|
export declare enum KeyAction {
|
|
63
64
|
Down = 'down',
|
|
64
65
|
Up = 'up',
|
|
65
|
-
}
|
|
66
|
+
}
|
|
@@ -36,6 +36,8 @@ const AdEvent = {
|
|
|
36
36
|
Reward: 'reward',
|
|
37
37
|
/** 广告失败 */
|
|
38
38
|
Error: 'error',
|
|
39
|
+
/** 退出确认(原生层确认退出) */
|
|
40
|
+
Exit: 'exit',
|
|
39
41
|
};
|
|
40
42
|
|
|
41
43
|
/** 广告错误码(聚合层统一) */
|
|
@@ -108,4 +110,4 @@ module.exports = {
|
|
|
108
110
|
DevicePlatform,
|
|
109
111
|
KeyCode,
|
|
110
112
|
KeyAction,
|
|
111
|
-
};
|
|
113
|
+
};
|
|
@@ -75,31 +75,71 @@ export interface IReporterConfig {
|
|
|
75
75
|
content_id?: string;
|
|
76
76
|
/** 游戏名 */
|
|
77
77
|
content_title?: string;
|
|
78
|
+
/** 操作系统类型 android/ios */
|
|
79
|
+
os_type?: string;
|
|
80
|
+
/** 操作系统版本号 */
|
|
81
|
+
os_version?: string;
|
|
82
|
+
/** APP版本号 */
|
|
83
|
+
app_version?: string;
|
|
84
|
+
/** APP名称 */
|
|
85
|
+
app_name?: string;
|
|
86
|
+
/** 产品编码 */
|
|
87
|
+
app_project?: string;
|
|
88
|
+
/** 省份编码 */
|
|
89
|
+
province?: string;
|
|
90
|
+
/** 城市编码 */
|
|
91
|
+
city?: string;
|
|
92
|
+
/** 注册登录用户全局UID;游客/未登录填空字符串 */
|
|
93
|
+
uid?: string;
|
|
94
|
+
/** 会员ID(memberId),无则填空字符串 */
|
|
95
|
+
user_id?: string;
|
|
96
|
+
/** 设备品牌,小写 */
|
|
97
|
+
device_brand?: string;
|
|
98
|
+
/** 设备型号 */
|
|
99
|
+
device_model?: string;
|
|
100
|
+
/** 网络类型:wifi/cellular */
|
|
101
|
+
network_type?: string;
|
|
102
|
+
/** 运营商 */
|
|
103
|
+
carrier?: string;
|
|
104
|
+
/** 推广标识(ubp接口获取,1推广/0自然) */
|
|
105
|
+
promotion_flag?: string;
|
|
106
|
+
/** 用户身份类型(0游客/1注册用户/2付费用户) */
|
|
107
|
+
user_type?: string;
|
|
78
108
|
}
|
|
79
109
|
|
|
80
110
|
/** 上报数据项(下划线字段格式) */
|
|
81
111
|
export interface IReportItem {
|
|
82
|
-
/**
|
|
83
|
-
|
|
84
|
-
/**
|
|
85
|
-
|
|
86
|
-
/**
|
|
87
|
-
|
|
88
|
-
/**
|
|
89
|
-
|
|
90
|
-
/**
|
|
112
|
+
/** 产品定义元素位置编码 */
|
|
113
|
+
element_position?: string;
|
|
114
|
+
/** 元素位置中文名称 */
|
|
115
|
+
position_name?: string;
|
|
116
|
+
/** OMS后台页面编码,无则空 */
|
|
117
|
+
page_code?: string;
|
|
118
|
+
/** OMS后台页面名称,无则空 */
|
|
119
|
+
page_name?: string;
|
|
120
|
+
/** OMS后台楼层ID,无则空 */
|
|
121
|
+
floor_id?: string;
|
|
122
|
+
/** OMS后台楼层名称,无则空 */
|
|
123
|
+
floor_name?: string;
|
|
124
|
+
/** 元素类型枚举(page/vlist/plist/res/act/link等) */
|
|
125
|
+
element_type?: string;
|
|
126
|
+
/** 元素名称/标题 */
|
|
127
|
+
element_name?: string;
|
|
128
|
+
/** 最小颗粒度内容ID */
|
|
91
129
|
content_id?: string;
|
|
92
|
-
/**
|
|
130
|
+
/** 最小颗粒度内容标题 */
|
|
93
131
|
content_title?: string;
|
|
94
|
-
/**
|
|
95
|
-
|
|
96
|
-
/**
|
|
132
|
+
/** 扩展属性1,补充附属信息 */
|
|
133
|
+
ext_attr1?: string;
|
|
134
|
+
/** 扩展属性2,补充附属ID */
|
|
135
|
+
ext_attr2?: string;
|
|
136
|
+
/** 行为枚举:曝光、点击、开始播放、结束播放、分享、订购、启动、退出、切后台 */
|
|
97
137
|
action_type?: string;
|
|
98
|
-
/**
|
|
138
|
+
/** 行为值,时长填秒数,订购填金额(单位:分);无时间跨度行为填空 */
|
|
139
|
+
action_value?: string;
|
|
140
|
+
/** 友盟需要上报的事件名(仅友盟使用) */
|
|
99
141
|
event_name?: string;
|
|
100
|
-
/**
|
|
101
|
-
ad_request_id?: string;
|
|
102
|
-
/** 客户端事件时间(yyyy-MM-dd HH:mm:ss,不传则自动生成) */
|
|
142
|
+
/** 事件发生时间,格式 yyyy-MM-dd HH:mm:ss,不传则自动生成 */
|
|
103
143
|
event_time?: string;
|
|
104
144
|
}
|
|
105
145
|
|
|
@@ -282,6 +322,8 @@ export interface IAdSdkConfig {
|
|
|
282
322
|
customAdapters?: IAdAdapter[];
|
|
283
323
|
/** 全局事件监听 */
|
|
284
324
|
onEvent?: (event: AdEvent, data: IAdEventData) => void;
|
|
325
|
+
/** 数据上报配置(不传则不上报) */
|
|
326
|
+
reporter?: IReporterConfig;
|
|
285
327
|
}
|
|
286
328
|
|
|
287
329
|
/** 聚合广告 SDK 主接口 */
|
|
@@ -330,4 +372,4 @@ export interface IAdSdk {
|
|
|
330
372
|
|
|
331
373
|
/** 销毁 SDK */
|
|
332
374
|
destroy(): void;
|
|
333
|
-
}
|
|
375
|
+
}
|
|
@@ -21,13 +21,15 @@ export default class ExitWin extends cc.Component {
|
|
|
21
21
|
}
|
|
22
22
|
|
|
23
23
|
private async onClickExit() {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
}
|
|
28
|
-
if (AdSdk.exitGame) {
|
|
24
|
+
console.log("onClickExit", PlatformAdapter.isXiaomi, PlatformAdapter.isWebBridge);
|
|
25
|
+
if (PlatformAdapter.isXiaomi) {
|
|
26
|
+
console.log("onClickExit Xiaomi");
|
|
29
27
|
await AdSdk.exitGame();
|
|
28
|
+
} else if (PlatformAdapter.isWebBridge) {
|
|
29
|
+
console.log("onClickExit WebBridge");
|
|
30
|
+
PlatformAdapter.webBridge.callHandler("router/navigateBack", {}, (a) => { cc.log(a); });
|
|
30
31
|
} else {
|
|
32
|
+
console.log("onClickExit Other");
|
|
31
33
|
cc.game.end();
|
|
32
34
|
}
|
|
33
35
|
}
|
package/package.json
CHANGED
package/drscript/BtnExtra.ts
DELETED
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
const { ccclass, property } = cc._decorator;
|
|
3
|
-
|
|
4
|
-
@ccclass('BtnExtra')
|
|
5
|
-
export class BtnExtra extends cc.Component {
|
|
6
|
-
@property({
|
|
7
|
-
type: cc.SpriteFrame,
|
|
8
|
-
tooltip: '悬停状态图片'
|
|
9
|
-
})
|
|
10
|
-
hoverSprite: cc.SpriteFrame = null;
|
|
11
|
-
|
|
12
|
-
@property({
|
|
13
|
-
type: cc.SpriteFrame,
|
|
14
|
-
tooltip: '普通状态图片'
|
|
15
|
-
})
|
|
16
|
-
normalSprite: cc.SpriteFrame = null;
|
|
17
|
-
}
|
|
@@ -1,150 +0,0 @@
|
|
|
1
|
-
import { ActionType, Reporter, IReportItem } from "./ad-sdk/ad-sdk";
|
|
2
|
-
import { AnalyticsEvent, AnalyticsAction } from "./Define";
|
|
3
|
-
|
|
4
|
-
const REPORT_URL = "https://sup.daoran.tv/bi-api/api/game/lewo/batch";
|
|
5
|
-
|
|
6
|
-
/** 事件定义:element_position + 曝光/点击事件名 */
|
|
7
|
-
const EVENT_MAP: Record<AnalyticsEvent, { ep: string; expose: string; click?: string }> = {
|
|
8
|
-
[AnalyticsEvent.GameLoading]: { ep: "game_loading", expose: "game_loading_expose" },
|
|
9
|
-
[AnalyticsEvent.StartGameButton]: { ep: "start_game_button", expose: "start_game_expose", click: "start_game_click" },
|
|
10
|
-
[AnalyticsEvent.WatchVideoContinueButton]: { ep: "watch_video_continue_button", expose: "watch_video_continue_expose", click: "watch_video_continue_click" },
|
|
11
|
-
[AnalyticsEvent.ReplayButton]: { ep: "replay_button", expose: "replay_expose", click: "replay_click" },
|
|
12
|
-
[AnalyticsEvent.RewardVideoAd]: { ep: "reward_video_ad", expose: "ad_expose" },
|
|
13
|
-
};
|
|
14
|
-
|
|
15
|
-
export default class GameAnalytics {
|
|
16
|
-
private static initialized: boolean = false;
|
|
17
|
-
private static loadingReported: boolean = false;
|
|
18
|
-
private static reportedExposures: { [event: string]: boolean } = {};
|
|
19
|
-
private static reportInterval: number = 1000 * 30; // 30秒上报一次
|
|
20
|
-
private static reportMaxSize: number = 50;
|
|
21
|
-
private static reportKey = "game_analytics_report_cache";
|
|
22
|
-
|
|
23
|
-
public static init(config: {
|
|
24
|
-
app_item: string;
|
|
25
|
-
content_type?: string;
|
|
26
|
-
content_id?: string;
|
|
27
|
-
content_title?: string;
|
|
28
|
-
}): void {
|
|
29
|
-
if (GameAnalytics.initialized) return;
|
|
30
|
-
|
|
31
|
-
try {
|
|
32
|
-
Reporter.init({
|
|
33
|
-
report_url: REPORT_URL,
|
|
34
|
-
app_item: config.app_item,
|
|
35
|
-
content_type: config.content_type || "游戏",
|
|
36
|
-
content_id: config.content_id || "",
|
|
37
|
-
content_title: config.content_title || "",
|
|
38
|
-
});
|
|
39
|
-
GameAnalytics.initialized = true;
|
|
40
|
-
var httpReq = new XMLHttpRequest();
|
|
41
|
-
httpReq.open("POST", 'https://sup.daoran.tv/bi-api/api/config/get');
|
|
42
|
-
httpReq.setRequestHeader("Content-Type", "application/json");
|
|
43
|
-
httpReq.setRequestHeader("Accept", "application/json");
|
|
44
|
-
httpReq.send();
|
|
45
|
-
httpReq.onreadystatechange = () => {
|
|
46
|
-
if (httpReq.readyState === 4 && httpReq.status === 200) {
|
|
47
|
-
console.log("[GameAnalytics] report batch success", httpReq.responseText);
|
|
48
|
-
}
|
|
49
|
-
};
|
|
50
|
-
setInterval(() => {
|
|
51
|
-
this.reportBatchCache();
|
|
52
|
-
}, this.reportInterval);
|
|
53
|
-
} catch (error) {
|
|
54
|
-
console.warn("[GameAnalytics] init failed", error);
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
public static reportLoadingOnce(): void {
|
|
59
|
-
if (this.loadingReported) return;
|
|
60
|
-
this.loadingReported = true;
|
|
61
|
-
this.report(AnalyticsEvent.GameLoading, AnalyticsAction.Exposure);
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
public static reportExposureOnce(event: AnalyticsEvent): void {
|
|
65
|
-
if (this.reportedExposures[event]) return;
|
|
66
|
-
this.reportedExposures[event] = true;
|
|
67
|
-
this.report(event, AnalyticsAction.Exposure);
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
public static report(
|
|
71
|
-
event: AnalyticsEvent,
|
|
72
|
-
action: AnalyticsAction,
|
|
73
|
-
adRequestId?: string
|
|
74
|
-
): void {
|
|
75
|
-
if (!this.initialized) return;
|
|
76
|
-
const def = EVENT_MAP[event];
|
|
77
|
-
const eventName = action === AnalyticsAction.Exposure ? def.expose : def.click;
|
|
78
|
-
if (!def || !eventName) {
|
|
79
|
-
console.warn("[GameAnalytics] unsupported event/action", event, action);
|
|
80
|
-
return;
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
try {
|
|
84
|
-
const reportItem: any = {
|
|
85
|
-
element_position: def.ep,
|
|
86
|
-
action_type: action === AnalyticsAction.Exposure
|
|
87
|
-
? ActionType.Exposure
|
|
88
|
-
: ActionType.Click,
|
|
89
|
-
event_name: eventName,
|
|
90
|
-
};
|
|
91
|
-
if (event === AnalyticsEvent.RewardVideoAd && adRequestId) {
|
|
92
|
-
reportItem.ad_request_id = adRequestId;
|
|
93
|
-
}
|
|
94
|
-
var reportCache: IReportItem[] = null;
|
|
95
|
-
const cache = localStorage.getItem(this.reportKey);
|
|
96
|
-
if (cache) {
|
|
97
|
-
reportCache = JSON.parse(cache);
|
|
98
|
-
}
|
|
99
|
-
if (reportCache) {
|
|
100
|
-
reportCache.push(reportItem);
|
|
101
|
-
} else {
|
|
102
|
-
reportCache = [reportItem];
|
|
103
|
-
}
|
|
104
|
-
localStorage.setItem(this.reportKey, JSON.stringify(reportCache));
|
|
105
|
-
} catch (error) {
|
|
106
|
-
console.warn("[GameAnalytics] report failed", error);
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
public static reportBatch(events: AnalyticsEvent[]): void {
|
|
111
|
-
if (!this.initialized || events.length === 0) return;
|
|
112
|
-
try {
|
|
113
|
-
const items: IReportItem[] = [];
|
|
114
|
-
for (const e of events) {
|
|
115
|
-
const def = EVENT_MAP[e];
|
|
116
|
-
if (!def) continue;
|
|
117
|
-
const item: any = {
|
|
118
|
-
element_position: def.ep,
|
|
119
|
-
action_type: ActionType.Exposure,
|
|
120
|
-
event_name: def.expose,
|
|
121
|
-
ad_request_id: "",
|
|
122
|
-
};
|
|
123
|
-
items.push(item);
|
|
124
|
-
}
|
|
125
|
-
if (items.length > 0) Reporter.reportBatch(items);
|
|
126
|
-
} catch (error) {
|
|
127
|
-
console.warn("[GameAnalytics] report failed", error);
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
private static reportBatchCache(): void {
|
|
132
|
-
if (!this.initialized) return;
|
|
133
|
-
var reportCache: IReportItem[] = null;
|
|
134
|
-
const cache = localStorage.getItem(this.reportKey);
|
|
135
|
-
if (cache) {
|
|
136
|
-
reportCache = JSON.parse(cache);
|
|
137
|
-
}
|
|
138
|
-
if (!reportCache || reportCache.length === 0) return;
|
|
139
|
-
|
|
140
|
-
try {
|
|
141
|
-
const reportItem = reportCache.splice(0, this.reportMaxSize);
|
|
142
|
-
Reporter.reportBatch(reportItem);
|
|
143
|
-
} catch (error) {
|
|
144
|
-
console.warn("[GameAnalytics] report failed", error);
|
|
145
|
-
reportCache = [];
|
|
146
|
-
} finally {
|
|
147
|
-
localStorage.setItem(this.reportKey, JSON.stringify(reportCache));
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
}
|