Skip to content

Commit

Permalink
feat: adaptive banner with container width and adaptive height
Browse files Browse the repository at this point in the history
  • Loading branch information
youedd committed Dec 23, 2024
1 parent fd5726b commit e0e4866
Show file tree
Hide file tree
Showing 14 changed files with 365 additions and 90 deletions.
84 changes: 58 additions & 26 deletions RNGoogleMobileAdsExample/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -185,9 +185,8 @@ class InterstitialTest implements Test {
class BannerTest implements Test {
bannerAdSize: BannerAdSize | string;

constructor(bannerAdSize) {
constructor(bannerAdSize: BannerAdSize | string) {
this.bannerAdSize = bannerAdSize;
this.bannerRef = React.createRef();
}

getPath(): string {
Expand All @@ -205,30 +204,11 @@ class BannerTest implements Test {

render(onMount: (component: any) => void): React.ReactNode {
return (
<View ref={onMount}>
<BannerAd
ref={this.bannerRef}
unitId={
this.bannerAdSize.includes('ADAPTIVE_BANNER')
? TestIds.ADAPTIVE_BANNER
: TestIds.BANNER
}
size={this.bannerAdSize}
onPaid={(event: PaidEvent) => {
console.log(
`Paid: ${event.value} ${event.currency} (precision ${
RevenuePrecisions[event.precision]
}})`,
);
}}
/>
<Button
title="reload"
onPress={() => {
this.bannerRef.current?.load();
}}
/>
</View>
<BannerContainer
ref={onMount}
bannerAdSize={this.bannerAdSize}
/>

);
}

Expand All @@ -244,6 +224,58 @@ class BannerTest implements Test {
}
}


class BannerContainer extends React.Component<{ bannerAdSize: string }, { enableContainerAdaptiveMode: boolean }> {
state = {
enableContainerAdaptiveMode: true
}
bannerRef = React.createRef();


render(): React.ReactNode {
return (
<>
<View style={{ width: "50%"}}>
<BannerAd
ref={this.bannerRef}
unitId={
this.props.bannerAdSize.includes('ADAPTIVE_BANNER')
? TestIds.ADAPTIVE_BANNER
: TestIds.BANNER
}
size={this.props.bannerAdSize}
adaptiveMode={this.state.enableContainerAdaptiveMode ? "CONTAINER" : "MAIN_SCREEN"}
onPaid={(event: PaidEvent) => {
console.log(
`Paid: ${event.value} ${event.currency} (precision ${RevenuePrecisions[event.precision]
}})`,
);
}}
/>
</View>
<Button
title="reload"
onPress={() => {
this.bannerRef.current?.load();
}}
/>
<Button
title={
this.state.enableContainerAdaptiveMode
? "Adapt to main screen"
: "Adapt to container"
}
onPress={() => {
this.setState(state => ({
enableContainerAdaptiveMode: !state.enableContainerAdaptiveMode
}))
}}
/>
</>
)
}
}

class CollapsibleBannerTest implements Test {
getPath(): string {
return 'CollapsibleBanner';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,15 @@ public String getName() {
@Nonnull
@Override
public ReactNativeAdView createViewInstance(@Nonnull ThemedReactContext themedReactContext) {
return new ReactNativeAdView(themedReactContext);
ReactNativeAdView reactViewGroup = new ReactNativeAdView(themedReactContext);

reactViewGroup.setWidthChangedConsumer(
(width) -> {
this.updateSizes(reactViewGroup);
this.requestAd(reactViewGroup);
});

return reactViewGroup;
}

@Override
Expand Down Expand Up @@ -120,23 +128,16 @@ public void setRequest(ReactNativeAdView reactViewGroup, String value) {

@ReactProp(name = "sizes")
public void setSizes(ReactNativeAdView reactViewGroup, ReadableArray value) {
List<AdSize> sizeList = new ArrayList<>();
ArrayList<String> sizeList = new ArrayList<>();

for (Object size : value.toArrayList()) {
if (size instanceof String) {
String sizeString = (String) size;
sizeList.add(ReactNativeGoogleMobileAdsCommon.getAdSize(sizeString, reactViewGroup));
sizeList.add((String) size);
}
}

if (sizeList.size() > 0 && !sizeList.contains(AdSize.FLUID)) {
AdSize adSize = sizeList.get(0);
WritableMap payload = Arguments.createMap();
payload.putDouble("width", adSize.getWidth());
payload.putDouble("height", adSize.getHeight());
sendEvent(reactViewGroup, EVENT_SIZE_CHANGE, payload);
}

reactViewGroup.setSizes(sizeList);
reactViewGroup.setRawSizes(sizeList);
this.updateSizes(reactViewGroup);
reactViewGroup.setPropsChanged(true);
}

Expand All @@ -146,6 +147,13 @@ public void setManualImpressionsEnabled(ReactNativeAdView reactViewGroup, boolea
reactViewGroup.setPropsChanged(true);
}

@ReactProp(name = "adaptiveMode")
public void setAdaptiveMode(ReactNativeAdView reactViewGroup, String value) {
reactViewGroup.setAdaptiveMode(value);
this.updateSizes(reactViewGroup);
reactViewGroup.setPropsChanged(true);
}

@Override
public void onAfterUpdateTransaction(@NonNull ReactNativeAdView reactViewGroup) {
super.onAfterUpdateTransaction(reactViewGroup);
Expand All @@ -169,6 +177,23 @@ public void onDropViewInstance(@NonNull ReactNativeAdView reactViewGroup) {
super.onDropViewInstance(reactViewGroup);
}

private void updateSizes(ReactNativeAdView reactViewGroup) {
List<AdSize> sizeList = new ArrayList<>();
for (String size : reactViewGroup.getRawSizes()) {
sizeList.add(ReactNativeGoogleMobileAdsCommon.getAdSize(size, reactViewGroup));
}

if (sizeList.size() > 0 && !sizeList.contains(AdSize.FLUID)) {
AdSize adSize = sizeList.get(0);
WritableMap payload = Arguments.createMap();
payload.putDouble("width", adSize.getWidth());
payload.putDouble("height", adSize.getHeight());
sendEvent(reactViewGroup, EVENT_SIZE_CHANGE, payload);
}

reactViewGroup.setSizes(sizeList);
}

private BaseAdView initAdView(ReactNativeAdView reactViewGroup) {
BaseAdView oldAdView = getAdView(reactViewGroup);
if (oldAdView != null) {
Expand Down Expand Up @@ -282,7 +307,11 @@ private void requestAd(ReactNativeAdView reactViewGroup) {
AdRequest request = reactViewGroup.getRequest();
Boolean manualImpressionsEnabled = reactViewGroup.getManualImpressionsEnabled();

if (sizes == null || unitId == null || request == null || manualImpressionsEnabled == null) {
if (sizes == null
|| sizes.get(0).getWidth() == 0
|| unitId == null
|| request == null
|| manualImpressionsEnabled == null) {
return;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@
import android.os.Bundle;
import android.util.DisplayMetrics;
import android.view.Display;
import android.view.ViewGroup;
import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.ReactContext;
import com.facebook.react.bridge.ReadableMap;
Expand All @@ -30,6 +29,7 @@
import com.google.android.gms.ads.AdRequest;
import com.google.android.gms.ads.AdSize;
import com.google.android.gms.ads.admanager.AdManagerAdRequest;
import io.invertase.googlemobileads.common.ReactNativeAdView;
import io.invertase.googlemobileads.common.ReactNativeEventEmitter;
import java.util.ArrayList;
import java.util.Map;
Expand All @@ -40,17 +40,49 @@

public class ReactNativeGoogleMobileAdsCommon {

static AdSize getAdSizeForAdaptiveBanner(String preDefinedAdSize, ViewGroup reactViewGroup) {
static DisplayMetrics getDisplayOutMetrics(ReactNativeAdView reactViewGroup) {
Display display =
Objects.requireNonNull(((ReactContext) reactViewGroup.getContext()).getCurrentActivity())
.getWindowManager()
.getDefaultDisplay();

DisplayMetrics outMetrics = new DisplayMetrics();
display.getMetrics(outMetrics);

return outMetrics;
}

static int getWindowWidth(ReactNativeAdView reactViewGroup) {
DisplayMetrics outMetrics =
ReactNativeGoogleMobileAdsCommon.getDisplayOutMetrics(reactViewGroup);
return (int) (outMetrics.widthPixels / outMetrics.density);
}

static int getViewWidth(ReactNativeAdView reactViewGroup) {
DisplayMetrics outMetrics =
ReactNativeGoogleMobileAdsCommon.getDisplayOutMetrics(reactViewGroup);
return (int) (reactViewGroup.getViewWidth() / outMetrics.density);
}

static AdSize getAdSizeForAdaptiveBanner(
String preDefinedAdSize, ReactNativeAdView reactViewGroup) {

try {
Display display =
Objects.requireNonNull(((ReactContext) reactViewGroup.getContext()).getCurrentActivity())
.getWindowManager()
.getDefaultDisplay();
String adaptiveMode = reactViewGroup.getAdaptiveMode();

if (adaptiveMode == null) {
return new AdSize(0, 0);
}

int adWidth = getViewWidth(reactViewGroup);

DisplayMetrics outMetrics = new DisplayMetrics();
display.getMetrics(outMetrics);
int adWidth = (int) (outMetrics.widthPixels / outMetrics.density);
if (!adaptiveMode.equals("CONTAINER")) {
adWidth = ReactNativeGoogleMobileAdsCommon.getWindowWidth(reactViewGroup);
}

if (adWidth == 0) {
return new AdSize(0, 0);
}

if ("INLINE_ADAPTIVE_BANNER".equals(preDefinedAdSize)) {
return AdSize.getCurrentOrientationInlineAdaptiveBannerAdSize(
Expand All @@ -63,7 +95,7 @@ static AdSize getAdSizeForAdaptiveBanner(String preDefinedAdSize, ViewGroup reac
}
}

static AdSize getAdSize(String preDefinedAdSize, ViewGroup reactViewGroup) {
static AdSize getAdSize(String preDefinedAdSize, ReactNativeAdView reactViewGroup) {
if (preDefinedAdSize.matches(
"ADAPTIVE_BANNER|ANCHORED_ADAPTIVE_BANNER|INLINE_ADAPTIVE_BANNER")) {
return ReactNativeGoogleMobileAdsCommon.getAdSizeForAdaptiveBanner(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import com.google.android.gms.ads.AdRequest;
import com.google.android.gms.ads.AdSize;
import java.util.List;
import java.util.function.Consumer;

/**
* Using FrameLayout instead of ReactViewGroup
Expand All @@ -18,10 +19,14 @@
public class ReactNativeAdView extends FrameLayout {
private AdRequest request;
private List<AdSize> sizes;
private List<String> rawSizes;
private String unitId;
private boolean manualImpressionsEnabled;
private boolean propsChanged;
private boolean isFluid;
private String adaptiveMode;
private int viewWidth = 0;
private Consumer<Integer> widthChangedConsumer;

@Override
public void requestLayout() {
Expand Down Expand Up @@ -74,6 +79,14 @@ public List<AdSize> getSizes() {
return this.sizes;
}

public void setRawSizes(List<String> rawSizes) {
this.rawSizes = rawSizes;
}

public List<String> getRawSizes() {
return this.rawSizes;
}

public void setUnitId(String unitId) {
this.unitId = unitId;
}
Expand Down Expand Up @@ -105,4 +118,33 @@ public void setIsFluid(boolean isFluid) {
public boolean getIsFluid() {
return this.isFluid;
}

public void setAdaptiveMode(String adaptiveMode) {
this.adaptiveMode = adaptiveMode;
}

public String getAdaptiveMode() {
return this.adaptiveMode;
}

public int getViewWidth() {
return this.viewWidth;
}

public void setWidthChangedConsumer(Consumer<Integer> consumer) {
this.widthChangedConsumer = consumer;
}

@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);

this.viewWidth = w;

if (!adaptiveMode.equals("CONTAINER") || widthChangedConsumer == null || w == oldw) {
return;
}

widthChangedConsumer.accept(viewWidth);
}
}
4 changes: 4 additions & 0 deletions ios/RNGoogleMobileAds/RNGoogleMobileAdsBannerComponent.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,17 @@

@interface RNGoogleMobileAdsBannerComponent : RCTView <GADBannerViewDelegate, GADAppEventDelegate>

@property CGFloat viewWidth;

@property GADBannerView *banner;
@property(nonatomic, assign) BOOL requested;

@property(nonatomic, copy) NSArray *rawSizes;
@property(nonatomic, copy) NSArray *sizes;
@property(nonatomic, copy) NSString *unitId;
@property(nonatomic, copy) NSDictionary *request;
@property(nonatomic, copy) NSNumber *manualImpressionsEnabled;
@property(nonatomic, copy) NSString *adaptiveMode;
@property(nonatomic, assign) BOOL propsChanged;

@property(nonatomic, copy) RCTBubblingEventBlock onNativeEvent;
Expand Down
Loading

0 comments on commit e0e4866

Please sign in to comment.