Skip to content

Commit 017ffbf

Browse files
authored
feat(banner): Support maximum height for Inline Adaptive banners
1 parent bcda5ad commit 017ffbf

15 files changed

+2020
-1999
lines changed

RNGoogleMobileAdsExample/App.tsx

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -199,12 +199,15 @@ class InterstitialTest implements AutoExecutableTest {
199199
}
200200

201201
class BannerTest implements AutoExecutableTest {
202-
bannerAdSize: BannerAdSize | string;
203202
bannerRef: RefObject<BannerAd>;
204-
205-
constructor(bannerAdSize: BannerAdSize) {
203+
bannerAdSize: BannerAdSize | string;
204+
maxHeight?: number;
205+
width?: number;
206+
constructor(bannerAdSize: BannerAdSize | string, maxHeight?: number, width?: number) {
206207
this.bannerAdSize = bannerAdSize;
207208
this.bannerRef = React.createRef();
209+
this.maxHeight = maxHeight;
210+
this.width = width;
208211
}
209212

210213
getPath(): string {
@@ -213,7 +216,9 @@ class BannerTest implements AutoExecutableTest {
213216
.map(
214217
s => s.toLowerCase().charAt(0).toUpperCase() + s.toLowerCase().slice(1),
215218
)
216-
.join('');
219+
.join('')
220+
.concat(this.maxHeight ? `MaxHeight${this.maxHeight}` : '')
221+
.concat(this.width ? `Width${this.width}` : '');
217222
}
218223

219224
getTestType(): TestType {
@@ -231,6 +236,8 @@ class BannerTest implements AutoExecutableTest {
231236
: TestIds.BANNER
232237
}
233238
size={this.bannerAdSize}
239+
maxHeight={this.maxHeight}
240+
width={this.width}
234241
onPaid={(event: PaidEvent) => {
235242
console.log(
236243
`Paid: ${event.value} ${event.currency} (precision ${
@@ -1145,7 +1152,11 @@ class DebugMenuTest implements AutoExecutableTest {
11451152
}
11461153

11471154
// All tests must be registered - a future feature will allow auto-bundling of tests via configured path or regex
1148-
Object.values(BannerAdSize).forEach(bannerAdSize => {
1155+
Object.keys(BannerAdSize).forEach(bannerAdSize => {
1156+
if (bannerAdSize === "INLINE_ADAPTIVE_BANNER") {
1157+
TestRegistry.registerTest(new BannerTest(bannerAdSize, 100))
1158+
TestRegistry.registerTest(new BannerTest(bannerAdSize, 200, 200))
1159+
}
11491160
TestRegistry.registerTest(new BannerTest(bannerAdSize));
11501161
});
11511162
TestRegistry.registerTest(new CollapsibleBannerTest());

android/src/main/java/io/invertase/googlemobileads/ReactNativeGoogleMobileAdsBannerAdViewManager.java

Lines changed: 47 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@
2323
import com.facebook.react.bridge.Arguments;
2424
import com.facebook.react.bridge.ReactContext;
2525
import com.facebook.react.bridge.ReadableArray;
26+
import com.facebook.react.bridge.ReadableMap;
27+
import com.facebook.react.bridge.ReadableType;
2628
import com.facebook.react.bridge.WritableMap;
2729
import com.facebook.react.common.MapBuilder;
2830
import com.facebook.react.uimanager.PixelUtil;
@@ -118,26 +120,54 @@ public void setRequest(ReactNativeAdView reactViewGroup, String value) {
118120
}
119121
}
120122

121-
@ReactProp(name = "sizes")
122-
public void setSizes(ReactNativeAdView reactViewGroup, ReadableArray value) {
123-
List<AdSize> sizeList = new ArrayList<>();
124-
for (Object size : value.toArrayList()) {
125-
if (size instanceof String) {
126-
String sizeString = (String) size;
127-
sizeList.add(ReactNativeGoogleMobileAdsCommon.getAdSize(sizeString, reactViewGroup));
123+
@ReactProp(name = "sizeConfig")
124+
public void setSizeConfig(ReactNativeAdView reactViewGroup, ReadableMap sizeConfig) {
125+
if (sizeConfig != null) {
126+
// Handle maxHeight
127+
if (sizeConfig.hasKey("maxHeight") && !sizeConfig.isNull("maxHeight")) {
128+
float maxHeight = (float) sizeConfig.getDouble("maxHeight");
129+
reactViewGroup.setMaxAdHeight(maxHeight);
130+
} else {
131+
reactViewGroup.setMaxAdHeight(0);
128132
}
129-
}
130133

131-
if (sizeList.size() > 0 && !sizeList.contains(AdSize.FLUID)) {
132-
AdSize adSize = sizeList.get(0);
133-
WritableMap payload = Arguments.createMap();
134-
payload.putDouble("width", adSize.getWidth());
135-
payload.putDouble("height", adSize.getHeight());
136-
sendEvent(reactViewGroup, EVENT_SIZE_CHANGE, payload);
137-
}
134+
// Handle width
135+
if (sizeConfig.hasKey("width") && !sizeConfig.isNull("width")) {
136+
float width = (float) sizeConfig.getDouble("width");
137+
reactViewGroup.setAdWidth(width);
138+
} else {
139+
reactViewGroup.setAdWidth(0);
140+
}
141+
// Handle the sizes array
142+
if (sizeConfig.hasKey("sizes") && !sizeConfig.isNull("sizes")) {
143+
ReadableArray sizesArray = sizeConfig.getArray("sizes");
144+
if (sizesArray != null) {
145+
// Process the sizes array and convert to AdSize objects
146+
List<AdSize> sizeList = new ArrayList<>();
147+
for (int i = 0; i < sizesArray.size(); i++) {
148+
if (sizesArray.getType(i) == ReadableType.String) {
149+
String sizeString = sizesArray.getString(i);
150+
AdSize adSize =
151+
ReactNativeGoogleMobileAdsCommon.getAdSize(sizeString, reactViewGroup);
152+
sizeList.add(adSize);
153+
}
154+
}
138155

139-
reactViewGroup.setSizes(sizeList);
140-
reactViewGroup.setPropsChanged(true);
156+
// Update the view with sizes and trigger size change event if needed
157+
if (sizeList.size() > 0 && !sizeList.contains(AdSize.FLUID)) {
158+
AdSize adSize = sizeList.get(0);
159+
WritableMap payload = Arguments.createMap();
160+
payload.putDouble("width", adSize.getWidth());
161+
payload.putDouble("height", adSize.getHeight());
162+
sendEvent(reactViewGroup, EVENT_SIZE_CHANGE, payload);
163+
}
164+
165+
reactViewGroup.setSizes(sizeList);
166+
}
167+
}
168+
169+
reactViewGroup.setPropsChanged(true);
170+
}
141171
}
142172

143173
@ReactProp(name = "manualImpressionsEnabled")

android/src/main/java/io/invertase/googlemobileads/ReactNativeGoogleMobileAdsCommon.java

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
import com.google.android.gms.ads.AdRequest;
3131
import com.google.android.gms.ads.AdSize;
3232
import com.google.android.gms.ads.admanager.AdManagerAdRequest;
33+
import io.invertase.googlemobileads.common.ReactNativeAdView;
3334
import io.invertase.googlemobileads.common.ReactNativeEventEmitter;
3435
import java.util.ArrayList;
3536
import java.util.Map;
@@ -50,9 +51,18 @@ static AdSize getAdSizeForAdaptiveBanner(String preDefinedAdSize, ViewGroup reac
5051

5152
DisplayMetrics outMetrics = new DisplayMetrics();
5253
display.getMetrics(outMetrics);
53-
int adWidth = (int) (outMetrics.widthPixels / outMetrics.density);
5454

55+
// Get custom width if set, otherwise use device width
56+
float customWidth = ((ReactNativeAdView) reactViewGroup).getAdWidth();
57+
int screenWidth = (int) (outMetrics.widthPixels / outMetrics.density);
58+
int adWidth = customWidth > 0 ? Math.min(Math.round(customWidth), screenWidth) : screenWidth;
59+
60+
float maxAdHeight = ((ReactNativeAdView) reactViewGroup).getMaxAdHeight();
5561
if ("INLINE_ADAPTIVE_BANNER".equals(preDefinedAdSize)) {
62+
if (maxAdHeight > 0) {
63+
return AdSize.getInlineAdaptiveBannerAdSize(
64+
adWidth, Math.round(Math.max(maxAdHeight, 32)));
65+
}
5666
return AdSize.getCurrentOrientationInlineAdaptiveBannerAdSize(
5767
reactViewGroup.getContext(), adWidth);
5868
}

android/src/main/java/io/invertase/googlemobileads/common/ReactNativeAdView.java

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818
public class ReactNativeAdView extends FrameLayout {
1919
private AdRequest request;
2020
private List<AdSize> sizes;
21+
private float maxAdHeight;
22+
private float adWidth;
2123
private String unitId;
2224
private boolean manualImpressionsEnabled;
2325
private boolean propsChanged;
@@ -74,6 +76,22 @@ public List<AdSize> getSizes() {
7476
return this.sizes;
7577
}
7678

79+
public void setMaxAdHeight(float maxAdHeight) {
80+
this.maxAdHeight = maxAdHeight;
81+
}
82+
83+
public float getMaxAdHeight() {
84+
return this.maxAdHeight;
85+
}
86+
87+
public void setAdWidth(float adWidth) {
88+
this.adWidth = adWidth;
89+
}
90+
91+
public float getAdWidth() {
92+
return this.adWidth;
93+
}
94+
7795
public void setUnitId(String unitId) {
7896
this.unitId = unitId;
7997
}

ios/RNGoogleMobileAds/RNGoogleMobileAdsBannerComponent.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
@property GADBannerView *banner;
2828
@property(nonatomic, assign) BOOL requested;
2929

30-
@property(nonatomic, copy) NSArray *sizes;
30+
@property(nonatomic, copy) NSDictionary *sizeConfig;
3131
@property(nonatomic, copy) NSString *unitId;
3232
@property(nonatomic, copy) NSDictionary *request;
3333
@property(nonatomic, copy) NSNumber *manualImpressionsEnabled;

ios/RNGoogleMobileAds/RNGoogleMobileAdsBannerComponent.m

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ - (void)initBanner:(GADAdSize)adSize {
4949
_banner.autoresizingMask = (UIViewAutoresizingFlexibleWidth);
5050
}
5151

52-
((GAMBannerView *)_banner).validAdSizes = _sizes;
52+
((GAMBannerView *)_banner).validAdSizes = _sizeConfig[@"sizes"];
5353
((GAMBannerView *)_banner).appEventDelegate = self;
5454
((GAMBannerView *)_banner).enableManualImpressions = [_manualImpressionsEnabled boolValue];
5555
} else {
@@ -64,17 +64,26 @@ - (void)setUnitId:(NSString *)unitId {
6464
_propsChanged = true;
6565
}
6666

67-
- (void)setSizes:(NSArray *)sizes {
67+
- (void)setSizeConfig:(NSDictionary *)sizeConfig {
68+
NSArray *sizes = sizeConfig[@"sizes"];
6869
__block NSMutableArray *adSizes = [[NSMutableArray alloc] initWithCapacity:sizes.count];
70+
CGFloat maxHeight = sizeConfig[@"maxHeight"] ? [sizeConfig[@"maxHeight"] doubleValue] : -1;
71+
CGFloat width = sizeConfig[@"width"] ? [sizeConfig[@"width"] doubleValue] : -1;
6972
[sizes enumerateObjectsUsingBlock:^(id jsonValue, NSUInteger idx, __unused BOOL *stop) {
70-
GADAdSize adSize = [RNGoogleMobileAdsCommon stringToAdSize:jsonValue];
73+
GADAdSize adSize = [RNGoogleMobileAdsCommon stringToAdSize:jsonValue
74+
withMaxHeight:maxHeight
75+
andWidth:width];
7176
if (GADAdSizeEqualToSize(adSize, GADAdSizeInvalid)) {
7277
RCTLogWarn(@"Invalid adSize %@", jsonValue);
7378
} else {
7479
[adSizes addObject:NSValueFromGADAdSize(adSize)];
7580
}
7681
}];
77-
_sizes = adSizes;
82+
_sizeConfig = @{
83+
@"sizes" : adSizes,
84+
@"maxHeight" : [NSNumber numberWithFloat:maxHeight],
85+
@"width" : [NSNumber numberWithFloat:width]
86+
};
7887
_propsChanged = true;
7988
}
8089

@@ -94,21 +103,22 @@ - (void)setManualImpressionsEnabled:(BOOL *)manualImpressionsEnabled {
94103
}
95104

96105
- (GADAdSize)getInitialAdSize {
97-
for (NSValue *sizeValue in _sizes) {
106+
NSArray *sizes = _sizeConfig[@"sizes"];
107+
for (NSValue *sizeValue in sizes) {
98108
GADAdSize adSize = GADAdSizeFromNSValue(sizeValue);
99109
if (GADAdSizeEqualToSize(adSize, GADAdSizeFluid)) {
100110
return GADAdSizeFluid;
101111
}
102112
}
103-
return GADAdSizeFromNSValue(_sizes[0]);
113+
return GADAdSizeFromNSValue(sizes[0]);
104114
}
105115

106116
- (void)requestAd {
107117
#ifndef __LP64__
108118
return; // prevent crash on 32bit
109119
#endif
110120

111-
if (_unitId == nil || _sizes == nil || _request == nil || _manualImpressionsEnabled == nil) {
121+
if (_unitId == nil || _sizeConfig == nil || _request == nil || _manualImpressionsEnabled == nil) {
112122
[self setRequested:NO];
113123
return;
114124
}

ios/RNGoogleMobileAds/RNGoogleMobileAdsBannerView.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ NS_ASSUME_NONNULL_BEGIN
1919
@property GADBannerView *banner;
2020
@property(nonatomic, assign) BOOL requested;
2121

22-
@property(nonatomic, copy) NSArray *sizes;
22+
@property(nonatomic, copy) NSDictionary *sizeConfig;
2323
@property(nonatomic, copy) NSString *unitId;
2424
@property(nonatomic, copy) NSDictionary *request;
2525
@property(nonatomic, copy) NSNumber *manualImpressionsEnabled;

ios/RNGoogleMobileAds/RNGoogleMobileAdsBannerView.mm

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -57,18 +57,31 @@ - (void)updateProps:(Props::Shared const &)props oldProps:(Props::Shared const &
5757
propsChanged = true;
5858
}
5959

60-
if (oldViewProps.sizes != newViewProps.sizes) {
61-
NSMutableArray *adSizes = [NSMutableArray arrayWithCapacity:newViewProps.sizes.size()];
62-
for (auto i = 0; i < newViewProps.sizes.size(); i++) {
63-
NSString *jsonValue = [[NSString alloc] initWithUTF8String:newViewProps.sizes[i].c_str()];
64-
GADAdSize adSize = [RNGoogleMobileAdsCommon stringToAdSize:jsonValue];
60+
if (oldViewProps.sizeConfig.sizes != newViewProps.sizeConfig.sizes ||
61+
oldViewProps.sizeConfig.maxHeight != newViewProps.sizeConfig.maxHeight ||
62+
oldViewProps.sizeConfig.width != newViewProps.sizeConfig.width) {
63+
NSMutableArray *adSizes =
64+
[NSMutableArray arrayWithCapacity:newViewProps.sizeConfig.sizes.size()];
65+
CGFloat maxAdHeight =
66+
newViewProps.sizeConfig.maxHeight > 0 ? newViewProps.sizeConfig.maxHeight : -1;
67+
CGFloat width = newViewProps.sizeConfig.width > 0 ? newViewProps.sizeConfig.width : -1;
68+
for (auto i = 0; i < newViewProps.sizeConfig.sizes.size(); i++) {
69+
NSString *jsonValue =
70+
[[NSString alloc] initWithUTF8String:newViewProps.sizeConfig.sizes[i].c_str()];
71+
GADAdSize adSize = [RNGoogleMobileAdsCommon stringToAdSize:jsonValue
72+
withMaxHeight:maxAdHeight
73+
andWidth:width];
6574
if (GADAdSizeEqualToSize(adSize, GADAdSizeInvalid)) {
6675
RCTLogWarn(@"Invalid adSize %@", jsonValue);
6776
} else {
6877
[adSizes addObject:NSValueFromGADAdSize(adSize)];
6978
}
7079
}
71-
_sizes = adSizes;
80+
_sizeConfig = @{
81+
@"sizes" : adSizes,
82+
@"maxHeight" : [NSNumber numberWithFloat:maxAdHeight],
83+
@"width" : [NSNumber numberWithFloat:width]
84+
};
7285
propsChanged = true;
7386
}
7487

@@ -117,7 +130,7 @@ - (void)initBanner:(GADAdSize)adSize {
117130
if ([RNGoogleMobileAdsCommon isAdManagerUnit:_unitId]) {
118131
_banner = [[GAMBannerView alloc] initWithAdSize:adSize];
119132

120-
((GAMBannerView *)_banner).validAdSizes = _sizes;
133+
((GAMBannerView *)_banner).validAdSizes = _sizeConfig[@"sizes"];
121134
((GAMBannerView *)_banner).appEventDelegate = self;
122135
((GAMBannerView *)_banner).enableManualImpressions = [_manualImpressionsEnabled boolValue];
123136
} else {
@@ -140,11 +153,11 @@ - (void)requestAd {
140153
return; // prevent crash on 32bit
141154
#endif
142155

143-
if (_unitId == nil || _sizes == nil || _request == nil || _manualImpressionsEnabled == nil) {
156+
if (_unitId == nil || _sizeConfig == nil || _request == nil || _manualImpressionsEnabled == nil) {
144157
[self setRequested:NO];
145158
return;
146159
} else {
147-
[self initBanner:GADAdSizeFromNSValue(_sizes[0])];
160+
[self initBanner:GADAdSizeFromNSValue(_sizeConfig[@"sizes"][0])];
148161
[self addSubview:_banner];
149162
_banner.adUnitID = _unitId;
150163
[self setRequested:YES];

ios/RNGoogleMobileAds/RNGoogleMobileAdsBannerViewManager.mm

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ @implementation RNGoogleMobileAdsBannerViewManager
3131

3232
RCT_EXPORT_MODULE(RNGoogleMobileAdsBannerView);
3333

34-
RCT_EXPORT_VIEW_PROPERTY(sizes, NSArray);
34+
RCT_EXPORT_VIEW_PROPERTY(sizeConfig, NSDictionary);
3535

3636
RCT_EXPORT_VIEW_PROPERTY(unitId, NSString);
3737

ios/RNGoogleMobileAds/RNGoogleMobileAdsCommon.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,9 @@
3434
error:(nullable NSDictionary *)error
3535
data:(nullable NSDictionary *)data;
3636

37-
+ (GADAdSize)stringToAdSize:(NSString *)value;
37+
+ (GADAdSize)stringToAdSize:(NSString *)value
38+
withMaxHeight:(CGFloat)maxHeight
39+
andWidth:(CGFloat)adWidth;
3840

3941
+ (BOOL)isAdManagerUnit:(NSString *)unitId;
4042

0 commit comments

Comments
 (0)