@singcl/ad-execute-manager 1.11.2 → 1.11.4
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/LICENSE +20 -20
- package/README.md +558 -199
- package/package.json +1 -1
package/LICENSE
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
MIT License
|
|
2
|
-
|
|
3
|
-
Copyright (c) 2025-present, singcl
|
|
4
|
-
|
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
-
in the Software without restriction, including without limitation the rights
|
|
8
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
-
furnished to do so, subject to the following conditions:
|
|
11
|
-
|
|
12
|
-
The above copyright notice and this permission notice shall be included in all
|
|
13
|
-
copies or substantial portions of the Software.
|
|
14
|
-
|
|
15
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025-present, singcl
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
21
|
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,200 +1,559 @@
|
|
|
1
|
-
# AD Execute Manager
|
|
2
|
-
|
|
3
|
-
A powerful and flexible ad execution management library for handling reward-based ads, interstitial ads, and other advertising formats in JavaScript applications.
|
|
4
|
-
|
|
5
|
-
## Table of Contents
|
|
6
|
-
|
|
7
|
-
- [Features](#features)
|
|
8
|
-
- [Installation](#installation)
|
|
9
|
-
- [
|
|
10
|
-
- [
|
|
11
|
-
- [
|
|
12
|
-
- [
|
|
13
|
-
- [
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
- **
|
|
19
|
-
- **
|
|
20
|
-
- **
|
|
21
|
-
- **
|
|
22
|
-
- **
|
|
23
|
-
- **
|
|
24
|
-
- **
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
if
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
- `
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
1
|
+
# AD Execute Manager
|
|
2
|
+
|
|
3
|
+
A powerful and flexible ad execution management library for handling reward-based ads, interstitial ads, and other advertising formats in JavaScript applications.
|
|
4
|
+
|
|
5
|
+
## Table of Contents
|
|
6
|
+
|
|
7
|
+
- [Features](#features)
|
|
8
|
+
- [Installation](#installation)
|
|
9
|
+
- [Quick Start](#quick-start)
|
|
10
|
+
- [Core Concepts](#core-concepts)
|
|
11
|
+
- [Example Code](#example-code)
|
|
12
|
+
- [API Reference](#api-reference)
|
|
13
|
+
- [Development Guide](#development-guide)
|
|
14
|
+
- [License](#license)
|
|
15
|
+
|
|
16
|
+
## Features
|
|
17
|
+
|
|
18
|
+
- **Unified Ad Execution Interface**: Single interface for managing different types of ads
|
|
19
|
+
- **Task Queue Management**: Handles multiple ad execution tasks in a queue
|
|
20
|
+
- **Flexible Control Flow**: Manual control over ad execution flow with `next` function
|
|
21
|
+
- **Comprehensive Error Handling**: Complete error handling and logging
|
|
22
|
+
- **State Persistence**: Built-in storage for ad state management
|
|
23
|
+
- **Analytics Integration**: Built-in analytics support
|
|
24
|
+
- **Middleware Pattern**: Uses middleware pattern for ad execution flow
|
|
25
|
+
- **Cancellation Support**: Ability to clear and cancel pending tasks
|
|
26
|
+
|
|
27
|
+
## Installation
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
npm install @singcl/ad-execute-manager
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## Quick Start
|
|
34
|
+
|
|
35
|
+
### Basic Usage
|
|
36
|
+
|
|
37
|
+
```javascript
|
|
38
|
+
import { AdExecuteManager, RewardAdFather } from '@singcl/ad-execute-manager';
|
|
39
|
+
|
|
40
|
+
// Get the singleton instance
|
|
41
|
+
const adManager = AdExecuteManager.getInstance();
|
|
42
|
+
|
|
43
|
+
// Create an ad instance (extend RewardAdFather)
|
|
44
|
+
class MyRewardAd extends RewardAdFather {
|
|
45
|
+
async ad(ctx, next) {
|
|
46
|
+
// Your ad logic here
|
|
47
|
+
console.log('Executing reward ad');
|
|
48
|
+
|
|
49
|
+
// Call next when ready to proceed
|
|
50
|
+
await next();
|
|
51
|
+
|
|
52
|
+
return { success: true, message: 'Ad executed successfully' };
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// Create ad instance
|
|
57
|
+
const myAd = new MyRewardAd();
|
|
58
|
+
|
|
59
|
+
// Add task to execution queue
|
|
60
|
+
const result = await adManager.addTask(myAd, {
|
|
61
|
+
options: { /* ad options */ },
|
|
62
|
+
collection: { /* callback collection */ }
|
|
63
|
+
});
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### Advanced Usage
|
|
67
|
+
|
|
68
|
+
```javascript
|
|
69
|
+
import { AdExecuteManager, RewardAdSceneTriggerManager } from '@singcl/ad-execute-manager';
|
|
70
|
+
|
|
71
|
+
// Initialize with logging enabled
|
|
72
|
+
const adManager = AdExecuteManager.getInstance({ log: true });
|
|
73
|
+
|
|
74
|
+
// Check if manager is running
|
|
75
|
+
if (adManager.isRunning()) {
|
|
76
|
+
console.log('Ad manager is currently executing tasks');
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// Get current task ID
|
|
80
|
+
const currentTaskId = adManager.getCurrentTaskId();
|
|
81
|
+
|
|
82
|
+
// Get total number of pending tasks
|
|
83
|
+
const taskCount = adManager.getTaskCount();
|
|
84
|
+
|
|
85
|
+
// Wait for all tasks to complete
|
|
86
|
+
await adManager.whenAllTasksComplete();
|
|
87
|
+
|
|
88
|
+
// Clear all pending tasks
|
|
89
|
+
adManager.clearTasks();
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
## Core Concepts
|
|
93
|
+
|
|
94
|
+
### Ad Execution Flow
|
|
95
|
+
|
|
96
|
+
AD Execute Manager uses a middleware pattern to handle ad execution flow. Each ad task goes through the following steps:
|
|
97
|
+
|
|
98
|
+
1. **Initialization**: Create ad instance and configure parameters
|
|
99
|
+
2. **Queue Management**: Ad task enters the execution queue
|
|
100
|
+
3. **Ad Execution**: Call the `ad` method of the ad instance
|
|
101
|
+
4. **Completion Callback**: Call callback functions after ad execution completes
|
|
102
|
+
5. **Task Cleanup**: Clean up task resources and execute the next task
|
|
103
|
+
|
|
104
|
+
### Ad Types
|
|
105
|
+
|
|
106
|
+
- **Reward Ads**: Inherit from `RewardAdFather`, used for scenarios where users need to complete viewing to receive rewards
|
|
107
|
+
- **Interstitial Ads**: Inherit from `InterstitialAdFather`, used for scenarios where ads are inserted into the application flow
|
|
108
|
+
|
|
109
|
+
### Scene Management
|
|
110
|
+
|
|
111
|
+
Manage ad trigger scenes through `RewardAdSceneTriggerManager`, which allows executing different ad logic based on different scenes.
|
|
112
|
+
|
|
113
|
+
### Frequency Control
|
|
114
|
+
|
|
115
|
+
Use `CountRecorder` to implement ad display frequency control, which can set daily display limits.
|
|
116
|
+
|
|
117
|
+
## Example Code
|
|
118
|
+
|
|
119
|
+
### 1. Launch Reward Ad
|
|
120
|
+
|
|
121
|
+
```javascript
|
|
122
|
+
import { CountRecorder, PubSub } from '@singcl/ad-execute-manager';
|
|
123
|
+
import CommonSettings from './CommonSettings';
|
|
124
|
+
import { SCENT_TEXT_OBJ } from './const';
|
|
125
|
+
import RewardAdNovelExb from './RewardAdNovelExb';
|
|
126
|
+
|
|
127
|
+
class RewardAdLaunch extends RewardAdNovelExb {
|
|
128
|
+
_scene = SCENT_TEXT_OBJ.launch_ad; // Ad execution scene
|
|
129
|
+
|
|
130
|
+
constructor(args) {
|
|
131
|
+
super(args);
|
|
132
|
+
this.launchSettings = RewardAdLaunchSettings.new();
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
adCloseLister(args) {
|
|
136
|
+
this._clearAdTimeout();
|
|
137
|
+
this._adCloseGlobalRecorder(args);
|
|
138
|
+
this._adCloseSuccessAnalytics({ scene: this._scene, ad_is_completed: args.isEnded ? 1 : 0, ad_count: args.count });
|
|
139
|
+
|
|
140
|
+
this.launchSettings.updateToday(); // Update today
|
|
141
|
+
this.launchSettings.updateFrequency();
|
|
142
|
+
const baseArgs = { ...args, scene: this._scene };
|
|
143
|
+
const _end = (ctx) => {
|
|
144
|
+
this.adDestroy();
|
|
145
|
+
this._resolve?.(Object.assign({}, args, { scene: this._scene }, ctx));
|
|
146
|
+
this._resolve = null;
|
|
147
|
+
this._next?.(); // Execute the next task's callback function to continue the flow
|
|
148
|
+
this._next = null;
|
|
149
|
+
};
|
|
150
|
+
|
|
151
|
+
const _circle = () => {
|
|
152
|
+
if (this.launchSettings.remainFrequency() > 0) {
|
|
153
|
+
this._adInner({ options: { scene: this._scene }, collection: { resolve: this._resolve } }, this._next);
|
|
154
|
+
} else {
|
|
155
|
+
_end({ frequency: this.launchSettings.getFrequency() });
|
|
156
|
+
}
|
|
157
|
+
};
|
|
158
|
+
if (args.isEnded) {
|
|
159
|
+
this.launchSettings.updateFinished();
|
|
160
|
+
if (this.launchSettings.remainFrequency() == 0) {
|
|
161
|
+
this.launchSettings.updateLastFinished(true);
|
|
162
|
+
}
|
|
163
|
+
this._outerFinishedCallback(baseArgs);
|
|
164
|
+
this._onFinish?.(baseArgs);
|
|
165
|
+
} else {
|
|
166
|
+
this._outerHalfwayCallback(baseArgs);
|
|
167
|
+
this._onHalfway?.(baseArgs);
|
|
168
|
+
}
|
|
169
|
+
this._outerCloseCallback();
|
|
170
|
+
_circle();
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
static build(args) {
|
|
174
|
+
if (!RewardAdLaunch.instance) {
|
|
175
|
+
RewardAdLaunch.instance = new RewardAdLaunch(args);
|
|
176
|
+
}
|
|
177
|
+
return RewardAdLaunch.instance;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
static getInstance() {
|
|
181
|
+
if (!RewardAdLaunch.instance) {
|
|
182
|
+
throw new Error('RewardAdLaunch instance is not init');
|
|
183
|
+
}
|
|
184
|
+
return RewardAdLaunch.instance;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
static new(args) {
|
|
188
|
+
return new RewardAdLaunch(args);
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
static ad = new Promise((resolve) => {
|
|
192
|
+
RewardAdLaunch.adResolve = resolve;
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
static satisfy(options, callback) {
|
|
196
|
+
const con = RewardAdLaunchSettings.new().condition();
|
|
197
|
+
if (typeof callback !== 'function') {
|
|
198
|
+
return Promise.resolve();
|
|
199
|
+
}
|
|
200
|
+
return callback(con ? { options } : null);
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
static eventEmitter = new PubSub();
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
export default RewardAdLaunch;
|
|
207
|
+
|
|
208
|
+
class RewardAdLaunchSettings {
|
|
209
|
+
_fixedFrequency = null; // Fixed display frequency, if null, use configuration
|
|
210
|
+
frequency = {
|
|
211
|
+
total: 0,
|
|
212
|
+
current: 0,
|
|
213
|
+
finished: 0,
|
|
214
|
+
lastFinished: false, // Whether the last one is completed
|
|
215
|
+
};
|
|
216
|
+
constructor() {
|
|
217
|
+
this.commonSettings = CommonSettings.new();
|
|
218
|
+
this.countRecorder = CountRecorder.new({
|
|
219
|
+
local_sign: 'launch_count',
|
|
220
|
+
total: this._adTimes(),
|
|
221
|
+
userId: this.commonSettings.getUserId(),
|
|
222
|
+
});
|
|
223
|
+
this.frequency.total = this.timesPerFrequency();
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
_adTimes() {
|
|
227
|
+
// Get launch ad configuration from system configuration
|
|
228
|
+
const { inter_site_pop_ups, inter_site_pop_ups_num } = this.commonSettings.getSysConfig();
|
|
229
|
+
// Return configuration value if it exists, otherwise return 0
|
|
230
|
+
return Number(inter_site_pop_ups) > 0 && inter_site_pop_ups_num >= 1 ? Number(inter_site_pop_ups_num) : 0;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
updateToday() {
|
|
234
|
+
this.countRecorder.updateToday();
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
updateFrequency() {
|
|
238
|
+
this.frequency.current += 1;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
updateFinished() {
|
|
242
|
+
this.frequency.finished += 1;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
updateLastFinished(v = true) {
|
|
246
|
+
this.frequency.lastFinished = v;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
remainFrequency() {
|
|
250
|
+
return this.frequency.total - this.frequency.current;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
getFrequency() {
|
|
254
|
+
return Object.assign({}, this.frequency);
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
timesPerFrequency() {
|
|
258
|
+
const { inter_site_pop_ups } = this.commonSettings.getSysConfig();
|
|
259
|
+
const ups = this._fixedFrequency ?? Number(inter_site_pop_ups);
|
|
260
|
+
const count = Math.min(Math.max(0, Number(ups)), this._remain());
|
|
261
|
+
return Math.max(0, count);
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
_remain() {
|
|
265
|
+
return this.countRecorder.remain();
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
condition() {
|
|
269
|
+
const remain = this._remain();
|
|
270
|
+
return Number(remain) > 0 && this.timesPerFrequency() > 0;
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
static new(args) {
|
|
274
|
+
return new RewardAdLaunchSettings(args);
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
### 2. Interstitial Ad
|
|
280
|
+
|
|
281
|
+
```javascript
|
|
282
|
+
import AdExecuteManager, { CountRecorder, Logger } from '@singcl/ad-execute-manager';
|
|
283
|
+
import { matchErrorWithKeywords, getCurrentPageInterScene } from './_utils';
|
|
284
|
+
import { SCENT_TEXT_OBJ } from './const';
|
|
285
|
+
import InterstitialAdNovelExb from './InterstitialAdNovelExb';
|
|
286
|
+
import RewardAdGlobalRecorder from './RewardAdGlobalRecorder';
|
|
287
|
+
import CommonSettings from './CommonSettings';
|
|
288
|
+
|
|
289
|
+
class InterstitialAdNormal extends InterstitialAdNovelExb {
|
|
290
|
+
_scene = SCENT_TEXT_OBJ.other;
|
|
291
|
+
_launchGap = 30 * 1000;
|
|
292
|
+
_adBetweenGap = 60 * 1000;
|
|
293
|
+
_timer = null;
|
|
294
|
+
_adClose = 20000;
|
|
295
|
+
_backgroundRetryTime = 3000; // Retry interval when app is in background
|
|
296
|
+
_foregroundRetryTime = 5000; // Retry interval when app is in foreground
|
|
297
|
+
|
|
298
|
+
constructor(args) {
|
|
299
|
+
super(args);
|
|
300
|
+
this.logger = new Logger({ prefix: InterstitialAdNormal.name });
|
|
301
|
+
this.commonSettings = CommonSettings.new();
|
|
302
|
+
this.countRecorder = CountRecorder.new({
|
|
303
|
+
local_sign: 'interstitial_show_count',
|
|
304
|
+
total: this.commonSettings.getCpAdDetails().dayAd,
|
|
305
|
+
userId: this.commonSettings.getUserId(),
|
|
306
|
+
});
|
|
307
|
+
this._launchGap = this.commonSettings.getCpAdDetails().firstAdGap * 1000;
|
|
308
|
+
this._adBetweenGap = this.commonSettings.getCpAdDetails().secondAdGap * 1000;
|
|
309
|
+
this._adClose = this.commonSettings.getCpAdDetails().adClose ?? 20000;
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
_adCloseSuccessAnalytics(_args) {
|
|
313
|
+
// ExbAnalyticsJS.getInstance().track('incentive_ad_close', {
|
|
314
|
+
// scene: _args.scene,
|
|
315
|
+
// ad_is_completed: _args.ad_is_completed,
|
|
316
|
+
// });
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
_onInnerAdShowSuccess() {
|
|
320
|
+
this.countRecorder.updateToday(); // Update today's display count
|
|
321
|
+
if (this._adClose) {
|
|
322
|
+
setTimeout(() => {
|
|
323
|
+
this.adCloseLister();
|
|
324
|
+
}, this._adClose);
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
async launch() {
|
|
329
|
+
const recordIns = RewardAdGlobalRecorder.getInstance();
|
|
330
|
+
const launchAdLastShowTime = recordIns.launchAdLastShowTime;
|
|
331
|
+
const startLaunchTime = Math.max(this._launchGap - (new Date().getTime() - launchAdLastShowTime), 0);
|
|
332
|
+
|
|
333
|
+
const circle = () => {
|
|
334
|
+
return new Promise((resolve) => {
|
|
335
|
+
const _fn = async () => {
|
|
336
|
+
await AdExecuteManager.getInstance().whenAllTasksComplete();
|
|
337
|
+
const nowTime = new Date().getTime();
|
|
338
|
+
const rewardAdLastShowTime = recordIns.rewardAdLastShowTime;
|
|
339
|
+
const interstitialAdLastShowTime = recordIns.interstitialAdLastShowTime;
|
|
340
|
+
|
|
341
|
+
const remain = Math.max(
|
|
342
|
+
this._adBetweenGap - (nowTime - Math.max(rewardAdLastShowTime, interstitialAdLastShowTime)),
|
|
343
|
+
0
|
|
344
|
+
);
|
|
345
|
+
if (remain > 0) {
|
|
346
|
+
setTimeout(_fn, remain);
|
|
347
|
+
} else {
|
|
348
|
+
resolve();
|
|
349
|
+
}
|
|
350
|
+
};
|
|
351
|
+
_fn();
|
|
352
|
+
});
|
|
353
|
+
};
|
|
354
|
+
|
|
355
|
+
const fn2 = async (t) => {
|
|
356
|
+
this._timer = setTimeout(async () => {
|
|
357
|
+
if (this.countRecorder.remain() <= 0) {
|
|
358
|
+
clearTimeout(this._timer);
|
|
359
|
+
this._timer = null;
|
|
360
|
+
return;
|
|
361
|
+
}
|
|
362
|
+
await circle();
|
|
363
|
+
let res = null;
|
|
364
|
+
if (this.getAppDisplayStatus() === 'hide') {
|
|
365
|
+
const msg = `app in background: pause ad show, interstitial ad, time retry: ${this._backgroundRetryTime}ms`;
|
|
366
|
+
this.logger.log(msg);
|
|
367
|
+
res = {
|
|
368
|
+
apiError: {
|
|
369
|
+
errMsg: msg,
|
|
370
|
+
errorCode: 110000,
|
|
371
|
+
},
|
|
372
|
+
};
|
|
373
|
+
this.record(res);
|
|
374
|
+
} else {
|
|
375
|
+
this.logger.log(`Ad entering queue, will play soon, GAP: ${this._adBetweenGap}ms`);
|
|
376
|
+
res = await this.addExecuteManager({
|
|
377
|
+
options: { retry: 0, scene: getCurrentPageInterScene() || this._scene },
|
|
378
|
+
});
|
|
379
|
+
}
|
|
380
|
+
if (res && !res.apiError) {
|
|
381
|
+
clearTimeout(this._timer);
|
|
382
|
+
this._timer = null;
|
|
383
|
+
fn2(this._adBetweenGap);
|
|
384
|
+
} else {
|
|
385
|
+
const e = res?.apiError;
|
|
386
|
+
if (matchErrorWithKeywords(this._ttErrorMsgs, e?.errMsg) || this._ttErrorCodes.includes(e?.errorCode)) {
|
|
387
|
+
clearTimeout(this._timer);
|
|
388
|
+
this._timer = null;
|
|
389
|
+
return;
|
|
390
|
+
}
|
|
391
|
+
setTimeout(
|
|
392
|
+
() => {
|
|
393
|
+
clearTimeout(this._timer);
|
|
394
|
+
this._timer = null;
|
|
395
|
+
fn2(0);
|
|
396
|
+
},
|
|
397
|
+
this.getAppDisplayStatus() === 'hide' ? this._backgroundRetryTime : this._foregroundRetryTime
|
|
398
|
+
);
|
|
399
|
+
}
|
|
400
|
+
}, t);
|
|
401
|
+
};
|
|
402
|
+
|
|
403
|
+
fn2(startLaunchTime);
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
getAppDisplayStatus() {
|
|
407
|
+
return RewardAdGlobalRecorder.getInstance().appDisplayStatus;
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
static build(args) {
|
|
411
|
+
if (!InterstitialAdNormal.instance) {
|
|
412
|
+
InterstitialAdNormal.instance = new InterstitialAdNormal(args);
|
|
413
|
+
}
|
|
414
|
+
return InterstitialAdNormal.instance;
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
static getInstance() {
|
|
418
|
+
if (!InterstitialAdNormal.instance) {
|
|
419
|
+
throw new Error('InterstitialAdNormal instance is not init');
|
|
420
|
+
}
|
|
421
|
+
return InterstitialAdNormal.instance;
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
static new(args) {
|
|
425
|
+
return new InterstitialAdNormal(args);
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
export default InterstitialAdNormal;
|
|
430
|
+
```
|
|
431
|
+
|
|
432
|
+
### 3. Ad Scene Trigger Manager
|
|
433
|
+
|
|
434
|
+
```javascript
|
|
435
|
+
import { Logger } from '@singcl/ad-execute-manager';
|
|
436
|
+
import { SCENT_TYPE_OBJ } from './const';
|
|
437
|
+
|
|
438
|
+
class RewardAdSceneTriggerManager {
|
|
439
|
+
static instance = null;
|
|
440
|
+
_initSign = ''; // Initialization sign
|
|
441
|
+
_currScene = null; // Current scene
|
|
442
|
+
|
|
443
|
+
constructor(args) {
|
|
444
|
+
if (RewardAdSceneTriggerManager.instance) {
|
|
445
|
+
return RewardAdSceneTriggerManager.instance;
|
|
446
|
+
}
|
|
447
|
+
this._initSign = args?.sign ?? ''; // Initialization sign
|
|
448
|
+
this.logger = new Logger({ prefix: '' });
|
|
449
|
+
RewardAdSceneTriggerManager.instance = this;
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
initialize(args) {
|
|
453
|
+
// Initialization logic
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
addScene(value) {
|
|
457
|
+
this.logger.log('-------------AD trigger scene:--------------', value);
|
|
458
|
+
this._currScene = value;
|
|
459
|
+
return this;
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
addSceneType(args) {
|
|
463
|
+
this.addScene(SCENT_TYPE_OBJ[args.scene]);
|
|
464
|
+
return this;
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
getCurrentScene() {
|
|
468
|
+
return this._currScene;
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
placeholder() {
|
|
472
|
+
return null;
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
static build(args) {
|
|
476
|
+
if (!RewardAdSceneTriggerManager.instance) {
|
|
477
|
+
RewardAdSceneTriggerManager.instance = new RewardAdSceneTriggerManager(args);
|
|
478
|
+
}
|
|
479
|
+
return RewardAdSceneTriggerManager.instance;
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
static getInstance() {
|
|
483
|
+
if (!RewardAdSceneTriggerManager.instance) {
|
|
484
|
+
throw new Error('RewardAdSceneTriggerManager instance is not init');
|
|
485
|
+
}
|
|
486
|
+
return RewardAdSceneTriggerManager.instance;
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
export default RewardAdSceneTriggerManager;
|
|
491
|
+
```
|
|
492
|
+
|
|
493
|
+
## API Reference
|
|
494
|
+
|
|
495
|
+
### AdExecuteManager
|
|
496
|
+
|
|
497
|
+
The main class for managing ad execution flow.
|
|
498
|
+
|
|
499
|
+
#### Methods
|
|
500
|
+
|
|
501
|
+
- `getInstance(args)`: Get the singleton instance of AdExecuteManager
|
|
502
|
+
- `getSafeInstance()`: Get the instance, returns null if not initialized
|
|
503
|
+
- `addTask(adInstance, ctx)`: Add an ad task to the execution queue
|
|
504
|
+
- `clearTasks()`: Cancel all pending tasks
|
|
505
|
+
- `getTaskCount()`: Get the number of pending tasks
|
|
506
|
+
- `isRunning()`: Check if tasks are currently running
|
|
507
|
+
- `getCurrentTaskId()`: Get the ID of the current executing task
|
|
508
|
+
- `whenAllTasksComplete()`: Returns a Promise that resolves when all tasks are complete
|
|
509
|
+
|
|
510
|
+
### RewardAdFather
|
|
511
|
+
|
|
512
|
+
Base class for reward ad implementations.
|
|
513
|
+
|
|
514
|
+
### InterstitialAdFather
|
|
515
|
+
|
|
516
|
+
Base class for interstitial ad implementations.
|
|
517
|
+
|
|
518
|
+
### Other Exports
|
|
519
|
+
|
|
520
|
+
- `SerializableError`: Error class that can be serialized
|
|
521
|
+
- `Logger`: Logging utility
|
|
522
|
+
- `Storage`: Storage management
|
|
523
|
+
- `CountRecorder`: Ad execution counter
|
|
524
|
+
- `RewardAdGlobalRecorder`: Global ad recorder
|
|
525
|
+
- `RewardAdSceneTriggerManager`: Scene-based ad trigger manager
|
|
526
|
+
- `AdAnalyticsJS`: Analytics integration
|
|
527
|
+
- `RewardAdNovel`: Novel-specific reward ad implementation
|
|
528
|
+
- `InterstitialAdNovel`: Novel-specific interstitial ad implementation
|
|
529
|
+
- `PubSub`: Publish-subscribe pattern implementation
|
|
530
|
+
|
|
531
|
+
## Development Guide
|
|
532
|
+
|
|
533
|
+
### Development Scripts
|
|
534
|
+
|
|
535
|
+
- `npm run build`: Build the library for production
|
|
536
|
+
- `npm run dev`: Turn on watch mode
|
|
537
|
+
- `npm run lint`: Lint your code
|
|
538
|
+
- `npm run format`: Format your code
|
|
539
|
+
- `npm run test`: Run tests
|
|
540
|
+
|
|
541
|
+
### Project Structure
|
|
542
|
+
|
|
543
|
+
```
|
|
544
|
+
src/
|
|
545
|
+
ad/ # Core ad-related code
|
|
546
|
+
helper/ # Helper utilities
|
|
547
|
+
typings/ # Type definitions
|
|
548
|
+
utils/ # Common utilities
|
|
549
|
+
index.js # Entry file
|
|
550
|
+
example/ # Example code
|
|
551
|
+
AdUnlock/ # Ad unlock related examples
|
|
552
|
+
mini_program/ # Mini program examples
|
|
553
|
+
typings/ # Example type definitions
|
|
554
|
+
*.js # Various ad implementation examples
|
|
555
|
+
```
|
|
556
|
+
|
|
557
|
+
## License
|
|
558
|
+
|
|
200
559
|
This project is licensed under the MIT License - see the [LICENSE](./LICENSE) file for details.
|