drgame-cc 1.0.63 → 1.0.64

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.
@@ -137,10 +137,11 @@ class AdSdkImpl implements IAdSdk {
137
137
  adapter.onKeyEvent(self._adapterKeyHandler);
138
138
  }
139
139
 
140
- // 自动初始化排行榜模块(serverUrl/project 由 ad-sdk 统一处理)
140
+ // 自动初始化排行榜模块(serverUrl/project/platform 由 ad-sdk 统一处理)
141
141
  Leaderboard.init({
142
142
  serverUrl: config.serverUrl,
143
143
  project: config.project,
144
+ platform: config.gamePlatform,
144
145
  });
145
146
 
146
147
  // 自动初始化用户游戏数据模块(serverUrl/project/platform 由 ad-sdk 统一处理)
@@ -0,0 +1,497 @@
1
+ /**
2
+ * 聚合广告 SDK - 小米电视适配器
3
+ *
4
+ * 底层通过 JSBridge 与电视应用商店客户端通信:
5
+ * H5 → Native: window.AppBridge.call(json)
6
+ * Native → H5: window.onNativeBridgeCallback(action, data)
7
+ */
8
+
9
+ import { AdPlatform, AdEvent, AdErrorCode } from '../types/enums';
10
+ import { EventEmitter } from '../event-emitter';
11
+ import {
12
+ IAdAdapter,
13
+ IAdapterConfig,
14
+ IAdRequest,
15
+ IAdRewardResult,
16
+ IDeviceInfo,
17
+ IAccountInfo,
18
+ IEventHandler,
19
+ } from '../types/interfaces';
20
+ const KEY_EVENT_NAME = '__key_event__';
21
+
22
+ // ────────────────────────────────────────
23
+ // 内部类型
24
+ // ────────────────────────────────────────
25
+
26
+ interface PromiseEntry<T> {
27
+ resolve: (value: T) => void;
28
+ reject: (reason?: any) => void;
29
+ }
30
+
31
+ interface KeyEvent {
32
+ key: string;
33
+ action: string;
34
+ }
35
+
36
+ interface BridgeMessage {
37
+ action: string;
38
+ data: Record<string, any>;
39
+ callbackId?: string;
40
+ }
41
+
42
+ interface NativeCallbackData {
43
+ callbackId?: string;
44
+ code?: number;
45
+ message?: string;
46
+ data?: any;
47
+ is_completed?: boolean;
48
+ key?: string;
49
+ action?: string;
50
+ }
51
+
52
+ // ────────────────────────────────────────
53
+ // JSBridge 底层封装
54
+ // ────────────────────────────────────────
55
+
56
+ /** 获取 JSBridge 全局对象 */
57
+ function getAppBridge(): any {
58
+ if (typeof window === 'undefined') return null;
59
+ return (window as any).AppBridge || null;
60
+ }
61
+
62
+ /** 检测是否在原生环境中 */
63
+ function isNativeEnv(): boolean {
64
+ return !!getAppBridge();
65
+ }
66
+
67
+ /** 调用 JSBridge */
68
+ function bridgeCall(msg: BridgeMessage): void {
69
+ const bridge = getAppBridge();
70
+ if (!bridge) {
71
+ console.warn('[AdSdk:Xiaomi] Not in native environment, bridge call ignored.');
72
+ return;
73
+ }
74
+ bridge.call(JSON.stringify(msg));
75
+ }
76
+
77
+ // ────────────────────────────────────────
78
+ // 适配器实现
79
+ // ────────────────────────────────────────
80
+
81
+ export class XiaomiAdapter implements IAdAdapter {
82
+ readonly platform: AdPlatform;
83
+
84
+ _config: IAdapterConfig;
85
+ _emitter: EventEmitter;
86
+ _cbId: number;
87
+ _callbacks: Map<string, PromiseEntry<IAdRewardResult>>;
88
+ _deviceCallbacks: Map<string, PromiseEntry<IDeviceInfo>>;
89
+ _accountCallbacks: Map<string, PromiseEntry<IAccountInfo>>;
90
+ _adInProgress: boolean;
91
+ _originalCallback: ((action: string, data: NativeCallbackData) => void) | null;
92
+ _exitResolve: (() => void) | null;
93
+ _keyHandlers: Array<(e: KeyEvent) => void>;
94
+
95
+ constructor() {
96
+ this.platform = AdPlatform.Xiaomi;
97
+ this._config = {};
98
+ this._emitter = new EventEmitter();
99
+ this._cbId = 0;
100
+ this._callbacks = new Map();
101
+ this._deviceCallbacks = new Map();
102
+ this._accountCallbacks = new Map();
103
+ this._adInProgress = false;
104
+ this._originalCallback = null;
105
+ this._exitResolve = null;
106
+ this._keyHandlers = [];
107
+ }
108
+
109
+ /**
110
+ * 初始化适配器
111
+ */
112
+ async init(config: IAdapterConfig): Promise<void> {
113
+ this._config = config || {};
114
+
115
+ // 保存已有的 onNativeBridgeCallback,避免覆盖
116
+ if (typeof window !== 'undefined' && (window as any).onNativeBridgeCallback) {
117
+ this._originalCallback = (window as any).onNativeBridgeCallback;
118
+ }
119
+
120
+ // 注册全局回调
121
+ const self = this;
122
+ (window as any).onNativeBridgeCallback = function (action: string, data: NativeCallbackData) {
123
+ // 先调用原有回调
124
+ if (self._originalCallback) {
125
+ try {
126
+ self._originalCallback(action, data);
127
+ } catch (_) {
128
+ // ignore
129
+ }
130
+ }
131
+ self._handleNativeCallback(action, data);
132
+ };
133
+
134
+ console.log('[AdSdk:Xiaomi] Adapter initialized.');
135
+ }
136
+
137
+ /**
138
+ * 请求播放广告
139
+ */
140
+ requestAd(request: IAdRequest): Promise<IAdRewardResult> {
141
+ const self = this;
142
+ return new Promise(function (resolve, reject) {
143
+ if (!isNativeEnv()) {
144
+ reject({
145
+ code: AdErrorCode.PlatformNotSupported,
146
+ message: 'Not in native JSBridge environment',
147
+ platform: self.platform,
148
+ requestId: '',
149
+ });
150
+ return;
151
+ }
152
+
153
+ if (self._adInProgress) {
154
+ reject({
155
+ code: AdErrorCode.AdInProgress,
156
+ message: 'An ad is already in progress',
157
+ platform: self.platform,
158
+ requestId: '',
159
+ });
160
+ return;
161
+ }
162
+
163
+ self._adInProgress = true;
164
+ const callbackId = 'ad_' + (++self._cbId);
165
+
166
+ self._callbacks.set(callbackId, { resolve: resolve, reject: reject });
167
+
168
+ // 发出 loaded 事件
169
+ self._emitter.emit(AdEvent.Loaded, { request: request as any });
170
+
171
+ bridgeCall({
172
+ action: 'requestAd',
173
+ data: {
174
+ cp_id: request.cpId || self._config.cpId,
175
+ reward_type: request.rewardType,
176
+ trigger_scene: request.triggerScene,
177
+ ...(request.extra || {}),
178
+ },
179
+ callbackId: callbackId,
180
+ });
181
+ });
182
+ }
183
+
184
+ /**
185
+ * 获取设备信息
186
+ */
187
+ getDeviceInfo(): Promise<IDeviceInfo> {
188
+ const self = this;
189
+ return new Promise(function (resolve, reject) {
190
+ if (!isNativeEnv()) {
191
+ reject({
192
+ code: AdErrorCode.PlatformNotSupported,
193
+ message: 'Not in native JSBridge environment',
194
+ platform: self.platform,
195
+ requestId: '',
196
+ });
197
+ return;
198
+ }
199
+
200
+ const callbackId = 'dev_' + (++self._cbId);
201
+ self._deviceCallbacks.set(callbackId, { resolve: resolve, reject: reject });
202
+
203
+ bridgeCall({
204
+ action: 'getDeviceInfo',
205
+ data: {},
206
+ callbackId: callbackId,
207
+ });
208
+ });
209
+ }
210
+
211
+ /**
212
+ * 获取玩家账户信息
213
+ */
214
+ getAccount(): Promise<IAccountInfo> {
215
+ const self = this;
216
+ return new Promise(function (resolve, reject) {
217
+ if (!isNativeEnv()) {
218
+ reject({
219
+ code: AdErrorCode.PlatformNotSupported,
220
+ message: 'Not in native JSBridge environment',
221
+ platform: self.platform,
222
+ requestId: '',
223
+ });
224
+ return;
225
+ }
226
+
227
+ const callbackId = 'acc_' + (++self._cbId);
228
+ self._accountCallbacks.set(callbackId, { resolve: resolve, reject: reject });
229
+
230
+ bridgeCall({
231
+ action: 'getAccount',
232
+ data: {},
233
+ callbackId: callbackId,
234
+ });
235
+ });
236
+ }
237
+
238
+ /**
239
+ * 通知游戏加载完成
240
+ */
241
+ onGameReady(version: string): void {
242
+ bridgeCall({
243
+ action: 'onGameReady',
244
+ data: { version: version },
245
+ });
246
+ }
247
+
248
+ /** 通知游戏暂停 */
249
+ onGamePause(): void {
250
+ bridgeCall({
251
+ action: 'onGamePause',
252
+ data: {},
253
+ });
254
+ }
255
+
256
+ /** 通知游戏恢复 */
257
+ onGameResume(): void {
258
+ bridgeCall({
259
+ action: 'onGameResume',
260
+ data: {},
261
+ });
262
+ }
263
+
264
+ /**
265
+ * 退出游戏
266
+ */
267
+ exitGame(): Promise<void> {
268
+ const self = this;
269
+ return new Promise<void>(function (resolve) {
270
+ if (!isNativeEnv()) {
271
+ resolve();
272
+ return;
273
+ }
274
+ self._exitResolve = resolve;
275
+ bridgeCall({
276
+ action: 'exitGame',
277
+ data: {},
278
+ });
279
+ });
280
+ }
281
+
282
+ /**
283
+ * 监听遥控器按键事件
284
+ */
285
+ onKeyEvent(handler: (e: KeyEvent) => void): void {
286
+ if (typeof handler === 'function' && this._keyHandlers.indexOf(handler) === -1) {
287
+ this._keyHandlers.push(handler);
288
+ }
289
+ }
290
+
291
+ /**
292
+ * 取消监听遥控器按键事件
293
+ */
294
+ offKeyEvent(handler?: (e: KeyEvent) => void): void {
295
+ if (!handler) {
296
+ this._keyHandlers = [];
297
+ } else {
298
+ const idx = this._keyHandlers.indexOf(handler);
299
+ if (idx !== -1) {
300
+ this._keyHandlers.splice(idx, 1);
301
+ }
302
+ }
303
+ }
304
+
305
+ /**
306
+ * 监听事件
307
+ */
308
+ on(event: AdEvent, handler: IEventHandler): void {
309
+ this._emitter.on(event, handler);
310
+ }
311
+
312
+ /**
313
+ * 取消事件
314
+ */
315
+ off(event: AdEvent, handler?: IEventHandler): void {
316
+ this._emitter.off(event, handler);
317
+ }
318
+
319
+ /** 销毁适配器 */
320
+ destroy(): void {
321
+ this._callbacks.clear();
322
+ this._deviceCallbacks.clear();
323
+ this._accountCallbacks.clear();
324
+ this._emitter.removeAllListeners();
325
+ this._adInProgress = false;
326
+ this._exitResolve = null;
327
+ this._keyHandlers = [];
328
+
329
+ // 恢复原有回调
330
+ if (this._originalCallback && typeof window !== 'undefined') {
331
+ (window as any).onNativeBridgeCallback = this._originalCallback;
332
+ }
333
+ }
334
+
335
+ // ────────────────────────────────────────
336
+ // 内部方法
337
+ // ────────────────────────────────────────
338
+
339
+ /** @private 处理 Native 回调 */
340
+ _handleNativeCallback(action: string, data: NativeCallbackData): void {
341
+ console.log(`[AdSdk:Xiaomi] Received native callback: ${action}`, data);
342
+ switch (action) {
343
+ // ── 通用回调(getDeviceInfo / getAccount 等) ──
344
+ case 'onBridgeCallback': {
345
+ const cbId = data.callbackId;
346
+ const code = data.code;
347
+
348
+ // getDeviceInfo 回调
349
+ if (cbId && this._deviceCallbacks.has(cbId)) {
350
+ const entry = this._deviceCallbacks.get(cbId);
351
+ this._deviceCallbacks.delete(cbId);
352
+ if (entry) {
353
+ if (code === 0) {
354
+ entry.resolve(data.data || {});
355
+ } else {
356
+ entry.reject({
357
+ code: code,
358
+ message: data.message || 'getDeviceInfo failed',
359
+ platform: this.platform,
360
+ requestId: cbId,
361
+ });
362
+ }
363
+ }
364
+ return;
365
+ }
366
+
367
+ // getAccount 回调
368
+ if (cbId && this._accountCallbacks.has(cbId)) {
369
+ const entry = this._accountCallbacks.get(cbId);
370
+ this._accountCallbacks.delete(cbId);
371
+ if (entry) {
372
+ if (code === 0) {
373
+ entry.resolve(data.data || {});
374
+ } else {
375
+ entry.reject({
376
+ code: code,
377
+ message: data.message || 'getAccount failed',
378
+ platform: this.platform,
379
+ requestId: cbId,
380
+ });
381
+ }
382
+ }
383
+ return;
384
+ }
385
+ break;
386
+ }
387
+
388
+ // ── 广告奖励 ──
389
+ case 'onReward': {
390
+ const cbId = data.callbackId;
391
+ const result: IAdRewardResult = {
392
+ isCompleted: true,
393
+ requestId: cbId,
394
+ };
395
+ this._adInProgress = false;
396
+
397
+ this._emitter.emit(AdEvent.Reward, result as any);
398
+
399
+ if (cbId && this._callbacks.has(cbId)) {
400
+ const entry = this._callbacks.get(cbId);
401
+ this._callbacks.delete(cbId);
402
+ if (entry) entry.resolve(result);
403
+ }
404
+ break;
405
+ }
406
+
407
+ // ── 广告关闭 ──
408
+ case 'onAdClosed': {
409
+ const cbId = data.callbackId;
410
+ const isCompleted = !!data.is_completed;
411
+ const closedResult: IAdRewardResult = {
412
+ isCompleted: isCompleted,
413
+ requestId: cbId,
414
+ };
415
+ this._adInProgress = false;
416
+
417
+ this._emitter.emit(AdEvent.Closed, closedResult as any);
418
+
419
+ if (cbId && this._callbacks.has(cbId)) {
420
+ const entry = this._callbacks.get(cbId);
421
+ this._callbacks.delete(cbId);
422
+
423
+ if (entry) {
424
+ if (isCompleted) {
425
+ entry.resolve({
426
+ isCompleted: true,
427
+ requestId: cbId,
428
+ });
429
+ } else {
430
+ entry.reject({
431
+ code: AdErrorCode.Unknown,
432
+ message: 'Ad closed by user before completion',
433
+ platform: this.platform,
434
+ requestId: cbId,
435
+ });
436
+ }
437
+ }
438
+ }
439
+ break;
440
+ }
441
+
442
+ // ── 广告失败 ──
443
+ case 'onAdFailed': {
444
+ const cbId = data.callbackId;
445
+ const errorCode = data.code;
446
+ const errorMsg = data.message;
447
+ this._adInProgress = false;
448
+
449
+ const adError = {
450
+ code: errorCode,
451
+ message: errorMsg,
452
+ platform: this.platform,
453
+ requestId: cbId,
454
+ };
455
+
456
+ this._emitter.emit(AdEvent.Error, adError as any);
457
+
458
+ if (cbId && this._callbacks.has(cbId)) {
459
+ const entry = this._callbacks.get(cbId);
460
+ this._callbacks.delete(cbId);
461
+ if (entry) entry.reject(adError);
462
+ }
463
+ break;
464
+ }
465
+
466
+ // ── 退出确认 ──
467
+ case 'onExitConfirmed': {
468
+ // 触发退出回调事件,供 SDK 层调用 reporter 上报
469
+ this._emitter.emit(AdEvent.Exit, {} as any);
470
+
471
+ if (this._exitResolve) {
472
+ this._exitResolve();
473
+ this._exitResolve = null;
474
+ }
475
+ break;
476
+ }
477
+
478
+ // ── 遥控器按键 ──
479
+ case 'onKeyEvent': {
480
+ const keyEvent: KeyEvent = {
481
+ key: data.key || '',
482
+ action: data.action || 'down',
483
+ };
484
+ for (let i = 0; i < this._keyHandlers.length; i++) {
485
+ try {
486
+ this._keyHandlers[i](keyEvent);
487
+ } catch (e) {
488
+ console.error('[AdSdk:Xiaomi] Key event handler error:', e);
489
+ }
490
+ }
491
+ break;
492
+ }
493
+ }
494
+ }
495
+ }
496
+
497
+ export default XiaomiAdapter;
@@ -0,0 +1,10 @@
1
+ {
2
+ "ver": "1.1.0",
3
+ "uuid": "72fd9cee-f479-4c1e-92c6-77c6923080ee",
4
+ "importer": "typescript",
5
+ "isPlugin": false,
6
+ "loadPluginInWeb": true,
7
+ "loadPluginInNative": true,
8
+ "loadPluginInEditor": false,
9
+ "subMetas": {}
10
+ }
@@ -28,6 +28,8 @@ interface LeaderboardConfig {
28
28
  project: string;
29
29
  /** 用户ID */
30
30
  user_id: string;
31
+ /** 游戏平台:互影派-hyp(默认),乐蜗-lewo */
32
+ platform: string;
31
33
  }
