feat(admob): add next-gen app open ad tracking - #4013
Merged
Conversation
polmiro
force-pushed
the
add-next-gen-admob-event-tracking
branch
from
August 19, 2026 11:33
b1c6581 to
138ff80
Compare
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## next-gen-admob-sdk #4013 +/- ##
======================================================
+ Coverage 82.99% 83.01% +0.01%
======================================================
Files 437 437
Lines 17893 17893
Branches 2684 2684
======================================================
+ Hits 14851 14854 +3
+ Misses 2148 2146 -2
+ Partials 894 893 -1 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
Base automatically changed from
add-next-gen-admob-event-tracking
to
next-gen-admob-sdk
August 19, 2026 11:51
polmiro
force-pushed
the
app-open-ad-support
branch
from
August 19, 2026 12:09
854bc05 to
a24f239
Compare
polmiro
marked this pull request as ready for review
August 19, 2026 12:25
polmiro
requested review from
AlvaroBrey,
ajpallares,
peterporfy and
tonidero
and removed request for
ajpallares
August 19, 2026 15:30
polmiro
added a commit
that referenced
this pull request
Aug 19, 2026
…ide (#4034) ### Motivation Two related bits of drift in the next-gen module. **Log messages were inline literals.** The rest of the SDK keeps them in a strings object — `purchases` has fifteen under `com.revenuecat.purchases.strings`, and `feature/galaxy` has `GalaxyStrings`. The two AdMob adapters are the exception, and legacy only half follows it: `RewardVerificationStrings` holds a single constant while six other call sites inline their text. **The placement override is copy-pasted per format.** Every full-screen format resolves a show-time override the same way — cast `adEventCallback` to the tracking wrapper, assign `placement`, warn when the cast fails. There are six copies across five branches (`InterstitialAdExtensions.kt` #3985, `RewardedAdExtensions.kt` #4011, `RewardedInterstitialAdExtensions.kt` #4012, `AppOpenAdExtensions.kt` #4013, and two in `RewardVerificationExtensions.kt` #4017), and the warning text already differs between them. Nothing pulls those copies back together. Because they live in **separate files**, git merges every one cleanly when those branches land here, and the divergent wording survives silently — there is no conflict to catch it. Worth noting the legacy adapter already routes its four formats through a single `applyPlacementOverride`. Next-gen dropped that shape; this restores it rather than inventing something new, and keeps the same name. ### Description Two commits: 1. **`AdMobNextGenStrings`** — holds the module's three log messages (the not-configured warning, the tracking-failure message, and the new placement-override warning). Existing `TrackIfConfigured` call sites route through it. 2. **`AdEventCallback?.applyPlacementOverride(placement)`** — holds the cast condition and the warning. All six call sites collapse to one line: ```kotlin adEventCallback.applyPlacementOverride(placement) ``` The receiver is the shared `AdEventCallback` supertype rather than each format's callback interface — every format callback (`RewardedAdEventCallback`, `InterstitialAdEventCallback`, `AppOpenAdEventCallback`, `RewardedInterstitialAdEventCallback`) extends it, and the per-format cast was never load-bearing: an ad's `adEventCallback` can only ever hold its own format's wrapper. The KDoc also records that passing `null` clears the load-time placement, which was previously documented only per-format. ### Adoption The helper is intentionally unused here — the extensions that call it live on the format branches, not on this base. Once this merges, each format PR swaps its inline block for the one-liner as it rebases. Verified that an unused `internal` function passes `detektAll` on this branch, so this lands green on its own. `TrackIfConfigured.kt` is byte-identical across all ten format/preload/SSV branches, so moving its strings conflicts with none of them. ### Validation - `./gradlew :feature:admob-next-gen:testDefaultsDebugUnitTest` - `./gradlew detektAll` - `./scripts/api-check.sh` — no public API change; both additions are `internal` <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Low Risk** > Internal refactor of logging and duplicated placement logic with no public API or runtime behavior change beyond unified warning text. > > **Overview** > Introduces **`AdMobNextGenStrings`** with three shared log messages (Purchases not configured, tracking failure, placement override ignored) and routes **`trackIfConfigured`** through them instead of inline literals. > > Adds **`AdEventCallback?.applyPlacementOverride(placement)`** so show-time placement override logic (cast to `TrackingAdEventCallback`, assign placement, warn on failure) lives in one place, aligned with the legacy AdMob adapter. The helper is **`internal`** and not wired from format extension files on this branch; those branches are expected to replace duplicated blocks with a single call after merge. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit d9a56d2. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY -->
polmiro
force-pushed
the
app-open-ad-support
branch
from
August 20, 2026 13:38
08f9492 to
e98a5c5
Compare
Public API changes in feature:admob-next-gen (6 new declarations)+ method @KotlinOnly @com.revenuecat.purchases.ExperimentalPreviewRevenueCatPurchasesAPI @kotlin.jvm.JvmSynthetic public static suspend Object? loadAndTrackAppOpenAd(com.revenuecat.purchases.ads.even…
+ method @KotlinOnly @com.revenuecat.purchases.ExperimentalPreviewRevenueCatPurchasesAPI @kotlin.jvm.JvmSynthetic public static void loadAndTrackAppOpenAd(com.revenuecat.purchases.ads.events.AdTracke…
+ method @KotlinOnly @com.revenuecat.purchases.ExperimentalPreviewRevenueCatPurchasesAPI @kotlin.jvm.JvmSynthetic public static void loadAndTrackAppOpenAdFromResponse(com.revenuecat.purchases.ads.eve…
+ public final class AppOpenAdExtensionsKt
+ method @KotlinOnly @com.revenuecat.purchases.ExperimentalPreviewRevenueCatPurchasesAPI @kotlin.jvm.JvmSynthetic public static void setTrackingAdEventCallback(com.google.android.libraries.ads.mobile…
+ method @KotlinOnly @com.revenuecat.purchases.ExperimentalPreviewRevenueCatPurchasesAPI @kotlin.jvm.JvmSynthetic public static void show(com.google.android.libraries.ads.mobile.sdk.appopen.AppOpenAd…Generated by 🚫 Danger |
AlvaroBrey
approved these changes
Aug 24, 2026
polmiro
force-pushed
the
app-open-ad-support
branch
2 times, most recently
from
August 26, 2026 08:48
ff33e1c to
50c1010
Compare
The warning named the least likely cause. It fires whenever the ad was not loaded through loadAndTrack, which is usually because the ad was loaded with Google's own API rather than because someone reassigned adEventCallback, so it sent readers looking for a reassignment that never happened. The KDoc also only promised that the show-time placement takes precedence. It did not say that passing null clears the placement recorded at load time, which is easy to hit because the parameter has no default and the SDK's own show is the only way to keep the load-time value.
The base branch now holds applyPlacementOverride, so drop this format's copy of the cast, the assignment and the warning in favour of the shared one. That leaves a single definition of the message rather than one per format.
polmiro
force-pushed
the
app-open-ad-support
branch
from
August 26, 2026 09:08
50c1010 to
de9355e
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Motivation
Expose Google Mobile Ads Next-Gen app-open loading and event tracking through a public RevenueCat API.
Description
AdTracker.loadAndTrackAppOpenAdAPIs for request-based loading through Google's Next-GenAdRequestAPI.loadAndTrackAppOpenAdFromResponsefor server-to-server ad responses, with an explicit ad unit ID for attribution.AppOpenAd.show(activity, placement)for overriding the tracking placement when the display location is only known at show time.setTrackingAdEventCallbackso applications can replace their callback without removing RevenueCat's wrapper.Tracking behavior
The load-time placement is used for load events and as the default for subsequent lifecycle events. A placement passed to
showtakes precedence for display, click, and revenue events.Full-screen display is tracked from
onAdShowedFullScreenContent; impressions are not also counted as displays. RevenueCat tracking runs before application callbacks.Assigning
adEventCallbackdirectly after a tracked load replaces RevenueCat's wrapper. Applications should provide the callback while loading or usesetTrackingAdEventCallback.If
show(activity, placement)is called after the callback was manually replaced, the ad is still shown but the placement override is ignored and a warning is logged.Validation
./gradlew :feature:admob-next-gen:testDebugUnitTest./gradlew detektAll :feature:admob-next-gen:lintDefaultsDebug :feature:admob-next-gen:metalavaCheckCompatibilityDefaultsDebug./gradlew :feature:admob-next-gen:metalavaGenerateSignatureDefaultsDebugNote
Medium Risk
New experimental public APIs affect ad revenue analytics attribution; incorrect callback assignment can silently drop tracking, but behavior matches existing interstitial adapters.
Overview
Adds RevenueCat ad tracking for Google Mobile Ads Next-Gen app open ads on the direct load path (alongside existing preload support), mirroring the interstitial/rewarded pattern.
New
AdTrackerentry points: callback and suspendingloadAndTrackAppOpenAd, plusloadAndTrackAppOpenAdFromResponsefor server-to-server responses with an explicitadUnitId. Successful loads install a tracking event callback before the app’s load callback runs; Google’s callbacks and suspendAdLoadResultare unchanged.AppOpenAd.show(activity, placement)overrides analytics placement at show time (including clearing placement whennull), andsetTrackingAdEventCallbacklets apps swap lifecycle handlers without dropping the RevenueCat wrapper. Publicapi.txt, README usage/placement guidance, and unit tests cover load, suspend, response, placement override, and callback wiring.Reviewed by Cursor Bugbot for commit de9355e. Bugbot is set up for automated code reviews on this repo. Configure here.