v0.3.0
-
Fix: calling
Elo.trackRenderorElo.trackImpressionyourself no longer
double-counts. Ads shown throughEloAdViewhave always recorded exactly
one render and one impression per ad opportunity, however often the
composable recomposes or re-enters the viewport — but that limit lived in the
view layer, so a fully custom layout calling the tracking hooks directly
could report the same opportunity more than once. It now sits behind the
public API and covers every path into it, so those hooks are safe to call on
every recomposition. A repeat load that returns the same creative is a
distinct opportunity and still records. A suppressed duplicate is silent: no
ping, and noEloAdListener.onAdDidTrackImpressioncallback. Matches the iOS
change of the same behavior. -
Internal: render tracking moved into the impression-tracking modifier.
EloAdViewand the adapter-rendered path each fired their own render ping
next to the impression modifier they already applied; both now come from the
modifier, so an ad surface cannot attach one and forget the other. No change
to when a render fires or how it is deduped. -
Fix:
EloAdListener.onAdDidTrackImpressionnow fires only when the
impression ping actually lands. It is documented as firing after the SDK
fires the ping, but it was dispatched alongside the attempt instead — so it
reported impressions the ad server rejected or never received, and publishers
counting impressions from it over-counted. Two things caused that, both
fixed: the callback did not wait for the ping, and the ping itself reported
success unconditionally. Render and impression pings now surface non-2xx
responses and transport failures, which also means
EloDiagnosticsSnapshot.trackingTotalscan finally report a non-zero
failedcount and the Diagnostics funnel shows real impression failures.
Matches iOS, which already gated its delegate callback on the delivery
outcome.onAdDidReceiveClickis unchanged — it is documented as firing on
the tap, before the click URL opens. -
Fix: a render or impression is no longer consumed when the SDK cannot send
it. Each ad opportunity records at most one render and one impression for
the process lifetime. Calling the tracking hooks beforeconfigure(or after
shutdown) marked the opportunity as counted even though nothing was sent,
so the real ping could never follow. The SDK now checks that it can deliver
before spending that budget. -
New:
EloDiagnosticsSnapshot.trackingTotalscounts every render,
impression, and click attempt since configure. The existing
trackingEntrieslist is a bounded ring buffer, so it could not tell you how
many impression pings failed once a session got past the newest twenty — and
a ping the SDK gives up on is a lost impression it will never retry. Each
EloTrackingTotalscarriesattempted,delivered,failed,
unobservable, andinFlight, is never evicted, and still records an
outcome whose entry had already aged out. The counts also appear in
asExportableText(). Cleared on configure andshutdown(), like the rest of
diagnostics. Matches the iOS change of the same behavior. -
Fix: an ad card no longer stays without its image when the same creative
comes back in a later ad. The card drops its thumbnail when a creative's
image can't be loaded, so a broken URL leaves text rather than a blank
square. That was remembered against the creative rather than the ad, so
while the card stayed in composition, one failure also suppressed the image
on every later ad that served the same creative. It now applies only to the
ad it was recorded for. Matches the iOS fix of the same behavior. -
Breaking:
EloAd.idis now the ad opportunity, and the creative moved to a
newEloAd.creativeId.idpreviously carried the ad server'sad_id—
the creative — which is stable across opportunities, so the same creative
served twice produced two ads that looked identical to the SDK. The ad
opportunity, which is what render, impression, and click URLs are keyed under
server-side, was tucked away in an internal field. They have swapped places:
idis the opportunity (one per showing) andcreativeIdnames the artwork.
Correlate delivery onid; group bycreativeId.If you log or store
ad.id, it now changes on every serve of the same
creative. Switch toad.creativeIdwherever you meant the creative.Adapter authors: the
EloAdconstructor now takes bothidand
creativeId, andidmust be unique per fill. Pass your network's
per-response id if it has one, or mint aUUID.randomUUID().toString().
Passing a creative id there collapses every serve of that creative into a
single tracked ad, so only the first reports a render and an impression. The
AdMob adapter now mints one per fill, which fixes exactly that
under-reporting on AdMob native fills.