@maccesar/titools 5.1.1 → 5.2.1

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.
Files changed (98) hide show
  1. package/CONTRIBUTING.md +69 -0
  2. package/README.md +112 -72
  3. package/agents/ti-pro.md +5 -1
  4. package/commands/ti-audit.md +5 -1
  5. package/docs/examples.md +91 -0
  6. package/docs/knowledge-index.md +57 -0
  7. package/lib/config.js +2 -0
  8. package/lib/downloader.js +1 -1
  9. package/package.json +4 -2
  10. package/skills/purgetss/references/multi-density-images.md +1 -1
  11. package/skills/ti-admob-unified/SKILL.md +58 -0
  12. package/skills/ti-admob-unified/agents/openai.yaml +4 -0
  13. package/skills/ti-admob-unified/assets/example/app.js +1207 -0
  14. package/skills/ti-admob-unified/assets/example/lib/ads.js +646 -0
  15. package/skills/ti-admob-unified/assets/example/library-usage.js +136 -0
  16. package/skills/ti-admob-unified/references/api-reference.md +615 -0
  17. package/skills/ti-admob-unified/references/banners.md +435 -0
  18. package/skills/ti-admob-unified/references/contributing.md +233 -0
  19. package/skills/ti-admob-unified/references/dependencies.md +91 -0
  20. package/skills/ti-admob-unified/references/fullscreen.md +238 -0
  21. package/skills/ti-admob-unified/references/game-monetization.md +148 -0
  22. package/skills/ti-admob-unified/references/getting-started.md +319 -0
  23. package/skills/ti-admob-unified/references/index.md +33 -0
  24. package/skills/ti-admob-unified/references/integration.md +87 -0
  25. package/skills/ti-admob-unified/references/library.md +220 -0
  26. package/skills/ti-admob-unified/references/mediation-parity.md +17 -0
  27. package/skills/ti-admob-unified/references/mediation.md +145 -0
  28. package/skills/ti-admob-unified/references/migration.md +259 -0
  29. package/skills/ti-admob-unified/references/module-changelog.md +84 -0
  30. package/skills/ti-admob-unified/references/module-license.txt +21 -0
  31. package/skills/ti-admob-unified/references/privacy.md +281 -0
  32. package/skills/ti-admob-unified/references/production.md +67 -0
  33. package/skills/ti-admob-unified/references/rewarded-interstitial.md +101 -0
  34. package/skills/ti-admob-unified/references/roadmap.md +143 -0
  35. package/skills/ti-admob-unified/references/source-notes.md +80 -0
  36. package/skills/ti-admob-unified/references/source-snapshot.json +644 -0
  37. package/skills/ti-admob-unified/references/third-party-notices.md +22 -0
  38. package/skills/ti-game/SKILL.md +31 -5
  39. package/skills/ti-game/references/api.md +36 -24
  40. package/skills/ti-game/references/debugging-performance.md +22 -7
  41. package/skills/ti-game/references/examples.md +113 -20
  42. package/skills/ti-game/references/input.md +101 -0
  43. package/skills/ti-game/references/patterns.md +56 -10
  44. package/skills/ti-game/references/physics.md +530 -0
  45. package/skills/ti-game/references/project-setup.md +131 -47
  46. package/skills/ti-game/references/recipes-action.md +149 -18
  47. package/skills/ti-game/references/recipes-adventure-effects.md +47 -4
  48. package/skills/ti-game/references/roadmap.md +11 -4
  49. package/skills/ti-game/references/source-notes.md +81 -0
  50. package/skills/ti-game/references/tilemaps.md +13 -4
  51. package/skills/ti-game-assets/SKILL.md +53 -0
  52. package/skills/ti-game-assets/agents/openai.yaml +4 -0
  53. package/skills/ti-game-assets/references/alpha.md +26 -0
  54. package/skills/ti-game-assets/references/art-direction.md +37 -0
  55. package/skills/ti-game-assets/references/integration.md +49 -0
  56. package/skills/ti-game-assets/references/manifest.example.json +429 -0
  57. package/skills/ti-game-assets/references/manifest.md +39 -0
  58. package/skills/ti-game-assets/references/offline-audio.md +33 -0
  59. package/skills/ti-game-assets/references/prompts.md +33 -0
  60. package/skills/ti-game-assets/references/repeating-textures.md +17 -0
  61. package/skills/ti-game-assets/references/responsible-ads.md +31 -0
  62. package/skills/ti-game-assets/references/sound-assets.md +42 -0
  63. package/skills/ti-game-assets/references/vector-sources.md +21 -0
  64. package/skills/ti-game-assets/scripts/alpha_tools.py +160 -0
  65. package/skills/ti-game-assets/scripts/requirements.txt +1 -0
  66. package/skills/ti-game-assets/scripts/validate_manifest.py +267 -0
  67. package/skills/ti-synthengine/SKILL.md +77 -67
  68. package/skills/ti-synthengine/assets/example/README.md +84 -0
  69. package/skills/ti-synthengine/assets/example/app.js +1178 -0
  70. package/skills/ti-synthengine/assets/example/lib/sequenceOwner.js +83 -0
  71. package/skills/ti-synthengine/assets/example/lib/sequenceScore.js +25 -0
  72. package/skills/ti-synthengine/references/advanced-examples.md +174 -0
  73. package/skills/ti-synthengine/references/android-sim80-correction-evidence.zip +0 -0
  74. package/skills/ti-synthengine/references/android-sim80-correction.json +162 -0
  75. package/skills/ti-synthengine/references/api.md +573 -153
  76. package/skills/ti-synthengine/references/audio-engine.md +272 -124
  77. package/skills/ti-synthengine/references/bypass-physical-recheck-evidence.zip +0 -0
  78. package/skills/ti-synthengine/references/examples.md +355 -106
  79. package/skills/ti-synthengine/references/frontier-android-evidence.zip +0 -0
  80. package/skills/ti-synthengine/references/frontier-ipad-evidence.zip +0 -0
  81. package/skills/ti-synthengine/references/frontier-physical-validation.json +1918 -0
  82. package/skills/ti-synthengine/references/guide.md +426 -75
  83. package/skills/ti-synthengine/references/performance-review-evidence.zip +0 -0
  84. package/skills/ti-synthengine/references/performance-review.json +1146 -0
  85. package/skills/ti-synthengine/references/physical-validation.json +1457 -0
  86. package/skills/ti-synthengine/references/recipes-interaction.md +549 -0
  87. package/skills/ti-synthengine/references/recipes.md +434 -420
  88. package/skills/ti-synthengine/references/recommendations.md +72 -85
  89. package/skills/ti-synthengine/references/sound-design.md +375 -155
  90. package/skills/ti-synthengine/references/source-notes.md +109 -0
  91. package/skills/ti-synthengine/references/source-snapshot.json +452 -0
  92. package/skills/ti-synthengine/references/stats-performance.json +2992 -0
  93. package/skills/ti-synthengine/references/stats-performance.md +82 -0
  94. package/skills/ti-synthengine/references/studio-validation.json +6202 -0
  95. package/skills/ti-synthengine/references/troubleshooting.md +123 -78
  96. package/skills/ti-synthengine/references/unified-bypass-performance.json +22425 -0
  97. package/skills/ti-synthengine/references/unified-validation.json +314 -0
  98. package/AGENTS-VERCEL-RESEARCH.md +0 -175
