Skip to content

Commit

Permalink
feat: add method to reload banner ad
Browse files Browse the repository at this point in the history
  • Loading branch information
dylancom committed May 21, 2024
1 parent 9eb3b51 commit 2a57487
Show file tree
Hide file tree
Showing 10 changed files with 82 additions and 22 deletions.
8 changes: 8 additions & 0 deletions RNGoogleMobileAdsExample/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,7 @@ class BannerTest implements Test {

constructor(bannerAdSize) {
this.bannerAdSize = bannerAdSize;
this.bannerRef = React.createRef();
}

getPath(): string {
Expand All @@ -206,6 +207,7 @@ class BannerTest implements Test {
return (
<View ref={onMount}>
<BannerAd
ref={this.bannerRef}
unitId={
this.bannerAdSize.includes('ADAPTIVE_BANNER')
? TestIds.ADAPTIVE_BANNER
Expand All @@ -220,6 +222,12 @@ class BannerTest implements Test {
);
}}
/>
<Button
title="reload"
onPress={() => {
this.bannerRef.current?.load();
}}
/>
</View>
);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ public class ReactNativeGoogleMobileAdsBannerAdViewManager
private final String EVENT_SIZE_CHANGE = "onSizeChange";
private final String EVENT_APP_EVENT = "onAppEvent";
private final int COMMAND_ID_RECORD_MANUAL_IMPRESSION = 1;
private final int COMMAND_ID_LOAD = 2;

@Nonnull
@Override
Expand All @@ -85,7 +86,9 @@ public Map<String, Object> getExportedCustomDirectEventTypeConstants() {
@Nullable
@Override
public Map<String, Integer> getCommandsMap() {
return MapBuilder.of("recordManualImpression", COMMAND_ID_RECORD_MANUAL_IMPRESSION);
return MapBuilder.of(
"recordManualImpression", COMMAND_ID_RECORD_MANUAL_IMPRESSION,
"load", COMMAND_ID_LOAD);
}

@Override
Expand All @@ -99,6 +102,10 @@ public void receiveCommand(
if (adView instanceof AdManagerAdView) {
((AdManagerAdView) adView).recordManualImpression();
}
} else if (commandIdInt == COMMAND_ID_LOAD) {
BaseAdView adView = getAdView(reactViewGroup);
AdRequest request = reactViewGroup.getRequest();
adView.loadAd(request);
}
}

Expand Down
8 changes: 5 additions & 3 deletions docs/displaying-ads.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -406,16 +406,16 @@ import { BannerAd, BannerAdSize, TestIds } from 'react-native-google-mobile-ads'
const adUnitId = __DEV__ ? TestIds.ADAPTIVE_BANNER : 'ca-app-pub-xxxxxxxxxxxxx/yyyyyyyyyyyyyy';

function App() {
const bannerRef = useRef<BannerAd>(null);
const appState = useRef(AppState.currentState);
const [key, setKey] = useState(`banner-${Date.now()}`);

// WKWebView can terminate if app is in a "suspended state", resulting in an empty banner when app returns to foreground.
// A Google Mobile Ads Advisor suggests requesting a new ad when the app is foregrounded.
// For more details, see: [https://groups.google.com/g/google-admob-ads-sdk/c/rwBpqOUr8m8]
useEffect(() => {
const subscription = AppState.addEventListener('change', nextAppState => {
if (appState.current.match(/background/) && nextAppState === 'active') {
setKey(`banner-${Date.now()}`);
bannerRef.current?.load();
}
appState.current = nextAppState;
});
Expand All @@ -425,7 +425,9 @@ function App() {
};
}, []);

return <BannerAd key={key} unitId={adUnitId} size={BannerAdSize.ANCHORED_ADAPTIVE_BANNER} />;
return (
<BannerAd ref={bannerRef} unitId={adUnitId} size={BannerAdSize.ANCHORED_ADAPTIVE_BANNER} />
);
}
```
Expand Down
1 change: 1 addition & 0 deletions ios/RNGoogleMobileAds/RNGoogleMobileAdsBannerComponent.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
@property(nonatomic, copy) RCTBubblingEventBlock onNativeEvent;

- (void)requestAd;
- (void)load;
- (void)recordManualImpression;

@end
Expand Down
14 changes: 9 additions & 5 deletions ios/RNGoogleMobileAds/RNGoogleMobileAdsBannerComponent.m
Original file line number Diff line number Diff line change
Expand Up @@ -122,13 +122,17 @@ - (void)requestAd {
typeof(self) strongSelf = weakSelf;
if (strongSelf) {
[strongSelf sendEvent:@"onPaid"
payload:@{
@"value" : value.value,
@"precision" : @(value.precision),
@"currency" : value.currencyCode,
}];
payload:@{
@"value" : value.value,
@"precision" : @(value.precision),
@"currency" : value.currencyCode,
}];
}
};
[self load];
}

- (void)load {
[_banner loadRequest:[RNGoogleMobileAdsCommon buildAdRequest:_request]];
[self sendEvent:@"onSizeChange"
payload:@{
Expand Down
24 changes: 15 additions & 9 deletions ios/RNGoogleMobileAds/RNGoogleMobileAdsBannerView.mm
Original file line number Diff line number Diff line change
Expand Up @@ -146,21 +146,27 @@ - (void)requestAd {
[self addSubview:_banner];
_banner.adUnitID = _unitId;
[self setRequested:YES];
[_banner loadRequest:[RNGoogleMobileAdsCommon buildAdRequest:_request]];
if (_eventEmitter != nullptr) {
std::dynamic_pointer_cast<const facebook::react::RNGoogleMobileAdsBannerViewEventEmitter>(
_eventEmitter)
->onNativeEvent(facebook::react::RNGoogleMobileAdsBannerViewEventEmitter::OnNativeEvent{
.type = "onSizeChange",
.width = _banner.bounds.size.width,
.height = _banner.bounds.size.height});
}
[self load];
}
}

- (void)load {
[_banner loadRequest:[RNGoogleMobileAdsCommon buildAdRequest:_request]];
if (_eventEmitter != nullptr) {
std::dynamic_pointer_cast<const facebook::react::RNGoogleMobileAdsBannerViewEventEmitter>(
_eventEmitter)
->onNativeEvent(facebook::react::RNGoogleMobileAdsBannerViewEventEmitter::OnNativeEvent{
.type = "onSizeChange",
.width = _banner.bounds.size.width,
.height = _banner.bounds.size.height});
}
}

- (void)handleCommand:(const NSString *)commandName args:(const NSArray *)args {
if ([commandName isEqual:@"recordManualImpression"]) {
[self recordManualImpression];
} else if ([commandName isEqual:@"load"]) {
[self load];
}
}

Expand Down
14 changes: 14 additions & 0 deletions ios/RNGoogleMobileAds/RNGoogleMobileAdsBannerViewManager.mm
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,20 @@ @implementation RNGoogleMobileAdsBannerViewManager
#endif
}

RCT_EXPORT_METHOD(load : (nonnull NSNumber *)reactTag) {
#if !TARGET_OS_MACCATALYST
[self.bridge.uiManager
addUIBlock:^(RCTUIManager *uiManager, NSDictionary<NSNumber *, UIView *> *viewRegistry) {
RNGoogleMobileAdsBannerComponent *banner = viewRegistry[reactTag];
if (!banner || ![banner isKindOfClass:[RNGoogleMobileAdsBannerComponent class]]) {
RCTLogError(@"Cannot find NativeView with tag #%@", reactTag);
return;
}
[banner load];
}];
#endif
}

#ifdef RCT_NEW_ARCH_ENABLE

#else
Expand Down
17 changes: 14 additions & 3 deletions src/ads/BannerAd.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,21 @@
*
*/

import React from 'react';
import React, { createRef } from 'react';
import { BannerAdProps } from '../types/BannerAdProps';
import { BaseAd } from './BaseAd';
import GoogleMobileAdsBannerView, { Commands } from './GoogleMobileAdsBannerViewNativeComponent';

export function BannerAd({ size, ...props }: BannerAdProps) {
return <BaseAd sizes={[size]} {...props} />;
export class BannerAd extends React.Component<BannerAdProps> {
private ref = createRef<React.ElementRef<typeof GoogleMobileAdsBannerView>>();

load() {
if (this.ref.current) {
Commands.load(this.ref.current);
}
}

render() {
return <BaseAd ref={this.ref} sizes={[this.props.size]} {...this.props} />;
}
}
6 changes: 6 additions & 0 deletions src/ads/GAMBannerAd.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,12 @@ export class GAMBannerAd extends React.Component<GAMBannerAdProps> {
}
}

load() {
if (this.ref.current) {
Commands.load(this.ref.current);
}
}

render() {
return <BaseAd ref={this.ref} {...this.props} />;
}
Expand Down
3 changes: 2 additions & 1 deletion src/ads/GoogleMobileAdsBannerViewNativeComponent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,11 @@ export type ComponentType = HostComponent<NativeProps>;

interface NativeCommands {
recordManualImpression: (viewRef: React.ElementRef<ComponentType>) => void;
load: (viewRef: React.ElementRef<ComponentType>) => void;
}

export const Commands: NativeCommands = codegenNativeCommands<NativeCommands>({
supportedCommands: ['recordManualImpression'],
supportedCommands: ['recordManualImpression', 'load'],
});

export default codegenNativeComponent<NativeProps>(
Expand Down

0 comments on commit 2a57487

Please sign in to comment.