drgame-cc 1.0.49 → 1.0.52
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 +29 -0
- package/drscript/PlatformAdapter.ts +98 -109
- package/drscript/PlatformUtil.ts +30 -0
- package/drscript/UIAdapter.ts +99 -105
- 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/BtnExtra.ts +4 -11
- package/drscript/focus/FocusManager.ts +167 -170
- package/drscript/focus/FocusVisualLayer.ts +124 -94
- package/package.json +1 -1
- package/drscript/BtnExtra.ts +0 -17
- package/drscript/GameAnalytics.ts +0 -150
- package/drscript/focus/FocusItem.ts +0 -39
- package/drscript/focus/FocusItem.ts.meta +0 -10
- package/drscript/focus/FocusScope.ts +0 -10
- package/drscript/focus/FocusScope.ts.meta +0 -10
package/drscript/Define.ts
CHANGED
|
@@ -39,4 +39,33 @@ export enum AnalyticsEvent {
|
|
|
39
39
|
export enum AnalyticsAction {
|
|
40
40
|
Exposure = "exposure",
|
|
41
41
|
Click = "click",
|
|
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
|
+
};
|
|
52
|
+
|
|
53
|
+
/** 奖励模式 */
|
|
54
|
+
export enum AwardModel {
|
|
55
|
+
/** 视频奖励 */
|
|
56
|
+
Video = "video",
|
|
57
|
+
/** 免费 */
|
|
58
|
+
Free = "free",
|
|
59
|
+
/** 付费时间限制 */
|
|
60
|
+
TimeLimit = "time_limit",
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/** 渠道类型 */
|
|
64
|
+
export enum EAppItem {
|
|
65
|
+
/** 小米 */
|
|
66
|
+
Xiaomi = "25",
|
|
67
|
+
/** 乐窝 */
|
|
68
|
+
LeWo = "29",
|
|
69
|
+
/** 咪咕 */
|
|
70
|
+
Migu = "30",
|
|
42
71
|
}
|
|
@@ -1,12 +1,10 @@
|
|
|
1
|
-
import { AdEvent, AdPlatform, AdSdk, AdType } from "./ad-sdk/ad-sdk";
|
|
2
|
-
import
|
|
1
|
+
import { AdEvent, AdPlatform, AdSdk, AdType, ActionType, Reporter } from "./ad-sdk/ad-sdk";
|
|
2
|
+
import BtnExtra from "./component/BtnExtra";
|
|
3
3
|
import HelperWin from "./component/HelperWin";
|
|
4
|
-
import { AnalyticsAction, AnalyticsEvent, EVideoScene, FingerStyle } from "./Define";
|
|
5
|
-
import FocusVisualLayer from "./focus/FocusVisualLayer";
|
|
6
|
-
import GameAnalytics from "./GameAnalytics";
|
|
4
|
+
import { AnalyticsAction, AnalyticsEvent, AnalyticsEventMap, AwardModel, EAppItem, EVideoScene, FingerStyle } from "./Define";
|
|
7
5
|
import { Loader } from "./Loader";
|
|
6
|
+
import { PlatformUtil } from "./PlatformUtil";
|
|
8
7
|
import { UIAdapter } from "./UIAdapter";
|
|
9
|
-
import { WebBridge } from "./WebBridge";
|
|
10
8
|
|
|
11
9
|
/** 平台适配器,公共 API 入口 */
|
|
12
10
|
export class PlatformAdapter {
|
|
@@ -16,6 +14,10 @@ export class PlatformAdapter {
|
|
|
16
14
|
public static back = UIAdapter.back;
|
|
17
15
|
/** WebBridge */
|
|
18
16
|
public static get webBridge() { return UIAdapter.webBridge; }
|
|
17
|
+
/** 渠道类型 */
|
|
18
|
+
private static appItem: EAppItem = EAppItem.Xiaomi;
|
|
19
|
+
/** 是否是会员 */
|
|
20
|
+
private static isVIP: boolean = false;
|
|
19
21
|
|
|
20
22
|
private static contentId: string = "";
|
|
21
23
|
|
|
@@ -26,54 +28,72 @@ export class PlatformAdapter {
|
|
|
26
28
|
/** 初始化
|
|
27
29
|
* @param cnName 中文名称
|
|
28
30
|
* @param minigameID 小游戏ID
|
|
31
|
+
* @param focusIcon 焦点的样式
|
|
29
32
|
*/
|
|
30
33
|
public static async init(cnName: string, minigameID: number, focusIcon: FingerStyle) {
|
|
31
|
-
|
|
34
|
+
// ── 初始化渠道类型 ──
|
|
35
|
+
this.appItem = PlatformUtil.getUrlParam('appItem') as EAppItem || EAppItem.Xiaomi;
|
|
36
|
+
this.isVIP = PlatformUtil.getUrlParam('isVIP') === '1';
|
|
37
|
+
|
|
38
|
+
// ── UI 初始化 ──
|
|
39
|
+
this.focus.setFocusStyle(focusIcon);
|
|
32
40
|
UIAdapter._zhName = cnName;
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
if (UIAdapter.webBridge.isAvailable()) {
|
|
36
|
-
} else if (this.isXiaomi) {
|
|
37
|
-
platform = AdPlatform.Xiaomi;
|
|
38
|
-
}
|
|
41
|
+
await UIAdapter.init();
|
|
42
|
+
|
|
39
43
|
this.contentId = minigameID.toString();
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
44
|
+
|
|
45
|
+
// ── 初始化广告 SDK ──
|
|
46
|
+
await AdSdk.init({
|
|
47
|
+
platform: AdPlatform.Xiaomi,
|
|
48
|
+
adapters: { [AdPlatform.Xiaomi]: { cpId: this.contentId } },
|
|
49
|
+
reporter: {
|
|
50
|
+
app_item: "25",
|
|
51
|
+
content_type: "游戏",
|
|
52
|
+
content_id: this.contentId,
|
|
53
|
+
content_title: cnName,
|
|
54
|
+
},
|
|
48
55
|
});
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
UIAdapter.prefab = await UIAdapter.loadPrefab('drres/prefab/Toast');
|
|
52
|
-
}
|
|
53
|
-
let adapters: any = {};
|
|
54
|
-
adapters[platform] = { cpId: this.contentId };
|
|
55
|
-
await AdSdk.init({ platform: AdPlatform.Xiaomi, adapters: adapters });
|
|
56
|
-
AdSdk.onGameReady(UIAdapter.version);
|
|
56
|
+
|
|
57
|
+
// ── 注册广告事件 ──
|
|
57
58
|
if (this.canWatchVideo) {
|
|
58
59
|
AdSdk.on(AdEvent.Closed, (data: any) => {
|
|
59
|
-
if (!data.isCompleted)
|
|
60
|
-
PlatformAdapter.showTip("必须看完视频,才能获取奖励");
|
|
61
|
-
}
|
|
60
|
+
if (!data.isCompleted) this.showTip("必须看完视频,才能获取奖励");
|
|
62
61
|
});
|
|
63
|
-
// 监听失败
|
|
64
62
|
AdSdk.on(AdEvent.Error, (data: any) => {
|
|
65
|
-
|
|
63
|
+
this.showTip(`广告暂不可用,请稍后再试(${data.message})`);
|
|
66
64
|
});
|
|
67
65
|
}
|
|
68
|
-
|
|
69
|
-
UIAdapter.
|
|
70
|
-
UIAdapter.back.setFallback(() => UIAdapter.backHandler());
|
|
66
|
+
|
|
67
|
+
AdSdk.onGameReady(UIAdapter.version);
|
|
71
68
|
}
|
|
72
69
|
|
|
73
|
-
|
|
70
|
+
// ========================================================================
|
|
71
|
+
// 属性
|
|
72
|
+
// ========================================================================
|
|
73
|
+
|
|
74
|
+
/** 是否 Cocos 环境 */
|
|
75
|
+
private static get isCocos() { return window['cc'] != undefined; }
|
|
76
|
+
/** 是否基座环境 */
|
|
77
|
+
private static get isWebBridge() { return this.webBridge.isAvailable(); }
|
|
78
|
+
/** 是否可以观看视频 */
|
|
79
|
+
private static get canWatchVideo() { return this.isXiaomi; }
|
|
80
|
+
/** 是否小米平台 */
|
|
81
|
+
private static get isXiaomi() {
|
|
74
82
|
if (typeof window === 'undefined') return null;
|
|
75
83
|
return window['AppBridge'] || null;
|
|
76
84
|
}
|
|
85
|
+
/** 是否需要观看视频 */
|
|
86
|
+
private static get needWatchVideo() {
|
|
87
|
+
return this.canWatchVideo && !this.isVIP;
|
|
88
|
+
}
|
|
89
|
+
private static get needTimeLimit() {
|
|
90
|
+
return !this.isVIP && this.appItem === EAppItem.Migu;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/** 奖励模式 */
|
|
94
|
+
public static get awardModel(): AwardModel {
|
|
95
|
+
return this.needWatchVideo ? AwardModel.Video : this.needTimeLimit ? AwardModel.TimeLimit : AwardModel.Free;
|
|
96
|
+
}
|
|
77
97
|
|
|
78
98
|
// ========================================================================
|
|
79
99
|
// Toast
|
|
@@ -87,13 +107,6 @@ export class PlatformAdapter {
|
|
|
87
107
|
// 广告
|
|
88
108
|
// ========================================================================
|
|
89
109
|
|
|
90
|
-
/**
|
|
91
|
-
* 显示奖励视频
|
|
92
|
-
* @param scene 视频场景
|
|
93
|
-
* @param rewardType 奖励类型
|
|
94
|
-
* @param callback 回调函数
|
|
95
|
-
* @param target 回调函数的this指向
|
|
96
|
-
*/
|
|
97
110
|
public static async showRewardVideo(scene: EVideoScene, rewardType: string, callback: Function, target?: any) {
|
|
98
111
|
let finishFired = false;
|
|
99
112
|
let fireFinish = () => {
|
|
@@ -102,15 +115,14 @@ export class PlatformAdapter {
|
|
|
102
115
|
};
|
|
103
116
|
let onSuccess = () => {
|
|
104
117
|
try {
|
|
105
|
-
|
|
118
|
+
this.report(AnalyticsEvent.RewardVideoAd, AnalyticsAction.Exposure);
|
|
106
119
|
callback && callback.call(target);
|
|
107
120
|
} finally {
|
|
108
121
|
fireFinish();
|
|
109
122
|
}
|
|
110
123
|
};
|
|
111
124
|
|
|
112
|
-
if (
|
|
113
|
-
// 监听奖励(用户完整看完广告触发)
|
|
125
|
+
if (this.canWatchVideo) {
|
|
114
126
|
try {
|
|
115
127
|
const result = await AdSdk.requestAd({
|
|
116
128
|
adType: AdType.RewardVideo,
|
|
@@ -137,54 +149,34 @@ export class PlatformAdapter {
|
|
|
137
149
|
// 按钮注册
|
|
138
150
|
// ========================================================================
|
|
139
151
|
|
|
140
|
-
/**
|
|
141
|
-
* 注册按钮事件,有 BtnExtra 组件会自动切换按钮图片
|
|
142
|
-
* @param button 按钮节点
|
|
143
|
-
*/
|
|
144
152
|
public static registerButton(button: cc.Node) {
|
|
145
153
|
var sprite = button.getComponent(cc.Sprite);
|
|
146
154
|
var btnExtra = button.getComponent(BtnExtra);
|
|
147
155
|
var onFocus = () => { sprite.spriteFrame = btnExtra.hoverSprite; };
|
|
148
156
|
var onRomove = () => { sprite.spriteFrame = btnExtra.normalSprite; };
|
|
149
|
-
|
|
157
|
+
this.focus.register(button, { onFocus: onFocus, onBlur: onRomove });
|
|
150
158
|
}
|
|
151
159
|
|
|
152
|
-
/**
|
|
153
|
-
* 按名称注册按钮
|
|
154
|
-
* @param name 按钮名称
|
|
155
|
-
* @param parent 查找的父节点,默认场景节点
|
|
156
|
-
*/
|
|
157
160
|
public static registerButtonByName(name: string, parent: cc.Node = null) {
|
|
158
161
|
if (!parent) parent = cc.director.getScene();
|
|
159
|
-
let button =
|
|
160
|
-
|
|
162
|
+
let button = this.findChildByName(parent, name);
|
|
163
|
+
this.registerButton(button);
|
|
161
164
|
}
|
|
162
165
|
|
|
163
|
-
/**
|
|
164
|
-
* 导航到指定名称的按钮
|
|
165
|
-
* @param name 按钮名称
|
|
166
|
-
* @param parent 查找的父节点,默认场景节点
|
|
167
|
-
*/
|
|
168
166
|
public static focusButtonByName(name: string, parent: cc.Node = null) {
|
|
169
167
|
if (!parent) parent = cc.director.getScene();
|
|
170
|
-
let button =
|
|
171
|
-
|
|
168
|
+
let button = this.findChildByName(parent, name);
|
|
169
|
+
this.focus.focus(button);
|
|
172
170
|
}
|
|
173
171
|
|
|
174
|
-
/** 导航到指定按钮 */
|
|
175
172
|
public static focusButton(btn: cc.Node) {
|
|
176
|
-
|
|
173
|
+
this.focus.focus(btn);
|
|
177
174
|
}
|
|
178
175
|
|
|
179
|
-
/**
|
|
180
|
-
* 递归查找指定名称的子节点
|
|
181
|
-
* @param parent 父节点
|
|
182
|
-
* @param name 子节点名称
|
|
183
|
-
*/
|
|
184
176
|
public static findChildByName(parent: cc.Node, name: string): cc.Node | null {
|
|
185
177
|
if (parent.name === name) return parent;
|
|
186
178
|
for (let i = 0; i < parent.children.length; i++) {
|
|
187
|
-
let result =
|
|
179
|
+
let result = this.findChildByName(parent.children[i], name);
|
|
188
180
|
if (result) return result;
|
|
189
181
|
}
|
|
190
182
|
return null;
|
|
@@ -194,31 +186,20 @@ export class PlatformAdapter {
|
|
|
194
186
|
// 场景 / 窗口 栈
|
|
195
187
|
// ========================================================================
|
|
196
188
|
|
|
197
|
-
/** 显示预制体场景(压入场景栈,返回键可回溯)
|
|
198
|
-
* @param onBack 自定义返回处理,返回 false 表示不关闭,保留当前场景
|
|
199
|
-
*/
|
|
200
189
|
public static showScene(scene: cc.Node, onBack?: () => boolean | void) { UIAdapter.showScene(scene, onBack); }
|
|
201
|
-
/** 关闭预制体场景(从栈中移除,不销毁) */
|
|
202
190
|
public static hideScene(scene: cc.Node) { UIAdapter.hideScene(scene); }
|
|
203
|
-
/** 打开界面
|
|
204
|
-
* @param onBack 自定义返回处理,返回 false 表示不关闭,保留当前窗口
|
|
205
|
-
*/
|
|
206
191
|
public static showWindow(window: cc.Node, onBack?: () => boolean | void) { UIAdapter.showWindow(window, onBack); }
|
|
207
|
-
/** 关闭界面 */
|
|
208
192
|
public static hideWindow(window: cc.Node) { UIAdapter.hideWindow(window); }
|
|
209
|
-
/** 刷新导航按钮 */
|
|
210
193
|
public static refreshFocus(window: cc.Node) { UIAdapter.refreshFocus(window); }
|
|
211
194
|
|
|
212
195
|
// ========================================================================
|
|
213
196
|
// 进度 / 加载
|
|
214
197
|
// ========================================================================
|
|
215
198
|
|
|
216
|
-
/** 设置启动页进度条 */
|
|
217
199
|
public static setProgress(progress: number, tip: string) {
|
|
218
200
|
if (window["setProgress"]) window["setProgress"](progress, tip);
|
|
219
201
|
}
|
|
220
202
|
|
|
221
|
-
/** 关闭启动页 */
|
|
222
203
|
public static closeLoading() {
|
|
223
204
|
if (window["closeLoading"]) window["closeLoading"]();
|
|
224
205
|
}
|
|
@@ -227,35 +208,43 @@ export class PlatformAdapter {
|
|
|
227
208
|
// 上报
|
|
228
209
|
// ========================================================================
|
|
229
210
|
|
|
230
|
-
/**
|
|
231
|
-
* 上报事件(缓存)
|
|
232
|
-
* @param event 事件类型
|
|
233
|
-
* @param action 操作类型,默认点击
|
|
234
|
-
* @param adRequestId 广告请求ID
|
|
235
|
-
*/
|
|
236
211
|
public static report(event: AnalyticsEvent, action: AnalyticsAction = AnalyticsAction.Click, adRequestId?: string) {
|
|
237
|
-
|
|
212
|
+
const def = AnalyticsEventMap[event];
|
|
213
|
+
if (!def) {
|
|
214
|
+
console.warn("[PlatformAdapter] unsupported event", event);
|
|
215
|
+
return;
|
|
216
|
+
}
|
|
217
|
+
const eventName = action === AnalyticsAction.Exposure ? def.expose : def.click;
|
|
218
|
+
if (!eventName) {
|
|
219
|
+
console.warn("[PlatformAdapter] unsupported action", action, "for event", event);
|
|
220
|
+
return;
|
|
221
|
+
}
|
|
222
|
+
const reportItem: any = {
|
|
223
|
+
element_position: def.ep,
|
|
224
|
+
action_type: action === AnalyticsAction.Exposure ? ActionType.Exposure : ActionType.Click,
|
|
225
|
+
event_name: eventName,
|
|
226
|
+
};
|
|
227
|
+
if (event === AnalyticsEvent.RewardVideoAd && adRequestId) {
|
|
228
|
+
reportItem.ad_request_id = adRequestId;
|
|
229
|
+
}
|
|
230
|
+
Reporter.report(reportItem);
|
|
238
231
|
}
|
|
239
232
|
|
|
240
|
-
/** 批量上报事件 */
|
|
241
233
|
public static reportBatch(events: AnalyticsEvent[]) {
|
|
242
|
-
|
|
234
|
+
if (events.length === 0) return;
|
|
235
|
+
const items: any[] = [];
|
|
236
|
+
for (const e of events) {
|
|
237
|
+
const def = AnalyticsEventMap[e];
|
|
238
|
+
if (!def) continue;
|
|
239
|
+
items.push({
|
|
240
|
+
element_position: def.ep,
|
|
241
|
+
action_type: ActionType.Exposure,
|
|
242
|
+
event_name: def.expose,
|
|
243
|
+
});
|
|
244
|
+
}
|
|
245
|
+
if (items.length > 0) Reporter.reportBatch(items);
|
|
243
246
|
}
|
|
244
247
|
|
|
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
|
-
/** 显示帮助窗口 */
|
|
259
248
|
public static async showHelperWin(url: string, cb: () => void) {
|
|
260
249
|
var key = `${UIAdapter._zhName}-isFirst`;
|
|
261
250
|
var isFirst = cc.sys.localStorage.getItem(key);
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
export class PlatformUtil {
|
|
2
|
+
static isBrowser: boolean = cc.sys.isBrowser;
|
|
3
|
+
private _browserParams: Map<string, string> = new Map();
|
|
4
|
+
|
|
5
|
+
/** 获取浏览器 URL 查询参数 */
|
|
6
|
+
private get browserParams(): Map<string, string> {
|
|
7
|
+
if (this._browserParams.size > 0) return this._browserParams;
|
|
8
|
+
|
|
9
|
+
const query = window.location.search.substring(1);
|
|
10
|
+
const params = new Map<string, string>();
|
|
11
|
+
if (!query) return params;
|
|
12
|
+
|
|
13
|
+
const vars = query.split("&");
|
|
14
|
+
for (let i = 0; i < vars.length; i++) {
|
|
15
|
+
const pair = vars[i].split("=");
|
|
16
|
+
const key = decodeURIComponent(pair[0]);
|
|
17
|
+
const value = decodeURIComponent(pair[1] || "");
|
|
18
|
+
params.set(key, value);
|
|
19
|
+
}
|
|
20
|
+
this._browserParams = params;
|
|
21
|
+
return params;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/** 获取指定 URL 参数的值 */
|
|
25
|
+
static getUrlParam(key: string): string | null {
|
|
26
|
+
if (!PlatformUtil.isBrowser) return null;
|
|
27
|
+
const params = new PlatformUtil().browserParams;
|
|
28
|
+
return params.get(key) || null;
|
|
29
|
+
}
|
|
30
|
+
}
|