32
34
 
33
35
  export interface LeaderboardLike {
@@ -69,11 +71,13 @@ const Leaderboard: LeaderboardLike = {
69
71
  project: '',
70
72
  /** 用户ID */
71
73
  user_id: '',
74
+ /** 游戏平台:互影派-hyp(默认),乐蜗-lewo */
75
+ platform: 'lewo',
72
76
  },
73
77
 
74
78
  /**
75
79
  * 初始化排行榜模块
76
- * @param config 仅需项目编码与服务基础域名(project 由 ad-sdk 统一处理)
80
+ * @param config 仅需项目编码与服务基础域名(project/platform 由 ad-sdk 统一处理)
77
81
  */
78
82
  init: function (config: Partial<ILeaderboardConfig>) {
79
83
  config = config || {};
@@ -82,6 +86,9 @@ const Leaderboard: LeaderboardLike = {
82
86
  this._config.rank_url = this._config.serverUrl + '/API_ACHIEVEMENT/api/user/point/rank';
83
87
  this._config.add_url = this._config.serverUrl + '/API_ACHIEVEMENT/api/user/point/add';
84
88
  this._config.project = config.project || '';
89
+ if (typeof config.platform === 'string' && config.platform) {
90
+ this._config.platform = config.platform;
91
+ }
85
92
 
86
93
  this._initialized = true;
87
94
  console.log('[Leaderboard] Initialized, project:', this._config.project);
@@ -98,6 +105,7 @@ const Leaderboard: LeaderboardLike = {
98
105
 
99
106
  const data: Record<string, any> = {
100
107
  project: this._config.project,
108
+ platform: this._config.platform || 'lewo',
101
109
  timestamp: Date.now(),
102
110
  time: this._formatTime(new Date()),
103
111
  };
@@ -118,6 +126,7 @@ const Leaderboard: LeaderboardLike = {
118
126
  project: this._config.project,
119
127
  userId: this._config.user_id,
120
128
  point: params.point || 0,
129
+ platform: this._config.platform || 'lewo',
121
130
  };
122
131
 
123
132
  // jsonData 为可选扩展数据
@@ -166,6 +166,8 @@ export interface ILeaderboardConfig {
166
166
  serverUrl?: string;
167
167
  /** 项目编码(如 "xmjump") */
168
168
  project?: string;
169
+ /** 游戏平台:互影派-hyp(默认),乐蜗-lewo(默认取 ad-sdk 的 gamePlatform) */
170
+ platform?: string;
169
171
  }
170
172
 
171
173
  /** 添加积分参数 */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "drgame-cc",
3
- "version": "1.0.63",
3
+ "version": "1.0.64",
4
4
  "description": "道然游戏适配包",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",