Skip to content

Commit f2caa45

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 870c12c commit f2caa45

22 files changed

Lines changed: 1094 additions & 31 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
@@ -65,6 +65,8 @@ class AdMessageCodec extends StandardMessageCodec {
6565
private static final byte VALUE_NATIVE_TEMPLATE_FONT_STYLE = (byte) 151;
6666
private static final byte VALUE_NATIVE_TEMPLATE_TYPE = (byte) 152;
6767
private static final byte VALUE_COLOR = (byte) 153;
68+
private static final byte VALUE_AD_MANAGER_AD_VIEW_OPTIONS = (byte) 154;
69+
private static final byte VALUE_BANNER_PARAMETERS = (byte) 155;
6870

6971
@NonNull Context context;
7072
@NonNull final FlutterAdSize.AdSizeFactory adSizeFactory;
@@ -242,6 +244,15 @@ protected void writeValue(ByteArrayOutputStream stream, Object value) {
242244
writeValue(stream, Color.red(colorValue));
243245
writeValue(stream, Color.green(colorValue));
244246
writeValue(stream, Color.blue(colorValue));
247+
} else if (value instanceof FlutterAdManagerAdViewOptions) {
248+
stream.write(VALUE_AD_MANAGER_AD_VIEW_OPTIONS);
249+
FlutterAdManagerAdViewOptions options = (FlutterAdManagerAdViewOptions) value;
250+
writeValue(stream, options.manualImpressionsEnabled);
251+
} else if (value instanceof FlutterBannerParameters) {
252+
stream.write(VALUE_BANNER_PARAMETERS);
253+
FlutterBannerParameters bannerParameters = (FlutterBannerParameters) value;
254+
writeValue(stream, bannerParameters.sizes);
255+
writeValue(stream, bannerParameters.adManagerAdViewOptions);
245256
} else {
246257
super.writeValue(stream, value);
247258
}
@@ -402,6 +413,12 @@ protected Object readValueOfType(byte type, ByteBuffer buffer) {
402413
final Integer green = (Integer) readValueOfType(buffer.get(), buffer);
403414
final Integer blue = (Integer) readValueOfType(buffer.get(), buffer);
404415
return new ColorDrawable(Color.argb(alpha, red, green, blue));
416+
case VALUE_AD_MANAGER_AD_VIEW_OPTIONS:
417+
return new FlutterAdManagerAdViewOptions((Boolean) readValueOfType(buffer.get(), buffer));
418+
case VALUE_BANNER_PARAMETERS:
419+
return new FlutterBannerParameters(
420+
(List<FlutterAdSize>) readValueOfType(buffer.get(), buffer),
421+
(FlutterAdManagerAdViewOptions) readValueOfType(buffer.get(), buffer));
405422
default:
406423
return super.readValueOfType(type, buffer);
407424
}

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
@@ -428,6 +428,7 @@ public void onAdInspectorClosed(@Nullable AdInspectorError adInspectorError) {
428428
.setAdManagerRequest(call.<FlutterAdManagerAdRequest>argument("adManagerRequest"))
429429
.setId(call.<Integer>argument("adId"))
430430
.setFlutterAdLoader(new FlutterAdLoader(context))
431+
.setBanner(call.<FlutterBannerParameters>argument("banner"))
431432
.build();
432433
instanceManager.trackAd(adLoaderAd, call.<Integer>argument("adId"));
433434
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
@@ -516,4 +516,48 @@ public void encodeRequestConfiguration() {
516516
RequestConfiguration.TAG_FOR_UNDER_AGE_OF_CONSENT_FALSE);
517517
assertEquals(result.getTestDeviceIds(), Arrays.asList("test-device-id"));
518518
}
519+
520+
@Test
521+
public void encodeAdManagerAdViewOptionsNull() {
522+
final ByteBuffer data = codec.encodeMessage(new FlutterAdManagerAdViewOptions(null));
523+
524+
final FlutterAdManagerAdViewOptions result =
525+
(FlutterAdManagerAdViewOptions) codec.decodeMessage((ByteBuffer) data.position(0));
526+
assertNull(result.manualImpressionsEnabled);
527+
}
528+
529+
@Test
530+
public void encodeAdManagerAdViewOptionsTrue() {
531+
final ByteBuffer data = codec.encodeMessage(new FlutterAdManagerAdViewOptions(true));
532+
533+
final FlutterAdManagerAdViewOptions result =
534+
(FlutterAdManagerAdViewOptions) codec.decodeMessage((ByteBuffer) data.position(0));
535+
assertTrue(result.manualImpressionsEnabled);
536+
}
537+
538+
@Test
539+
public void encodeAdManagerAdViewOptionsFalse() {
540+
final ByteBuffer data = codec.encodeMessage(new FlutterAdManagerAdViewOptions(false));
541+
542+
final FlutterAdManagerAdViewOptions result =
543+
(FlutterAdManagerAdViewOptions) codec.decodeMessage((ByteBuffer) data.position(0));
544+
assertFalse(result.manualImpressionsEnabled);
545+
}
546+
547+
@Test
548+
public void encodeBannerParameters() {
549+
final ByteBuffer data =
550+
codec.encodeMessage(
551+
new FlutterBannerParameters(
552+
Collections.singletonList(new FlutterAdSize(1, 2)),
553+
new FlutterAdManagerAdViewOptions(null)));
554+
555+
final FlutterBannerParameters result =
556+
(FlutterBannerParameters) codec.decodeMessage((ByteBuffer) data.position(0));
557+
558+
assertEquals(result.sizes.size(), 1);
559+
assertEquals(result.sizes.get(0).width, 1);
560+
assertEquals(result.sizes.get(0).height, 2);
561+
assertNull(result.adManagerAdViewOptions.manualImpressionsEnabled);
562+
}
519563
}

0 commit comments

Comments
 (0)