cocos-rewarded-ads-kit 1.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 +190 -0
- package/ads.config.schema.json +45 -0
- package/bin/cocos-rewarded-ads.js +11 -0
- package/dist/packages/adapter-android-admob/src/index.d.ts +2 -0
- package/dist/packages/adapter-android-admob/src/index.js +13 -0
- package/dist/packages/adapter-android-max/src/index.d.ts +2 -0
- package/dist/packages/adapter-android-max/src/index.js +13 -0
- package/dist/packages/adapter-android-topon/src/index.d.ts +2 -0
- package/dist/packages/adapter-android-topon/src/index.js +13 -0
- package/dist/packages/adapter-douyin-mini-game/src/index.d.ts +15 -0
- package/dist/packages/adapter-douyin-mini-game/src/index.js +134 -0
- package/dist/packages/adapter-ios-admob/src/index.d.ts +2 -0
- package/dist/packages/adapter-ios-admob/src/index.js +13 -0
- package/dist/packages/adapter-ios-max/src/index.d.ts +2 -0
- package/dist/packages/adapter-ios-max/src/index.js +13 -0
- package/dist/packages/adapter-ios-topon/src/index.d.ts +2 -0
- package/dist/packages/adapter-ios-topon/src/index.js +13 -0
- package/dist/packages/adapter-wechat-mini-game/src/index.d.ts +15 -0
- package/dist/packages/adapter-wechat-mini-game/src/index.js +134 -0
- package/dist/packages/build-plugin/src/cli.d.ts +21 -0
- package/dist/packages/build-plugin/src/cli.js +60 -0
- package/dist/packages/build-plugin/src/context.d.ts +24 -0
- package/dist/packages/build-plugin/src/context.js +108 -0
- package/dist/packages/build-plugin/src/extension-hook.d.ts +71 -0
- package/dist/packages/build-plugin/src/extension-hook.js +62 -0
- package/dist/packages/build-plugin/src/generated-entry.d.ts +30 -0
- package/dist/packages/build-plugin/src/generated-entry.js +34 -0
- package/dist/packages/build-plugin/src/index.d.ts +8 -0
- package/dist/packages/build-plugin/src/index.js +8 -0
- package/dist/packages/build-plugin/src/materialize.d.ts +13 -0
- package/dist/packages/build-plugin/src/materialize.js +29 -0
- package/dist/packages/build-plugin/src/native-patcher.d.ts +9 -0
- package/dist/packages/build-plugin/src/native-patcher.js +147 -0
- package/dist/packages/build-plugin/src/native-provider.d.ts +22 -0
- package/dist/packages/build-plugin/src/native-provider.js +267 -0
- package/dist/packages/build-plugin/src/platform-select.d.ts +60 -0
- package/dist/packages/build-plugin/src/platform-select.js +302 -0
- package/dist/packages/build-plugin/templates/cocos-extension/main.ts.template +11 -0
- package/dist/packages/build-plugin/templates/cocos-extension/package.json.template.json +16 -0
- package/dist/packages/build-plugin/templates/native/android/admob/RewardedAdsAdMobBridge.kt.template +201 -0
- package/dist/packages/build-plugin/templates/native/android/max/RewardedAdsMaxBridge.kt.template +213 -0
- package/dist/packages/build-plugin/templates/native/android/topon/RewardedAdsTopOnBridge.kt.template +212 -0
- package/dist/packages/build-plugin/templates/native/ios/admob/RewardedAdsAdMobBridge.h.template +23 -0
- package/dist/packages/build-plugin/templates/native/ios/admob/RewardedAdsAdMobBridge.mm.template +187 -0
- package/dist/packages/build-plugin/templates/native/ios/max/RewardedAdsMaxBridge.h.template +23 -0
- package/dist/packages/build-plugin/templates/native/ios/max/RewardedAdsMaxBridge.mm.template +199 -0
- package/dist/packages/build-plugin/templates/native/ios/topon/RewardedAdsTopOnBridge.h.template +23 -0
- package/dist/packages/build-plugin/templates/native/ios/topon/RewardedAdsTopOnBridge.mm.template +200 -0
- package/dist/packages/core/src/config.d.ts +8 -0
- package/dist/packages/core/src/config.js +86 -0
- package/dist/packages/core/src/index.d.ts +3 -0
- package/dist/packages/core/src/index.js +3 -0
- package/dist/packages/core/src/native-bridge.d.ts +19 -0
- package/dist/packages/core/src/native-bridge.js +163 -0
- package/dist/packages/core/src/types.d.ts +99 -0
- package/dist/packages/core/src/types.js +21 -0
- package/dist/packages/runtime/src/RewardedAds.d.ts +20 -0
- package/dist/packages/runtime/src/RewardedAds.js +80 -0
- package/dist/packages/runtime/src/active-adapter.d.ts +2 -0
- package/dist/packages/runtime/src/active-adapter.js +4 -0
- package/dist/packages/runtime/src/index.d.ts +2 -0
- package/dist/packages/runtime/src/index.js +2 -0
- package/dist/packages/runtime/src/registry.d.ts +6 -0
- package/dist/packages/runtime/src/registry.js +18 -0
- package/docs/getting-started.md +381 -0
- package/docs/superpowers/plans/2026-03-29-bootstrap-v1.md +274 -0
- package/docs/superpowers/specs/2026-03-29-cocos-rewarded-ads-kit-design.md +462 -0
- package/examples/android-admob/ads.config.json +22 -0
- package/examples/android-max/ads.config.json +22 -0
- package/examples/android-topon/ads.config.json +24 -0
- package/examples/cocos-consumer/README.md +34 -0
- package/examples/cocos-consumer/src/RewardedAdsService.ts +33 -0
- package/examples/douyin-mini-game/ads.config.json +20 -0
- package/examples/ios-admob/ads.config.json +22 -0
- package/examples/ios-max/ads.config.json +22 -0
- package/examples/ios-topon/ads.config.json +24 -0
- package/examples/wechat-mini-game/ads.config.json +20 -0
- package/package.json +104 -0
- package/packages/adapter-android-admob/package.json +7 -0
- package/packages/adapter-android-admob/src/index.ts +19 -0
- package/packages/adapter-android-max/package.json +7 -0
- package/packages/adapter-android-max/src/index.ts +19 -0
- package/packages/adapter-android-topon/package.json +7 -0
- package/packages/adapter-android-topon/src/index.ts +19 -0
- package/packages/adapter-douyin-mini-game/package.json +7 -0
- package/packages/adapter-douyin-mini-game/src/index.ts +174 -0
- package/packages/adapter-ios-admob/package.json +7 -0
- package/packages/adapter-ios-admob/src/index.ts +19 -0
- package/packages/adapter-ios-max/package.json +7 -0
- package/packages/adapter-ios-max/src/index.ts +19 -0
- package/packages/adapter-ios-topon/package.json +7 -0
- package/packages/adapter-ios-topon/src/index.ts +19 -0
- package/packages/adapter-wechat-mini-game/package.json +7 -0
- package/packages/adapter-wechat-mini-game/src/index.ts +174 -0
- package/packages/build-plugin/package.json +10 -0
- package/packages/build-plugin/src/cli.ts +76 -0
- package/packages/build-plugin/src/context.ts +153 -0
- package/packages/build-plugin/src/extension-hook.ts +91 -0
- package/packages/build-plugin/src/generated-entry.ts +53 -0
- package/packages/build-plugin/src/index.ts +8 -0
- package/packages/build-plugin/src/materialize.ts +43 -0
- package/packages/build-plugin/src/native-patcher.ts +193 -0
- package/packages/build-plugin/src/native-provider.ts +334 -0
- package/packages/build-plugin/src/platform-select.ts +383 -0
- package/packages/build-plugin/templates/cocos-extension/main.ts.template +11 -0
- package/packages/build-plugin/templates/cocos-extension/package.json.template.json +16 -0
- package/packages/build-plugin/templates/native/android/admob/RewardedAdsAdMobBridge.kt.template +201 -0
- package/packages/build-plugin/templates/native/android/max/RewardedAdsMaxBridge.kt.template +213 -0
- package/packages/build-plugin/templates/native/android/topon/RewardedAdsTopOnBridge.kt.template +212 -0
- package/packages/build-plugin/templates/native/ios/admob/RewardedAdsAdMobBridge.h.template +23 -0
- package/packages/build-plugin/templates/native/ios/admob/RewardedAdsAdMobBridge.mm.template +187 -0
- package/packages/build-plugin/templates/native/ios/max/RewardedAdsMaxBridge.h.template +23 -0
- package/packages/build-plugin/templates/native/ios/max/RewardedAdsMaxBridge.mm.template +199 -0
- package/packages/build-plugin/templates/native/ios/topon/RewardedAdsTopOnBridge.h.template +23 -0
- package/packages/build-plugin/templates/native/ios/topon/RewardedAdsTopOnBridge.mm.template +200 -0
- package/packages/core/package.json +7 -0
- package/packages/core/src/config.ts +106 -0
- package/packages/core/src/index.ts +3 -0
- package/packages/core/src/native-bridge.ts +232 -0
- package/packages/core/src/types.ts +138 -0
- package/packages/runtime/package.json +7 -0
- package/packages/runtime/src/RewardedAds.ts +107 -0
- package/packages/runtime/src/active-adapter.ts +6 -0
- package/packages/runtime/src/index.ts +8 -0
- package/packages/runtime/src/registry.ts +25 -0
package/README.md
ADDED
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
# Cocos Rewarded Ads Kit
|
|
2
|
+
|
|
3
|
+
一个独立的、面向多个 Cocos Creator 项目的激励视频广告插件仓库。
|
|
4
|
+
|
|
5
|
+
推荐先看:
|
|
6
|
+
|
|
7
|
+
- [Quick Start](./docs/getting-started.md)
|
|
8
|
+
- [设计稿](./docs/superpowers/specs/2026-03-29-cocos-rewarded-ads-kit-design.md)
|
|
9
|
+
- [实现计划](./docs/superpowers/plans/2026-03-29-bootstrap-v1.md)
|
|
10
|
+
|
|
11
|
+
## v1 范围
|
|
12
|
+
|
|
13
|
+
- 只做激励视频
|
|
14
|
+
- 支持按平台按需接入
|
|
15
|
+
- 重点 provider / platform:
|
|
16
|
+
- Android AdMob
|
|
17
|
+
- iOS AdMob
|
|
18
|
+
- Android MAX
|
|
19
|
+
- iOS MAX
|
|
20
|
+
- Android TopOn
|
|
21
|
+
- iOS TopOn
|
|
22
|
+
- 微信小游戏
|
|
23
|
+
- 抖音小游戏
|
|
24
|
+
|
|
25
|
+
## 当前目录结构
|
|
26
|
+
|
|
27
|
+
```text
|
|
28
|
+
packages/
|
|
29
|
+
core/
|
|
30
|
+
runtime/
|
|
31
|
+
adapter-wechat-mini-game/
|
|
32
|
+
adapter-douyin-mini-game/
|
|
33
|
+
adapter-android-admob/
|
|
34
|
+
adapter-ios-admob/
|
|
35
|
+
adapter-android-max/
|
|
36
|
+
adapter-ios-max/
|
|
37
|
+
adapter-android-topon/
|
|
38
|
+
adapter-ios-topon/
|
|
39
|
+
build-plugin/
|
|
40
|
+
examples/
|
|
41
|
+
cocos-consumer/
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## 业务侧目标用法
|
|
45
|
+
|
|
46
|
+
```ts
|
|
47
|
+
import { createPreparedRewardedAdsRuntime } from './build/rewarded-ads/generated/bootstrap-runtime.ts';
|
|
48
|
+
|
|
49
|
+
const rewardedAds = createPreparedRewardedAdsRuntime({
|
|
50
|
+
platform: 'wechat-mini-game',
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
await rewardedAds.init();
|
|
54
|
+
await rewardedAds.preload('reward_revive');
|
|
55
|
+
|
|
56
|
+
const result = await rewardedAds.show('reward_revive');
|
|
57
|
+
if (result.earned) {
|
|
58
|
+
// 发奖励
|
|
59
|
+
}
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
## 配置文件
|
|
63
|
+
|
|
64
|
+
每个接入项目维护一份 `ads.config.json`,按目标平台分别配置:
|
|
65
|
+
|
|
66
|
+
- 微信小游戏 / 抖音小游戏:`adUnitId`
|
|
67
|
+
- AdMob:`appId + adUnitId`
|
|
68
|
+
- MAX:`sdkKey + adUnitId`
|
|
69
|
+
- TopOn:`appId + appKey + adUnitId`
|
|
70
|
+
|
|
71
|
+
### v1 provider 约束
|
|
72
|
+
|
|
73
|
+
- 同一目标平台只允许一个 rewarded provider
|
|
74
|
+
- 同一平台可以有多个 placement
|
|
75
|
+
- 这些 placement 在 v1 中必须共用同一个 provider
|
|
76
|
+
- 如果同平台混用 MAX / TopOn,build-plugin 会直接校验失败
|
|
77
|
+
|
|
78
|
+
可参考:
|
|
79
|
+
- [consumer example](./examples/cocos-consumer/README.md)
|
|
80
|
+
- [android-admob example](./examples/android-admob/ads.config.json)
|
|
81
|
+
- [ios-admob example](./examples/ios-admob/ads.config.json)
|
|
82
|
+
- [wechat-mini-game example](./examples/wechat-mini-game/ads.config.json)
|
|
83
|
+
- [douyin-mini-game example](./examples/douyin-mini-game/ads.config.json)
|
|
84
|
+
- [android-max example](./examples/android-max/ads.config.json)
|
|
85
|
+
- [ios-max example](./examples/ios-max/ads.config.json)
|
|
86
|
+
- [android-topon example](./examples/android-topon/ads.config.json)
|
|
87
|
+
- [ios-topon example](./examples/ios-topon/ads.config.json)
|
|
88
|
+
|
|
89
|
+
## 当前实现进度
|
|
90
|
+
|
|
91
|
+
已完成:
|
|
92
|
+
- 核心类型与配置归一化
|
|
93
|
+
- 运行时 facade 与 generated binding registry
|
|
94
|
+
- provider 包入口与 runtime 工厂签名对齐
|
|
95
|
+
- 微信小游戏 / 抖音小游戏 adapter
|
|
96
|
+
- Android / iOS AdMob / MAX / TopOn native provider bridge 模板
|
|
97
|
+
- build-plugin 平台选择、prepare CLI、Cocos build extension、bootstrap-runtime 生成
|
|
98
|
+
- Android / iOS 宿主工程自动 patch
|
|
99
|
+
- Cocos 项目消费者示例与接入文档
|
|
100
|
+
|
|
101
|
+
仓库外仍需人工验收:
|
|
102
|
+
- 使用真实 MAX / TopOn 凭据做一次 Android / iOS 最终构建
|
|
103
|
+
- 在真实广告位上确认 preload / show / earned / cancelled 行为
|
|
104
|
+
|
|
105
|
+
## npm 安装
|
|
106
|
+
|
|
107
|
+
推荐在接入项目里直接安装发布包:
|
|
108
|
+
|
|
109
|
+
```bash
|
|
110
|
+
npm i -D cocos-rewarded-ads-kit@1.0.0
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
## 一键 prepare 命令
|
|
114
|
+
|
|
115
|
+
安装后可直接用 CLI 生成当前平台广告产物:
|
|
116
|
+
|
|
117
|
+
```bash
|
|
118
|
+
npx cocos-rewarded-ads prepare --config ./ads.config.json --platform wechatgame --output ./build/rewarded-ads
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
可选参数:
|
|
122
|
+
- `--extension-name`
|
|
123
|
+
|
|
124
|
+
当前支持的平台参数:
|
|
125
|
+
- `android`
|
|
126
|
+
- `ios`
|
|
127
|
+
- `wechatgame`
|
|
128
|
+
- `bytedance-mini-game`
|
|
129
|
+
|
|
130
|
+
## prepare 输出内容
|
|
131
|
+
|
|
132
|
+
执行 `prepare:ads` 后,当前版本会生成这几类产物:
|
|
133
|
+
|
|
134
|
+
- `generated/`
|
|
135
|
+
- `active-adapter.ts`
|
|
136
|
+
- `generated-rewarded-config.ts`
|
|
137
|
+
- `install-generated-bindings.ts`
|
|
138
|
+
- `bootstrap-runtime.ts`
|
|
139
|
+
- `cocos-extension/`
|
|
140
|
+
- `package.json`
|
|
141
|
+
- `dist/main.js`
|
|
142
|
+
- `dist/builder.js`
|
|
143
|
+
- `dist/hooks.js`
|
|
144
|
+
- `native/`(仅 Android / iOS)
|
|
145
|
+
- provider bridge 模板
|
|
146
|
+
- `RewardedAdsInstaller`
|
|
147
|
+
- provider config JSON
|
|
148
|
+
- 依赖片段
|
|
149
|
+
- AppActivity / AppDelegate 接入 snippet
|
|
150
|
+
|
|
151
|
+
## 当前 native 输出说明
|
|
152
|
+
|
|
153
|
+
Android / iOS 当前已经能生成:
|
|
154
|
+
|
|
155
|
+
- provider bridge 模板
|
|
156
|
+
- 统一 installer 入口
|
|
157
|
+
- provider 配置文件
|
|
158
|
+
- Gradle / Pod 依赖片段
|
|
159
|
+
- 原生接入 snippet
|
|
160
|
+
- 原生宿主工程 patch plan
|
|
161
|
+
|
|
162
|
+
并且当前版本已经会在检测到宿主工程文件存在时,自动 patch:
|
|
163
|
+
|
|
164
|
+
- Android
|
|
165
|
+
- `native/engine/android/app/build.gradle`
|
|
166
|
+
- `native/engine/android/app/src/**/AppActivity.java|kt`
|
|
167
|
+
- iOS
|
|
168
|
+
- `native/engine/ios/Podfile.in`
|
|
169
|
+
- `native/engine/ios/CMakeLists.txt`
|
|
170
|
+
- `native/engine/ios/AppDelegate.mm`
|
|
171
|
+
|
|
172
|
+
这意味着:
|
|
173
|
+
|
|
174
|
+
- 微信小游戏 / 抖音小游戏已经接近可直接接入状态
|
|
175
|
+
- Android / iOS 已经具备“生成 + 自动 patch”的基础闭环
|
|
176
|
+
- provider SDK 的最终真机构建验收仍需要接入项目用真实凭据完成
|
|
177
|
+
|
|
178
|
+
## 推荐接入姿势
|
|
179
|
+
|
|
180
|
+
如果你是把这套能力接进一个新的 Cocos 项目,当前最稳的方式是:
|
|
181
|
+
|
|
182
|
+
1. 在项目根目录维护 `ads.config.json`
|
|
183
|
+
2. build 前执行 `cocos-rewarded-ads prepare`
|
|
184
|
+
3. 在业务代码里只引入 `generated/bootstrap-runtime.ts`
|
|
185
|
+
4. 用 placement 调用统一 runtime
|
|
186
|
+
|
|
187
|
+
参考:
|
|
188
|
+
|
|
189
|
+
- [Quick Start](./docs/getting-started.md)
|
|
190
|
+
- [Cocos 项目接入示例](./examples/cocos-consumer/README.md)
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"type": "object",
|
|
4
|
+
"required": ["version", "placements"],
|
|
5
|
+
"properties": {
|
|
6
|
+
"version": {
|
|
7
|
+
"type": "integer",
|
|
8
|
+
"const": 1
|
|
9
|
+
},
|
|
10
|
+
"defaults": {
|
|
11
|
+
"type": "object",
|
|
12
|
+
"properties": {
|
|
13
|
+
"preloadOnInit": {
|
|
14
|
+
"type": "array",
|
|
15
|
+
"items": {
|
|
16
|
+
"type": "string"
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
"additionalProperties": false
|
|
21
|
+
},
|
|
22
|
+
"placements": {
|
|
23
|
+
"type": "object",
|
|
24
|
+
"additionalProperties": {
|
|
25
|
+
"type": "object",
|
|
26
|
+
"properties": {
|
|
27
|
+
"android": {
|
|
28
|
+
"type": "object"
|
|
29
|
+
},
|
|
30
|
+
"ios": {
|
|
31
|
+
"type": "object"
|
|
32
|
+
},
|
|
33
|
+
"wechat-mini-game": {
|
|
34
|
+
"type": "object"
|
|
35
|
+
},
|
|
36
|
+
"douyin-mini-game": {
|
|
37
|
+
"type": "object"
|
|
38
|
+
}
|
|
39
|
+
},
|
|
40
|
+
"additionalProperties": true
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
},
|
|
44
|
+
"additionalProperties": false
|
|
45
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { createNativeRewardedAdapter, createUnsupportedNativeRewardedAdapter, resolveNativeBridgeWrapper, } from "../../core/src/native-bridge.js";
|
|
2
|
+
export function createAdapter(options) {
|
|
3
|
+
const wrapper = resolveNativeBridgeWrapper(options.wrapper);
|
|
4
|
+
if (!wrapper) {
|
|
5
|
+
return createUnsupportedNativeRewardedAdapter('android jsbBridgeWrapper is unavailable');
|
|
6
|
+
}
|
|
7
|
+
return createNativeRewardedAdapter({
|
|
8
|
+
provider: 'admob',
|
|
9
|
+
wrapper,
|
|
10
|
+
placements: options.config.placements,
|
|
11
|
+
timeoutMs: options.timeoutMs,
|
|
12
|
+
});
|
|
13
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { createNativeRewardedAdapter, createUnsupportedNativeRewardedAdapter, resolveNativeBridgeWrapper, } from "../../core/src/native-bridge.js";
|
|
2
|
+
export function createAdapter(options) {
|
|
3
|
+
const wrapper = resolveNativeBridgeWrapper(options.wrapper);
|
|
4
|
+
if (!wrapper) {
|
|
5
|
+
return createUnsupportedNativeRewardedAdapter('android jsbBridgeWrapper is unavailable');
|
|
6
|
+
}
|
|
7
|
+
return createNativeRewardedAdapter({
|
|
8
|
+
provider: 'max',
|
|
9
|
+
wrapper,
|
|
10
|
+
placements: options.config.placements,
|
|
11
|
+
timeoutMs: options.timeoutMs,
|
|
12
|
+
});
|
|
13
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { createNativeRewardedAdapter, createUnsupportedNativeRewardedAdapter, resolveNativeBridgeWrapper, } from "../../core/src/native-bridge.js";
|
|
2
|
+
export function createAdapter(options) {
|
|
3
|
+
const wrapper = resolveNativeBridgeWrapper(options.wrapper);
|
|
4
|
+
if (!wrapper) {
|
|
5
|
+
return createUnsupportedNativeRewardedAdapter('android jsbBridgeWrapper is unavailable');
|
|
6
|
+
}
|
|
7
|
+
return createNativeRewardedAdapter({
|
|
8
|
+
provider: 'topon',
|
|
9
|
+
wrapper,
|
|
10
|
+
placements: options.config.placements,
|
|
11
|
+
timeoutMs: options.timeoutMs,
|
|
12
|
+
});
|
|
13
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { DouyinMiniGameApiLike, NormalizedRewardedAdsConfig, NormalizedPlatformPlacementConfig, RewardedAdapter, RewardedAdapterFactory } from '../../core/src/types.ts';
|
|
2
|
+
interface DouyinAdapterOptions {
|
|
3
|
+
ttApi?: DouyinMiniGameApiLike | null;
|
|
4
|
+
placements: Record<string, NormalizedPlatformPlacementConfig>;
|
|
5
|
+
showTimeoutMs?: number;
|
|
6
|
+
}
|
|
7
|
+
export declare function createDouyinMiniGameRewardedAdapter(options: DouyinAdapterOptions): RewardedAdapter;
|
|
8
|
+
export declare const createRuntimeAdapter: RewardedAdapterFactory;
|
|
9
|
+
export declare function createAdapter(options: DouyinAdapterOptions | {
|
|
10
|
+
platform: NormalizedRewardedAdsConfig['platform'];
|
|
11
|
+
config: NormalizedRewardedAdsConfig;
|
|
12
|
+
ttApi?: DouyinMiniGameApiLike | null;
|
|
13
|
+
showTimeoutMs?: number;
|
|
14
|
+
}): RewardedAdapter;
|
|
15
|
+
export {};
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
function createError(code, message, cause) {
|
|
2
|
+
return { code, message, cause };
|
|
3
|
+
}
|
|
4
|
+
function createErrorResult(error) {
|
|
5
|
+
return {
|
|
6
|
+
completed: false,
|
|
7
|
+
cancelled: false,
|
|
8
|
+
earned: false,
|
|
9
|
+
error,
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
function toResult(result) {
|
|
13
|
+
if (!result || typeof result.isEnded !== 'boolean') {
|
|
14
|
+
return {
|
|
15
|
+
completed: true,
|
|
16
|
+
cancelled: false,
|
|
17
|
+
earned: true,
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
return {
|
|
21
|
+
completed: true,
|
|
22
|
+
cancelled: !result.isEnded,
|
|
23
|
+
earned: !!result.isEnded,
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
export function createDouyinMiniGameRewardedAdapter(options) {
|
|
27
|
+
const showTimeoutMs = Math.max(1, options.showTimeoutMs ?? 15000);
|
|
28
|
+
const ads = new Map();
|
|
29
|
+
const states = new Map();
|
|
30
|
+
const getAd = (placement) => {
|
|
31
|
+
const placementConfig = options.placements[placement];
|
|
32
|
+
if (!placementConfig) {
|
|
33
|
+
return { ad: null, error: createError('configInvalid', `${placement} config is unavailable`) };
|
|
34
|
+
}
|
|
35
|
+
if (!options.ttApi) {
|
|
36
|
+
return { ad: null, error: createError('unsupported', `${placement} tt api is unavailable`) };
|
|
37
|
+
}
|
|
38
|
+
const cached = ads.get(placement);
|
|
39
|
+
if (cached) {
|
|
40
|
+
return { ad: cached, error: null };
|
|
41
|
+
}
|
|
42
|
+
const ad = options.ttApi.createRewardedVideoAd({ adUnitId: placementConfig.adUnitId });
|
|
43
|
+
ads.set(placement, ad);
|
|
44
|
+
return { ad, error: null };
|
|
45
|
+
};
|
|
46
|
+
return {
|
|
47
|
+
async init() {
|
|
48
|
+
return undefined;
|
|
49
|
+
},
|
|
50
|
+
async preload(placement) {
|
|
51
|
+
const { ad, error } = getAd(placement);
|
|
52
|
+
if (!ad) {
|
|
53
|
+
states.set(placement, 'unsupported');
|
|
54
|
+
throw error;
|
|
55
|
+
}
|
|
56
|
+
states.set(placement, 'loading');
|
|
57
|
+
if (typeof ad.load === 'function') {
|
|
58
|
+
await ad.load();
|
|
59
|
+
}
|
|
60
|
+
states.set(placement, 'ready');
|
|
61
|
+
},
|
|
62
|
+
async show(placement) {
|
|
63
|
+
const { ad, error } = getAd(placement);
|
|
64
|
+
if (!ad) {
|
|
65
|
+
states.set(placement, 'unsupported');
|
|
66
|
+
return createErrorResult(error);
|
|
67
|
+
}
|
|
68
|
+
states.set(placement, 'showing');
|
|
69
|
+
return await new Promise((resolve) => {
|
|
70
|
+
let settled = false;
|
|
71
|
+
const settle = (result) => {
|
|
72
|
+
if (settled) {
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
settled = true;
|
|
76
|
+
clearTimeout(timer);
|
|
77
|
+
states.set(placement, 'idle');
|
|
78
|
+
if (typeof ad.offClose === 'function') {
|
|
79
|
+
ad.offClose(handleClose);
|
|
80
|
+
}
|
|
81
|
+
if (typeof ad.offError === 'function') {
|
|
82
|
+
ad.offError(handleError);
|
|
83
|
+
}
|
|
84
|
+
resolve(result);
|
|
85
|
+
};
|
|
86
|
+
const handleClose = (result) => settle(toResult(result));
|
|
87
|
+
const handleError = (cause) => settle(createErrorResult(createError('showFailed', `${placement} show failed`, cause)));
|
|
88
|
+
const timer = setTimeout(() => settle(createErrorResult(createError('timeout', `${placement} show timed out`))), showTimeoutMs);
|
|
89
|
+
if (typeof ad.onClose === 'function') {
|
|
90
|
+
ad.onClose(handleClose);
|
|
91
|
+
}
|
|
92
|
+
if (typeof ad.onError === 'function') {
|
|
93
|
+
ad.onError(handleError);
|
|
94
|
+
}
|
|
95
|
+
Promise.resolve(typeof ad.show === 'function' ? ad.show() : undefined)
|
|
96
|
+
.catch((cause) => settle(createErrorResult(createError('showFailed', `${placement} show failed`, cause))));
|
|
97
|
+
});
|
|
98
|
+
},
|
|
99
|
+
isReady(placement) {
|
|
100
|
+
return states.get(placement) === 'ready';
|
|
101
|
+
},
|
|
102
|
+
getState(placement) {
|
|
103
|
+
return states.get(placement) ?? 'idle';
|
|
104
|
+
},
|
|
105
|
+
reset(placement) {
|
|
106
|
+
if (placement) {
|
|
107
|
+
ads.delete(placement);
|
|
108
|
+
states.delete(placement);
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
ads.clear();
|
|
112
|
+
states.clear();
|
|
113
|
+
},
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
function resolveDouyinApi(override) {
|
|
117
|
+
if (override) {
|
|
118
|
+
return override;
|
|
119
|
+
}
|
|
120
|
+
return globalThis.tt ?? null;
|
|
121
|
+
}
|
|
122
|
+
export const createRuntimeAdapter = (options) => {
|
|
123
|
+
return createDouyinMiniGameRewardedAdapter({
|
|
124
|
+
ttApi: resolveDouyinApi(options.ttApi),
|
|
125
|
+
placements: options.config.placements,
|
|
126
|
+
showTimeoutMs: options.showTimeoutMs,
|
|
127
|
+
});
|
|
128
|
+
};
|
|
129
|
+
export function createAdapter(options) {
|
|
130
|
+
if ('placements' in options) {
|
|
131
|
+
return createDouyinMiniGameRewardedAdapter(options);
|
|
132
|
+
}
|
|
133
|
+
return createRuntimeAdapter(options);
|
|
134
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { createNativeRewardedAdapter, createUnsupportedNativeRewardedAdapter, resolveNativeBridgeWrapper, } from "../../core/src/native-bridge.js";
|
|
2
|
+
export function createAdapter(options) {
|
|
3
|
+
const wrapper = resolveNativeBridgeWrapper(options.wrapper);
|
|
4
|
+
if (!wrapper) {
|
|
5
|
+
return createUnsupportedNativeRewardedAdapter('ios jsbBridgeWrapper is unavailable');
|
|
6
|
+
}
|
|
7
|
+
return createNativeRewardedAdapter({
|
|
8
|
+
provider: 'admob',
|
|
9
|
+
wrapper,
|
|
10
|
+
placements: options.config.placements,
|
|
11
|
+
timeoutMs: options.timeoutMs,
|
|
12
|
+
});
|
|
13
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { createNativeRewardedAdapter, createUnsupportedNativeRewardedAdapter, resolveNativeBridgeWrapper, } from "../../core/src/native-bridge.js";
|
|
2
|
+
export function createAdapter(options) {
|
|
3
|
+
const wrapper = resolveNativeBridgeWrapper(options.wrapper);
|
|
4
|
+
if (!wrapper) {
|
|
5
|
+
return createUnsupportedNativeRewardedAdapter('ios jsbBridgeWrapper is unavailable');
|
|
6
|
+
}
|
|
7
|
+
return createNativeRewardedAdapter({
|
|
8
|
+
provider: 'max',
|
|
9
|
+
wrapper,
|
|
10
|
+
placements: options.config.placements,
|
|
11
|
+
timeoutMs: options.timeoutMs,
|
|
12
|
+
});
|
|
13
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { createNativeRewardedAdapter, createUnsupportedNativeRewardedAdapter, resolveNativeBridgeWrapper, } from "../../core/src/native-bridge.js";
|
|
2
|
+
export function createAdapter(options) {
|
|
3
|
+
const wrapper = resolveNativeBridgeWrapper(options.wrapper);
|
|
4
|
+
if (!wrapper) {
|
|
5
|
+
return createUnsupportedNativeRewardedAdapter('ios jsbBridgeWrapper is unavailable');
|
|
6
|
+
}
|
|
7
|
+
return createNativeRewardedAdapter({
|
|
8
|
+
provider: 'topon',
|
|
9
|
+
wrapper,
|
|
10
|
+
placements: options.config.placements,
|
|
11
|
+
timeoutMs: options.timeoutMs,
|
|
12
|
+
});
|
|
13
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { NormalizedRewardedAdsConfig, NormalizedPlatformPlacementConfig, RewardedAdapter, RewardedAdapterFactory, WeChatMiniGameApiLike } from '../../core/src/types.ts';
|
|
2
|
+
interface WeChatAdapterOptions {
|
|
3
|
+
wxApi?: WeChatMiniGameApiLike | null;
|
|
4
|
+
placements: Record<string, NormalizedPlatformPlacementConfig>;
|
|
5
|
+
showTimeoutMs?: number;
|
|
6
|
+
}
|
|
7
|
+
export declare function createWeChatMiniGameRewardedAdapter(options: WeChatAdapterOptions): RewardedAdapter;
|
|
8
|
+
export declare const createRuntimeAdapter: RewardedAdapterFactory;
|
|
9
|
+
export declare function createAdapter(options: WeChatAdapterOptions | {
|
|
10
|
+
platform: NormalizedRewardedAdsConfig['platform'];
|
|
11
|
+
config: NormalizedRewardedAdsConfig;
|
|
12
|
+
wxApi?: WeChatMiniGameApiLike | null;
|
|
13
|
+
showTimeoutMs?: number;
|
|
14
|
+
}): RewardedAdapter;
|
|
15
|
+
export {};
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
function createError(code, message, cause) {
|
|
2
|
+
return { code, message, cause };
|
|
3
|
+
}
|
|
4
|
+
function createErrorResult(error) {
|
|
5
|
+
return {
|
|
6
|
+
completed: false,
|
|
7
|
+
cancelled: false,
|
|
8
|
+
earned: false,
|
|
9
|
+
error,
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
function toResult(result) {
|
|
13
|
+
if (!result || typeof result.isEnded !== 'boolean') {
|
|
14
|
+
return {
|
|
15
|
+
completed: true,
|
|
16
|
+
cancelled: false,
|
|
17
|
+
earned: true,
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
return {
|
|
21
|
+
completed: true,
|
|
22
|
+
cancelled: !result.isEnded,
|
|
23
|
+
earned: !!result.isEnded,
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
export function createWeChatMiniGameRewardedAdapter(options) {
|
|
27
|
+
const showTimeoutMs = Math.max(1, options.showTimeoutMs ?? 15000);
|
|
28
|
+
const ads = new Map();
|
|
29
|
+
const states = new Map();
|
|
30
|
+
const getAd = (placement) => {
|
|
31
|
+
const placementConfig = options.placements[placement];
|
|
32
|
+
if (!placementConfig) {
|
|
33
|
+
return { ad: null, error: createError('configInvalid', `${placement} config is unavailable`) };
|
|
34
|
+
}
|
|
35
|
+
if (!options.wxApi) {
|
|
36
|
+
return { ad: null, error: createError('unsupported', `${placement} wx api is unavailable`) };
|
|
37
|
+
}
|
|
38
|
+
const cached = ads.get(placement);
|
|
39
|
+
if (cached) {
|
|
40
|
+
return { ad: cached, error: null };
|
|
41
|
+
}
|
|
42
|
+
const ad = options.wxApi.createRewardedVideoAd({ adUnitId: placementConfig.adUnitId });
|
|
43
|
+
ads.set(placement, ad);
|
|
44
|
+
return { ad, error: null };
|
|
45
|
+
};
|
|
46
|
+
return {
|
|
47
|
+
async init() {
|
|
48
|
+
return undefined;
|
|
49
|
+
},
|
|
50
|
+
async preload(placement) {
|
|
51
|
+
const { ad, error } = getAd(placement);
|
|
52
|
+
if (!ad) {
|
|
53
|
+
states.set(placement, 'unsupported');
|
|
54
|
+
throw error;
|
|
55
|
+
}
|
|
56
|
+
states.set(placement, 'loading');
|
|
57
|
+
if (typeof ad.load === 'function') {
|
|
58
|
+
await ad.load();
|
|
59
|
+
}
|
|
60
|
+
states.set(placement, 'ready');
|
|
61
|
+
},
|
|
62
|
+
async show(placement) {
|
|
63
|
+
const { ad, error } = getAd(placement);
|
|
64
|
+
if (!ad) {
|
|
65
|
+
states.set(placement, 'unsupported');
|
|
66
|
+
return createErrorResult(error);
|
|
67
|
+
}
|
|
68
|
+
states.set(placement, 'showing');
|
|
69
|
+
return await new Promise((resolve) => {
|
|
70
|
+
let settled = false;
|
|
71
|
+
const settle = (result) => {
|
|
72
|
+
if (settled) {
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
settled = true;
|
|
76
|
+
clearTimeout(timer);
|
|
77
|
+
states.set(placement, 'idle');
|
|
78
|
+
if (typeof ad.offClose === 'function') {
|
|
79
|
+
ad.offClose(handleClose);
|
|
80
|
+
}
|
|
81
|
+
if (typeof ad.offError === 'function') {
|
|
82
|
+
ad.offError(handleError);
|
|
83
|
+
}
|
|
84
|
+
resolve(result);
|
|
85
|
+
};
|
|
86
|
+
const handleClose = (result) => settle(toResult(result));
|
|
87
|
+
const handleError = (cause) => settle(createErrorResult(createError('showFailed', `${placement} show failed`, cause)));
|
|
88
|
+
const timer = setTimeout(() => settle(createErrorResult(createError('timeout', `${placement} show timed out`))), showTimeoutMs);
|
|
89
|
+
if (typeof ad.onClose === 'function') {
|
|
90
|
+
ad.onClose(handleClose);
|
|
91
|
+
}
|
|
92
|
+
if (typeof ad.onError === 'function') {
|
|
93
|
+
ad.onError(handleError);
|
|
94
|
+
}
|
|
95
|
+
Promise.resolve(typeof ad.show === 'function' ? ad.show() : undefined)
|
|
96
|
+
.catch((cause) => settle(createErrorResult(createError('showFailed', `${placement} show failed`, cause))));
|
|
97
|
+
});
|
|
98
|
+
},
|
|
99
|
+
isReady(placement) {
|
|
100
|
+
return states.get(placement) === 'ready';
|
|
101
|
+
},
|
|
102
|
+
getState(placement) {
|
|
103
|
+
return states.get(placement) ?? 'idle';
|
|
104
|
+
},
|
|
105
|
+
reset(placement) {
|
|
106
|
+
if (placement) {
|
|
107
|
+
ads.delete(placement);
|
|
108
|
+
states.delete(placement);
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
ads.clear();
|
|
112
|
+
states.clear();
|
|
113
|
+
},
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
function resolveWeChatApi(override) {
|
|
117
|
+
if (override) {
|
|
118
|
+
return override;
|
|
119
|
+
}
|
|
120
|
+
return globalThis.wx ?? null;
|
|
121
|
+
}
|
|
122
|
+
export const createRuntimeAdapter = (options) => {
|
|
123
|
+
return createWeChatMiniGameRewardedAdapter({
|
|
124
|
+
wxApi: resolveWeChatApi(options.wxApi),
|
|
125
|
+
placements: options.config.placements,
|
|
126
|
+
showTimeoutMs: options.showTimeoutMs,
|
|
127
|
+
});
|
|
128
|
+
};
|
|
129
|
+
export function createAdapter(options) {
|
|
130
|
+
if ('placements' in options) {
|
|
131
|
+
return createWeChatMiniGameRewardedAdapter(options);
|
|
132
|
+
}
|
|
133
|
+
return createRuntimeAdapter(options);
|
|
134
|
+
}
|