Skip to content

Commit 08231cb

Browse files
committed
Allow serving Banner ads in AdLoaderAd
Allow the `AdLoaderAd` instance to serve `Banner` ads, which are instances of: * `AdManagerAdView` under Android, and * `GAMBannerView` under iOS
1 parent 70d33b1 commit 08231cb

22 files changed

Lines changed: 1094 additions & 30 deletions

packages/google_mobile_ads/android/src/main/java/io/flutter/plugins/googlemobileads/AdMessageCodec.java

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,8 @@ class AdMessageCodec extends StandardMessageCodec {
5454
private static final byte VALUE_VIDEO_OPTIONS = (byte) 145;
5555
private static final byte VALUE_INLINE_ADAPTIVE_BANNER_AD_SIZE = (byte) 146;
5656
private static final byte VALUE_REQUEST_CONFIGURATION_PARAMS = (byte) 148;
57+
private static final byte VALUE_AD_MANAGER_AD_VIEW_OPTIONS = (byte) 149;
58+
private static final byte VALUE_BANNER_PARAMETERS = (byte) 150;
5759

5860
@NonNull Context context;
5961
@NonNull final FlutterAdSize.AdSizeFactory adSizeFactory;
@@ -202,6 +204,15 @@ protected void writeValue(ByteArrayOutputStream stream, Object value) {
202204
writeValue(stream, options.clickToExpandRequested);
203205
writeValue(stream, options.customControlsRequested);
204206
writeValue(stream, options.startMuted);
207+
} else if (value instanceof FlutterAdManagerAdViewOptions) {
208+
stream.write(VALUE_AD_MANAGER_AD_VIEW_OPTIONS);
209+
FlutterAdManagerAdViewOptions options = (FlutterAdManagerAdViewOptions) value;
210+
writeValue(stream, options.manualImpressionsEnabled);
211+
} else if (value instanceof FlutterBannerParameters) {
212+
stream.write(VALUE_BANNER_PARAMETERS);
213+
FlutterBannerParameters bannerParameters = (FlutterBannerParameters) value;
214+
writeValue(stream, bannerParameters.sizes);
215+
writeValue(stream, bannerParameters.adManagerAdViewOptions);
205216
} else {
206217
super.writeValue(stream, value);
207218
}
@@ -336,6 +347,12 @@ protected Object readValueOfType(byte type, ByteBuffer buffer) {
336347
rcb.setTagForUnderAgeOfConsent((Integer) readValueOfType(buffer.get(), buffer));
337348
rcb.setTestDeviceIds((List<String>) readValueOfType(buffer.get(), buffer));
338349
return rcb.build();
350+
case VALUE_AD_MANAGER_AD_VIEW_OPTIONS:
351+
return new FlutterAdManagerAdViewOptions((Boolean) readValueOfType(buffer.get(), buffer));
352+
case VALUE_BANNER_PARAMETERS:
353+
return new FlutterBannerParameters(
354+
(List<FlutterAdSize>) readValueOfType(buffer.get(), buffer),
355+
(FlutterAdManagerAdViewOptions) readValueOfType(buffer.get(), buffer));
339356
default:
340357
return super.readValueOfType(type, buffer);
341358
}

packages/google_mobile_ads/android/src/main/java/io/flutter/plugins/googlemobileads/FlutterAdListener.java

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616
import androidx.annotation.NonNull;
1717
import com.google.android.gms.ads.AdListener;
1818
import com.google.android.gms.ads.LoadAdError;
19+
import com.google.android.gms.ads.admanager.AdManagerAdView;
20+
import com.google.android.gms.ads.formats.OnAdManagerAdViewLoadedListener;
1921
import com.google.android.gms.ads.nativead.NativeAd;
2022
import com.google.android.gms.ads.nativead.NativeAd.OnNativeAdLoadedListener;
2123
import java.lang.ref.WeakReference;
@@ -118,3 +120,20 @@ public void onNativeAdLoaded(@NonNull NativeAd nativeAd) {
118120
}
119121
}
120122
}
123+
124+
/** {@link OnAdManagerAdViewLoadedListener} for banner ads. */
125+
class FlutterAdManagerAdViewLoadedListener implements OnAdManagerAdViewLoadedListener {
126+
127+
private final WeakReference<OnAdManagerAdViewLoadedListener> reference;
128+
129+
FlutterAdManagerAdViewLoadedListener(OnAdManagerAdViewLoadedListener listener) {
130+
reference = new WeakReference<>(listener);
131+
}
132+
133+
@Override
134+
public void onAdManagerAdViewLoaded(AdManagerAdView adView) {
135+
if (reference.get() != null) {
136+
reference.get().onAdManagerAdViewLoaded(adView);
137+
}
138+
}
139+
}

