@singcl/ad-execute-manager 2.0.0-alpha.0 → 2.0.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.
package/README.md CHANGED
@@ -6,18 +6,19 @@ A powerful and flexible ad execution management library for handling reward-base
6
6
 
7
7
  - [Features](#features)
8
8
  - [Installation](#installation)
9
- - [Usage](#usage)
9
+ - [Quick Start](#quick-start)
10
+ - [Core Concepts](#core-concepts)
11
+ - [Usage Examples](#usage-examples)
10
12
  - [API Reference](#api-reference)
11
- - [Examples](#examples)
12
- - [Contributing](#contributing)
13
+ - [Development Guide](#development-guide)
13
14
  - [License](#license)
14
15
 
15
16
  ## Features
16
17
 
17
- - **Unified Ad Execution**: Single interface for managing different types of ads
18
+ - **Unified Ad Execution Interface**: Single interface for managing different types of ads
18
19
  - **Task Queue Management**: Handles multiple ad execution tasks in a queue
19
- - **Flexible Control**: Manual control over ad execution flow with `next` function
20
- - **Error Handling**: Comprehensive error handling and logging
20
+ - **Flexible Control Flow**: Manual control over ad execution flow with `next` function
21
+ - **Comprehensive Error Handling**: Complete error handling and logging
21
22
  - **State Persistence**: Built-in storage for ad state management
22
23
  - **Analytics Integration**: Built-in analytics support
23
24
  - **Middleware Pattern**: Uses middleware pattern for ad execution flow
@@ -29,163 +30,578 @@ A powerful and flexible ad execution management library for handling reward-base
29
30
  npm install @singcl/ad-execute-manager
30
31
  ```
31
32
 
32
- ## Usage
33
+ ## Quick Start
33
34
 
34
35
  ### Basic Usage
35
36
 
36
37
  ```javascript
37
- import { AdExecuteManager, RewardAdFather } from '@singcl/ad-execute-manager';
38
+ import { RewardAdNovel, InterstitialAdNovel } from '@singcl/ad-execute-manager';
38
39
 
39
- // Get the singleton instance
40
- const adManager = AdExecuteManager.getInstance();
40
+ // Create reward ad instance
41
+ const rewardAd = RewardAdNovel.new({
42
+ adConfig: { /* ad configuration */ },
43
+ collection: {
44
+ always: (args) => console.log('Ad always callback', args),
45
+ halfway: (args) => console.log('Ad halfway callback', args),
46
+ finished: (args) => console.log('Ad finished callback', args),
47
+ before: (args) => console.log('Ad before callback', args),
48
+ success: (args) => console.log('Ad success callback', args),
49
+ prelude: (args) => console.log('Ad prelude callback', args)
50
+ }
51
+ });
41
52
 
42
- // Create an ad instance (extend RewardAdFather)
43
- class MyRewardAd extends RewardAdFather {
44
- async ad(ctx, next) {
45
- // Your ad logic here
46
- console.log('Executing reward ad');
47
-
48
- // Call next when ready to proceed
49
- await next();
50
-
51
- return { success: true, message: 'Ad executed successfully' };
53
+ // Initialize ad
54
+ rewardAd.initialize({
55
+ adUnitId: 'your-reward-ad-unit-id'
56
+ });
57
+
58
+ // Execute ad
59
+ const rewardResult = await rewardAd.addExecuteManager({
60
+ options: {
61
+ scene: 'reward_ad_scene',
62
+ timeout: 8000 // Optional timeout
52
63
  }
53
- }
64
+ });
65
+
66
+ // Create interstitial ad instance
67
+ const interstitialAd = InterstitialAdNovel.new({
68
+ adConfig: { /* ad configuration */ },
69
+ collection: {
70
+ always: (args) => console.log('Interstitial ad always callback', args),
71
+ halfway: (args) => console.log('Interstitial ad halfway callback', args),
72
+ finished: (args) => console.log('Interstitial ad finished callback', args),
73
+ before: (args) => console.log('Interstitial ad before callback', args),
74
+ success: (args) => console.log('Interstitial ad success callback', args),
75
+ prelude: (args) => console.log('Interstitial ad prelude callback', args)
76
+ }
77
+ });
54
78
 
55
- // Create ad instance
56
- const myAd = new MyRewardAd();
79
+ // Initialize ad
80
+ interstitialAd.initialize({
81
+ adUnitId: 'your-interstitial-ad-unit-id'
82
+ });
57
83
 
58
- // Add task to execution queue
59
- const result = await adManager.addTask(myAd, {
60
- options: { /* ad options */ },
61
- collection: { /* callback collection */ }
84
+ // Execute ad
85
+ const interstitialResult = await interstitialAd.addExecuteManager({
86
+ options: {
87
+ scene: 'interstitial_ad_scene'
88
+ }
62
89
  });
63
90
  ```
64
91
 
65
92
  ### Advanced Usage
66
93
 
67
94
  ```javascript
68
- import { AdExecuteManager, RewardAdSceneTriggerManager } from '@singcl/ad-execute-manager';
95
+ import { RewardAdNovel, InterstitialAdNovel, RewardAdSceneTriggerManager } from '@singcl/ad-execute-manager';
69
96
 
70
- // Initialize with logging enabled
71
- const adManager = AdExecuteManager.getInstance({ log: true });
97
+ // Create reward ad with logging enabled
98
+ const rewardAd = RewardAdNovel.new({
99
+ log: true, // Enable logging
100
+ adConfig: { /* ad configuration */ },
101
+ collection: { /* callback collection */ }
102
+ });
72
103
 
73
- // Check if manager is running
74
- if (adManager.isRunning()) {
75
- console.log('Ad manager is currently executing tasks');
76
- }
104
+ // Initialize ad with custom configuration
105
+ rewardAd.initialize({
106
+ adUnitId: 'your-reward-ad-unit-id',
107
+ // Other ad configuration options
108
+ });
77
109
 
78
- // Get current task ID
79
- const currentTaskId = adManager.getCurrentTaskId();
110
+ // Execute ad with custom options
111
+ const result = await rewardAd.addExecuteManager({
112
+ options: {
113
+ scene: 'reward_ad_scene',
114
+ timeout: 10000 // Custom timeout
115
+ },
116
+ collection: {
117
+ always: (args) => {
118
+ console.log('Ad execution completed', args);
119
+ // Handle completion
120
+ },
121
+ halfway: (args) => {
122
+ console.log('Ad interrupted', args);
123
+ // Handle interruption
124
+ },
125
+ finished: (args) => {
126
+ console.log('Ad finished successfully', args);
127
+ // Handle success
128
+ }
129
+ }
130
+ });
80
131
 
81
- // Get total number of pending tasks
82
- const taskCount = adManager.getTaskCount();
132
+ // Use scene trigger manager
133
+ const sceneManager = RewardAdSceneTriggerManager.build({ sign: 'init_sign' });
134
+ sceneManager.addScene('custom_ad_scene');
83
135
 
84
- // Wait for all tasks to complete
85
- await adManager.whenAllTasksComplete();
136
+ // Create interstitial ad with custom settings
137
+ const interstitialAd = InterstitialAdNovel.new({
138
+ needEndOnTimeout: true, // Enable timeout handling
139
+ adConfig: { /* ad configuration */ }
140
+ });
86
141
 
87
- // Clear all pending tasks
88
- adManager.clearTasks();
89
- ```
142
+ // Initialize and execute
143
+ interstitialAd.initialize({
144
+ adUnitId: 'your-interstitial-ad-unit-id'
145
+ });
90
146
 
91
- ## API Reference
147
+ const interstitialResult = await interstitialAd.addExecuteManager({
148
+ options: {
149
+ scene: 'interstitial_ad_scene'
150
+ }
151
+ });
152
+ ```
92
153
 
93
- ### AdExecuteManager
154
+ ## Core Concepts
94
155
 
95
- The main class for managing ad execution flow.
156
+ ### Ad Execution Flow
96
157
 
97
- #### Methods
158
+ RewardAdNovel and InterstitialAdNovel use a middleware pattern to handle ad execution flow. Each ad task goes through the following steps:
98
159
 
99
- - `getInstance(args)`: Get the singleton instance of AdExecuteManager
100
- - `getSafeInstance()`: Get the instance, returns null if not initialized
101
- - `addTask(adInstance, ctx)`: Add an ad task to the execution queue
102
- - `clearTasks()`: Cancel all pending tasks
103
- - `getTaskCount()`: Get the number of pending tasks
104
- - `isRunning()`: Check if tasks are currently running
105
- - `getCurrentTaskId()`: Get the ID of the current executing task
106
- - `whenAllTasksComplete()`: Returns a Promise that resolves when all tasks are complete
160
+ 1. **Initialization**: Create ad instance and configure parameters using `new()` or `build()`
161
+ 2. **Configuration**: Call `initialize()` to set up ad unit ID and other configuration
162
+ 3. **Execution**: Call `addExecuteManager()` to execute the ad with custom options
163
+ 4. **Completion Callback**: Call callback functions after ad execution completes
164
+ 5. **Cleanup**: Automatically clean up resources after execution
107
165
 
108
- ### RewardAdFather
166
+ ### Ad Types
109
167
 
110
- Base class for reward ad implementations.
168
+ - **Reward Ads**: Use `RewardAdNovel` for scenarios where users need to complete viewing to receive rewards
169
+ - **Interstitial Ads**: Use `InterstitialAdNovel` for scenarios where ads are inserted into the application flow
111
170
 
112
- ### InterstitialAdFather
171
+ ### Scene Management
113
172
 
114
- Base class for interstitial ad implementations.
173
+ Manage ad trigger scenes through `RewardAdSceneTriggerManager`, which allows executing different ad logic based on different scenes.
115
174
 
116
- ### Other Exports
175
+ ### Frequency Control
117
176
 
118
- - `SerializableError`: Error class that can be serialized
119
- - `Logger`: Logging utility
120
- - `Storage`: Storage management
121
- - `CountRecorder`: Ad execution counter
122
- - `RewardAdGlobalRecorder`: Global ad recorder
123
- - `RewardAdSceneTriggerManager`: Scene-based ad trigger manager
124
- - `AdAnalyticsJS`: Analytics integration
125
- - `RewardAdNovel`: Novel-specific reward ad implementation
126
- - `InterstitialAdNovel`: Novel-specific interstitial ad implementation
127
- - `PubSub`: Publish-subscribe pattern implementation
177
+ Use `CountRecorder` to implement ad display frequency control, which can set daily display limits.
128
178
 
129
- ## Examples
179
+ ## Usage Examples
130
180
 
131
- ### Reward Ad Unlock
181
+ ### 1. Launch Reward Ad
132
182
 
133
183
  ```javascript
134
- import { AdExecuteManager, RewardAdFather } from '@singcl/ad-execute-manager';
184
+ // 启动激励视频
185
+ import { CountRecorder, PubSub } from '@singcl/ad-execute-manager';
186
+ import CommonSettings from './CommonSettings';
187
+ import { SCENT_TEXT_OBJ } from './const';
188
+ import RewardAdNovelExb from './RewardAdNovelExb';
189
+
190
+ class RewardAdLaunch extends RewardAdNovelExb {
191
+ _scene = SCENT_TEXT_OBJ.launch_ad; // 广告执行场景
192
+
193
+ constructor(args) {
194
+ super(args);
195
+ this.launchSettings = RewardAdLaunchSettings.new();
196
+ }
135
197
 
136
- class UnlockAd extends RewardAdFather {
137
- async ad(ctx, next) {
138
- const { options, collection } = ctx;
139
-
140
- try {
141
- // Show reward ad
142
- const result = await this.showAd();
143
-
144
- if (result.isRewarded) {
145
- // Execute success callback
146
- collection.onSuccess && collection.onSuccess(result);
147
-
148
- // Proceed to next task
149
- await next();
150
-
151
- return { success: true, data: result };
198
+ adCloseLister(args) {
199
+ this._clearAdTimeout();
200
+ this._adCloseGlobalRecorder(args);
201
+ this._adCloseSuccessAnalytics({ scene: this._scene, ad_is_completed: args.isEnded ? 1 : 0, ad_count: args.count });
202
+
203
+ this.launchSettings.updateToday(); // 更新今天
204
+ this.launchSettings.updateFrequency();
205
+ const baseArgs = { ...args, scene: this._scene };
206
+ const _end = (ctx) => {
207
+ this.adDestroy();
208
+ this._resolve?.(Object.assign({}, args, { scene: this._scene }, ctx));
209
+ this._resolve = null;
210
+ this._next?.(); // 执行下一个任务的回调函数,以继续执行流程
211
+ this._next = null;
212
+ };
213
+
214
+ const _circle = () => {
215
+ if (this.launchSettings.remainFrequency() > 0) {
216
+ this._adInner({ options: { scene: this._scene }, collection: { resolve: this._resolve } }, this._next);
152
217
  } else {
153
- // Ad not completed
154
- collection.onCancel && collection.onCancel();
155
- return { success: false, message: 'Ad not completed' };
218
+ _end({ frequency: this.launchSettings.getFrequency() });
219
+ }
220
+ };
221
+ if (args.isEnded) {
222
+ this.launchSettings.updateFinished();
223
+ if (this.launchSettings.remainFrequency() == 0) {
224
+ this.launchSettings.updateLastFinished(true);
156
225
  }
157
- } catch (error) {
158
- collection.onError && collection.onError(error);
159
- throw error;
226
+ this._outerFinishedCallback(baseArgs);
227
+ this._onFinish?.(baseArgs);
228
+ } else {
229
+ this._outerHalfwayCallback(baseArgs);
230
+ this._onHalfway?.(baseArgs);
231
+ }
232
+ this._outerCloseCallback();
233
+ _circle();
234
+ }
235
+
236
+ static build(args) {
237
+ if (!RewardAdLaunch.instance) {
238
+ RewardAdLaunch.instance = new RewardAdLaunch(args);
239
+ }
240
+ return RewardAdLaunch.instance;
241
+ }
242
+
243
+ static getInstance() {
244
+ if (!RewardAdLaunch.instance) {
245
+ throw new Error('RewardAdLaunch instance is not init');
246
+ }
247
+ return RewardAdLaunch.instance;
248
+ }
249
+
250
+ static new(args) {
251
+ return new RewardAdLaunch(args);
252
+ }
253
+
254
+ static ad = new Promise((resolve) => {
255
+ RewardAdLaunch.adResolve = resolve;
256
+ });
257
+
258
+ static satisfy(options, callback) {
259
+ const con = RewardAdLaunchSettings.new().condition();
260
+ if (typeof callback !== 'function') {
261
+ return Promise.resolve();
160
262
  }
263
+ return callback(con ? { options } : null);
161
264
  }
265
+
266
+ static eventEmitter = new PubSub();
162
267
  }
163
268
 
164
- const adManager = AdExecuteManager.getInstance();
165
- const unlockAd = new UnlockAd();
269
+ export default RewardAdLaunch;
270
+
271
+ class RewardAdLaunchSettings {
272
+ _fixedFrequency = null; // 固定展示次数,如果为null, 表示使用配置
273
+ frequency = {
274
+ total: 0,
275
+ current: 0,
276
+ finished: 0,
277
+ lastFinished: false, // 最后一个是否完成
278
+ };
279
+ constructor() {
280
+ this.commonSettings = CommonSettings.new();
281
+ this.countRecorder = CountRecorder.new({
282
+ local_sign: 'launch_count',
283
+ total: this._adTimes(),
284
+ userId: this.commonSettings.getUserId(),
285
+ });
286
+ this.frequency.total = this.timesPerFrequency();
287
+ }
166
288
 
167
- await adManager.addTask(unlockAd, {
168
- options: { /* ad options */ },
169
- collection: {
170
- onSuccess: () => console.log('Reward received!'),
171
- onCancel: () => console.log('Ad cancelled'),
172
- onError: (error) => console.error('Ad error:', error)
289
+ _adTimes() {
290
+ // 从系统配置中获取启动广告的配置项
291
+ const { inter_site_pop_ups, inter_site_pop_ups_num } = this.commonSettings.getSysConfig();
292
+ // 如果配置存在则返回配置值,否则返回0
293
+ return Number(inter_site_pop_ups) > 0 && inter_site_pop_ups_num >= 1 ? Number(inter_site_pop_ups_num) : 0;
173
294
  }
174
- });
295
+
296
+ updateToday() {
297
+ this.countRecorder.updateToday();
298
+ }
299
+
300
+ updateFrequency() {
301
+ this.frequency.current += 1;
302
+ }
303
+
304
+ updateFinished() {
305
+ this.frequency.finished += 1;
306
+ }
307
+
308
+ updateLastFinished(v = true) {
309
+ this.frequency.lastFinished = v;
310
+ }
311
+
312
+ remainFrequency() {
313
+ return this.frequency.total - this.frequency.current;
314
+ }
315
+
316
+ getFrequency() {
317
+ return Object.assign({}, this.frequency);
318
+ }
319
+
320
+ timesPerFrequency() {
321
+ const { inter_site_pop_ups } = this.commonSettings.getSysConfig();
322
+ const ups = this._fixedFrequency ?? Number(inter_site_pop_ups);
323
+ const count = Math.min(Math.max(0, Number(ups)), this._remain());
324
+ return Math.max(0, count);
325
+ }
326
+
327
+ _remain() {
328
+ return this.countRecorder.remain();
329
+ }
330
+
331
+ condition() {
332
+ const remain = this._remain();
333
+ return Number(remain) > 0 && this.timesPerFrequency() > 0;
334
+ }
335
+
336
+ static new(args) {
337
+ return new RewardAdLaunchSettings(args);
338
+ }
339
+ }
175
340
  ```
176
341
 
177
- More examples can be found in the [examples](./example/) directory.
342
+ ### 2. Interstitial Ad
343
+
344
+ ```javascript
345
+ // 启动插屏广告
346
+ import AdExecuteManager, { CountRecorder, Logger } from '@singcl/ad-execute-manager';
347
+ import { matchErrorWithKeywords, getCurrentPageInterScene } from './_utils';
348
+ import { SCENT_TEXT_OBJ } from './const';
349
+ import InterstitialAdNovelExb from './InterstitialAdNovelExb';
350
+ import RewardAdGlobalRecorder from './RewardAdGlobalRecorder';
351
+ import CommonSettings from './CommonSettings';
352
+
353
+ class InterstitialAdNormal extends InterstitialAdNovelExb {
354
+ _scene = SCENT_TEXT_OBJ.other;
355
+ _launchGap = 30 * 1000;
356
+ _adBetweenGap = 60 * 1000;
357
+ _timer = null;
358
+ _adClose = 20000;
359
+ _backgroundRetryTime = 3000; // app在后台时,重试间隔时间
360
+ _foregroundRetryTime = 5000; // app在前台时,重试间隔时间
361
+
362
+ constructor(args) {
363
+ super(args);
364
+ this.logger = new Logger({ prefix: InterstitialAdNormal.name });
365
+ this.commonSettings = CommonSettings.new();
366
+ this.countRecorder = CountRecorder.new({
367
+ local_sign: 'interstitial_show_count',
368
+ total: this.commonSettings.getCpAdDetails().dayAd,
369
+ userId: this.commonSettings.getUserId(),
370
+ });
371
+ this._launchGap = this.commonSettings.getCpAdDetails().firstAdGap * 1000;
372
+ this._adBetweenGap = this.commonSettings.getCpAdDetails().secondAdGap * 1000;
373
+ this._adClose = this.commonSettings.getCpAdDetails().adClose ?? 20000;
374
+ }
375
+
376
+ _adCloseSuccessAnalytics(_args) {
377
+ // ExbAnalyticsJS.getInstance().track('incentive_ad_close', {
378
+ // scene: _args.scene,
379
+ // ad_is_completed: _args.ad_is_completed,
380
+ // });
381
+ }
382
+
383
+ _onInnerAdShowSuccess() {
384
+ this.countRecorder.updateToday(); // 更新今日展示次数
385
+ if (this._adClose) {
386
+ setTimeout(() => {
387
+ this.adCloseLister();
388
+ }, this._adClose);
389
+ }
390
+ }
391
+
392
+ async launch() {
393
+ const recordIns = RewardAdGlobalRecorder.getInstance();
394
+ const launchAdLastShowTime = recordIns.launchAdLastShowTime;
395
+ const startLaunchTime = Math.max(this._launchGap - (new Date().getTime() - launchAdLastShowTime), 0);
396
+
397
+ const circle = () => {
398
+ return new Promise((resolve) => {
399
+ const _fn = async () => {
400
+ await AdExecuteManager.getInstance().whenAllTasksComplete();
401
+ const nowTime = new Date().getTime();
402
+ const rewardAdLastShowTime = recordIns.rewardAdLastShowTime;
403
+ const interstitialAdLastShowTime = recordIns.interstitialAdLastShowTime;
404
+
405
+ const remain = Math.max(
406
+ this._adBetweenGap - (nowTime - Math.max(rewardAdLastShowTime, interstitialAdLastShowTime)),
407
+ 0
408
+ );
409
+ if (remain > 0) {
410
+ setTimeout(_fn, remain);
411
+ } else {
412
+ resolve();
413
+ }
414
+ };
415
+ _fn();
416
+ });
417
+ };
418
+
419
+ const fn2 = async (t) => {
420
+ this._timer = setTimeout(async () => {
421
+ if (this.countRecorder.remain() <= 0) {
422
+ clearTimeout(this._timer);
423
+ this._timer = null;
424
+ return;
425
+ }
426
+ await circle();
427
+ let res = null;
428
+ if (this.getAppDisplayStatus() === 'hide') {
429
+ const msg = `app in background: pause ad show, interstitial ad, time retry: ${this._backgroundRetryTime}ms`;
430
+ this.logger.log(msg);
431
+ res = {
432
+ apiError: {
433
+ errMsg: msg,
434
+ errorCode: 110000,
435
+ },
436
+ };
437
+ this.record(res);
438
+ } else {
439
+ this.logger.log(`Ad 进入队列,即将播放,GAP: ${this._adBetweenGap}ms`);
440
+ res = await this.addExecuteManager({
441
+ options: { retry: 0, scene: getCurrentPageInterScene() || this._scene },
442
+ });
443
+ }
444
+ if (res && !res.apiError) {
445
+ clearTimeout(this._timer);
446
+ this._timer = null;
447
+ fn2(this._adBetweenGap);
448
+ } else {
449
+ const e = res?.apiError;
450
+ if (matchErrorWithKeywords(this._ttErrorMsgs, e?.errMsg) || this._ttErrorCodes.includes(e?.errorCode)) {
451
+ clearTimeout(this._timer);
452
+ this._timer = null;
453
+ return;
454
+ }
455
+ setTimeout(
456
+ () => {
457
+ clearTimeout(this._timer);
458
+ this._timer = null;
459
+ fn2(0);
460
+ },
461
+ this.getAppDisplayStatus() === 'hide' ? this._backgroundRetryTime : this._foregroundRetryTime
462
+ );
463
+ }
464
+ }, t);
465
+ };
466
+
467
+ fn2(startLaunchTime);
468
+ }
178
469
 
179
- ## Contributing
470
+ getAppDisplayStatus() {
471
+ return RewardAdGlobalRecorder.getInstance().appDisplayStatus;
472
+ }
180
473
 
181
- We welcome contributions to this project! Please follow these steps:
474
+ static build(args) {
475
+ if (!InterstitialAdNormal.instance) {
476
+ InterstitialAdNormal.instance = new InterstitialAdNormal(args);
477
+ }
478
+ return InterstitialAdNormal.instance;
479
+ }
182
480
 
183
- 1. Fork the repository
184
- 2. Create a feature branch (`git checkout -b feature/amazing-feature`)
185
- 3. Make your changes
186
- 4. Commit your changes (`git commit -m 'Add some amazing feature'`)
187
- 5. Push to the branch (`git push origin feature/amazing-feature`)
188
- 6. Open a Pull Request
481
+ static getInstance() {
482
+ if (!InterstitialAdNormal.instance) {
483
+ throw new Error('InterstitialAdNormal instance is not init');
484
+ }
485
+ return InterstitialAdNormal.instance;
486
+ }
487
+
488
+ static new(args) {
489
+ return new InterstitialAdNormal(args);
490
+ }
491
+ }
492
+
493
+ export default InterstitialAdNormal;
494
+ ```
495
+
496
+ ### 3. Ad Scene Trigger Manager
497
+
498
+ ```javascript
499
+ import { Logger } from '@singcl/ad-execute-manager';
500
+ import { SCENT_TYPE_OBJ } from './const';
501
+
502
+ class RewardAdSceneTriggerManager {
503
+ static instance = null;
504
+ _initSign = ''; // 初始化标识
505
+ _currScene = null; // 当前场景
506
+
507
+ constructor(args) {
508
+ if (RewardAdSceneTriggerManager.instance) {
509
+ return RewardAdSceneTriggerManager.instance;
510
+ }
511
+ this._initSign = args?.sign ?? ''; // 初始化标识
512
+ this.logger = new Logger({ prefix: '' });
513
+ RewardAdSceneTriggerManager.instance = this;
514
+ }
515
+
516
+ initialize(args) {
517
+ // 初始化逻辑
518
+ }
519
+
520
+ addScene(value) {
521
+ this.logger.log('-------------AD trigger scene:--------------', value);
522
+ this._currScene = value;
523
+ return this;
524
+ }
525
+
526
+ addSceneType(args) {
527
+ this.addScene(SCENT_TYPE_OBJ[args.scene]);
528
+ return this;
529
+ }
530
+
531
+ getCurrentScene() {
532
+ return this._currScene;
533
+ }
534
+
535
+ placeholder() {
536
+ return null;
537
+ }
538
+
539
+ static build(args) {
540
+ if (!RewardAdSceneTriggerManager.instance) {
541
+ RewardAdSceneTriggerManager.instance = new RewardAdSceneTriggerManager(args);
542
+ }
543
+ return RewardAdSceneTriggerManager.instance;
544
+ }
545
+
546
+ static getInstance() {
547
+ if (!RewardAdSceneTriggerManager.instance) {
548
+ throw new Error('RewardAdSceneTriggerManager instance is not init');
549
+ }
550
+ return RewardAdSceneTriggerManager.instance;
551
+ }
552
+ }
553
+
554
+ export default RewardAdSceneTriggerManager;
555
+ ```
556
+
557
+ ## API Reference
558
+
559
+ ### RewardAdNovel
560
+
561
+ Main class for reward ad implementations, providing a complete solution for reward-based ads.
562
+
563
+ #### Methods
564
+
565
+ - `new(args)`: Create a new instance of RewardAdNovel
566
+ - `build(args)`: Get or create the singleton instance of RewardAdNovel
567
+ - `getInstance()`: Get the singleton instance of RewardAdNovel
568
+ - `initialize(args, callback)`: Initialize the ad with configuration
569
+ - `addExecuteManager(ctx)`: Execute the ad with custom options and callbacks
570
+ - `ad(ctx, next)`: Core ad execution method
571
+ - `adLoad()`: Load the ad
572
+ - `adShow()`: Show the ad
573
+ - `adDestroy()`: Destroy the ad instance
574
+ - `clear()`: Clear all resources
575
+
576
+ ### InterstitialAdNovel
577
+
578
+ Main class for interstitial ad implementations, providing a complete solution for interstitial ads.
579
+
580
+ #### Methods
581
+
582
+ - `new(args)`: Create a new instance of InterstitialAdNovel
583
+ - `build(args)`: Get or create the singleton instance of InterstitialAdNovel
584
+ - `getInstance()`: Get the singleton instance of InterstitialAdNovel
585
+ - `initialize(args, callback)`: Initialize the ad with configuration
586
+ - `addExecuteManager(ctx)`: Execute the ad with custom options and callbacks
587
+ - `ad(ctx, next)`: Core ad execution method
588
+ - `adLoad()`: Load the ad
589
+ - `adShow()`: Show the ad
590
+ - `adDestroy()`: Destroy the ad instance
591
+ - `clear()`: Clear all resources
592
+
593
+ ### Other Exports
594
+
595
+ - `SerializableError`: Error class that can be serialized
596
+ - `Logger`: Logging utility
597
+ - `Storage`: Storage management
598
+ - `CountRecorder`: Ad execution counter
599
+ - `RewardAdGlobalRecorder`: Global ad recorder
600
+ - `RewardAdSceneTriggerManager`: Scene-based ad trigger manager
601
+ - `AdAnalyticsJS`: Analytics integration
602
+ - `PubSub`: Publish-subscribe pattern implementation
603
+
604
+ ## Development Guide
189
605
 
190
606
  ### Development Scripts
191
607
 
@@ -195,6 +611,22 @@ We welcome contributions to this project! Please follow these steps:
195
611
  - `npm run format`: Format your code
196
612
  - `npm run test`: Run tests
197
613
 
614
+ ### Project Structure
615
+
616
+ ```
617
+ src/
618
+ ad/ # Core ad-related code
619
+ helper/ # Helper utilities
620
+ typings/ # Type definitions
621
+ utils/ # Common utilities
622
+ index.js # Entry file
623
+ example/ # Example code
624
+ AdUnlock/ # Ad unlock related examples
625
+ mini_program/ # Mini program examples
626
+ typings/ # Example type definitions
627
+ *.js # Various ad implementation examples
628
+ ```
629
+
198
630
  ## License
199
631
 
200
632
  This project is licensed under the MIT License - see the [LICENSE](./LICENSE) file for details.