From f5f216f9870adb464c82d017a495e2f5b73a8ade Mon Sep 17 00:00:00 2001 From: Felipe Fuzaro Date: Tue, 1 Sep 2026 13:38:36 +0200 Subject: [PATCH 1/2] fix: request-forward on `AdLoaderAd` --- .../googlemobileads/FlutterAdLoader.java | 6 +++++- .../googlemobileads/FlutterAdLoaderAd.java | 4 ++-- .../FlutterAdManagerAdRequest.java | 21 +++++++++++++++++++ .../googlemobileads/FlutterAdRequest.java | 19 +++++++++++++++++ 4 files changed, 47 insertions(+), 3 deletions(-) diff --git a/packages/google_mobile_ads/android/src/adsNextGenSdk/java/io/flutter/plugins/googlemobileads/FlutterAdLoader.java b/packages/google_mobile_ads/android/src/adsNextGenSdk/java/io/flutter/plugins/googlemobileads/FlutterAdLoader.java index 4f24c2cb2..4e796f3dd 100644 --- a/packages/google_mobile_ads/android/src/adsNextGenSdk/java/io/flutter/plugins/googlemobileads/FlutterAdLoader.java +++ b/packages/google_mobile_ads/android/src/adsNextGenSdk/java/io/flutter/plugins/googlemobileads/FlutterAdLoader.java @@ -127,6 +127,7 @@ public void loadAdManagerNativeAd( /** Load an ad loader ad. */ public void loadAdLoaderAd( @NonNull String adUnitId, + @NonNull FlutterAdRequest request, @NonNull NativeAdLoaderCallback adLoaderAdLoaderCallback, @Nullable FlutterAdLoaderAd.BannerParameters bannerParameters, @Nullable FlutterAdLoaderAd.CustomParameters customParameters, @@ -167,6 +168,8 @@ public void loadAdLoaderAd( } } + request.configureNativeAdRequestBuilder(builder, adUnitId); + NativeAdLoader.load( builder.build(), adLoaderAdLoaderCallback); @@ -175,11 +178,12 @@ public void loadAdLoaderAd( /** Load an ad manager ad loader ad. */ public void loadAdManagerAdLoaderAd( @NonNull String adUnitId, + @NonNull FlutterAdManagerAdRequest adManagerRequest, @NonNull NativeAdLoaderCallback adLoaderAdLoaderCallback, @Nullable FlutterAdLoaderAd.BannerParameters bannerParameters, @Nullable FlutterAdLoaderAd.CustomParameters customParameters, @Nullable FlutterAdLoaderAd.NativeParameters nativeParameters) { - loadAdLoaderAd(adUnitId, adLoaderAdLoaderCallback, bannerParameters, customParameters, nativeParameters); + loadAdLoaderAd(adUnitId, adManagerRequest, adLoaderAdLoaderCallback, bannerParameters, customParameters, nativeParameters); } static AdChoicesPlacement convertAdChoicesPlacement(int adChoicesPlacement) { diff --git a/packages/google_mobile_ads/android/src/adsNextGenSdk/java/io/flutter/plugins/googlemobileads/FlutterAdLoaderAd.java b/packages/google_mobile_ads/android/src/adsNextGenSdk/java/io/flutter/plugins/googlemobileads/FlutterAdLoaderAd.java index 1f5a0d874..dcb6e3248 100644 --- a/packages/google_mobile_ads/android/src/adsNextGenSdk/java/io/flutter/plugins/googlemobileads/FlutterAdLoaderAd.java +++ b/packages/google_mobile_ads/android/src/adsNextGenSdk/java/io/flutter/plugins/googlemobileads/FlutterAdLoaderAd.java @@ -218,10 +218,10 @@ void load() { // As of 20.0.0 of GMA, mockito is unable to mock AdLoader. if (request != null) { adLoader.loadAdLoaderAd( - adUnitId, loadedListener, bannerParameters, customParameters, nativeParameters); + adUnitId, request, loadedListener, bannerParameters, customParameters, nativeParameters); } else if (adManagerRequest != null) { adLoader.loadAdManagerAdLoaderAd( - adUnitId, loadedListener, bannerParameters, customParameters, nativeParameters); + adUnitId, adManagerRequest, loadedListener, bannerParameters, customParameters, nativeParameters); } else { Log.e(TAG, "A null or invalid ad request was provided."); } diff --git a/packages/google_mobile_ads/android/src/adsNextGenSdk/java/io/flutter/plugins/googlemobileads/FlutterAdManagerAdRequest.java b/packages/google_mobile_ads/android/src/adsNextGenSdk/java/io/flutter/plugins/googlemobileads/FlutterAdManagerAdRequest.java index da53ddd1a..f34c578a5 100644 --- a/packages/google_mobile_ads/android/src/adsNextGenSdk/java/io/flutter/plugins/googlemobileads/FlutterAdManagerAdRequest.java +++ b/packages/google_mobile_ads/android/src/adsNextGenSdk/java/io/flutter/plugins/googlemobileads/FlutterAdManagerAdRequest.java @@ -19,6 +19,7 @@ import com.google.android.libraries.ads.mobile.sdk.banner.AdSize; import com.google.android.libraries.ads.mobile.sdk.banner.BannerAdRequest; import com.google.android.libraries.ads.mobile.sdk.common.AdRequest; +import com.google.android.libraries.ads.mobile.sdk.nativead.NativeAdRequest; import com.google.errorprone.annotations.CanIgnoreReturnValue; import java.util.List; import java.util.Map; @@ -149,6 +150,26 @@ protected BannerAdRequest.Builder toBannerAdRequestBuilder(String adUnitId, return builder; } + @Override + protected NativeAdRequest.Builder configureNativeAdRequestBuilder( + NativeAdRequest.Builder builder, String adUnitId) { + super.configureNativeAdRequestBuilder(builder, adUnitId); + if (customTargeting != null) { + for (final Map.Entry entry : customTargeting.entrySet()) { + builder.putCustomTargeting(entry.getKey(), entry.getValue()); + } + } + if (customTargetingLists != null) { + for (final Map.Entry> entry : customTargetingLists.entrySet()) { + builder.putCustomTargeting(entry.getKey(), entry.getValue()); + } + } + if (publisherProvidedId != null) { + builder.setPublisherProvidedId(publisherProvidedId); + } + return builder; + } + @Nullable protected Map getCustomTargeting() { return customTargeting; diff --git a/packages/google_mobile_ads/android/src/adsNextGenSdk/java/io/flutter/plugins/googlemobileads/FlutterAdRequest.java b/packages/google_mobile_ads/android/src/adsNextGenSdk/java/io/flutter/plugins/googlemobileads/FlutterAdRequest.java index 95ccf9b56..6fdda788a 100644 --- a/packages/google_mobile_ads/android/src/adsNextGenSdk/java/io/flutter/plugins/googlemobileads/FlutterAdRequest.java +++ b/packages/google_mobile_ads/android/src/adsNextGenSdk/java/io/flutter/plugins/googlemobileads/FlutterAdRequest.java @@ -23,6 +23,7 @@ import com.google.android.libraries.ads.mobile.sdk.banner.AdSize; import com.google.android.libraries.ads.mobile.sdk.banner.BannerAdRequest; import com.google.android.libraries.ads.mobile.sdk.common.AdRequest; +import com.google.android.libraries.ads.mobile.sdk.nativead.NativeAdRequest; import com.google.errorprone.annotations.CanIgnoreReturnValue; import java.util.HashMap; import java.util.HashSet; @@ -324,6 +325,24 @@ protected BannerAdRequest.Builder toBannerAdRequestBuilder(String adUnitId, List return builder; } + /** Applies the common request properties onto a next-gen {@link NativeAdRequest.Builder}. */ + protected NativeAdRequest.Builder configureNativeAdRequestBuilder( + NativeAdRequest.Builder builder, String adUnitId) { + if (keywords != null) { + for (final String keyword : keywords) { + builder.addKeyword(keyword); + } + } + if (contentUrl != null) { + builder.setContentUrl(contentUrl); + } + if (neighboringContentUrls != null) { + builder.setNeighboringContentUrls(new HashSet(neighboringContentUrls)); + } + builder.setRequestAgent(requestAgent); + return builder; + } + AdRequest asAdRequest(String adUnitId) { return ((AdRequest.Builder) updateAdRequestBuilder(new AdRequest.Builder(adUnitId), adUnitId)) .build(); From e8f2cb8840c0148eb266c757c1f6caa1c9f0aea5 Mon Sep 17 00:00:00 2001 From: LTphantom Date: Tue, 28 Jul 2026 12:16:19 -0700 Subject: [PATCH 2/2] Made domain nullsafe in LoadAdError for Android Next-Gen (#1461) --- .../plugins/googlemobileads/FlutterAd.java | 5 +++- .../lib/src/ad_instance_manager.dart | 6 ++--- .../test/ad_containers_test.dart | 25 +++++++++++++++++++ 3 files changed, 32 insertions(+), 4 deletions(-) diff --git a/packages/google_mobile_ads/android/src/adsNextGenSdk/java/io/flutter/plugins/googlemobileads/FlutterAd.java b/packages/google_mobile_ads/android/src/adsNextGenSdk/java/io/flutter/plugins/googlemobileads/FlutterAd.java index a6fd9b86b..7ce6baa1b 100644 --- a/packages/google_mobile_ads/android/src/adsNextGenSdk/java/io/flutter/plugins/googlemobileads/FlutterAd.java +++ b/packages/google_mobile_ads/android/src/adsNextGenSdk/java/io/flutter/plugins/googlemobileads/FlutterAd.java @@ -335,7 +335,10 @@ static class FlutterLoadAdError { if (error.getResponseInfo() != null) { responseInfo = new FlutterResponseInfo(error.getResponseInfo()); - domain = responseInfo.getMediationAdapterClassName(); + String adapterClassName = responseInfo.getMediationAdapterClassName(); + domain = adapterClassName != null + ? adapterClassName + : "com.google.android.libraries.ads.mobile.sdk"; } else { domain = "com.google.android.libraries.ads.mobile.sdk"; } diff --git a/packages/google_mobile_ads/lib/src/ad_instance_manager.dart b/packages/google_mobile_ads/lib/src/ad_instance_manager.dart index 9c5471b58..48d69b8da 100644 --- a/packages/google_mobile_ads/lib/src/ad_instance_manager.dart +++ b/packages/google_mobile_ads/lib/src/ad_instance_manager.dart @@ -1192,8 +1192,8 @@ class AdMessageCodec extends StandardMessageCodec { ); case _valueRewardItem: return RewardItem( - readValueOfType(buffer.getUint8(), buffer), - readValueOfType(buffer.getUint8(), buffer), + readValueOfType(buffer.getUint8(), buffer) ?? 0, + _safeReadString(buffer), ); case _valueResponseInfo: return ResponseInfo( @@ -1278,7 +1278,7 @@ class AdMessageCodec extends StandardMessageCodec { buffer.getUint8(), buffer, ); - final String description = readValueOfType(buffer.getUint8(), buffer); + final String description = _safeReadString(buffer); double latency = readValueOfType(buffer.getUint8(), buffer).toDouble(); // Android provides this value as an int in milliseconds while iOS diff --git a/packages/google_mobile_ads/test/ad_containers_test.dart b/packages/google_mobile_ads/test/ad_containers_test.dart index ef0652449..d6c615756 100644 --- a/packages/google_mobile_ads/test/ad_containers_test.dart +++ b/packages/google_mobile_ads/test/ad_containers_test.dart @@ -1196,6 +1196,31 @@ void main() { expect(result.type, 'type'); }); + test('encode/decode $RewardItem with null values', () async { + final WriteBuffer buffer = WriteBuffer(); + buffer.putUint8(132); + codec.writeValue(buffer, null); + codec.writeValue(buffer, null); + + final RewardItem result = codec.decodeMessage(buffer.done()); + expect(result.amount, 0); + expect(result.type, ''); + }); + + test('encode/decode $AdapterStatus with null description', () async { + debugDefaultTargetPlatformOverride = TargetPlatform.android; + final WriteBuffer buffer = WriteBuffer(); + buffer.putUint8(136); + codec.writeValue(buffer, AdapterInitializationState.ready); + codec.writeValue(buffer, null); + codec.writeValue(buffer, 1000); + + final AdapterStatus result = codec.decodeMessage(buffer.done()); + expect(result.state, AdapterInitializationState.ready); + expect(result.description, ''); + expect(result.latency, 1.0); + }); + test('encode/decode $InlineAdaptiveSize', () async { ByteData byteData = codec.encodeMessage( AdSize.getCurrentOrientationInlineAdaptiveBannerAdSize(100),