packages/google_mobile_ads/android/src/main/java/io/flutter/plugins/googlemobileads/FlutterAdLoader.java

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
import android.content.Context;
1818
import androidx.annotation.NonNull;
19+
import androidx.annotation.Nullable;
1920
import com.google.android.gms.ads.AdListener;
2021
import com.google.android.gms.ads.AdLoader;
2122
import com.google.android.gms.ads.AdRequest;
@@ -142,18 +143,33 @@ public void loadAdManagerNativeAd(
142143

143144
/** Load an ad loader ad. */
144145
public void loadAdLoaderAd(
145-
@NonNull String adUnitId, @NonNull AdListener adListener, @NonNull AdRequest request) {
146-
new AdLoader.Builder(context, adUnitId).withAdListener(adListener).build().loadAd(request);
146+
@NonNull String adUnitId,
147+
@NonNull AdListener adListener,
148+
@NonNull AdRequest request,
149+
@Nullable FlutterAdLoaderAd.BannerParameters bannerParameters) {
150+
AdLoader.Builder builder = new AdLoader.Builder(context, adUnitId);
151+
if (bannerParameters != null) {
152+
builder = builder.forAdManagerAdView(bannerParameters.listener, bannerParameters.adSizes);
153+
if (bannerParameters.adManagerAdViewOptions != null) {
154+
builder.withAdManagerAdViewOptions(bannerParameters.adManagerAdViewOptions);
155+
}
156+
}
157+
builder.withAdListener(adListener).build().loadAd(request);
147158
}
148159

149160
/** Load an ad manager ad loader ad. */
150161
public void loadAdManagerAdLoaderAd(
151162
@NonNull String adUnitId,
152163
@NonNull AdListener adListener,
153-
@NonNull AdManagerAdRequest adManagerAdRequest) {
154-
new AdLoader.Builder(context, adUnitId)
155-
.withAdListener(adListener)
156-
.build()
157-
.loadAd(adManagerAdRequest);
164+
@NonNull AdManagerAdRequest adManagerAdRequest,
165+
@Nullable FlutterAdLoaderAd.BannerParameters bannerParameters) {
166+
AdLoader.Builder builder = new AdLoader.Builder(context, adUnitId);
167+
if (bannerParameters != null) {
168+
builder = builder.forAdManagerAdView(bannerParameters.listener, bannerParameters.adSizes);
169+
if (bannerParameters.adManagerAdViewOptions != null) {
170+
builder.withAdManagerAdViewOptions(bannerParameters.adManagerAdViewOptions);
171+
}
172+
}
173+
builder.withAdListener(adListener).build().loadAd(adManagerAdRequest);
158174
}
159175
}

packages/google_mobile_ads/android/src/main/java/io/flutter/plugins/googlemobileads/FlutterAdLoaderAd.java

Lines changed: 68 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,22 +15,31 @@
1515
package io.flutter.plugins.googlemobileads;
1616

1717
import android.util.Log;
18+
import android.view.View;
1819
import androidx.annotation.NonNull;
1920
import androidx.annotation.Nullable;
2021
import com.google.android.gms.ads.AdListener;
22+
import com.google.android.gms.ads.AdSize;
23+
import com.google.android.gms.ads.BaseAdView;
24+
import com.google.android.gms.ads.admanager.AdManagerAdView;
25+
import com.google.android.gms.ads.formats.AdManagerAdViewOptions;
26+
import com.google.android.gms.ads.formats.OnAdManagerAdViewLoadedListener;
27+
import io.flutter.plugin.platform.PlatformView;
2128

