GMA Next-Gen SDK Support#925
Conversation
postindustria-code
commented
Feb 25, 2026
- Created module nextEventHandlers with event handlers for banner, interstitial, rewarded ads with unit tests
- Created a demo application for Prebid+Next-Gen SDK integration
- Added unit and instrumented tests
- Add targeting and cache propagation to Next Gen SDK request objects - Add banner 320x50 example to Next Gen SDK demo
- Rework check for Next Gen SDK classes - Add Native Ad example to Next Gen SDK Demo App - Fix Prebid Kotlin Demo app not building
- Change naming order
- Create layout for Next Gen SDK native layout
- Add event handlers for banner ads - Add banner event handler example to demo app
- Add display interstitial event handler example to demo app
- Add display rewarded video event handler example to demo app
- Cleanup resources
- Add equals and hashCode methods to AdEvent - Put main dispatcher in wrappers to the constructor for better testability
YuriyVelichkoPI
left a comment
There was a problem hiding this comment.
Please address the items from the following Claude review. All of them looks reasonable to me.
Code Review: next-gen-sdk-support branch
1. SDK Core (PrebidMobile-core)
Critical / Bugs
Util.java — Incomplete refactoring of apply() and propagateNativeParameters()
The apply() method was refactored to cache adObj.getClass() into adObjClass, but the substitution is incomplete — some branches were missed:
// apply() — second half of OR still calls adObj.getClass()
if (adObjClass == getClassFromString(AD_MANAGER_REQUEST_CLASS)
|| adObj.getClass() == getClassFromString(AD_MANAGER_REQUEST_CLASS_V20)) {
// same issue on the builder branch:
} else if (adObjClass == getClassFromString(AD_MANAGER_REQUEST_BUILDER_CLASS)
|| adObj.getClass() == getClassFromString(AD_MANAGER_REQUEST_BUILDER_CLASS_V20)) {Same problem in propagateNativeParameters(). The double class-lookup is harmless (it's the same object) but it's noise that defeats the purpose of the refactor and will confuse readers. All four occurrences need to be updated to adObjClass.
PrebidDisplayView.java — onDetachedFromWindow() removal is a breaking lifecycle change
Removing the super.onDetachedFromWindow() → destroy() call means the view no longer self-cleans when detached from the window. This is a significant change: any caller that adds the view to a recycling container (RecyclerView, ViewPager) without explicitly calling destroy() will now leak. There is no unit test covering this new PrebidDestroyable path in DisplayView.destroy(). At minimum:
- Add a test that verifies
DisplayView.destroy()delegates to the inner view when it implementsPrebidDestroyable. - Document in the
PrebidDisplayViewclass why manualdestroy()is now required.
Missing Unit Test Coverage
The following new code has no corresponding tests:
| Code | What to test |
|---|---|
Util.isNextGenSdkRequestBuilderClass() |
Returns true for subclasses, false for unrelated classes, false when Next-Gen SDK not on classpath |
Util.handleNextGenSdkTargeting() |
Calls putCustomTargeting for every entry in the bid map |
Util.setCacheIdToNextGenSdk() |
Propagates cache ID; no-ops when cacheId is null |
Util.supportedAdObject() / apply() |
Next-Gen builder is accepted; cache ID is set via reflection |
AdViewUtils.findCacheId(null) |
Returns null without NPE (the null-guard added here) — trivial to add, protects from regression |
DisplayView.destroy() delegating to PrebidDestroyable |
See lifecycle note above |
AdUnitConfiguration.globalOrtbConfig getter/setter |
Basic round-trip test; verify it starts as null |
The two
BasicParameterBuilderTesttests added forglobalOrtbConfigare good and thorough.
Minor
NativeAdUnit / VideoBaseAdUnit — removed getImpOrtbConfig()/setImpOrtbConfig() overrides
Fine as long as AdUnit already exposes those publicly (which it does). Just confirm the base-class methods are public, not protected, so callers on NativeAdUnit don't silently lose access.
Javadoc typo in AdUnit.java:setGlobalOrtbConfig() (copy-pasted into 4 classes):
"It takes precedence over
Targeting.setGlobalOrtbConfig"
The correct class name is TargetingParams, not Targeting.
PrebidMobile.TESTED_GOOGLE_NEXT_GEN_SDK_VERSION — the constant is declared but there's no compile-time or runtime version check at SDK init (unlike the GAM SDK version check). Consider adding a version-warning log at init time following the same pattern.
2. Next-Gen Event Handlers (PrebidMobile-nextEventHandlers)
Critical
Missing Maven build and deploy support
This is the most important missing piece. The module is not included in either:
scripts/buildPrebidMobile.sh—modulesandprojectPathsarraysscripts/Maven/deployPrebidMobile.sh—modulesandextensionsarraysscripts/Maven/— noPrebidMobile-nextEventHandlers-pom.xmlexists
All other event handler modules (PrebidMobile-gamEventHandlers, PrebidMobile-admobAdapters, etc.) are covered. Without this, the module cannot be released to Maven Central. The pattern to follow is directly visible in the existing scripts — add the module to both arrays and create the POM by copying PrebidMobile-gamEventHandlers-pom.xml and updating the <artifactId>.
Package namespace collision with PrebidMobile-gamEventHandlers
Both modules declare namespace "org.prebid.mobile.eventhandlers" and place source in the same Java package. They share class names: AdEvent, Constants, package-info.java. If a developer ever includes both in one project, the build will fail with duplicate class errors.
At minimum, document clearly that these modules are mutually exclusive. Long-term, consider renaming the Next-Gen package to org.prebid.mobile.nextgeneventhandlers to make the distinction explicit.
Code Issues
AdViewWrapper.kt — hardcoded Dispatchers.Main in onAdLoaded
override fun onAdLoaded(ad: BannerAd) {
...
CoroutineScope(Dispatchers.Main).launch { // ← should be mainDispatcher
listener.onEvent(AdEvent.Loaded())
}
}All other callbacks in AdViewWrapper correctly use the injected mainDispatcher. This inconsistency breaks test isolation — the testDispatcher passed in the constructor is ignored for this specific callback.
NextRewardedEventHandler.kt — wrong error message in show()
listener?.onAdFailed(AdException(AdException.THIRD_PARTY, "GAM SDK - failed to display ad."))Should say "Next-Gen SDK" (copy-paste from GamRewardedEventHandler).
RewardedAdWrapper.kt — wrong class KDoc
/** Internal wrapper of rewarded ad from GAM SDK. */Should say "Next-Gen SDK".
NextInterstitialEventHandler.kt — unnecessary null check in initPublisherInterstitialAd()
if (requestInterstitial != null) {
requestInterstitial = null
}Can be simplified to just requestInterstitial = null.
Unscoped CoroutineScope in all three wrappers
Each callback creates CoroutineScope(mainDispatcher).launch { ... } — a new scope with no parent Job and no structured cancellation. For these short-lived callbacks it's not a practical leak, but it deviates from coroutine best practices. Consider holding a val scope = CoroutineScope(mainDispatcher + SupervisorJob()) per wrapper and cancelling it on destroy().
Test Issues
Copy-pasted test method names from GAM in NextRewardedEventHandlerTest and NextInterstitialEventHandlerTest:
onGamAdClosed_NotifyEventCloseListeneronGamAdFailedToLoad_NotifyEventErrorListeneronGamAdLoadedAppEventExpected_ScheduleAppEventHandler- etc.
These should be renamed to onNextAd* to match the banner test naming and avoid confusion.
Missing test coverage:
RewardedAdWrapper.metadataContainsAdEvent()— not directly tested; only therewardedAd == nullpath is implicitly coveredUtils.handleCustomTargetingUpdate()— the empty-keywords early-return path is untestedInterstitialAdWrapperTestandRewardedAdWrapperTest— should follow theStandardTestDispatcher/advanceUntilIdlepattern used inAdViewWrapperTestto properly test coroutine dispatch
Minor
NextInterstitialEventHandler.ktandNextRewardedEventHandler.ktare missing the Apache 2.0 license header present in all other files in this module.
3. Demo App (PrebidNextGenDemo)
The app is clean and achieves its goal well. Integration code is readable and follows a consistent pattern.
General suggestions:
-
TAGinBaseAdActivityis hardcoded to"ExampleActivity"for all subclasses. UsingjavaClass.simpleNamewould make Logcat filtering per-activity useful without extra effort. -
Error feedback — ad failures are only logged via
Log.e. For a demo/integration testing app, surfacing errors in the UI (even a simple Toast orTextView) would speed up on-device debugging without ADB. -
setOpenRtbConfig()— the "Optional" comment pattern is clear and good. Keep it consistent across all activities that add optional config. -
Multiformat activities — a brief comment explaining which bid configuration drives which ad format would help new integrators understand the intent.
|
@postindustria-code you should also prepare the docs PR describing the support of new SDK. |
ValentinPostindustria
left a comment
There was a problem hiding this comment.
We should create Maven XML files for releasing the SDK. As example.
Also if it's possible to target Next Gen SDK test ad, maybe we should create Rendering API examples where Next Gen SDK wins, but Prebid with no bids. It will allow to test the Next Gen SDK rendering.
- Add legal headers - Fix copypasted text
- Nullify rewarded ad on onAdFailedToShowFullScreenContent - Fix typo in AdUnit
…dlers module - Add maven pom for PrebidMobile-nextGenEventHandlers - Fix import in admob PrebidBaseAdapter
- Add events to the ad case UI
|
Updated with requested changes. I couldn't make noBids examples with our GAM ad unit to work, so I've used GAM test ad units. |
|
Hey guys @YuriyVelichkoPI @ValentinPostindustria |
|
The last step before final approval is a PR for the docs. As soon as it is opened this one will be approved. The work on docs is in progress. |
| } | ||
|
|
||
| private static void handleNextGenSdkTargeting(HashMap<String, String> bids, Object builder) { | ||
| Set<Map.Entry<String, String>> entries = bids.entrySet(); |
There was a problem hiding this comment.
Just came across a NPE here. Can we add this to avoid the bug
if(bids == null || bids.isEmpty()) {
return;
}