@@ -0,0 +1,319 @@
1
+ > Source snapshot: official ti.admob.unified 1.0.0 documentation at release source commit `034843299b2984253988e0ffccb9f6a1c91682c9` (copied 2026-10-24). Relative links rebased for this skill.
2
+
3
+ # Getting started
4
+
5
+ <!-- TOC-START -->
6
+ ## Contents
7
+
8
+ - [1. Install the modules](#1-install-the-modules)
9
+ - [2. Configure the AdMob application IDs](#2-configure-the-admob-application-ids)
10
+ - [3. Configure mediation if needed](#3-configure-mediation-if-needed)
11
+ - [4. Configure Privacy & messaging](#4-configure-privacy--messaging)
12
+ - [5. Use official test units](#5-use-official-test-units)
13
+ - [6. Request consent, then initialize](#6-request-consent-then-initialize)
14
+ - [7. Create an ad only after the gate opens](#7-create-an-ad-only-after-the-gate-opens)
15
+ - [Common setup mistakes](#common-setup-mistakes)
16
+ - [Before shipping](#before-shipping)
17
+ - [Example appearance](#example-appearance)
18
+
19
+ <!-- TOC-END -->
20
+
21
+ ## 1. Install the modules
22
+
23
+ Download the core archives from [GitHub Releases](https://github.com/macCesar/ti.admob.unified/releases). Use `ti.admob.unified-iphone-1.0.0.zip` for iOS and `ti.admob.unified-android-1.0.0.zip` for Android. Extract each ZIP at your Titanium application's root, keeping the archive's `modules/` directory. The resulting manifests must be at `modules/iphone/ti.admob.unified/1.0.0/manifest` and `modules/android/ti.admob.unified/1.0.0/manifest`. Do not add another nested `modules/` directory.
24
+
25
+ Install the `1.0.0` ZIP of `ti.admob.unified` for every platform you build. All artifacts of a given module must have the same module ID and version:
26
+
27
+ ```xml
28
+ <modules>
29
+ <module version="1.0.0">ti.admob.unified</module>
30
+ </modules>
31
+ ```
32
+
33
+ An application that serves AdMob demand needs only the core. Android resolves its Maven dependencies during the consumer build, so the module ZIP size is not the installed app-size cost. CocoaPods and the framework installer scripts are for building this repository, not for applications installing its release ZIPs.
34
+
35
+ If the application mediates, install the selected per-network complements at the same version. For AppLovin:
36
+
37
+ ```xml
38
+ <modules>
39
+ <module version="1.0.0">ti.admob.unified</module>
40
+ <module version="1.0.0">ti.admob.unified.mediation.applovin</module>
41
+ </modules>
42
+ ```
43
+
44
+ Each complement carries one adapter and its dependencies, with no JavaScript API. Add a module line for each intended network; leave unneeded networks out. See [AdMob mediation](mediation.md).
45
+
46
+ The minimum versions are Titanium `13.4.1.GA`, iOS `15.0+`, and Android API `24+`.
47
+
48
+ For an existing AdMob integration, see [Migrating to ti.admob.unified](migration.md).
49
+
50
+ ## 2. Configure the AdMob application IDs
51
+
52
+ An AdMob **application ID** contains a tilde:
53
+
54
+ ```text
55
+ ca-app-pub-0000000000000000~0000000000
56
+ ```
57
+
58
+ An **ad unit ID** contains a slash:
59
+
60
+ ```text
61
+ ca-app-pub-0000000000000000/0000000000
62
+ ```
63
+
64
+ Put the application ID in `tiapp.xml` and pass ad unit IDs to factories such as `createAdaptiveBanner()`. Each field requires its own ID type.
65
+
66
+ ### iOS
67
+
68
+ Add the iOS application ID to the app plist section:
69
+
70
+ ```xml
71
+ <ios>
72
+ <plist>
73
+ <dict>
74
+ <key>GADApplicationIdentifier</key>
75
+ <string>ca-app-pub-0000000000000000~0000000000</string>
76
+ </dict>
77
+ </plist>
78
+ </ios>
79
+ ```
80
+
81
+ App Tracking Transparency is optional and separate from UMP. Serving ads does not require tracking users across other companies' apps and websites. Add the usage description only when the application uses tracking, and describe that use accurately. Apple reviews the prompt against the app's behavior.
82
+
83
+ ```xml
84
+ <ios>
85
+ <plist>
86
+ <dict>
87
+ <key>NSUserTrackingUsageDescription</key>
88
+ <string>This identifier helps us measure advertising performance.</string>
89
+ </dict>
90
+ </plist>
91
+ </ios>
92
+ ```
93
+
94
+ Include this key whenever the app or an included SDK requests ATT, including an IDFA message configured in AdMob UMP. Omit it only when the app and its SDK configuration never request ATT and do not perform tracking. UMP regional consent can run without ATT.
95
+
96
+ The usage description is the explanation shown in Apple's ATT prompt. Localize it with `i18n/<language>/app.xml` in the consumer app, using the `NSUserTrackingUsageDescription` string name. Provide an English value and a translation for each supported language, including Spanish when the app supports it. This applies to Classic and Alloy projects; verify that the built app contains `<language>.lproj/InfoPlist.strings` with those values.
97
+
98
+ ```xml
99
+ <resources>
100
+ <string name="NSUserTrackingUsageDescription">This identifier helps us measure advertising performance.</string>
101
+ </resources>
102
+ ```
103
+
104
+ These settings serve separate purposes:
105
+
106
+ - `NSUserTrackingUsageDescription` and its translations explain the ATT request. They do not request permission by themselves.
107
+ - `GADApplicationIdentifier` identifies the iOS app to AdMob. It is required even when ATT is disabled.
108
+ - `SKAdNetworkItems` configures attribution identifiers. It does not grant ATT permission.
109
+ - App Store Connect privacy disclosures describe the app's actual collection and tracking, including its SDKs. They must match the integration; a plist entry does not complete those disclosures. See Apple's [privacy and data use guidance](https://developer.apple.com/app-store/user-privacy-and-data-use/).
110
+
111
+ A successful App Store review of another integration is a reference, not a promise that Apple will approve this app. Review depends on its behavior, configuration and disclosures.
112
+
113
+ Keep any required `SKAdNetworkItems` in the consuming app. Follow Google's [iOS setup guide](https://developers.google.com/admob/ios/quick-start) for the current list and App Store requirements.
114
+
115
+ ### Android
116
+
117
+ Merge the Android application ID into the application element:
118
+
119
+ ```xml
120
+ <android xmlns:android="http://schemas.android.com/apk/res/android">
121
+ <manifest>
122
+ <application>
123
+ <meta-data
124
+ android:name="com.google.android.gms.ads.APPLICATION_ID"
125
+ android:value="ca-app-pub-0000000000000000~0000000000"/>
126
+ </application>
127
+ </manifest>
128
+ </android>
129
+ ```
130
+
131
+ Omitting this metadata causes the native Google Mobile Ads SDK to fail with a missing application ID. See Google's [Android setup guide](https://developers.google.com/admob/android/quick-start).
132
+
133
+ Do not pass `applicationId` to `initialize()`; the module does not consume that property.
134
+
135
+ ## 3. Configure mediation if needed
136
+
137
+ Skip this step unless the application already has, or is about to have, an AdMob mediation group with real ad sources in it. Installing adapters does not raise fill on its own: a network participates only once its publisher account is approved, it is added as an ad source, and its credentials are mapped to the ad unit.
138
+
139
+ Install the corresponding complements from step 1 when the application will mediate. AppLovin, Meta, InMobi, Unity and Liftoff are available on both platforms; ironSource mediation is deferred. Add the intended networks to the AdMob mediation groups and complete their account, placement, privacy and store-disclosure setup.
140
+
141
+ No platform-specific JavaScript or manual adapter initialization is required. After `module_initialized`, use `getMediationStatus()` to inspect the adapter states reported by Google; check package contents separately. See [AdMob mediation](mediation.md).
142
+
143
+ ### Automatic adapter discovery
144
+
145
+ After the privacy gate, use `Admob.initialize({})` with either the core alone or selected complements. Google discovers the adapters included by `tiapp.xml`; no mediation flag or manual provider initialization is required.
146
+
147
+ Install only networks with the intended accounts and AdMob mappings configured. An installed adapter with incomplete configuration may delay startup until it responds or times out. For exceptional sessions that deliberately skip installed adapters, see the [initialization reference](api-reference.md#automatic-adapter-discovery).
148
+
149
+ ## 4. Configure Privacy & messaging
150
+
151
+ Create the required messages in the **Privacy & messaging** section of the AdMob console. UMP resolves the message configuration from the application ID in the consuming app.
152
+
153
+ The application must request a fresh consent-information update on every launch. See [Privacy and initialization](privacy.md) before loading any ad.
154
+
155
+ ## 5. Use official test units
156
+
157
+ The `TEST_*` constants resolve to Google's platform-specific demo ad unit IDs:
158
+
159
+ ```js
160
+ const Admob = require('ti.admob.unified')
161
+
162
+ const adaptiveId = Admob.TEST_ADAPTIVE_BANNER
163
+ const interstitialId = Admob.TEST_INTERSTITIAL
164
+ const rewardedId = Admob.TEST_REWARDED
165
+ ```
166
+
167
+ The module exports the full set of test constants for compatibility. Native remains reserved without a factory:
168
+
169
+ | Constant | Factory that accepts it |
170
+ | ---------------------------- | ------------------------------------------------- |
171
+ | `TEST_BANNER` | `createBanner()` |
172
+ | `TEST_ADAPTIVE_BANNER` | `createAdaptiveBanner()` |
173
+ | `TEST_INTERSTITIAL` | `createInterstitial()` |
174
+ | `TEST_INTERSTITIAL_VIDEO` | `createInterstitial()` (same API, video creative) |
175
+ | `TEST_REWARDED` | `createRewarded()` |
176
+ | `TEST_REWARDED_INTERSTITIAL` | `createRewardedInterstitial()` |
177
+ | `TEST_NATIVE` | None. Reserved; the format is not implemented |
178
+ | `TEST_APP_OPEN` | `createAppOpen()` |
179
+
180
+ See [Reserved and unavailable APIs](api-reference.md#reserved-and-unavailable-apis).
181
+
182
+ Do not copy an Android demo ID into an iOS branch or the reverse. Let the module constant select the correct ID.
183
+
184
+ Google recommends demo units or explicitly registered test devices during development. See the official [Android test-ad guide](https://developers.google.com/admob/android/test-ads) and [iOS test-ad guide](https://developers.google.com/admob/ios/test-ads).
185
+
186
+ ## 6. Request consent, then initialize
187
+
188
+ Register all listeners first:
189
+
190
+ ```js
191
+ const Admob = require('ti.admob.unified')
192
+
193
+ let initialized = false
194
+
195
+ function initializeOnce() {
196
+ if (initialized || !Admob.canRequestAds()) {
197
+ return
198
+ }
199
+
200
+ initialized = true
201
+ Admob.initialize({
202
+ ageRestrictedTreatment: Admob.AGE_RESTRICTED_TREATMENT_UNSPECIFIED,
203
+ maxAdContentRating: Admob.MAX_AD_CONTENT_RATING_GENERAL
204
+ })
205
+ }
206
+
207
+ Admob.addEventListener('module_initialized', event => {
208
+ if (event.success) {
209
+ Ti.API.info('Google Mobile Ads initialized')
210
+ // Create/load placements here, after initialization succeeds.
211
+ } else {
212
+ initialized = false // allow a later app-controlled retry
213
+ Ti.API.warn(`Google Mobile Ads initialization failed: ${event.error}`)
214
+ }
215
+ })
216
+
217
+ Admob.addEventListener('consent_complete', event => {
218
+ if (event.canRequestAds) {
219
+ initializeOnce()
220
+ }
221
+ })
222
+
223
+ Admob.requestConsent({
224
+ tagForUnderAgeOfConsent: false
225
+ })
226
+ ```
227
+
228
+ ### Optional: if the application requests ATT
229
+
230
+ Skip this section unless step 2 added `NSUserTrackingUsageDescription`. ATT is not a prerequisite for serving ads, and requesting it without a real tracking case invites an App Store rejection.
231
+
232
+ Replace the `consent_complete` listener from step 6 with the listener below; do not register both. An application that requests ATT waits for the Apple prompt to settle before initializing, so that the SDK reads a final tracking status. Present it while the app is active and no other system prompt or consent form is onscreen:
233
+
234
+ ```js
235
+ Admob.addEventListener('consent_complete', event => {
236
+ if (!event.canRequestAds) {
237
+ return
238
+ }
239
+
240
+ const onTrackingComplete = trackingEvent => {
241
+ Admob.removeEventListener(
242
+ 'tracking_authorization_completed',
243
+ onTrackingComplete
244
+ )
245
+ Ti.API.info(`ATT status: ${trackingEvent.status}`)
246
+ initializeOnce()
247
+ }
248
+
249
+ Admob.addEventListener(
250
+ 'tracking_authorization_completed',
251
+ onTrackingComplete
252
+ )
253
+ Admob.requestTrackingAuthorization()
254
+ })
255
+ ```
256
+
257
+ Google Mobile Ads reads `trackingAuthorizationStatus` on its own on iOS; that read does not open Apple's prompt. An IDFA message configured in AdMob can let UMP present ATT during `requestConsent()`. In that integration, keep the usage description and translations, let UMP finish, and use `getTrackingAuthorizationStatus()` to inspect the result. A separate explicit ATT request is unnecessary when UMP already handles it. See Google's [UMP IDFA message guide](https://developers.google.com/admob/ios/privacy/idfa).
258
+
259
+ `initialize()` and `requestConsent()` are idempotent native operations. Application-level guards are still useful because cached terminal events may be emitted again when a caller invokes an already-completed operation.
260
+
261
+ ## 7. Create an ad only after the gate opens
262
+
263
+ For a complete first banner, use the integration library below **instead of the raw startup listeners in step 6**. It runs the same consent/initialization sequence and waits for a real layout. Keep `const Admob = require('ti.admob.unified')` from step 5. Choose one startup owner for the app.
264
+
265
+ Reserve the host height before the ad arrives. Growing it from zero when `loaded` fires moves surrounding content after the screen appears. Give the host its expected height and a background color that matches the screen. The empty slot then looks like a bottom margin:
266
+
267
+ ```js
268
+ // Classic Titanium; copy example/lib/ads.js into Resources/lib/ first.
269
+ // Alloy: copy to app/lib/ads.js and use require('ads').
270
+ const ads = require('lib/ads')
271
+ const win = Ti.UI.createWindow({ backgroundColor: '#ffffff' })
272
+ const content = Ti.UI.createView({ top: 0, left: 0, right: 0, bottom: 0 })
273
+ const bannerHost = Ti.UI.createView({ left: 0, right: 0, bottom: 0, height: '50dp' })
274
+ win.add(content)
275
+ win.add(bannerHost)
276
+
277
+ const banner = ads.createAdaptiveBanner({
278
+ host: bannerHost,
279
+ content,
280
+ reservedHeight: 50,
281
+ adUnitId: Admob.TEST_ADAPTIVE_BANNER,
282
+ adaptiveType: Admob.ADAPTIVE_ANCHORED
283
+ })
284
+
285
+ win.addEventListener('close', event => {
286
+ if (!event._closeFromActivityForcedToDestroy) banner.destroy()
287
+ })
288
+ win.open()
289
+ ads.start({ consent: { tagForUnderAgeOfConsent: false } }).catch(error => {
290
+ Ti.API.warn(`Ads startup failed: ${error.message || error}`)
291
+ })
292
+ ```
293
+
294
+ A fixed `BANNER` is `50dp` and `FULLBANNER` is `60dp`, so a fixed-size placement can reserve its exact height. An adaptive banner reports its final height after loading. Reserve a suitable minimum, then adjust it in the loaded event to avoid growing the host from zero.
295
+
296
+ [Banner ads](banners.md) covers the full placement contract: reserving layout space without overlapping bottom-aligned UI, the named-listener lifecycle, and `pause()` / `resume()` / `destroy()`.
297
+
298
+ The module does not enforce the privacy gate inside ad proxies. The consuming application owns the order.
299
+
300
+ ## Common setup mistakes
301
+
302
+ - Passing an ad unit ID where an application ID is required.
303
+ - Passing `applicationId` or `debugGeography` to `initialize()`.
304
+ - Loading ads before `consent_complete` and `canRequestAds === true`.
305
+ - Using `canShowPersonalizedAds()` or `isGDPR()` as a gate.
306
+ - Hardcoding an adaptive banner height.
307
+ - Keeping banner listeners after destroying or removing a placement.
308
+ - Using a production ad unit while clicking ads during development.
309
+ - Requesting ATT, or shipping `NSUserTrackingUsageDescription`, in an app with no tracking case. UMP does not require either one.
310
+ - Installing mediation complements without configured ad sources adds SDK size and may delay startup while unused networks time out.
311
+ - Publishing an app that is supposed to mediate without the selected complements installed, which must be checked through package inventories and Ad Inspector; an empty diagnostic map alone is not an installation check.
312
+
313
+ ## Before shipping
314
+
315
+ Follow [Shipping an application](production.md) for production configuration, app-ads.txt, store disclosures, validation and troubleshooting.
316
+
317
+ ## Example appearance
318
+
319
+ For the classic playground, copy `example/app.js` and `example/semantic.colors.json` into `Resources/`, and `example/lib/ads.js` into `Resources/lib/`. The named colors provide light and dark variants for the content and window title. Keep the default DayNight Android theme so system icons follow the selected appearance. The sample keeps the title and status bars visible. Changing appearance does not require rebuilding the ad proxies or resetting the scroll position.
@@ -0,0 +1,33 @@
1
+ > Source snapshot: official ti.admob.unified 1.0.0 documentation at release source commit `034843299b2984253988e0ffccb9f6a1c91682c9` (copied 2026-10-24). Relative links rebased for this skill.
2
+
3
+ # ti.admob.unified documentation
4
+
5
+ This documentation describes the public JavaScript contract implemented by `ti.admob.unified` `1.0.0`.
6
+
7
+ ## Start here
8
+
9
+ 1. [Getting started](getting-started.md): install the platform artifacts, configure the AdMob application IDs, and make a first test request.
10
+ 2. [Integrating the module](integration.md): the boundary between native lifecycle, application navigation, layout, and refresh ownership.
11
+ 3. [Copy-ready JavaScript library](library.md): copy one maintained file into `lib/` for startup, every implemented ad format, privacy, and cleanup.
12
+ 4. [Privacy and initialization](privacy.md): implement UMP, ATT, the `canRequestAds()` gate, and privacy options correctly.
13
+ 5. [AdMob mediation](mediation.md): install selected complements, and configure and validate the five networks without platform-specific JavaScript.
14
+ 6. [Banner ads](banners.md): integrate standard or adaptive banners with real layout space and deterministic cleanup.
15
+ 7. [Fullscreen ads](fullscreen.md): interstitial, rewarded, rewarded interstitial, and app open ads on one lifecycle, and when it is acceptable to interrupt the user.
16
+
17
+ 8. [Rewarded interstitial ads](rewarded-interstitial.md): introduce the reward, allow skipping, and handle actual earned rewards.
18
+ 9. [Shipping an application](production.md): production configuration, app verification, store disclosures, troubleshooting and validation.
19
+
20
+ ## Reference
21
+
22
+ - [Complete API reference](api-reference.md): module methods, proxy methods, events, payloads, constants, compatibility APIs, and platform notes.
23
+ - [Migrating to ti.admob.unified](migration.md): replace `ti.admob`, `ti.android.admob`, or an internal pre-release build.
24
+ - [Third-party SDK notices](third-party-notices.md): licenses and terms for the distributed advertising SDKs.
25
+
26
+ - [Adding a network](contributing.md#adding-a-network): package and validate an existing official mediation adapter.
27
+
28
+ ## Project information
29
+
30
+ - [Dependency inventory](dependencies.md)
31
+ - [Changelog](module-changelog.md)
32
+ - [Roadmap](roadmap.md)
33
+ - [Contributing](contributing.md)
@@ -0,0 +1,87 @@
1
+ > Source snapshot: official ti.admob.unified 1.0.0 documentation at release source commit `034843299b2984253988e0ffccb9f6a1c91682c9` (copied 2026-10-24). Relative links rebased for this skill.
2
+
3
+ # Integrating the module
4
+
5
+ The native module manages Google Mobile Ads, UMP, proxy behavior and host lifecycle on both platforms. Your application controls navigation, layout and which screen is visible.
6
+
7
+ ## Recommended path
8
+
9
+ Copy [`example/lib/ads.js`](../assets/example/lib/ads.js) to `app/lib/ads.js` in Alloy or `Resources/lib/ads.js` in Classic Titanium. It supports every format in version `1.0.0` and handles startup, placement lifecycle and cleanup.
10
+
11
+ See [Copy-ready JavaScript library](library.md) for the API and examples, and [`example/library-usage.js`](../assets/example/library-usage.js) for a compact runnable integration.
12
+
13
+ ## Division of responsibility
14
+
15
+ | Responsibility | Owner |
16
+ | ------------------------------------------------------------ | ------------------------------------------------------------------- |
17
+ | UMP, Google Mobile Ads initialization and native callbacks | Module |
18
+ | Application/activity background and foreground | Module |
19
+ | Automatic banner refresh | Google Mobile Ads SDK, using the ad-unit policy configured in AdMob |
20
+ | Consent → `canRequestAds()` → initialization sequence | Copy-ready library, or the application when using the raw API |
21
+ | Tab/window coverage | Application |
22
+ | Permanent banner host and content inset | Application |
23
+ | Production/test ad-unit selection | Application build configuration |
24
+ | Frequency and natural presentation points for fullscreen ads | Application |
25
+
26
+ ## Screen lifecycle
27
+
28
+ Handle screen navigation separately from application backgrounding.
29
+
30
+ The module automatically follows the Android activity and iOS application lifecycle. Do not add duplicate `Ti.App` pause/resume handlers for banners.
31
+
32
+ An Android secondary window backed by another activity is already covered by the automatic lifecycle handling. The application calls `pause()` only when its own navigation hides a placement while the same host lifecycle remains active, such as a custom same-activity overlay:
33
+
34
+ ```js
35
+ banner.pause()
36
+ showSameActivityOverlay()
37
+
38
+ function onOverlayDismissed() {
39
+ banner.resume()
40
+ }
41
+ ```
42
+
43
+ Pausing does not change `visible`, opacity, height, the host, or the loaded creative. Do not destroy/recreate on tab changes, focus/blur, or light/dark appearance changes. Rebuild only for a real configuration or authorization boundary, or after a recoverable failure.
44
+
45
+ On Android, the module handles activity recreation caused by a configuration change. It releases the stale native `AdView`, preserves the JavaScript proxy without emitting `destroyed`, and reloads after Titanium creates the replacement view.
46
+
47
+ ## Refresh ownership
48
+
49
+ Call `load()` once when creating a banner. Do not add `setInterval`, `setTimeout`, or a periodic destroy/create loop. Google Mobile Ads reads the refresh policy configured for that ad unit in AdMob and owns subsequent banner requests.
50
+
51
+ The application pauses a placement when navigation hides it. On iOS the module disables native autoload until every pause cause clears. On Android it pauses native ad-view processing; Google also requires the banner to be visible for automatic refresh. Keep a visible banner active even if an internal screen state changes.
52
+
53
+ ## Banner layout
54
+
55
+ Reserve the slot when creating the placement. Expanding it after the first creative arrives moves content that is already on screen.
56
+
57
+ Keep these layout values aligned:
58
+
59
+ ```js
60
+ bannerHost.height = dimension
61
+ content.bottom = dimension
62
+ ```
63
+
64
+ Keep both values unchanged during `pause()` and `resume()` to avoid reflowing lists and scroll views while the same placement remains in use.
65
+
66
+ Adaptive banners report their real `event.height` in dp. Fixed banners should reserve the exact height of the requested size. See [Banner ads](banners.md#reserve-real-layout-space).
67
+
68
+ ## Raw API
69
+
70
+ Applications that do not want the copy-ready library can use the module directly. [`example/app.js`](../assets/example/app.js) exercises the low-level API, including:
71
+
72
+ - consent and optional ATT;
73
+ - initialization and mediation diagnostics;
74
+ - standard and adaptive banners;
75
+ - explicit screen-level banner pause/resume;
76
+ - interstitial, rewarded and app-open load/show separation;
77
+ - privacy options and deterministic cleanup.
78
+
79
+ When using the raw API, keep named event callbacks so every listener can be removed before `destroy()`.
80
+
81
+ ## Next
82
+
83
+ - [Copy-ready JavaScript library](library.md)
84
+ - [Banner ads](banners.md)
85
+ - [Fullscreen ads](fullscreen.md)
86
+ - [Privacy and initialization](privacy.md)
87
+ - [Shipping an application](production.md)
@@ -0,0 +1,220 @@
1
+ > Source snapshot: official ti.admob.unified 1.0.0 documentation at release source commit `034843299b2984253988e0ffccb9f6a1c91682c9` (copied 2026-10-24). Relative links rebased for this skill.
2
+
3
+ # Copy-ready JavaScript library
4
+
5
+ The integration library is [`example/lib/ads.js`](../assets/example/lib/ads.js). Copy it unchanged to the appropriate location:
6
+
7
+ - Alloy: `app/lib/ads.js`
8
+ - Classic Titanium: `Resources/lib/ads.js`
9
+
10
+ Import it from an Alloy controller with `require('ads')`, or from Classic Titanium with `require('lib/ads')`:
11
+
12
+ ```js
13
+ const Admob = require('ti.admob.unified')
14
+ const ads = require('lib/ads') // Classic; Alloy: require('ads')
15
+ ```
16
+
17
+ Alloy copies `app/lib/ads.js` to the generated Resources root. Keep that import distinction when adapting the Classic examples.
18
+
19
+ The library handles UMP sequencing, the `canRequestAds()` check, initialization, named-listener cleanup, banner slots, deferred loads, privacy-option reauthorization and terminal cleanup. You can also use the native module directly, as [`example/app.js`](../assets/example/app.js) does while sharing the library’s fullscreen size guard.
20
+
21
+ ## What it covers
22
+
23
+ | Format | Library factory | Lifecycle returned |
24
+ | --------------- | ------------------------ | ------------------------------------------------------------------------ |
25
+ | Standard banner | `createBanner()` | `pause()`, `resume()`, `retry()`, `rebuild()`, `isLoaded()`, `destroy()` |
26
+ | Adaptive banner | `createAdaptiveBanner()` | `pause()`, `resume()`, `retry()`, `rebuild()`, `isLoaded()`, `destroy()` |
27
+ | Interstitial | `createInterstitial()` | `load()`, `show()`, `retry()`, `isLoaded()`, `destroy()` |
28
+ | Rewarded | `createRewarded()` | `load()`, `show()`, `retry()`, `isLoaded()`, `destroy()` |
29
+ | Rewarded interstitial | `createRewardedInterstitial()` | `load()`, `show()`, `retry()`, `isLoaded()`, `destroy()` |
30
+ | App open | `createAppOpen()` | `load()`, `show()`, `retry()`, `isLoaded()`, `destroy()` |
31
+
32
+ Native ads have no factory in version `1.0.0`. For rewarded interstitials, show an introduction with a skip option before calling the manager's `show()`; see [Rewarded interstitial ads](rewarded-interstitial.md).
33
+
34
+ ## Start once
35
+
36
+ Create placements before or after `start()`. Loads requested before initialization wait until privacy checks and SDK initialization complete.
37
+
38
+ ```js
39
+ ads.start({
40
+ consent: {
41
+ tagForUnderAgeOfConsent: false
42
+ },
43
+ initialization: {
44
+ testDeviceIds: ['YOUR_TEST_DEVICE_ID']
45
+ }
46
+ }).then(result => {
47
+ if (!result.initialized) {
48
+ Ti.API.warn('Ads are unavailable for this session')
49
+ }
50
+ }).catch(error => {
51
+ Ti.API.warn(`Ads startup failed: ${error.message || error}`)
52
+ })
53
+ ```
54
+
55
+ Set `requestTrackingAuthorization: true` only when the application has a real ATT use case and a valid `NSUserTrackingUsageDescription`. This option controls only the library's explicit ATT request. An IDFA message configured in AdMob may let UMP present ATT during the consent step even when this option is false. When UMP handles ATT, leave the option false and retain the required description/translations. The startup result's `tracking` value describes the explicit request only; query `Admob.getTrackingAuthorizationStatus()` for current system state. ATT is not another ad-request gate. Call `start()` from the active foreground after other prompts have closed. If an iOS interruption occurs during UMP, the library waits for `Ti.App.resumed` before requesting ATT, then removes its temporary lifecycle listeners. It does not coordinate unrelated prompts opened by application code.
56
+
57
+ Use `Admob.getTrackingAuthorizationStatus()` to inspect ATT without prompting, including after a return from Settings. The same method works in Classic and Alloy. Android reports `applicable: false`; its `authorized: true` convention does not grant general tracking permission.
58
+
59
+ `start()` caches its promise for the JavaScript session, including an unavailable result. Repeating it does not retry a failed consent update or initialization. If the app needs a recoverable startup retry UI, use the [raw event-based flow](privacy.md#requestconsentconfig), which supports consent retries; do not call `resetConsent()` in production. Native invocation exceptions are converted into failure results by the library; inspect `result.initialized` and the result events. Catch errors in application promise callbacks as well.
60
+
61
+ ## Banners
62
+
63
+ A banner needs a permanent host and a positive reservation in dp. The library changes the host height and the adjacent content inset together; it never overlays the content.
64
+
65
+ ```js
66
+ const banner = ads.createAdaptiveBanner({
67
+ host: bannerHost,
68
+ content,
69
+ reservedHeight: 50,
70
+ adUnitId: Admob.TEST_ADAPTIVE_BANNER,
71
+ adaptiveType: Admob.ADAPTIVE_ANCHORED,
72
+ onLoaded: event => Ti.API.info(`Banner: ${event.height}${event.heightUnit}`),
73
+ onFailedToLoad: event => Ti.API.warn(event.error)
74
+ })
75
+ ```
76
+
77
+ Use `createBanner()` with `adSize` or `customAdSize` for a fixed banner. Use `createAdaptiveBanner()` when Google should choose the height for the available width.
78
+
79
+ Call `pause()` when that placement stops being shown because the application selected another tab or opened another window over it. Call `resume()` when the same screen is shown again. These methods preserve the same native proxy, creative, visibility, opacity, host, and reserved height:
80
+
81
+ ```js
82
+ banner.pause()
83
+ openChildWindow()
84
+
85
+ child.addEventListener('close', () => {
86
+ banner.resume()
87
+ })
88
+ ```
89
+
90
+ Do not mirror `Ti.App` background and foreground events. The native module already owns activity/application lifecycle as an independent pause cause.
91
+
92
+ The library creates no refresh timer. Banner managers start their first request automatically when the gate and layout are ready; there is no public banner-manager `load()` method. Later banner refreshes belong to Google Mobile Ads and the refresh policy configured for that ad unit in AdMob. A banner that is not actually on screen is ineligible for Android auto-refresh. On iOS the module disables and restores native autoload while paused.
93
+
94
+ Use `retry()` after a recoverable failure. Use `rebuild()` when the placement configuration changes, such as its width or orientation. Tab focus, window focus, appearance changes and ordinary background/foreground transitions do not require a rebuild.
95
+
96
+ ### Banner manager options
97
+
98
+ Alongside the native banner properties, the library accepts:
99
+
100
+ | Option | Default | Purpose |
101
+ | --- | --- | --- |
102
+ | `host` | Required | Permanent Titanium container for the banner. |
103
+ | `content` | Omitted | Adjacent composite-layout view whose bottom inset follows the slot. |
104
+ | `reservedHeight` | Required | Positive initial reservation in dp. |
105
+ | `paused` | `false` | Defer the first request until `resume()`. |
106
+ | `collapseOnFailure` | `true` | Set to `false` to preserve the slot on a load failure. |
107
+ | `onLoaded`, `onFailedToLoad`, `onDestroyed` | Omitted | Placement lifecycle callbacks receiving the event. |
108
+ | `onClicked`, `onImpression`, `onOpened`, `onClosed` | Omitted | Forwarded native event callbacks. |
109
+
110
+ Keep the options object stable. Managers do not expose the raw proxy's mutable properties; use a new manager when changing configuration. `rebuild()` recreates the proxy from the manager's existing options, and `retry()` does the same for a failed placement. `destroy()` removes the placement and collapses its slot.
111
+
112
+ ## Fullscreen ads
113
+
114
+ Create the placement once. Load before the intended break and show it when the application reaches that break:
115
+
116
+ ```js
117
+ const interstitial = ads.createInterstitial({
118
+ window: win,
119
+ adUnitId: Admob.TEST_INTERSTITIAL,
120
+ autoReload: true,
121
+ onLoaded: () => Ti.API.info('Ready for the next natural break')
122
+ })
123
+
124
+ interstitial.load()
125
+
126
+ function onNaturalBreak() {
127
+ interstitial.show() // false means no ready ad; continue without blocking
128
+ }
129
+ ```
130
+
131
+ Rewarded ads grant value only from `onRewarded`:
132
+
133
+ ```js
134
+ const rewarded = ads.createRewarded({
135
+ window: win,
136
+ adUnitId: Admob.TEST_REWARDED,
137
+ onRewarded: event => grantReward(event.rewardAmount, event.rewardType)
138
+ })
139
+ ```
140
+
141
+ App-open ads are prepared the same way and shown only during the application's own foreground loading experience:
142
+
143
+ ```js
144
+ const appOpen = ads.createAppOpen({
145
+ window: win,
146
+ adUnitId: Admob.TEST_APP_OPEN
147
+ })
148
+
149
+ appOpen.load()
150
+
151
+ function onApplicationResumed() {
152
+ appOpen.show()
153
+ }
154
+ ```
155
+
156
+ Pass the owning `window` to each fullscreen factory (otherwise the library reads `Ti.UI.currentWindow`). The library records that window's dimensions when requesting the ad. Rotation alone makes no requests. At `show()`, a changed size discards and reloads only that ad and returns `false`; wait for `onLoaded` and a later user action to show it. Banners are not rebuilt by this check.
157
+
158
+ The raw-API playground shares this logic through `createFullscreenSizeGuard(getSize)`: call `recordLoad()` before requesting, then `show(present, reload)` when the user requests presentation. The callback can return the window itself (preferred) or a measured `{ width, height }` size. For a window, the guard compares valid outer `rect` bounds and falls back to `size` before layout. Transient Android client-area changes after dismissing an ad therefore keep a ready preload, while rotation and window resizing still invalidate it. This helper does not initialize the SDK or run consent. The playground adds a pending user request around this check so its Show button can wait for a replacement and present it without another tap. The manager API itself keeps the immediate Boolean return contract above; it does not queue a later presentation after returning `false`.
159
+
160
+ `show()` returns `false` when no valid ad is ready. Do not delay navigation or user work waiting for a fullscreen request.
161
+
162
+ ### Fullscreen manager options and return values
163
+
164
+ Pass the native creation properties plus `window` and optionally `autoLoad: true` to request the first ad automatically after startup. Otherwise call `load()`. `autoReload: true` requests another ad after close only. Managers forward `onLoaded`, `onFailedToLoad`, `onOpened`, `onShowed`, `onClosed`, `onClicked`, `onImpression`, `onFailedToShow`, `onDestroyed` and, for rewarded, `onRewarded`.
165
+
166
+ `load()` and `retry()` report whether the manager accepted the call, not whether an ad arrived. `show()` reports whether presentation was attempted; native presentation may still fail and emit `onFailedToShow`. `isLoaded()` checks native readiness. These Boolean manager results differ from the raw proxy's `void` `load()` / `show()` methods.
167
+
168
+ ## Privacy and diagnostics
169
+
170
+ Expose the privacy entry point only when required:
171
+
172
+ ```js
173
+ privacyButton.visible = ads.isPrivacyOptionsRequired()
174
+
175
+ function openPrivacyOptions() {
176
+ ads.showPrivacyOptions().then(event => {
177
+ if (event.success === false) {
178
+ Ti.API.warn(event.error)
179
+ }
180
+ })
181
+ }
182
+ ```
183
+
184
+ After the form closes, the library reevaluates authorization and rebuilds active ad requests to account for any consent changes.
185
+
186
+ Ad Inspector also has a promise wrapper:
187
+
188
+ ```js
189
+ ads.openAdInspector().then(event => {
190
+ if (!event.success) {
191
+ Ti.API.warn(event.error)
192
+ }
193
+ })
194
+ ```
195
+
196
+ ## Cleanup
197
+
198
+ Destroy a placement when its owning window closes. For application shutdown or a test harness, dispose every registered placement at once.
199
+
200
+ On Android, Titanium also fires `close` while it recreates the window's activity, for example when the user switches between light and dark mode. The window survives, and the event carries `_closeFromActivityForcedToDestroy`. Skip that event, or the ads and their listeners are gone when the window comes back:
201
+
202
+ ```js
203
+ win.addEventListener('close', event => {
204
+ if (!event._closeFromActivityForcedToDestroy) banner.destroy()
205
+ })
206
+
207
+ // Or, when this ads service owns every placement:
208
+ ads.destroyAll()
209
+ ```
210
+
211
+ Every destroy operation is idempotent. A destroyed manager cannot be reused; create another manager for a new placement.
212
+
213
+ See [`example/library-usage.js`](../assets/example/library-usage.js) for a complete runnable integration.
214
+
215
+
216
+ ## Concurrent operations and cleanup
217
+
218
+ Concurrent calls to `showPrivacyOptions()` share one native presentation and one promise. `openAdInspector()` does the same for Inspector. Terminal events and synchronous native exceptions clear the operation's listeners. A later call starts a new operation. `destroyAll()` releases placements only. It does not cancel an SDK form or its pending promise.
219
+
220
+ A banner failure or destruction cleans up the old proxy before invoking application callbacks, so calling `retry()` from those callbacks preserves the replacement. On iOS, adaptive placements reserve the native anchored height when width is known and wait for positive layout before loading. Destroying a placement removes any pending layout listener.