2229
/**
2330
* A central wrapper for {@link AdManagerAdView}, {@link NativeCustomFormatAd} and {@link NativeAd}
2431
* instances served for a single {@link AdRequest} or {@link AdManagerAdRequest}
2532
*/
26-
class FlutterAdLoaderAd extends FlutterAd {
33+
class FlutterAdLoaderAd extends FlutterAd implements OnAdManagerAdViewLoadedListener {
2734
private static final String TAG = "FlutterAdLoaderAd";
2835

2936
@NonNull private final AdInstanceManager manager;
3037
@NonNull private final String adUnitId;
3138
@NonNull private final FlutterAdLoader adLoader;
3239
@Nullable private FlutterAdRequest request;
3340
@Nullable private FlutterAdManagerAdRequest adManagerRequest;
41+
@Nullable private View view;
42+
@Nullable protected BannerParameters bannerParameters;
3443

3544
static class Builder {
3645
@Nullable private AdInstanceManager manager;
@@ -39,6 +48,7 @@ static class Builder {
3948
@Nullable private FlutterAdManagerAdRequest adManagerRequest;
4049
@Nullable private Integer id;
4150
@Nullable private FlutterAdLoader adLoader;
51+
@Nullable private FlutterBannerParameters bannerParameters;
4252

4353
public Builder setId(int id) {
4454
this.id = id;
@@ -70,6 +80,11 @@ public Builder setFlutterAdLoader(@NonNull FlutterAdLoader adLoader) {
7080
return this;
7181
}
7282

83+
public Builder setBanner(@Nullable FlutterBannerParameters bannerParameters) {
84+
this.bannerParameters = bannerParameters;
85+
return this;
86+
}
87+
7388
FlutterAdLoaderAd build() {
7489
if (manager == null) {
7590
throw new IllegalStateException("manager must be provided");
@@ -90,10 +105,32 @@ FlutterAdLoaderAd build() {
90105
} else {
91106
adLoaderAd = new FlutterAdLoaderAd(id, manager, adUnitId, request, adLoader);
92107
}
108+
109+
if (bannerParameters != null) {
110+
adLoaderAd.bannerParameters =
111+
bannerParameters.asBannerParameters(
112+
new FlutterAdManagerAdViewLoadedListener(adLoaderAd));
113+
}
114+
93115
return adLoaderAd;
94116
}
95117
}
96118

119+
static class BannerParameters {
120+
@NonNull final OnAdManagerAdViewLoadedListener listener;
121+
@NonNull final AdSize[] adSizes;
122+
@Nullable final AdManagerAdViewOptions adManagerAdViewOptions;
123+
124+
BannerParameters(
125+
@NonNull OnAdManagerAdViewLoadedListener listener,
126+
@NonNull AdSize[] adSizes,
127+
@Nullable AdManagerAdViewOptions adManagerAdViewOptions) {
128+
this.listener = listener;
129+
this.adSizes = adSizes;
130+
this.adManagerAdViewOptions = adManagerAdViewOptions;
131+
}
132+
}
133+
97134
protected FlutterAdLoaderAd(
98135
int adId,
99136
@NonNull AdInstanceManager manager,
@@ -126,19 +163,46 @@ void load() {
126163
// Note we delegate loading the ad to FlutterAdLoader mainly for testing purposes.
127164
// As of 20.0.0 of GMA, mockito is unable to mock AdLoader.
128165
if (request != null) {
129-
adLoader.loadAdLoaderAd(adUnitId, adListener, request.asAdRequest(adUnitId));
166+
adLoader.loadAdLoaderAd(
167+
adUnitId, adListener, request.asAdRequest(adUnitId), bannerParameters);
130168
return;
131169
}
132170

133171
if (adManagerRequest != null) {
134172
adLoader.loadAdManagerAdLoaderAd(
135-
adUnitId, adListener, adManagerRequest.asAdManagerAdRequest(adUnitId));
173+
adUnitId, adListener, adManagerRequest.asAdManagerAdRequest(adUnitId), bannerParameters);
136174
return;
137175
}
138176

139177
Log.e(TAG, "A null or invalid ad request was provided.");
140178
}
141179

142180
@Override
143-
void dispose() {}
181+
@Nullable
182+
public PlatformView getPlatformView() {
183+
if (view == null) {
184+
return null;
185+
}
186+
187+
return new FlutterPlatformView(view);
188+
}
189+
190+
@Override
191+
public void onAdManagerAdViewLoaded(@NonNull AdManagerAdView adView) {
192+
view = adView;
193+
manager.onAdLoaded(adId, adView.getResponseInfo());
194+
}
195+
196+
@Override
197+
void dispose() {
198+
if (view == null) {
199+
return;
200+
}
201+
202+
if (view instanceof BaseAdView) {
203+
((BaseAdView) view).destroy();
204+
}
205+
206+
view = null;
207+
}
144208
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
// Copyright 2022 Google LLC
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// https://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.c language governing permissions and
14+
// limitations under the License.
15+
16+
package io.flutter.plugins.googlemobileads;
17+
18+
import androidx.annotation.Nullable;
19+
import com.google.android.gms.ads.formats.AdManagerAdViewOptions;
20+
21+
/** A wrapper for {@link com.google.android.gms.ads.formats.AdManagerAdViewOptions}. */
22+
class FlutterAdManagerAdViewOptions {
23+
24+
@Nullable final Boolean manualImpressionsEnabled;
25+
26+
FlutterAdManagerAdViewOptions(@Nullable Boolean manualImpressionsEnabled) {
27+
this.manualImpressionsEnabled = manualImpressionsEnabled;
28+
}
29+
30+
AdManagerAdViewOptions asAdManagerAdViewOptions() {
31+
AdManagerAdViewOptions.Builder builder = new AdManagerAdViewOptions.Builder();
32+
if (manualImpressionsEnabled != null) {
33+
builder.setManualImpressionsEnabled(manualImpressionsEnabled);
34+
}
35+
return builder.build();
36+
}
37+
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
// Copyright 20222 Google LLC
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// https://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package io.flutter.plugins.googlemobileads;
16+
17+
import androidx.annotation.NonNull;
18+
import androidx.annotation.Nullable;
19+
import com.google.android.gms.ads.AdSize;
20+
import com.google.android.gms.ads.formats.OnAdManagerAdViewLoadedListener;
21+
import java.util.List;
22+
23+
class FlutterBannerParameters {
24+
@NonNull final List<FlutterAdSize> sizes;
25+
@Nullable final FlutterAdManagerAdViewOptions adManagerAdViewOptions;
26+
27+
FlutterBannerParameters(
28+
@NonNull List<FlutterAdSize> sizes,
29+
@Nullable FlutterAdManagerAdViewOptions adManagerAdViewOptions) {
30+
this.sizes = sizes;
31+
this.adManagerAdViewOptions = adManagerAdViewOptions;
32+
}
33+
34+
FlutterAdLoaderAd.BannerParameters asBannerParameters(
35+
@NonNull OnAdManagerAdViewLoadedListener listener) {
36+
AdSize[] adSizes = new AdSize[sizes.size()];
37+
int i = 0;
38+
for (FlutterAdSize size : sizes) {
39+
adSizes[i++] = size.getAdSize();
40+
}
41+
return new FlutterAdLoaderAd.BannerParameters(
42+
listener,
43+
adSizes,
44+
adManagerAdViewOptions != null ? adManagerAdViewOptions.asAdManagerAdViewOptions() : null);
45+
}
46+
}

packages/google_mobile_ads/android/src/main/java/io/flutter/plugins/googlemobileads/GoogleMobileAdsPlugin.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -424,6 +424,7 @@ public void onAdInspectorClosed(@Nullable AdInspectorError adInspectorError) {
424424
.setAdManagerRequest(call.<FlutterAdManagerAdRequest>argument("adManagerRequest"))
425425
.setId(call.<Integer>argument("adId"))
426426
.setFlutterAdLoader(new FlutterAdLoader(context))
427+
.setBanner(call.<FlutterBannerParameters>argument("banner"))
427428
.build();
428429
instanceManager.trackAd(adLoaderAd, call.<Integer>argument("adId"));
429430
adLoaderAd.load();

packages/google_mobile_ads/android/src/test/java/io/flutter/plugins/googlemobileads/AdMessageCodecTest.java

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -411,4 +411,48 @@ public void encodeRequestConfiguration() {
411411
RequestConfiguration.TAG_FOR_UNDER_AGE_OF_CONSENT_FALSE);
412412
assertEquals(result.getTestDeviceIds(), Arrays.asList("test-device-id"));
413413
}
414+
415+
@Test
416+
public void encodeAdManagerAdViewOptionsNull() {
417+
final ByteBuffer data = codec.encodeMessage(new FlutterAdManagerAdViewOptions(null));
418+
419+
final FlutterAdManagerAdViewOptions result =
420+
(FlutterAdManagerAdViewOptions) codec.decodeMessage((ByteBuffer) data.position(0));
421+
assertNull(result.manualImpressionsEnabled);
422+
}
423+
424+
@Test
425+
public void encodeAdManagerAdViewOptionsTrue() {
426+
final ByteBuffer data = codec.encodeMessage(new FlutterAdManagerAdViewOptions(true));
427+
428+
final FlutterAdManagerAdViewOptions result =
429+
(FlutterAdManagerAdViewOptions) codec.decodeMessage((ByteBuffer) data.position(0));
430+
assertTrue(result.manualImpressionsEnabled);
431+
}
432+
433+
@Test
434+
public void encodeAdManagerAdViewOptionsFalse() {
435+
final ByteBuffer data = codec.encodeMessage(new FlutterAdManagerAdViewOptions(false));
436+
437+
final FlutterAdManagerAdViewOptions result =
438+
(FlutterAdManagerAdViewOptions) codec.decodeMessage((ByteBuffer) data.position(0));
439+
assertFalse(result.manualImpressionsEnabled);
440+
}
441+
442+
@Test
443+
public void encodeBannerParameters() {
444+
final ByteBuffer data =
445+
codec.encodeMessage(
446+
new FlutterBannerParameters(
447+
Collections.singletonList(new FlutterAdSize(1, 2)),
448+
new FlutterAdManagerAdViewOptions(null)));
449+
450+
final FlutterBannerParameters result =
451+
(FlutterBannerParameters) codec.decodeMessage((ByteBuffer) data.position(0));
452+
453+
assertEquals(result.sizes.size(), 1);
454+
assertEquals(result.sizes.get(0).width, 1);
455+
assertEquals(result.sizes.get(0).height, 2);
456+
assertNull(result.adManagerAdViewOptions.manualImpressionsEnabled);
457+
}
414458
}

0 commit comments

Comments
 (0)