@hungvv/super-ads-skills 1.0.0 → 1.1.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 +71 -13
- package/dist/cli.js +8 -2
- package/package.json +1 -1
- package/skills/README.md +4 -0
- package/skills/adspro-to-superads/SKILL.md +157 -732
- package/skills/adspro-to-superads/references/global-invariant-check.md +49 -0
- package/skills/adspro-to-superads/references/migration-contract.md +57 -0
- package/skills/adspro-to-superads/references/phase-0-inventory.md +39 -0
- package/skills/adspro-to-superads/references/phase-1-2-gradle-manifest.md +85 -0
- package/skills/adspro-to-superads/references/phase-3-config-migration.md +159 -0
- package/skills/adspro-to-superads/references/phase-4-wrapper-observability.md +70 -0
- package/skills/adspro-to-superads/references/phase-5-7-callsites-layout-cleanup.md +73 -0
- package/skills/adspro-to-superads/references/principles-and-authority.md +73 -0
- package/skills/adspro-to-superads/references/user-questions.md +53 -0
- package/skills/adspro-to-superads/snippets/ads-api-quick.md +20 -0
- package/skills/adspro-to-superads/templates/migration-inventory.md +42 -0
- package/skills/super-ads-ab-test/SKILL.md +91 -23
- package/skills/super-ads-adb-test/SKILL.md +85 -36
- package/skills/super-ads-adb-test/{references → examples}/scenarios-sample.md +5 -5
- package/skills/super-ads-add-placement/SKILL.md +145 -50
- package/skills/super-ads-add-placement/references/call-site-api.md +33 -0
- package/skills/super-ads-add-placement/snippets/app-open.md +25 -0
- package/skills/super-ads-add-placement/snippets/fullscreen-nav.md +14 -0
- package/skills/super-ads-add-placement/snippets/inline-banner-native.md +19 -0
- package/skills/super-ads-add-placement/snippets/preload-event.md +13 -0
- package/skills/super-ads-add-placement/snippets/reward.md +17 -0
- package/skills/super-ads-config/SKILL.md +94 -36
- package/skills/super-ads-debug/SKILL.md +87 -37
- package/skills/super-ads-debug/references/logging-setup.md +2 -0
- package/skills/super-ads-debug/scripts/filter-logads.sh +21 -0
- package/skills/super-ads-debug-override/SKILL.md +154 -81
- package/skills/super-ads-debug-override/snippets/arm-override.md +9 -0
- package/skills/super-ads-debug-override/snippets/check-module.md +8 -0
- package/skills/super-ads-debug-override/snippets/clear-override.md +9 -0
- package/skills/super-ads-debug-override/snippets/confirm-active.md +16 -0
- package/skills/super-ads-guide/SKILL.md +129 -0
- package/skills/super-ads-guide/references/compatibility.md +26 -0
- package/skills/super-ads-guide/references/sdk-version-check.md +50 -0
- package/skills/super-ads-integrate/SKILL.md +145 -47
- package/skills/super-ads-integrate/references/application-setup.md +2 -21
- package/skills/super-ads-integrate/references/gradle-setup.md +1 -13
- package/skills/super-ads-integrate/snippets/consent-request.md +12 -0
- package/skills/super-ads-integrate/templates/application-oncreate.md +17 -0
- package/skills/super-ads-integrate/templates/gradle-dependencies.md +17 -0
- package/skills/super-ads-release-check/SKILL.md +85 -32
- package/skills/super-ads-show-rate/SKILL.md +87 -36
- package/skills/super-ads-show-rate/references/collect-snippet.md +2 -36
- package/skills/super-ads-show-rate/scripts/show-rate.sh +25 -0
- package/skills/super-ads-show-rate/snippets/show-events-logger.md +26 -0
- package/skills/super-ads-upgrade/SKILL.md +137 -0
- package/skills/super-ads-upgrade/references/upgrade-hops.md +26 -0
- package/skills/super-ads-upgrade/templates/changelog-template.md +39 -0
- package/skills/super-ads-add-placement/references/call-site-snippets.md +0 -90
- /package/skills/super-ads-ab-test/{references → templates}/firebase-handoff-template.md +0 -0
- /package/skills/super-ads-config/{references → examples}/patch-examples.md +0 -0
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
---
|
|
2
2
|
schema: 1
|
|
3
3
|
name: adspro-to-superads
|
|
4
|
-
description: Use when migrating an Android app from AdsPro (
|
|
5
|
-
version: 1.
|
|
4
|
+
description: Use when migrating an Android app from AdsPro (AdsSDK, Admob*) to SuperAds (Ads.show) - JSON-first, wrapper-first
|
|
5
|
+
version: 1.3.0
|
|
6
6
|
group: Ads
|
|
7
|
+
superAds: ">=4.0.0 <5.0.0"
|
|
7
8
|
---
|
|
8
9
|
|
|
9
10
|
# AdsPro → SuperAds
|
|
@@ -11,94 +12,61 @@ group: Ads
|
|
|
11
12
|
Đây là **deterministic migration procedure**, không phải tài liệu giới thiệu SuperAds. Mọi chỗ
|
|
12
13
|
agent có thể "sáng tạo" đều bị khoá bằng contract, invariant hoặc stop condition.
|
|
13
14
|
|
|
14
|
-
Đọc `references/` khi đến phase tương ứng — đừng đoán API.
|
|
15
|
-
|
|
16
|
-
| Phase | File |
|
|
17
|
-
|---|---|
|
|
18
|
-
| 0 + 3 | [references/migration-pitfalls.md](references/migration-pitfalls.md) — bẫy SDK + cách **đo app đang migrate** (không copy số liệu app khác) |
|
|
19
|
-
| 3 — config | [references/config-template.md](references/config-template.md) |
|
|
20
|
-
| 4 — wrapper | [references/wrapper-template.md](references/wrapper-template.md) |
|
|
21
|
-
| 3 + 5 — map API | [references/api-mapping.md](references/api-mapping.md) |
|
|
22
|
-
| fail runtime | [references/troubleshooting.md](references/troubleshooting.md) |
|
|
23
|
-
| sau Phase 7 | [references/verification.md](references/verification.md) |
|
|
24
|
-
|
|
25
15
|
## When to use
|
|
26
16
|
|
|
27
17
|
Dùng skill này khi app đang phụ thuộc `com.android.fullhd.adssdk:AdsPro` (entry `AdsSDK` +
|
|
28
18
|
`Admob*`) và cần chuyển sang SuperAds (`object Ads`, config 3 tầng `units / adItems / placements`).
|
|
29
19
|
|
|
30
|
-
## When NOT to use
|
|
20
|
+
## 🚫 When NOT to use
|
|
31
21
|
|
|
32
22
|
- App đã dùng SuperAds — đây không phải skill thêm placement mới (dùng `super-ads-add-placement`).
|
|
33
23
|
- Sửa bug SuperAds core, thêm network plugin, hay đổi schema JSON của SDK.
|
|
34
24
|
- App không có AdsPro (không có `AdsSDK.init`, không có `AdmobInter` / `AdmobNative`).
|
|
35
25
|
|
|
36
|
-
##
|
|
37
|
-
|
|
38
|
-
Khi các nguồn xung đột, thứ tự thẩm quyền:
|
|
39
|
-
|
|
40
|
-
1. Source SuperAds hiện tại (`super-ads/src/main/.../api/`, `domain/config/key/AdConfigKey.kt`, `core/flow/`)
|
|
41
|
-
2. Migration production của SlideShow — **cho API và JSON**, không cho chiến lược diff
|
|
42
|
-
3. Source AdsPro
|
|
43
|
-
4. Template / example trong skill này
|
|
44
|
-
5. Suy luận của agent
|
|
45
|
-
|
|
46
|
-
Không dùng example/template trong skill để suy ra API nếu source thực tế khác. **Không được tự
|
|
47
|
-
suy luận nếu source chưa chứng minh.** Không copy `showEvery`, số native chain, countdown, RC
|
|
48
|
-
key, hay `mode.navigate` từ SlideShow / app đã migrate khác — đo app hiện tại.
|
|
49
|
-
|
|
50
|
-
## Ba nguyên tắc
|
|
26
|
+
## 📋 Prerequisites
|
|
51
27
|
|
|
52
|
-
|
|
53
|
-
|
|
28
|
+
- Định tuyến skill và kiểm version SDK: [super-ads-guide](../super-ads-guide/SKILL.md).
|
|
29
|
+
- Skill này nhắm SuperAds `>=4.0.0 <5.0.0`. Nếu app đang dùng SuperAds thấp hơn, **dừng** và khuyến nghị
|
|
30
|
+
(không ép) nâng cấp bằng [super-ads-upgrade](../super-ads-upgrade/SKILL.md) trước khi tiếp tục.
|
|
31
|
+
- App phụ thuộc AdsPro (`com.android.fullhd.adssdk:AdsPro`), repo git để tạo checkpoint `migration/*`
|
|
32
|
+
(rollback phải biết điểm trở về).
|
|
33
|
+
- Truy cập repo SuperAds artifacts `http://repo.volio.vn/repository/maven-s3/` (chi tiết trong
|
|
34
|
+
[phase-1-2-gradle-manifest.md](references/phase-1-2-gradle-manifest.md)).
|
|
35
|
+
- Đã đọc [migration-pitfalls.md](references/migration-pitfalls.md): đo **app này**, không copy số liệu app khác.
|
|
54
36
|
|
|
55
|
-
|
|
37
|
+
## ⚡ Quick Reference
|
|
56
38
|
|
|
57
|
-
|
|
58
|
-
hình (bảng đầy đủ behavior → key JSON, theo từng tầng `adItems`/`placements`/`wrapper`: xem
|
|
59
|
-
[references/config-template.md](references/config-template.md) §"Key theo tầng" và
|
|
60
|
-
[references/api-mapping.md](references/api-mapping.md)):
|
|
61
|
-
|
|
62
|
-
| Behavior | Kotlin cũ (AdsPro) | JSON mới |
|
|
63
|
-
|---|---|---|
|
|
64
|
-
| preload theo thời điểm | `AdmobX.load(space)` rải rác | `preload.eventActive` |
|
|
65
|
-
| gate "chỉ show khi đã load" | `getStatusBySpace == LOADED` | `mode.show: SHOW_LOADED` |
|
|
66
|
-
| auto reload chu kỳ | timer trong Fragment | `reload.auto.placementID` + `show.timeAutoReloadMs` |
|
|
39
|
+
Đọc file tương ứng khi đến phase đó — đừng đoán API.
|
|
67
40
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
-
|
|
96
|
-
-
|
|
97
|
-
Không phải 40 màn hình.
|
|
98
|
-
|
|
99
|
-
SlideShow (commit `4e36e791`) tạo `AdsSP.kt` mới và comment bỏ 650 dòng `AdsUtils.kt`, sửa ~158
|
|
100
|
-
file. Skill dùng SlideShow làm authority cho **API và JSON**, nhưng **không** copy chiến lược
|
|
101
|
-
diff của nó.
|
|
41
|
+
| Cần gì | Mở file |
|
|
42
|
+
|---|---|
|
|
43
|
+
| Bẫy SDK + cách đo app đang migrate (phase 0 + 3) | [references/migration-pitfalls.md](references/migration-pitfalls.md) |
|
|
44
|
+
| Map API AdsPro → SuperAds, bảng `adsType` → `format` (phase 3 + 5) | [references/api-mapping.md](references/api-mapping.md) |
|
|
45
|
+
| Mẫu config JSON, key theo tầng, referential integrity (phase 3) | [references/config-template.md](references/config-template.md) |
|
|
46
|
+
| Mẫu wrapper `AdsUtils.kt` + `EventScreen` (phase 4) | [references/wrapper-template.md](references/wrapper-template.md) |
|
|
47
|
+
| Authority order, ba nguyên tắc, diff budget | [references/principles-and-authority.md](references/principles-and-authority.md) |
|
|
48
|
+
| Contract MUST / MUST NOT, Stop Conditions | [references/migration-contract.md](references/migration-contract.md) |
|
|
49
|
+
| Câu hỏi nhóm A-D phải hỏi user | [references/user-questions.md](references/user-questions.md) |
|
|
50
|
+
| Phase 0: checkpoint, inventory, verify | [references/phase-0-inventory.md](references/phase-0-inventory.md) |
|
|
51
|
+
| Bảng A-D, Decisions, Inert, Exclusions (mẫu) | [templates/migration-inventory.md](templates/migration-inventory.md) |
|
|
52
|
+
| Phase 1-2: Gradle, Manifest | [references/phase-1-2-gradle-manifest.md](references/phase-1-2-gradle-manifest.md) |
|
|
53
|
+
| Phase 3: 3a-3g config | [references/phase-3-config-migration.md](references/phase-3-config-migration.md) |
|
|
54
|
+
| Phase 4: wrapper, EventScreen, observability | [references/phase-4-wrapper-observability.md](references/phase-4-wrapper-observability.md) |
|
|
55
|
+
| Phase 5-7: call site, layout, cleanup | [references/phase-5-7-callsites-layout-cleanup.md](references/phase-5-7-callsites-layout-cleanup.md) |
|
|
56
|
+
| Global Invariant Check + 13 chuỗi `adType` | [references/global-invariant-check.md](references/global-invariant-check.md) |
|
|
57
|
+
| Runtime fail | [references/troubleshooting.md](references/troubleshooting.md) |
|
|
58
|
+
| Verify sau Phase 7 | [references/verification.md](references/verification.md) |
|
|
59
|
+
| API `Ads.*` tra nhanh | [snippets/ads-api-quick.md](snippets/ads-api-quick.md) |
|
|
60
|
+
|
|
61
|
+
## 🏗️ Recommended Architecture
|
|
62
|
+
|
|
63
|
+
Thứ tự khi xung đột: **JSON-first > wrapper-first > minimal-diff**. Giữ diff nhỏ không bao giờ là lý do
|
|
64
|
+
để giữ behavior trong Kotlin. Chi tiết và authority order:
|
|
65
|
+
[principles-and-authority.md](references/principles-and-authority.md).
|
|
66
|
+
|
|
67
|
+
- **JSON-first** — behavior mà JSON diễn đạt được thì không được tồn tại trong Kotlin.
|
|
68
|
+
- **Wrapper-first** — giữ vỏ, bỏ ruột: hàm gọi ad gốc giữ nguyên chữ ký, delegate xuống `Ads.show`.
|
|
69
|
+
- **Minimal-diff** — mục tiêu `≈ 1 file config JSON + 1 file wrapper + 1 file base + n màn hình có lý do 5b`.
|
|
102
70
|
|
|
103
71
|
```text
|
|
104
72
|
AdsPro: 40 màn --space + R.layout + timing--> AdsUtils (650 dòng) --> Admob*.load/show
|
|
@@ -107,666 +75,69 @@ SuperAds: 40 màn KHÔNG ĐỔI --chữ ký cũ--> AdsUtils moi ruột --> A
|
|
|
107
75
|
JSON (format, layout, mode, preload, reload, chain)
|
|
108
76
|
```
|
|
109
77
|
|
|
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
|
-
- Gặp API AdsPro không có trong bảng mapping.
|
|
154
|
-
- Placement không có format mapping xác định.
|
|
155
|
-
- Thiếu module provider SuperAds cho network trong config.
|
|
156
|
-
- Callback semantics không thể bảo toàn.
|
|
157
|
-
- Config có placement trùng tên.
|
|
158
|
-
- Không xác định được hành vi của RC key ads.
|
|
159
|
-
- Call site `load()` không xác định được ứng với screen event nào.
|
|
160
|
-
- App chưa có `screenName()` hoặc registry tracking screen.
|
|
161
|
-
- AdItem `NATIVE_COLLAPSIBLE` không đủ cặp layout collapsed + expanded.
|
|
162
|
-
- Không xác định được code cũ nav từ callback show hay dismiss.
|
|
163
|
-
- Click reload: cùng space AdsPro nhưng **khác** layout / unit — không biết tách bao nhiêu target (P2).
|
|
164
|
-
- Flag RC / AB / counter ads không diễn đạt được bằng một JSON tĩnh (P4).
|
|
165
|
-
- Reload cũ không xác định được trigger là click, dismiss hay timer.
|
|
166
|
-
- Wrapper không thể giữ chữ ký cũ (hàm cũ trả về giá trị SuperAds không cung cấp).
|
|
167
|
-
|
|
168
|
-
## Câu hỏi phải hỏi user
|
|
169
|
-
|
|
170
|
-
Mỗi câu hỏi phải có **phương án khuyến nghị** và nêu **hệ quả**. Agent không được tự chọn thay
|
|
171
|
-
user ở nhóm A và B. Gộp câu hỏi cùng nhóm vào **một** lần hỏi.
|
|
172
|
-
|
|
173
|
-
- Nhóm B: hỏi khi lập inventory Phase 0.
|
|
174
|
-
- Nhóm A và D: hỏi **trước** Phase 3.
|
|
175
|
-
- Nhóm C: hỏi **một lần** đầu Phase 4.
|
|
176
|
-
|
|
177
|
-
Mọi câu trả lời ghi vào mục "Decisions" trong `migration-inventory.md`.
|
|
178
|
-
|
|
179
|
-
### Nhóm A — tính năng không chuyển được (loại C)
|
|
180
|
-
|
|
181
|
-
| Tình huống | Câu hỏi | Phương án gợi ý |
|
|
182
|
-
|---|---|---|
|
|
183
|
-
| App dùng `AdmobNativePip` | SuperAds không có native PIP. Xử lý placement này thế nào? | (1) Bỏ PIP, chuyển thành `NATIVE` thường ở cùng vị trí — khuyến nghị; (2) Giữ AdsPro riêng cho PIP — không khuyến nghị, hai SDK cùng tồn tại; (3) Tạm tắt placement |
|
|
184
|
-
| App dùng `AdmobNativeCollapsibleHalfSize` | Không có half-size. Dùng gì thay? | (1) `NATIVE_COLLAPSIBLE` với layout expanded nhỏ hơn — khuyến nghị; (2) Bỏ, dùng `NATIVE` |
|
|
185
|
-
| Space có `adsType` không nằm trong bảng map | `adsType` này không có format tương ứng. Ý định sản phẩm là gì? | Liệt kê 2–3 format gần nhất kèm khác biệt hành vi |
|
|
186
|
-
|
|
187
|
-
### Nhóm B — behavior không suy ra được từ code
|
|
188
|
-
|
|
189
|
-
| Tình huống | Câu hỏi | Phương án gợi ý |
|
|
190
|
-
|---|---|---|
|
|
191
|
-
| Code cũ nav ở cả hai callback, hoặc nav ngoài callback | Placement này nav khi ad *hiện* hay khi ad *đóng*? | Mặc định SDK là `NAVIGATE_ON_DISMISS`; nêu hệ quả UX từng lựa chọn |
|
|
192
|
-
| `load()` gọi trong `onCreate` của Activity, không thuộc màn nào | Preload này nên gắn với event màn nào? | Đề xuất màn gần nhất trong flow + phương án preload ngay sau init |
|
|
193
|
-
| Không rõ preload áp cho phiên nào | Preload cho người mở lần đầu, người quay lại, hay cả hai? | Khuyến nghị **cả hai** (`_fo` + `_fn`) nếu code cũ preload vô điều kiện |
|
|
194
|
-
| Reload cũ vừa có timer vừa có click | Giữ cả `reload.auto` và `reload.click`, hay chỉ một? | Chain chỉ nhận click |
|
|
195
|
-
| Space trong JSON nhưng zero call site (vd `Banner_chung`) | Giữ placement này hay bỏ? | (1) Giữ, ghi vào Documented exclusions — khuyến nghị (an toàn cho RC); (2) Bỏ khỏi config |
|
|
196
|
-
| Hai space khác nhau nhưng cùng ý nghĩa | Gộp hay giữ tách? | Khuyến nghị **giữ tách** để bảo toàn analytics |
|
|
197
|
-
| Event cũ mang `previous_screen`/`next_screen` trong bundle | Event khai trong JSON không mang được cặp screen. Bỏ cặp screen, hay giữ tracking app-side? | (1) Bỏ, dùng `adItemId` — khuyến nghị; (2) Collect `TrackerEvent.Impression` rồi tự ghép screen từ state app |
|
|
198
|
-
| Tên event analytics cũ rải rác trong Kotlin | Tên nào đưa vào `tracking.event*`, tên nào giữ app-side? | Event AB/theo placement vào JSON; event bespoke cần ngữ cảnh app thì giữ trên flow |
|
|
199
|
-
|
|
200
|
-
### Nhóm C — quyết định kiến trúc (đầu Phase 4)
|
|
201
|
-
|
|
202
|
-
| Câu hỏi | Phương án gợi ý |
|
|
203
|
-
|---|---|
|
|
204
|
-
| Nhà cho wrapper: moi ruột `AdsUtils.kt` cũ, hay tạo `AdsSP.kt` mới? | (1) Moi ruột file cũ — **khuyến nghị**, giữ path nên ~40 màn không đổi import; (2) File mới kiểu SlideShow — sạch tên nhưng phải sửa import ở mọi màn |
|
|
205
|
-
| Nhà cho `EventScreen`: thêm vào file base có sẵn hay tạo file mới? | (1) Thêm vào file base sẵn có; (2) File mới `EventScreen.kt` nếu package base không có nhà hợp lý |
|
|
206
|
-
| Có dọn tham số inert trong migration không? | Khuyến nghị **không** — tách commit riêng sau khi verify xong |
|
|
207
|
-
| Config: một file JSON asset, hay thêm nhánh Remote Config ngay? | Khuyến nghị asset trước, RC sau khi verify |
|
|
208
|
-
|
|
209
|
-
### Nhóm D — hạ tầng (hỏi ngay khi phát hiện)
|
|
210
|
-
|
|
211
|
-
| Tình huống | Câu hỏi |
|
|
212
|
-
|---|---|
|
|
213
|
-
| Config có network nhưng thiếu module | Config có `"network": "CloudX"` nhưng chưa có `SuperAdsCloudX`. Thêm module hay bỏ network khỏi config? |
|
|
214
|
-
| Thiếu `io.cloudx.APP_KEY` / `applovin.sdk.key` | Cung cấp key, hay bỏ network đó? |
|
|
215
|
-
| App chưa có `screenName()` / registry tracking | Không có gì dựng chuỗi event preload. Wire tracking screen trước, hay preload theo cách khác? |
|
|
216
|
-
| App có RC key timing ads (tên tuỳ app, vd `keyTimeBetweenAdInter`) | JSON chỉ có `show.timeBetweenMs` cố định. Ops còn chỉnh nóng qua RC không? |
|
|
217
|
-
| Có native-sau-inter | Production: mấy native/lần inter? RC/AB nào (nếu có) tắt native phụ? Counter `% N` ra pos nào? Điền JSON theo đo, không theo template |
|
|
218
|
-
| Click reload cùng space, khác layout | Tách twin SuperAds theo Bảng D, chung unit nếu AdsPro chung `ids[]` |
|
|
219
|
-
| `minimumFetchIntervalInSeconds` | SlideShow đặt `0` (fetch mọi lần). Giữ `0` hay đặt giá trị an toàn hơn cho production? |
|
|
220
|
-
| App đã có AppsFlyer / Adjust / Meta | Giữ nguyên kênh nào? `SuperAdsTracking` là **mặc định nên có** (Phase 1) — thiếu nó là mất `ad_impression` / `ad_click` Firebase (`MIGRATION.md:452`). Chỉ bỏ khi app tự bắn doanh thu Firebase ở chỗ khác và user xác nhận |
|
|
221
|
-
|
|
222
|
-
## Checkpoint git
|
|
223
|
-
|
|
224
|
-
Trước Phase 1, tạo checkpoint và **luôn biết mình đang ở checkpoint nào**. Không bắt buộc commit
|
|
225
|
-
tự động — nhưng rollback phải biết điểm trở về.
|
|
226
|
-
|
|
227
|
-
| Checkpoint | Khi nào |
|
|
228
|
-
|---|---|
|
|
229
|
-
| `migration/00-inventory` | Sau khi `migration-inventory.md` đầy đủ |
|
|
230
|
-
| `migration/01-gradle` | Sau Phase 1 |
|
|
231
|
-
| `migration/02-manifest` | Sau Phase 2 |
|
|
232
|
-
| `migration/03-config` | Sau Phase 3 |
|
|
233
|
-
| `migration/04-wrapper` | Sau Phase 4 |
|
|
234
|
-
| `migration/05-call-sites` | Sau Phase 5 |
|
|
235
|
-
| `migration/06-layout` | Sau Phase 6 |
|
|
236
|
-
| `migration/07-cleanup` | Sau Phase 7, trước Global Invariant Check |
|
|
237
|
-
|
|
238
|
-
---
|
|
239
|
-
|
|
240
|
-
## Phase 0 — Inventory matrix (artifact bắt buộc)
|
|
241
|
-
|
|
242
|
-
Tạo file `migration-inventory.md` trong repo **app** trước khi sửa dòng code nào. Không có file
|
|
243
|
-
này thì không được sang Phase 1.
|
|
244
|
-
|
|
245
|
-
Nguồn: `rg -l "com.android.fullhd.adssdk"`, `rg -n "\.load\("`, mọi `spaceName` trong
|
|
246
|
-
`assets/*.json`, layout native XML + view id, RC key ads.
|
|
247
|
-
|
|
248
|
-
### Bảng A — placement identity + behavior
|
|
249
|
-
|
|
250
|
-
| spaceName | adsType | ids[] | layout collapsed | layout expanded | show API cũ | nav từ callback nào | reload trigger cũ | space reload cũ | RC key | placement | format | mode.show | mode.navigate | status |
|
|
251
|
-
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
252
|
-
| Native_Home | native | 1 | native_collap_small | - | show | - | click | Native_Reload | config_ads_22_4 | Native_Home | NATIVE | LOAD_AND_SHOW | - | TODO |
|
|
253
|
-
| Interstitial_Chung | interstitial | 1 | - | - | show + gate LOADED | onAdDismissed | - | - | config_ads_22_4 | Interstitial_Chung | INTER | SHOW_LOADED | NAVIGATE_ON_DISMISS | TODO |
|
|
254
|
-
|
|
255
|
-
Cột `placement` = nguyên văn `spaceName`. **MUST NOT CHANGE.**
|
|
256
|
-
|
|
257
|
-
### Bảng B — preload moment (một hàng mỗi call site `load()`)
|
|
258
|
-
|
|
259
|
-
| File:line | space | màn đang đứng | screenName() | thời điểm | chuỗi event | status |
|
|
260
|
-
|---|---|---|---|---|---|---|
|
|
261
|
-
| LanguageFragment.kt:45 | Native_Onboarding | Language | open_screen_1 | onViewReady | create_open_screen_1_fo | TODO |
|
|
262
|
-
|
|
263
|
-
Không gom nhiều `load()` của cùng space thành một hàng. Mỗi thời điểm là một hàng.
|
|
264
|
-
|
|
265
|
-
### Bảng C — cặp reload
|
|
266
|
-
|
|
267
|
-
| placement nguồn | trigger | placement đích | chu kỳ (ms) | key JSON | status |
|
|
268
|
-
|---|---|---|---|---|---|
|
|
269
|
-
| Native_Home | click | Native_Reload | - | reload.click.placementID | TODO |
|
|
270
|
-
| Native_Record_Video | auto | Native_Record_Video_ReLoad_15s | 15000 | reload.auto.placementID + show.timeAutoReloadMs | TODO |
|
|
271
|
-
|
|
272
|
-
### Bảng D — click reload theo layout (khi app có click reload)
|
|
273
|
-
|
|
274
|
-
Bảng C gom trigger. Bảng D vì SDK bind layout trên **adItem đích**. Hàng mẫu chỉ hiểu cột —
|
|
275
|
-
điền space/layout/unit **của app này**. Tách twin **chỉ khi** layout hoặc unit lúc click khác nhau.
|
|
276
|
-
|
|
277
|
-
| nguồn | layout lúc show | unit AdsPro lúc click | SuperAds reload placement | unit | layout đích | self-click? |
|
|
278
|
-
|---|---|---|---|---|---|---|
|
|
279
|
-
| *(space)* | *(xml)* | *(ids click)* | *(space reload cũ hoặc twin mới)* | *(khớp AdsPro)* | *(= layout show)* | *(click lại cùng space?)* |
|
|
280
|
-
|
|
281
|
-
Space reload **zero call site** → Exclusions, không làm đích vì tên.
|
|
282
|
-
|
|
283
|
-
### Các mục khác trong cùng file
|
|
284
|
-
|
|
285
|
-
- **Decisions** — câu trả lời nhóm A/B/C/D.
|
|
286
|
-
- **Inert parameters** — tham số giữ chữ ký nhưng không còn tác dụng.
|
|
287
|
-
- **Documented exclusions** — space được giữ / bỏ có lý do (vd `Banner_chung` zero call site).
|
|
288
|
-
|
|
289
|
-
### Verify Phase 0
|
|
290
|
-
|
|
291
|
-
- [ ] Mọi hàng có `status`
|
|
292
|
-
- [ ] Không hàng nào trống `format`
|
|
293
|
-
- [ ] Số hàng Bảng B = số call site `load()` đếm được
|
|
294
|
-
- [ ] Mọi space reload **có call site** xuất hiện ở Bảng C
|
|
295
|
-
- [ ] Nếu có click reload: Bảng D; layout/unit đích khớp AdsPro lúc click
|
|
296
|
-
- [ ] Đã đọc [migration-pitfalls.md](references/migration-pitfalls.md) — đo **app này**, không copy số liệu app khác
|
|
297
|
-
- [ ] Nhóm câu hỏi B đã hỏi và ghi vào Decisions
|
|
298
|
-
- [ ] Checkpoint `migration/00-inventory`
|
|
299
|
-
|
|
300
|
-
---
|
|
301
|
-
|
|
302
|
-
## Phase 1 — Gradle
|
|
303
|
-
|
|
304
|
-
Bỏ:
|
|
305
|
-
|
|
306
|
-
```gradle
|
|
307
|
-
implementation 'com.android.fullhd.adssdk:AdsPro:...'
|
|
308
|
-
```
|
|
309
|
-
|
|
310
|
-
Thêm (phiên bản hiện tại của core và mọi plugin: `4.0.0` — `super-ads/build.gradle:6`,
|
|
311
|
-
`MIGRATION.md:7-15`; **đọc lại source / maven hiện tại, không hardcode từ skill nếu source khác**):
|
|
312
|
-
|
|
313
|
-
```gradle
|
|
314
|
-
def superAds = '4.0.0' // core + MỌI plugin cùng một version (SPI đổi package ở 4.0.0 — trộn 3.x là NoClassDefFoundError lúc chạy)
|
|
315
|
-
implementation "com.android.fullhd.ads:SuperAds:$superAds"
|
|
316
|
-
// Bộ nền: LUÔN khai (kể cả config chưa có unit InHouse)
|
|
317
|
-
implementation "com.android.fullhd.ads:SuperAdsInHouse:$superAds"
|
|
318
|
-
implementation "com.android.fullhd.ads:SuperAdsDebug:$superAds" // có cả ở release
|
|
319
|
-
debugImplementation "com.android.fullhd.ads:SuperAdsDebugOverride:$superAds" // chỉ debug, không lọt release
|
|
320
|
-
implementation "com.android.fullhd.ads:SuperAdsAdmob:$superAds" // BẮT BUỘC nếu config có network Admob (kéo theo SuperAdsUmp)
|
|
321
|
-
implementation "com.android.fullhd.ads:SuperAdsTracking:$superAds" // ad_impression / ad_click Firebase — thiếu là mất doanh thu
|
|
322
|
-
implementation 'com.android.fullhd.layout:SuperAdsLayout:1.0.0-alpha27'
|
|
323
|
-
|
|
324
|
-
// Chỉ thêm khi config có network tương ứng:
|
|
325
|
-
implementation "com.android.fullhd.ads:SuperAdsCloudX:$superAds"
|
|
326
|
-
implementation "com.android.fullhd.ads:SuperAdsApplovin:$superAds"
|
|
327
|
-
```
|
|
328
|
-
|
|
329
|
-
Wrapper (Phase 4) viết theo API 4.0.0 (vd `com.android.fullhd.super_ads.api.lifecycle.AppLifecycleMonitor`,
|
|
330
|
-
`MIGRATION.md:26`). Pin bản 3.x trở xuống thì wrapper không compile.
|
|
331
|
-
|
|
332
|
-
`SuperAdsTracking` tự cài qua `TrackingInstaller` (ContentProvider), không gọi code. Thiếu module ⇒
|
|
333
|
-
**mất `ad_impression` (doanh thu) và `ad_click`** dù config bật (`MIGRATION.md:452`). Cờ bật/tắt là
|
|
334
|
-
key phẳng trong `global`: `"global": { "tracking.revenue": true }` (mặc định `true`,
|
|
335
|
-
`SA/domain/config/model/AdsConfig.kt:85`).
|
|
336
|
-
|
|
337
|
-
**Thiếu `SuperAdsAdmob` = zero ads im lặng, không crash.** `ConfigRegistryCheck` log
|
|
338
|
-
`ERROR_AND_CRASH` lúc init — chỉ thấy được nếu đã nối logger sink (Phase 4).
|
|
339
|
-
|
|
340
|
-
Giữ nguyên mọi `com.google.ads.mediation:*` hiện có. CloudX adapter (`io.cloudx:adapter-*`) chỉ
|
|
341
|
-
thêm khi user chọn dùng CloudX (nhóm D).
|
|
342
|
-
|
|
343
|
-
Repo SuperAds artifacts: `http://repo.volio.vn/repository/maven-s3/` (`allowInsecureProtocol = true`).
|
|
344
|
-
|
|
345
|
-
Kiểm version **trước khi khai** (mỗi artifact sẽ dùng, `<A>` = `SuperAds`, `SuperAdsAdmob`, `SuperAdsUmp`, `SuperAdsTracking`…):
|
|
346
|
-
|
|
347
|
-
```bash
|
|
348
|
-
curl -sL https://repo.volio.vn/repository/maven-s3/com/android/fullhd/ads/<A>/maven-metadata.xml | grep -o "<version>[^<]*</version>"
|
|
349
|
-
```
|
|
350
|
-
|
|
351
|
-
Trạng thái đã kiểm ngày 2026-10-27: repo có `4.0.0` của cả 11 artifact SDK (`SuperAds`, `SuperAdsAdmob`, `SuperAdsAdmobNextGen`, `SuperAdsApplovin`, `SuperAdsArbiter`, `SuperAdsCloudX`, `SuperAdsInHouse`, `SuperAdsTracking`, `SuperAdsUmp`, `SuperAdsDebug`, `SuperAdsDebugOverride`); `SuperAdsContract:1.0.0-alpha` đã có. Trạng thái đổi theo thời gian: luôn chạy lệnh trên, đừng tin con số này. Version cần dùng chưa có trên repo ⇒ Stop, hỏi user: chờ nhóm SDK publish (`scripts/publish-modules.sh --remote`, script đã gồm `ump` và `admob-next-gen`), hay dùng tạm `mavenLocal` / project dependency. Không tự hạ xuống bản cũ: wrapper và config theo API 4.0.0.
|
|
352
|
-
|
|
353
|
-
### Verify Phase 1
|
|
354
|
-
|
|
355
|
-
- [ ] `./gradlew :app:dependencies --configuration releaseRuntimeClasspath` thấy `SuperAds`,
|
|
356
|
-
`SuperAdsAdmob`, `SuperAdsTracking` cùng `4.0.0`, và **không còn** `AdsPro`
|
|
357
|
-
- [ ] Mediation adapter cũ vẫn còn
|
|
358
|
-
- [ ] Checkpoint `migration/01-gradle`
|
|
359
|
-
|
|
360
|
-
---
|
|
361
|
-
|
|
362
|
-
## Phase 2 — Manifest
|
|
363
|
-
|
|
364
|
-
Giữ:
|
|
365
|
-
|
|
366
|
-
```xml
|
|
367
|
-
<meta-data
|
|
368
|
-
android:name="com.google.android.gms.ads.APPLICATION_ID"
|
|
369
|
-
android:value="@string/admob_app_id" />
|
|
370
|
-
```
|
|
371
|
-
|
|
372
|
-
Thêm **chỉ khi** config có network tương ứng:
|
|
373
|
-
|
|
374
|
-
```xml
|
|
375
|
-
<meta-data android:name="io.cloudx.APP_KEY" android:value="..." />
|
|
376
|
-
<meta-data android:name="applovin.sdk.key" android:value="..." />
|
|
377
|
-
```
|
|
378
|
-
|
|
379
|
-
Không khai activity / provider ads thủ công — mỗi module SuperAds tự register bằng
|
|
380
|
-
`ContentProvider` (`AdmobInstaller`, `InHouseInstaller`, `CloudXInstaller`, `AppLovinInstaller`).
|
|
381
|
-
|
|
382
|
-
### Verify Phase 2
|
|
383
|
-
|
|
384
|
-
- [ ] AdMob APPLICATION_ID còn
|
|
385
|
-
- [ ] Key CloudX / AppLovin khớp quyết định nhóm D
|
|
386
|
-
- [ ] Checkpoint `migration/02-manifest`
|
|
387
|
-
|
|
388
|
-
---
|
|
389
|
-
|
|
390
|
-
## Phase 3 — Config migration
|
|
391
|
-
|
|
392
|
-
Đọc [references/config-template.md](references/config-template.md),
|
|
393
|
-
[references/api-mapping.md](references/api-mapping.md) và
|
|
394
|
-
[references/migration-pitfalls.md](references/migration-pitfalls.md) **trước** khi viết JSON. Hỏi
|
|
395
|
-
nhóm A và D nếu chưa hỏi.
|
|
396
|
-
|
|
397
|
-
Bảy bảng con 3a–3g + Bảng D. Cập nhật cột `status` của Bảng A/B/C/D khi xong từng hàng.
|
|
398
|
-
|
|
399
|
-
### 3a — Identity
|
|
400
|
-
|
|
401
|
-
- 1 `spaceName` → 1 `placement` **giữ nguyên tên**.
|
|
402
|
-
- `ids[]` (waterfall high-floor) → nhiều `units` entry, **giữ đúng thứ tự** trong `adItem.units[]`.
|
|
403
|
-
- `adsType` → `format` theo bảng 15 giá trị. Không map được → stop, hỏi nhóm A.
|
|
404
|
-
|
|
405
|
-
### 3b — Preload: từ `load()` sang event
|
|
406
|
-
|
|
407
|
-
```text
|
|
408
|
-
BaseFragment.onCreate -> EventScreen.pushEventCreateScreen(screenName())
|
|
409
|
-
BaseFragment.onDestroy -> EventScreen.pushEventDestroyScreen(screenName())
|
|
410
|
-
-> emit "create_{screenName}_{fo|fn}" / "destroy_{screenName}_{fo|fn}"
|
|
411
|
-
-> setUpPreloadTrigger() collect -> Ads.waitAdSDKReady { Ads.dispatchEvent(activity, event) }
|
|
412
|
-
-> khớp "preload.eventActive" của adItem -> preload
|
|
413
|
-
```
|
|
414
|
-
|
|
415
|
-
SlideShow gọi `pushEventCreateScreen` trong `onCreate`, `pushEventDestroyScreen` trong
|
|
416
|
-
`onDestroy` — không phải `onViewCreated` / `onDestroyView`. Khớp source app đang migrate, không
|
|
417
|
-
đoán lifecycle.
|
|
418
|
-
|
|
419
|
-
- Chuỗi event là **convention của app**, không phải hằng số SDK. JSON khớp **từng ký tự**; lệch
|
|
420
|
-
một ký tự là **im lặng không preload**, không log lỗi.
|
|
421
|
-
- `_fo` / `_fn` (first-open / quay lại) là **hai chuỗi khác nhau**. Code cũ preload vô điều kiện
|
|
422
|
-
thì khai **cả hai**, như SlideShow: `["create_open_screen_5_fo", "create_open_screen_5_fn"]`.
|
|
423
|
-
- Chỉ màn **đã hook** `pushEventCreateScreen` mới emit (Activity thường sót). `isFo` nếu
|
|
424
|
-
`lazy` thì lock lần đầu. Event = màn **đang đứng** lúc `load()`, không đoán màn kế.
|
|
425
|
-
- Key thuộc tầng **`adItems`**; đặt lên `placements` bị bỏ qua.
|
|
426
|
-
- `preload.enabled` default **true** (`AdItemConfig.isPreloadEnabled()`). Lật false trên adItem
|
|
427
|
-
`SHOW_LOADED` giết âm thầm placement vì cache luôn rỗng.
|
|
428
|
-
- Key phụ: `preload.max`, `preload.delayLoadFistMs` (đúng chính tả source — `Fist` không phải
|
|
429
|
-
`First`), `preload.delayLoadAfterShowMs`, `preload.autoPreloadAfterDismiss`.
|
|
430
|
-
- Mỗi hàng Bảng B → một chuỗi thêm vào `preload.eventActive` của adItem tương ứng.
|
|
431
|
-
- **Không** thay `load()` bằng `Ads.preload.preloadNow` (API thủ công, đã `@Deprecated` —
|
|
432
|
-
`SA/api/AdsFeatures.kt:90`).
|
|
433
|
-
|
|
434
|
-
Phase 3b và Phase 4 khớp nhau **qua chuỗi event** — coupling duy nhất được phép.
|
|
435
|
-
|
|
436
|
-
### 3c — Layout
|
|
437
|
-
|
|
438
|
-
- Native / banner thường: **một** key `ui.layoutAdName.{network}`.
|
|
439
|
-
- Collapsible (`NATIVE_COLLAPSIBLE`): **hai** key —
|
|
440
|
-
`ui.layoutAdName.{network}` = **collapsed / small**,
|
|
441
|
-
`ui.layoutAdNameExpand.{network}` = **expanded / large**.
|
|
442
|
-
- Từ AdsPro: `AdmobNativeCollapsible.show(..., layoutRes, collapsibleLayoutRes, ...)` →
|
|
443
|
-
`layoutRes` vào key thường, `collapsibleLayoutRes` vào key Expand.
|
|
444
|
-
**Đảo hai cái thì ad vẫn fill, vẫn có impression, build vẫn pass, chỉ hiện sai cỡ.**
|
|
445
|
-
- Suffix network **chữ thường, phân biệt hoa thường**: `.admob`, `.cloudx`, `.applovin`, `.meta`.
|
|
446
|
-
AdItem trộn network phải khai key cho **từng** network, thiếu là `RenderError.LayoutNotFound`.
|
|
447
|
-
- Giá trị là **tên file XML không đuôi**, resolve trong res app hoặc `SuperAdsLayout`.
|
|
448
|
-
- Loading: `ui.loading.layoutName` + `ui.loading.enable`.
|
|
449
|
-
- `NativeConfig(resNativeMeta)` (layout riêng khi mediation AdMob trả về Meta) → **loại B**:
|
|
450
|
-
`ui.layoutAdName.meta` (+ `ui.layoutAdNameExpand.meta` cho collapsible). Plugin AdMob chọn layout
|
|
451
|
-
meta khi response là Meta mediation và file XML tồn tại, ngược lại dùng layout thường
|
|
452
|
-
(`SA/presentation/render/NativeRenderer.kt:97`, `SA/presentation/render/CollapsibleNativeRenderer.kt:80`;
|
|
453
|
-
`super-ads-admob/src/main/java/com/android/fullhd/super_ads/plugin/admob/nativead/NativeLayoutResolver.kt:40`). `meta` chỉ là **hậu tố key**, không phải
|
|
454
|
-
network — không khai unit `"network": "Meta"` (`SA/domain/config/key/AdConfigKey.kt:42`).
|
|
455
|
-
- **Một** `ui.layoutAdName` / adItem / network. AdsPro xoay `index % N` layout → P5, hỏi product.
|
|
456
|
-
- Native full chain: XML app **hoặc** catalog SuperAdsLayout — product chọn, ghi Decisions. Không tự coi lệch XML là bug, cũng không mặc định catalog.
|
|
457
|
-
|
|
458
|
-
### 3d — Chuyển màn: theo behavior thật của app
|
|
459
|
-
|
|
460
|
-
- `mode.show`: `LOAD_AND_SHOW` (default) ứng `loadAndShow(...)`; `SHOW_LOADED` ứng `show(...)`
|
|
461
|
-
**có gate `getStatusBySpace == LOADED`**. Vì vậy `getStatusBySpace` làm gate là loại **B**.
|
|
462
|
-
- `mode.navigate`: chỉ `NAVIGATE_ON_SHOW` / `NAVIGATE_ON_DISMISS`. Default
|
|
463
|
-
`NAVIGATE_ON_DISMISS` (`AdItemConfig.getModeNavigate()`; giá trị lạ bị ép về default).
|
|
464
|
-
Xác định **bắt buộc đọc từ app**: nav trong `onAdShowedFullScreenContent` → `NAVIGATE_ON_SHOW`;
|
|
465
|
-
trong `onAdDismissedFullScreenContent` → `NAVIGATE_ON_DISMISS`. Không suy ra được thì hỏi nhóm B.
|
|
466
|
-
- Sau migration app **vẫn sở hữu nav đi đâu** qua `NavAdCallback`, chỉ không còn sở hữu *thời điểm*.
|
|
467
|
-
- Không áp một `mode.navigate` chung. Splash / leftover / in-app / chain đo riêng (P1).
|
|
468
|
-
- Placement chain: một giá trị không cover hai path AdsPro (nav lúc show vs lúc đóng native). Ghi Decisions nếu lệch.
|
|
469
|
-
|
|
470
|
-
### 3e — Reload: đưa hết vào `placements`
|
|
471
|
-
|
|
472
|
-
SDK tự chạy — `ReloadCoordinator.Plan.from(placement, surface)` trong core đọc config. App
|
|
473
|
-
**không viết một dòng reload nào**. Wrapper **không** có hàm reload. SlideShow từng viết
|
|
474
|
-
`showAdViewWithReload` rồi comment bỏ toàn bộ — đó là bằng chứng, không phải code cần copy.
|
|
475
|
-
|
|
476
|
-
| Trigger | Key | Timing kèm theo |
|
|
477
|
-
|---|---|---|
|
|
478
|
-
| click vào ad | `reload.click.placementID` | - |
|
|
479
|
-
| đóng ad (collapsible dismiss) | `reload.dismiss.placementID` | `show.timeDelayShowAfterDismissMs` |
|
|
480
|
-
| chu kỳ tự động | `reload.auto.placementID` | `show.timeAutoReloadMs` |
|
|
481
|
-
|
|
482
|
-
Mẫu chuẩn: cặp placement sinh đôi `X` / `X_Reload`, khớp họ space `*_Reload` của app cũ.
|
|
78
|
+
## Workflow
|
|
79
|
+
|
|
80
|
+
Mỗi phase kết thúc bằng mục "Verify Phase N" và một checkpoint `migration/NN-*`
|
|
81
|
+
(bảng checkpoint: [phase-0-inventory.md](references/phase-0-inventory.md)).
|
|
82
|
+
|
|
83
|
+
1. **Chốt contract.** Đọc [migration-contract.md](references/migration-contract.md) (MUST / MUST NOT,
|
|
84
|
+
Stop Conditions). Gặp stop condition thì dừng và hỏi user, không đoán.
|
|
85
|
+
2. **Hỏi user theo nhóm.** [user-questions.md](references/user-questions.md): nhóm B khi lập inventory
|
|
86
|
+
Phase 0; nhóm A và D trước Phase 3; nhóm C một lần đầu Phase 4. Mọi câu trả lời ghi vào "Decisions".
|
|
87
|
+
3. **Phase 0 — Inventory.** Tạo `migration-inventory.md` trong repo **app** (Bảng A/B/C/D) từ
|
|
88
|
+
[templates/migration-inventory.md](templates/migration-inventory.md) trước khi sửa dòng code nào.
|
|
89
|
+
Quy trình: [phase-0-inventory.md](references/phase-0-inventory.md).
|
|
90
|
+
4. **Phase 1 — Gradle.** Bỏ `AdsPro`, thêm core + mọi plugin cùng một version `4.0.0`, giữ mediation
|
|
91
|
+
adapter. Kiểm version trên maven trước khi khai.
|
|
92
|
+
[phase-1-2-gradle-manifest.md](references/phase-1-2-gradle-manifest.md).
|
|
93
|
+
5. **Phase 2 — Manifest.** Giữ AdMob `APPLICATION_ID`; chỉ thêm key CloudX / AppLovin khi config có
|
|
94
|
+
network đó; không khai activity / provider ads thủ công.
|
|
95
|
+
[phase-1-2-gradle-manifest.md](references/phase-1-2-gradle-manifest.md).
|
|
96
|
+
6. **Phase 3 — Config JSON** (3a identity, 3b preload, 3c layout, 3d chuyển màn, 3e reload, 3f analytics,
|
|
97
|
+
3g native sau inter). Đọc [config-template.md](references/config-template.md),
|
|
98
|
+
[api-mapping.md](references/api-mapping.md), [migration-pitfalls.md](references/migration-pitfalls.md)
|
|
99
|
+
trước khi viết JSON. Chi tiết: [phase-3-config-migration.md](references/phase-3-config-migration.md).
|
|
100
|
+
7. **Phase 4 — Wrapper + EventScreen + observability.** Mặc định moi ruột `AdsUtils.kt` cũ, giữ path và
|
|
101
|
+
chữ ký; nối đủ logger sink, tracker collector, config provider; consent trước preload / app open.
|
|
102
|
+
Mẫu: [wrapper-template.md](references/wrapper-template.md); chi tiết:
|
|
103
|
+
[phase-4-wrapper-observability.md](references/phase-4-wrapper-observability.md).
|
|
104
|
+
8. **Phase 5 — Call sites.** 5a: không sửa màn hình nếu wrapper giữ được chữ ký. 5b: chỉ sửa màn hình khi
|
|
105
|
+
có lý do trong danh sách đóng. [phase-5-7-callsites-layout-cleanup.md](references/phase-5-7-callsites-layout-cleanup.md).
|
|
106
|
+
9. **Phase 6 — Layout.** Id badge `ivAdMark` → `tvAdMark`, bỏ `R.layout.*` khỏi thân wrapper, mọi
|
|
107
|
+
`ui.layoutAdName*` có file XML thật. Cùng file ở bước 8.
|
|
108
|
+
10. **Phase 7 — Cleanup.** Xoá dialog ads tự viết và timer đã bị JSON thay thế; không xoá wrapper, không
|
|
109
|
+
dọn tham số inert (commit riêng). Cùng file ở bước 8.
|
|
110
|
+
11. **Global Invariant Check** sau Phase 7, **trước** build:
|
|
111
|
+
[global-invariant-check.md](references/global-invariant-check.md).
|
|
112
|
+
12. **Verify runtime** theo [verification.md](references/verification.md); gặp lỗi xem
|
|
113
|
+
[troubleshooting.md](references/troubleshooting.md).
|
|
114
|
+
|
|
115
|
+
## 🔧 API Reference
|
|
116
|
+
|
|
117
|
+
Ba ví dụ điển hình "JSON-first" (bảng đầy đủ behavior → key JSON theo tầng `adItems` / `placements` /
|
|
118
|
+
`wrapper`: [config-template.md](references/config-template.md) §"Key theo tầng" và
|
|
119
|
+
[api-mapping.md](references/api-mapping.md)):
|
|
483
120
|
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
`ConfigRegistryCheck` log issue lúc init (key vẫn bị bỏ qua, không crash):
|
|
487
|
-
|
|
488
|
-
- `show.timeAutoReloadMs` mà **thiếu** `reload.auto.placementID` ⇒ auto-reload **không chạy**.
|
|
489
|
-
- Placement gốc INTER / REWARD / APP_OPEN mang `reload.*` ⇒ bỏ qua (không có container để thay tại
|
|
490
|
-
chỗ, `SA/config/validate/ConfigRegistryCheck.kt:182`).
|
|
491
|
-
- Placement đích không tồn tại / tắt / priority rỗng / **khác loại bề mặt** với gốc ⇒ bỏ qua
|
|
492
|
-
(`SA/config/validate/ConfigRegistryCheck.kt:202`).
|
|
493
|
-
- Placement **chain** không nhận `reload.auto` (tự advance slot, timer tranh render).
|
|
494
|
-
- Placement **chain** không nhận `reload.dismiss` (đóng slot = sang bước kế). Chain chỉ reload bằng click.
|
|
495
|
-
|
|
496
|
-
Ngoài `ConfigRegistryCheck`:
|
|
497
|
-
|
|
498
|
-
- Chu kỳ auto bị `ReloadCoordinator` kẹp sàn `MIN_AUTO_RELOAD_MS = 5_000L`
|
|
499
|
-
(`SA/show/ReloadCoordinator.kt:23`, `SA/show/ReloadCoordinator.kt:82`).
|
|
500
|
-
- Key `reload.placementID` (thiếu `.click` / `.dismiss` / `.auto`) **không tồn tại** trong
|
|
501
|
-
`AdConfigKey.Reload` — có trong config demo nhưng **vô hiệu**, SDK không báo gì. Không được dùng.
|
|
502
|
-
|
|
503
|
-
### 3f — Analytics: tên event vào JSON
|
|
504
|
-
|
|
505
|
-
| Key (tầng `adItems`) | Bắn khi | Tương ứng AdsPro |
|
|
121
|
+
| Behavior | Kotlin cũ (AdsPro) | JSON mới |
|
|
506
122
|
|---|---|---|
|
|
507
|
-
| `
|
|
508
|
-
|
|
|
509
|
-
|
|
|
510
|
-
| `tracking.mode` | `ALWAYS` / `ONCE_PER_PROCESS` / `ONCE_PER_LIFETIME` | `Set` chống trùng tự viết |
|
|
511
|
-
|
|
512
|
-
Giá trị là **mảng** tên event. Event bắn ra `TrackerEvent.TrackingEvent` trên `Ads.tracker.events`;
|
|
513
|
-
app forward sang Firebase / Meta ở **một** chỗ trong wrapper.
|
|
514
|
-
|
|
515
|
-
Doanh thu tự động: artifact `com.android.fullhd.ads:SuperAdsTracking` (Phase 1; tự cài khi có
|
|
516
|
-
dependency, không gọi code; bật/tắt bằng key phẳng `tracking.enable` / `tracking.revenue` /
|
|
517
|
-
`tracking.perf` / `tracking.arbiter` trong object `global`) và
|
|
518
|
-
`Ads.tracking.enableAppsflyer(app, appsflyerId)` — thay `pushAppsflyerRevenue` thủ công.
|
|
519
|
-
|
|
520
|
-
Event JSON **không mang** được cặp `previous_screen` / `next_screen`. Hỏi nhóm B.
|
|
521
|
-
|
|
522
|
-
`global.version` là nhãn để soi config nào đang chạy (Toast `UpdateJson`). Bump version mỗi lần
|
|
523
|
-
sửa JSON để Toast chứng minh file đang chạy (O1).
|
|
524
|
-
|
|
525
|
-
### 3g — Native sau inter (`INTERSTITIAL_NATIVE_CHAIN`)
|
|
526
|
-
|
|
527
|
-
Chỉ khi **app này** có dialog / flow native sau inter. Công thức SDK:
|
|
528
|
-
`nextPos >= firstShowAt && (nextPos - firstShowAt) % showEvery == 0`.
|
|
529
|
-
Điền số từ counter AdsPro của app — template `1`/`2`/`5000` / 1–2 native **không** phải chuẩn sản phẩm.
|
|
530
|
-
|
|
531
|
-
- `adItems.native[]` = số native production (kèm RC/AB **tên key của app này**), không = số space JSON.
|
|
532
|
-
- Countdown = timer dialog app này.
|
|
533
|
-
- `reload.click` trên placement chain. Xoá dialog Kotlin song song (Phase 5b).
|
|
534
|
-
- adItem chain `SHOW_LOADED` cần cache: `preload.enabled` (mặc định true) **không** được tắt và phải
|
|
535
|
-
có `preload.eventActive`. Tắt preload thì không preload, không vào event map, nhánh `SHOW_LOADED`
|
|
536
|
-
luôn `ModeShowedButNotHaveAdCached` ⇒ placement không bao giờ show
|
|
537
|
-
(`SA/engine/load/Preloader.kt:225`, `SA/config/repository/AdsConfigRepositoryImpl.kt:180`, `SA/engine/load/PriorityLoader.kt:163`).
|
|
538
|
-
Không preload được thì dùng `LOAD_AND_SHOW`.
|
|
539
|
-
|
|
540
|
-
`forceLoadNewAdIfShowed` **không** suy ra `mode.show`. Đọc `show` vs `loadAndShow` + gate `LOADED`.
|
|
541
|
-
|
|
542
|
-
### Verify Phase 3
|
|
543
|
-
|
|
544
|
-
- [ ] Checklist referential integrity trong `config-template.md` pass
|
|
545
|
-
- [ ] Cột `status` Bảng A/B/C cập nhật; nếu có click reload thì Bảng D layout/unit khớp AdsPro
|
|
546
|
-
- [ ] `Ads.init` / RC khớp file JSON vừa viết (P0)
|
|
547
|
-
- [ ] Nếu có chain: `adItems.native` + gate khớp đo Phase 0 của **app này**
|
|
548
|
-
- [ ] Checkpoint `migration/03-config`
|
|
549
|
-
|
|
550
|
-
---
|
|
551
|
-
|
|
552
|
-
## Phase 4 — Wrapper + EventScreen + observability
|
|
553
|
-
|
|
554
|
-
Hỏi nhóm C trước. Mặc định khuyến nghị: **moi ruột file `AdsUtils.kt` cũ**, giữ path, giữ chữ ký
|
|
555
|
-
mọi hàm public, thay ruột bằng delegate xuống `Ads.show`.
|
|
556
|
-
|
|
557
|
-
Đọc [references/wrapper-template.md](references/wrapper-template.md).
|
|
558
|
-
|
|
559
|
-
Bề mặt cần có: `init / setPremium / isPremium / showCmp / setUpAppOpen / setUpPreloadTrigger /
|
|
560
|
-
dispatcherEvent` + 4 extension `showAdView`, `showAdFull`, `showAdFullInApp`, `showAdRewardFull`
|
|
561
|
-
(extension có thể private nội bộ file nếu màn hình vẫn gọi chữ ký cũ).
|
|
562
|
-
|
|
563
|
-
`EventScreen`: `MutableSharedFlow` replay 0, extraBufferCapacity 64. Hook base fragment:
|
|
564
|
-
`onCreate` → `pushEventCreateScreen(screenName())`, `onDestroy` →
|
|
565
|
-
`pushEventDestroyScreen(screenName())`. Collector của `EventScreen` phải subscribe **trước** màn đầu
|
|
566
|
-
emit (replay 0 ⇒ emit khi chưa có subscriber là mất): launch bằng `Dispatchers.Main.immediate`.
|
|
567
|
-
|
|
568
|
-
**Consent trước preload / app open.** Core không tự chặn request khi chưa có consent
|
|
569
|
-
(`MIGRATION.md:126-127`). Wrapper giữ cờ `consentDone`: `showCmp` set cờ trong callback; preload
|
|
570
|
-
trigger chỉ `Ads.dispatchEvent` khi cờ bật (event màn đầu nhận trong lúc chờ CMP được giữ lại, phát
|
|
571
|
-
sau callback); `setUpAppOpen` bỏ qua khi cờ tắt. Xem wrapper-template.
|
|
572
|
-
|
|
573
|
-
Ba mối observability — **bắt buộc trước khi verify**, không phải tuỳ chọn:
|
|
574
|
-
|
|
575
|
-
**(a) Logger sink** — `Ads.logger.init(LogConfig(enabled = true, minLevel = LogLevel.FLOW),
|
|
576
|
-
debug = isDebug, externalSink)` (`LogLevel` không có `VERBOSE`; `FLOW` là mức thấp nhất,
|
|
577
|
-
`SA/domain/model/log/LogLevel.kt:6`). Logcat chỉ ở debug; `ERROR` / `ERROR_AND_CRASH` thì debug Toast (post lên
|
|
578
|
-
main — sink chạy đồng bộ trên luồng đang log, thường là IO; Toast ngoài main thread ném exception và
|
|
579
|
-
bị SDK nuốt trong `runCatching`, `SA/infra/logger/SdkAdLogger.kt:50`, nên Toast không hiện), release
|
|
580
|
-
`Firebase.crashlytics.recordException(Exception(event.toJsonString()))`. Đây là đường duy nhất
|
|
581
|
-
thấy issue `ConfigRegistryCheck`.
|
|
582
|
-
|
|
583
|
-
**(b) Tracker collector** — collect `Ads.tracker.events` một lần trên `Dispatchers.Main`:
|
|
584
|
-
|
|
585
|
-
| Event | Việc làm |
|
|
586
|
-
|---|---|
|
|
587
|
-
| `TrackingEvent` | forward `event.eventName` sang Firebase; thêm hậu tố `_oke` / `_fail` theo `FirebaseRemoteConfig.getValue(key).source == VALUE_SOURCE_REMOTE` |
|
|
588
|
-
| `StartRequest` / `Impression` | event bespoke theo `event.data.adItemId` (`logOnce` cho impression) |
|
|
589
|
-
| `UpdateJson` | DEBUG: Toast `"Load version ${event.version}"` |
|
|
590
|
-
| `Click` | DEBUG: Toast `unitId.takeLast(4)` + `adItemId` |
|
|
591
|
-
| `FailedToLoad` / `FailedToShowFull` | DEBUG: Toast kèm `error.code` |
|
|
592
|
-
|
|
593
|
-
`global.tracking.item_events` mặc định bật (không khai = `true`, từ 3.0.6) ⇒ `SuperAdsTracking` tự forward `TrackingEvent` (kèm `ab_variant`): **bỏ** dòng forward `TrackingEvent` ở trên (hoặc khai `false`), nếu không event bị gửi đôi. Dự án chạy Firebase A/B bằng RC: nạp lại config bằng `Ads.loadFromJson(json, firebaseActivated = true)` **chỉ** sau `activate()` (`loadFromJson(json)` và config provider không push activation event) — xem `MIGRATION.md`, mục A/B test bằng remote config.
|
|
594
|
-
|
|
595
|
-
**(c) Config provider** — overload `Ads.init(application, configProvider = { ... }, isDebug)`:
|
|
596
|
-
|
|
597
|
-
```text
|
|
598
|
-
assets = readAssetString(file, timeout 2000)
|
|
599
|
-
remote = getRemoteConfigString(key, fallbackToOldValue = true, timeout 3500)
|
|
600
|
-
remote hợp lệ (parse được JSON object có "placements") ? remote : assets
|
|
601
|
-
```
|
|
602
|
-
|
|
603
|
-
JSON RC hỏng mà vẫn trả về ⇒ SDK parse ra `null` ⇒ init **FAILED**, mất sạch ad, không có bản dự
|
|
604
|
-
phòng (`SA/runtime/SdkRuntime.kt:226`, `SA/runtime/SdkRuntime.kt:275`). Vì vậy provider phải kiểm
|
|
605
|
-
JSON trước khi trả. Muốn có bản dự phòng: `Ads.init(application, fileNameAsset)` chạy asset ngay, rồi nạp
|
|
606
|
-
giá trị RC sau `fetchAndActivate()` bằng `Ads.loadFromJson(json, firebaseActivated = true)` (`SA/api/Ads.kt:197`);
|
|
607
|
-
JSON hỏng bị từ chối, giữ bản đang chạy — hỏi nhóm C. (`initRemote` mới mở lại, chỉ app mẫu dùng; chưa kiểm trên thiết bị.)
|
|
608
|
-
|
|
609
|
-
`minimumFetchIntervalInSeconds = 0` như SlideShow là rất hung — hỏi nhóm D. RC key phụ
|
|
610
|
-
`keyTimeBetweenAdInter` không có tương đương.
|
|
611
|
-
|
|
612
|
-
Cấm thêm vào wrapper: state timing, cache riêng, retry, adapter callback SDK, preload thủ công,
|
|
613
|
-
driver reload, tách file helper theo loại ad.
|
|
614
|
-
|
|
615
|
-
### Verify Phase 4
|
|
616
|
-
|
|
617
|
-
- [ ] Chữ ký public của wrapper cũ không đổi
|
|
618
|
-
- [ ] EventScreen emit chuỗi khớp `preload.eventActive` đã viết ở Phase 3b
|
|
619
|
-
- [ ] Ba mối observability đã nối
|
|
620
|
-
- [ ] Không event preload / app open nào chạy trước callback `showCmp`
|
|
621
|
-
- [ ] Checkpoint `migration/04-wrapper`
|
|
622
|
-
|
|
623
|
-
---
|
|
624
|
-
|
|
625
|
-
## Phase 5 — Call sites, chia hai nhóm
|
|
626
|
-
|
|
627
|
-
### 5a — Không sửa màn hình
|
|
628
|
-
|
|
629
|
-
Mọi lời gọi mà wrapper giữ được chữ ký thì **màn hình không đổi một ký tự**:
|
|
630
|
-
`showAdsNative(...)`, `showAdsInterGeneral(...)`, `showNativeCollapsible(...)`,
|
|
631
|
-
`showInterAdsSplash(...)`, `showInterSplashLate(...)`.
|
|
632
|
-
|
|
633
|
-
### 5b — Danh sách đóng: chỉ những lý do này mới được sửa màn hình
|
|
634
|
-
|
|
635
|
-
| Lý do | Hành động |
|
|
636
|
-
|---|---|
|
|
637
|
-
| `AdmobX.load(space)` gọi trực tiếp trong màn | Xoá call site (đã ở `preload.eventActive`) |
|
|
638
|
-
| `getStatusBySpace(...) == LOADED` làm gate trước show | Xoá gate (đã ở `mode.show: SHOW_LOADED`) |
|
|
639
|
-
| Gọi lại `showAdsNative("X_Reload", ...)` trong `onAdClicked` | Xoá (đã ở `reload.click.placementID`) |
|
|
640
|
-
| Timer reload trong Fragment | Xoá (đã ở `reload.auto.placementID` + `show.timeAutoReloadMs`) |
|
|
641
|
-
| `AdmobOpenResume.loadAndAutoShowIfAvailable(...)` rải rác | Xoá, dồn về `setUpAppOpen(...)` một lần trong init |
|
|
642
|
-
| Dialog native-sau-inter tự viết | Xoá, dùng `INTERSTITIAL_NATIVE_CHAIN` + `chain.native.showEvery` |
|
|
643
|
-
| Pseudo-reward bằng native dialog | Đổi sang placement `REWARD` / `NATIVE_FULL_ACTIVITY` thật |
|
|
644
|
-
| Màn gọi trực tiếp `Admob*` không qua wrapper | Đổi sang chữ ký wrapper |
|
|
645
|
-
| Base fragment | Thêm hook `EventScreen` |
|
|
646
|
-
| Override `onAdPaidValueListener` / `logPairValue*` trong màn hoặc dialog | Xoá, gom về tracker collector (tên event ở `tracking.event*`) |
|
|
647
|
-
|
|
648
|
-
Không có lý do trong bảng này thì **không sửa file đó**.
|
|
649
|
-
|
|
650
|
-
### Verify Phase 5
|
|
651
|
-
|
|
652
|
-
- [ ] `rg "com.android.fullhd.adssdk"` rỗng
|
|
653
|
-
- [ ] Không còn `.load(` trên code ads
|
|
654
|
-
- [ ] Không còn lời gọi tay tới placement `*_Reload`
|
|
655
|
-
- [ ] Mọi file màn hình bị sửa truy được về đúng một dòng bảng 5b
|
|
656
|
-
- [ ] Ba bảng inventory `status = DONE`
|
|
657
|
-
- [ ] Checkpoint `migration/05-call-sites`
|
|
658
|
-
|
|
659
|
-
---
|
|
660
|
-
|
|
661
|
-
## Phase 6 — Layout
|
|
662
|
-
|
|
663
|
-
Layout AdMob chuẩn giữ nguyên. Sửa tay:
|
|
664
|
-
|
|
665
|
-
- Id badge `ivAdMark` (AdsPro) → `tvAdMark` (SuperAds `ProtectedAssets`).
|
|
666
|
-
- `iv_blur` chỉ còn ý nghĩa với AdMob.
|
|
667
|
-
|
|
668
|
-
Xoá `R.layout.*` khỏi **thân wrapper** (call site vẫn truyền vào — tham số inert). Đối chiếu
|
|
669
|
-
ngược: mỗi giá trị `ui.layoutAdName*` có file XML tồn tại thật (app res hoặc SuperAdsLayout).
|
|
670
|
-
|
|
671
|
-
View id bắt buộc: `ad_media`, `ad_app_icon`, `ad_headline`, `ad_body`, `ad_call_to_action`,
|
|
672
|
-
`ad_choices_container`, `tvAdMark`. Optional: `ad_price`, `ad_store`, `ad_stars`, `ad_advertiser`.
|
|
673
|
-
|
|
674
|
-
### Verify Phase 6
|
|
675
|
-
|
|
676
|
-
- [ ] Không layout collapsible nào đảo collapsed / expanded
|
|
677
|
-
- [ ] Mọi `ui.layoutAdName*` resolve được
|
|
678
|
-
- [ ] Checkpoint `migration/06-layout`
|
|
679
|
-
|
|
680
|
-
---
|
|
681
|
-
|
|
682
|
-
## Phase 7 — Cleanup
|
|
683
|
-
|
|
684
|
-
Xoá dialog ads tự viết và timer đã bị JSON thay thế. Xoá import chết.
|
|
685
|
-
|
|
686
|
-
**Không** xoá file wrapper. **Không** dọn tham số inert (commit riêng).
|
|
687
|
-
|
|
688
|
-
Cách SlideShow comment lại 650 dòng `AdsUtils.kt` là điều **không** nên copy — hoặc moi ruột,
|
|
689
|
-
hoặc xoá, không để code chết.
|
|
690
|
-
|
|
691
|
-
### Verify Phase 7
|
|
692
|
-
|
|
693
|
-
- [ ] Không còn dialog ads tự viết đã bị `INTERSTITIAL_NATIVE_CHAIN` thay
|
|
694
|
-
- [ ] Không còn file utils ads mới ngoài quyết định nhóm C
|
|
695
|
-
- [ ] Checkpoint `migration/07-cleanup`
|
|
696
|
-
|
|
697
|
-
---
|
|
698
|
-
|
|
699
|
-
## Global Invariant Check
|
|
700
|
-
|
|
701
|
-
Chạy sau Phase 7, **trước** build. Đọc [references/verification.md](references/verification.md).
|
|
702
|
-
|
|
703
|
-
```text
|
|
704
|
-
COUNT(unique AdsPro spaceName) <= COUNT(SuperAds placements)
|
|
705
|
-
AdsPro spaceName \ SuperAds placements = rỗng
|
|
706
|
-
SuperAds placements \ AdsPro spaceName ⊆ Bảng D reload extras ∪ Documented exclusions
|
|
707
|
-
COUNT(AdsPro ids toàn bộ) == COUNT(SuperAds units toàn bộ)
|
|
708
|
-
(gộp unit trùng network+id chỉ khi product yêu cầu; DUPLICATE_UNIT_ID = warning)
|
|
709
|
-
|
|
710
|
-
COUNT(call site load() cũ) == COUNT(hàng Bảng B đã map)
|
|
711
|
-
mọi chuỗi preload.eventActive ⊆ tập EventScreen app này thực sự emit
|
|
712
|
-
|
|
713
|
-
mọi adItem NATIVE_COLLAPSIBLE có đủ 2 key layout, và collapsed != expanded
|
|
714
|
-
mọi ui.layoutAdName* trỏ tới file XML tồn tại
|
|
715
|
-
mọi network trong adItem.units có key layout tương ứng
|
|
716
|
-
|
|
717
|
-
mọi reload.*.placementID trỏ tới placement tồn tại
|
|
718
|
-
mọi placement có show.timeAutoReloadMs đều có reload.auto.placementID
|
|
719
|
-
không placement chain nào mang reload.auto hoặc reload.dismiss
|
|
720
|
-
mọi space reload AdsPro **có call site** là đích của đúng một reload.*.placementID
|
|
721
|
-
zero-call-site reload → Documented exclusions
|
|
722
|
-
nếu Bảng D: layout đích == layout show; unit == unit AdsPro lúc click
|
|
723
|
-
không gộp ≥2 layout nguồn khác nhau vào một adItem reload
|
|
724
|
-
|
|
725
|
-
file Ads.init / configProvider == file JSON đang migrate
|
|
726
|
-
nếu có chain: len(native) + firstShowAt/showEvery khớp đo app này
|
|
727
|
-
mọi INTER fullscreen: mode.navigate từ callback app, không default SDK
|
|
728
|
-
|
|
729
|
-
mọi file màn hình bị sửa có lý do thuộc bảng 5b
|
|
730
|
-
mọi tham số inert đã ghi vào bảng Inert parameters
|
|
731
|
-
không có file utils ads mới nào được tạo ngoài quyết định nhóm C
|
|
732
|
-
|
|
733
|
-
ba mối observability đã nối: logger sink, tracker collector, config provider
|
|
734
|
-
không dispatchEvent / app open nào trước callback consent
|
|
735
|
-
mọi tên event analytics cũ đều có nhà mới (tracking.event* trong JSON, hoặc collector app-side)
|
|
736
|
-
không tên event analytics nào bị mất mà không ghi vào Decisions
|
|
737
|
-
```
|
|
738
|
-
|
|
739
|
-
Ngoại lệ chỉ hợp lệ khi ghi vào "Documented exclusions".
|
|
740
|
-
|
|
741
|
-
Sau invariant: build → Toast `UpdateJson` version (bước đầu tiên) → `ConfigRegistryCheck` sạch →
|
|
742
|
-
fill từng placement → semantic matrix → 13 chuỗi `adType` analytics không đổi.
|
|
743
|
-
|
|
744
|
-
13 chuỗi khoá bởi `AdProfileMappingTest`: `INTER`, `NATIVE`, `NATIVE_COLLAPSIBLE`,
|
|
745
|
-
`NATIVE_FULL_ACTIVITY`, `APP_OPEN`, `BANNER`, `BANNER320x250`, `BANNER_COLLAPSIBLE_TOP`,
|
|
746
|
-
`BANNER_COLLAPSIBLE_BOTTOM`, `REWARD`, `REWARD_INTER`, `NATIVE_CHAIN`,
|
|
747
|
-
`INTERSTITIAL_NATIVE_CHAIN`. Đổi chuỗi ⇒ dashboard doanh thu trắng, không có gì fail.
|
|
748
|
-
|
|
749
|
-
## Quick Reference
|
|
750
|
-
|
|
751
|
-
```kotlin
|
|
752
|
-
// Init
|
|
753
|
-
Ads.init(application, configProvider = { getConfig(...) }, isDebug = isDebug)
|
|
754
|
-
Ads.isPremium = purchased
|
|
755
|
-
// Consent TRƯỚC preload/show/app open (core không tự chặn): Activity đầu
|
|
756
|
-
Ads.gdpr.requestAndShowIfRequired(activity, isDebug, timeoutMs = /* timeout AdsPro của app */) { onConsentDone(); next() }
|
|
123
|
+
| preload theo thời điểm | `AdmobX.load(space)` rải rác | `preload.eventActive` |
|
|
124
|
+
| gate "chỉ show khi đã load" | `getStatusBySpace == LOADED` | `mode.show: SHOW_LOADED` |
|
|
125
|
+
| auto reload chu kỳ | timer trong Fragment | `reload.auto.placementID` + `show.timeAutoReloadMs` |
|
|
757
126
|
|
|
758
|
-
|
|
759
|
-
Ads.show(placementId, activity, AdTarget.AdView(container, lifecycle), callback)
|
|
127
|
+
Gọi `Ads.*` tra nhanh: [snippets/ads-api-quick.md](snippets/ads-api-quick.md).
|
|
760
128
|
|
|
761
|
-
|
|
762
|
-
Ads.show(placementId, activity, callback = NavAdCallback { ... })
|
|
763
|
-
Ads.show(placementId, activity, callback = RewardAdCallback(true) { ... })
|
|
129
|
+
## ✅ Best Practices
|
|
764
130
|
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
131
|
+
- Placement name giữ **nguyên văn** `spaceName` cũ, kể cả sai chính tả.
|
|
132
|
+
- Đo behavior từ **app đang migrate** (`showEvery`, số native, countdown, RC key, `mode.navigate`), không
|
|
133
|
+
copy từ SlideShow / app khác.
|
|
134
|
+
- Mỗi tham số inert ghi vào bảng "Inert parameters" kèm một dòng comment trong thân wrapper.
|
|
135
|
+
- Bump `global.version` mỗi lần sửa JSON để Toast `UpdateJson` chứng minh file đang chạy.
|
|
136
|
+
- Code smell còn thấy sau migration là chưa xong: `Handler` / `delay` quanh ads, `countShowAd`,
|
|
137
|
+
`Ads.preload*` thủ công, `if (status == LOADED)` trước show, `R.layout.*` trong thân wrapper, timer reload
|
|
138
|
+
trong Fragment.
|
|
768
139
|
|
|
769
|
-
## Anti-patterns
|
|
140
|
+
## ❌ Anti-patterns
|
|
770
141
|
|
|
771
142
|
- Mang nguyên `AdsUtils.kt` 650 dòng sang SuperAds.
|
|
772
143
|
- Tạo `LegacyAdCallbackAdapter`.
|
|
@@ -782,6 +153,38 @@ Ads.dispatchEvent(activity, "create_open_screen_5_fo")
|
|
|
782
153
|
- Comment 650 dòng rồi để chết trong repo.
|
|
783
154
|
- Sửa 40 màn hình trong khi chữ ký wrapper giữ được.
|
|
784
155
|
|
|
156
|
+
## ⚠️ Common Issues
|
|
157
|
+
|
|
158
|
+
Lỗi runtime (không preload, layout sai cỡ, zero ads, init FAILED…): xem
|
|
159
|
+
[troubleshooting.md](references/troubleshooting.md) và bẫy SDK trong
|
|
160
|
+
[migration-pitfalls.md](references/migration-pitfalls.md).
|
|
161
|
+
|
|
162
|
+
## Files created
|
|
163
|
+
|
|
164
|
+
Trong repo **app** được migrate:
|
|
165
|
+
|
|
166
|
+
- `migration-inventory.md` (Bảng A/B/C/D + Decisions + Inert parameters + Documented exclusions).
|
|
167
|
+
- File JSON config SuperAds (assets).
|
|
168
|
+
- `EventScreen` — ưu tiên thêm vào file base sẵn có; chỉ tạo file mới nếu package base không có nhà hợp lý
|
|
169
|
+
(quyết định nhóm C).
|
|
170
|
+
|
|
171
|
+
Skill này không tạo file helper ads mới ngoài quyết định nhóm C.
|
|
172
|
+
|
|
173
|
+
## Files modified
|
|
174
|
+
|
|
175
|
+
- Gradle (Phase 1) và `AndroidManifest.xml` (Phase 2).
|
|
176
|
+
- File wrapper cũ (`AdsUtils.kt` hoặc tương đương) — moi ruột, giữ path và chữ ký.
|
|
177
|
+
- Base fragment (hook `EventScreen`).
|
|
178
|
+
- Màn hình / dialog **chỉ** khi có lý do thuộc bảng 5b.
|
|
179
|
+
- Layout native (id badge `tvAdMark`) theo Phase 6.
|
|
180
|
+
|
|
181
|
+
## Verification
|
|
182
|
+
|
|
183
|
+
Chạy Global Invariant Check ([global-invariant-check.md](references/global-invariant-check.md)) trước
|
|
184
|
+
build. Sau đó: build → Toast `UpdateJson` version (bước đầu tiên) → `ConfigRegistryCheck` sạch → fill từng
|
|
185
|
+
placement → semantic matrix → 13 chuỗi `adType` analytics không đổi. Chi tiết:
|
|
186
|
+
[verification.md](references/verification.md). Báo output thật; bước bỏ qua thì ghi là bỏ qua.
|
|
187
|
+
|
|
785
188
|
## Checklist
|
|
786
189
|
|
|
787
190
|
- [ ] `migration-inventory.md` tồn tại với Bảng A/B/C/D + Decisions + Inert + Exclusions
|
|
@@ -792,13 +195,35 @@ Ads.dispatchEvent(activity, "create_open_screen_5_fo")
|
|
|
792
195
|
- [ ] Diff budget: số màn hình bị sửa giải thích được bằng bảng 5b
|
|
793
196
|
- [ ] Báo cáo file đã sửa, tóm tắt, và lỗi / vấn đề còn lại
|
|
794
197
|
|
|
198
|
+
## 📈 Performance Notes
|
|
199
|
+
|
|
200
|
+
> **Not applicable for this skill.**
|
|
201
|
+
|
|
202
|
+
## 🔒 Security Notes
|
|
203
|
+
|
|
204
|
+
> **Not applicable for this skill.**
|
|
205
|
+
|
|
206
|
+
## 🔄 Migration Guide
|
|
207
|
+
|
|
208
|
+
Skill này chính là quy trình migration AdsPro → SuperAds (các phase ở mục Workflow). Nâng cấp SuperAds
|
|
209
|
+
phiên bản thấp lên `>=4.0.0` không thuộc skill này: dùng [super-ads-upgrade](../super-ads-upgrade/SKILL.md).
|
|
210
|
+
|
|
795
211
|
## Output
|
|
796
212
|
|
|
797
213
|
Báo cáo: file đã sửa, tóm tắt từng phase, Decisions đã hỏi, diff budget (config / wrapper / base /
|
|
798
214
|
màn 5b), kết quả invariant + runtime, và lỗi còn lại.
|
|
799
215
|
|
|
800
|
-
##
|
|
216
|
+
## Examples
|
|
217
|
+
|
|
218
|
+
- Hàng mẫu Bảng A/B/C/D: [templates/migration-inventory.md](templates/migration-inventory.md).
|
|
219
|
+
- Gọi `Ads.*` mẫu: [snippets/ads-api-quick.md](snippets/ads-api-quick.md).
|
|
220
|
+
- Wrapper và config đầy đủ: [wrapper-template.md](references/wrapper-template.md),
|
|
221
|
+
[config-template.md](references/config-template.md).
|
|
222
|
+
|
|
223
|
+
## 📚 References
|
|
801
224
|
|
|
225
|
+
- [super-ads-guide](../super-ads-guide/SKILL.md), [super-ads-upgrade](../super-ads-upgrade/SKILL.md)
|
|
226
|
+
- [super-ads-add-placement](../super-ads-add-placement/SKILL.md)
|
|
802
227
|
- [references/migration-pitfalls.md](references/migration-pitfalls.md)
|
|
803
228
|
- [references/api-mapping.md](references/api-mapping.md)
|
|
804
229
|
- [references/config-template.md](references/config-template.md)
|
|
@@ -806,7 +231,7 @@ màn 5b), kết quả invariant + runtime, và lỗi còn lại.
|
|
|
806
231
|
- [references/troubleshooting.md](references/troubleshooting.md)
|
|
807
232
|
- [references/verification.md](references/verification.md)
|
|
808
233
|
|
|
809
|
-
## Tags
|
|
234
|
+
## 🏷️ Tags
|
|
810
235
|
|
|
811
236
|
- android
|
|
812
237
|
- kotlin
|