Skip to content

Commit

Permalink
feat(ios): sdk methods and banners on new architecture
Browse files Browse the repository at this point in the history
  • Loading branch information
dylancom committed Jul 20, 2023
1 parent 2bd1339 commit cdfd151
Show file tree
Hide file tree
Showing 17 changed files with 396 additions and 105 deletions.
14 changes: 14 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,20 @@ React Native Google Mobile Ads is built with three key principals in mind;
- 📄 **Well documented**
- full reference & installation documentation alongside detailed guides and FAQs

## Migrating to the New Architecture Status (backwards compatible)
See [The New Architecture](https://reactnative.dev/docs/the-new-architecture/landing-page)

- **iOS**
- Mobile Ads SDK Methods (Turbo Native Module) 🟢🟢🟢🟢
- Banners (Fabric Native Component) 🟢🟢🟢🟢
- Full Screen Ads (Turbo Native Module) ⚪⚪⚪⚪
- User Messaging Platform (Turbo Native Module) ⚪⚪⚪⚪
- **Android**
- Mobile Ads SDK Methods (Turbo Native Module) ⚪⚪⚪⚪
- Banners (Fabric Native Component) ⚪⚪⚪⚪
- Full Screen Ads (Turbo Native Module) ⚪⚪⚪⚪
- User Messaging Platform (Turbo Native Module) ⚪⚪⚪⚪

## Documentation

- [Installation](https://docs.page/invertase/react-native-google-mobile-ads)
Expand Down
4 changes: 2 additions & 2 deletions RNGoogleMobileAds.podspec
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,11 @@ Pod::Spec.new do |s|
s.source = { :git => "#{package["repository"]["url"]}.git", :tag => "v#{s.version}" }
s.social_media_url = 'http://twitter.com/invertaseio'
s.ios.deployment_target = "10.0"
s.source_files = 'ios/**/*.{h,m,swift}'
s.source_files = "ios/**/*.{h,m,mm,swift}"
s.weak_frameworks = "AppTrackingTransparency"

# React Native dependencies
s.dependency 'React-Core'
install_modules_dependencies(s)

# Other dependencies
if defined?($RNGoogleUmpSDKVersion)
Expand Down
30 changes: 30 additions & 0 deletions ios/RNGoogleMobileAds/RNGoogleMobileAdsBannerView.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// This guard prevent this file to be compiled in the old architecture.
#ifdef RCT_NEW_ARCH_ENABLED
#import <GoogleMobileAds/GADAppEventDelegate.h>
#import <GoogleMobileAds/GADBannerView.h>
#import <GoogleMobileAds/GADBannerViewDelegate.h>
#import <React/RCTViewComponentView.h>
#import <UIKit/UIKit.h>

#ifndef NativeComponentExampleComponentView_h
#define NativeComponentExampleComponentView_h

NS_ASSUME_NONNULL_BEGIN

@interface RNGoogleMobileAdsBannerView
: RCTViewComponentView <GADBannerViewDelegate, GADAppEventDelegate>

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

@property(nonatomic, copy) NSArray *sizes;
@property(nonatomic, copy) NSString *unitId;
@property(nonatomic, copy) NSDictionary *request;
@property(nonatomic, copy) NSNumber *manualImpressionsEnabled;

@end

NS_ASSUME_NONNULL_END

#endif /* NativeComponentExampleComponentView_h */
#endif /* RCT_NEW_ARCH_ENABLED */
196 changes: 196 additions & 0 deletions ios/RNGoogleMobileAds/RNGoogleMobileAdsBannerView.mm
Original file line number Diff line number Diff line change
@@ -0,0 +1,196 @@
// This guard prevent the code from being compiled in the old architecture
#ifdef RCT_NEW_ARCH_ENABLED
#import "RNGoogleMobileAdsBannerView.h"
#import "RNGoogleMobileAdsCommon.h"

#import <react/renderer/components/RNGoogleMobileAdsSpec/ComponentDescriptors.h>
#import <react/renderer/components/RNGoogleMobileAdsSpec/EventEmitters.h>
#import <react/renderer/components/RNGoogleMobileAdsSpec/Props.h>
#import <react/renderer/components/RNGoogleMobileAdsSpec/RCTComponentViewHelpers.h>

#import "RCTFabricComponentsPlugins.h"

using namespace facebook::react;

@interface RNGoogleMobileAdsBannerView () <RCTRNGoogleMobileAdsBannerViewViewProtocol>

@end

@implementation RNGoogleMobileAdsBannerView

+ (ComponentDescriptorProvider)componentDescriptorProvider {
return concreteComponentDescriptorProvider<RNGoogleMobileAdsBannerViewComponentDescriptor>();
}

- (instancetype)initWithFrame:(CGRect)frame {
if (self = [super initWithFrame:frame]) {
static const auto defaultProps = std::make_shared<const RNGoogleMobileAdsBannerViewProps>();
_props = defaultProps;
}

return self;
}

- (void)initBanner:(GADAdSize)adSize {
if (_requested) {
[_banner removeFromSuperview];
}
if ([RNGoogleMobileAdsCommon isAdManagerUnit:_unitId]) {
_banner = [[GAMBannerView alloc] initWithAdSize:adSize];

((GAMBannerView *)_banner).validAdSizes = _sizes;
((GAMBannerView *)_banner).appEventDelegate = self;
((GAMBannerView *)_banner).enableManualImpressions = [_manualImpressionsEnabled boolValue];
} else {
_banner = [[GADBannerView alloc] initWithAdSize:adSize];
}
_banner.rootViewController = [UIApplication sharedApplication].delegate.window.rootViewController;
_banner.delegate = self;
}

- (void)requestAd {
#ifndef __LP64__
return; // prevent crash on 32bit
#endif

if (_unitId == nil || _sizes == nil || _request == nil || _manualImpressionsEnabled == nil) {
[self setRequested:NO];
return;
} else {
[self initBanner:GADAdSizeFromNSValue(_sizes[0])];
[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});
}
}
}

- (void)updateProps:(Props::Shared const &)props oldProps:(Props::Shared const &)oldProps {
const auto &oldViewProps =
*std::static_pointer_cast<RNGoogleMobileAdsBannerViewProps const>(_props);
const auto &newViewProps =
*std::static_pointer_cast<RNGoogleMobileAdsBannerViewProps const>(props);

BOOL propsChanged = false;

if (oldViewProps.unitId != newViewProps.unitId) {
_unitId = [[NSString alloc] initWithUTF8String:newViewProps.unitId.c_str()];
propsChanged = true;
}

if (oldViewProps.sizes != newViewProps.sizes) {
NSMutableArray *adSizes = [NSMutableArray arrayWithCapacity:newViewProps.sizes.size()];
for (auto i = 0; i < newViewProps.sizes.size(); i++) {
NSString *jsonValue = [[NSString alloc] initWithUTF8String:newViewProps.sizes[i].c_str()];
GADAdSize adSize = [RNGoogleMobileAdsCommon stringToAdSize:jsonValue];
if (GADAdSizeEqualToSize(adSize, GADAdSizeInvalid)) {
RCTLogWarn(@"Invalid adSize %@", jsonValue);
} else {
[adSizes addObject:NSValueFromGADAdSize(adSize)];
}
}
_sizes = adSizes;
propsChanged = true;
}

if (_request == nil) {
_request = [NSDictionary dictionary];
}
// if (oldViewProps.request != newViewProps.request) {
// not implemented yet.
// propsChanged = true;
// }

if (_manualImpressionsEnabled == nil) {
_manualImpressionsEnabled = [NSNumber numberWithBool:oldViewProps.manualImpressionsEnabled];
}
if (oldViewProps.manualImpressionsEnabled != newViewProps.manualImpressionsEnabled) {
_manualImpressionsEnabled = [NSNumber numberWithBool:newViewProps.manualImpressionsEnabled];
propsChanged = true;
}

if (propsChanged) {
[self requestAd];
}

[super updateProps:props oldProps:oldProps];
}

Class<RCTComponentViewProtocol> RNGoogleMobileAdsBannerViewCls(void) {
return RNGoogleMobileAdsBannerView.class;
}

- (void)bannerViewDidReceiveAd:(GADBannerView *)bannerView {
if (_eventEmitter != nullptr) {
std::dynamic_pointer_cast<const facebook::react::RNGoogleMobileAdsBannerViewEventEmitter>(
_eventEmitter)
->onNativeEvent(facebook::react::RNGoogleMobileAdsBannerViewEventEmitter::OnNativeEvent{
.type = "onAdLoaded",
.width = bannerView.bounds.size.width,
.height = bannerView.bounds.size.height});
}
}

- (void)bannerView:(GADBannerView *)bannerView didFailToReceiveAdWithError:(NSError *)error {
NSDictionary *errorAndMessage = [RNGoogleMobileAdsCommon getCodeAndMessageFromAdError:error];
if (_eventEmitter != nullptr) {
std::dynamic_pointer_cast<const facebook::react::RNGoogleMobileAdsBannerViewEventEmitter>(
_eventEmitter)
->onNativeEvent(facebook::react::RNGoogleMobileAdsBannerViewEventEmitter::OnNativeEvent{
.type = "onAdFailedToLoad",
.code = std::string([[errorAndMessage valueForKey:@"code"] UTF8String]),
.message = std::string([[errorAndMessage valueForKey:@"message"] UTF8String])});
}
}

- (void)bannerViewWillPresentScreen:(GADBannerView *)bannerView {
if (_eventEmitter != nullptr) {
std::dynamic_pointer_cast<const facebook::react::RNGoogleMobileAdsBannerViewEventEmitter>(
_eventEmitter)
->onNativeEvent(facebook::react::RNGoogleMobileAdsBannerViewEventEmitter::OnNativeEvent{
.type = "onAdOpened"});
}
}

- (void)bannerViewWillDismissScreen:(GADBannerView *)bannerView {
// not in use
}

- (void)bannerViewDidDismissScreen:(GADBannerView *)bannerView {
if (_eventEmitter != nullptr) {
std::dynamic_pointer_cast<const facebook::react::RNGoogleMobileAdsBannerViewEventEmitter>(
_eventEmitter)
->onNativeEvent(facebook::react::RNGoogleMobileAdsBannerViewEventEmitter::OnNativeEvent{
.type = "onAdClosed"});
}
}

- (void)adView:(nonnull GADBannerView *)banner
didReceiveAppEvent:(nonnull NSString *)name
withInfo:(nullable NSString *)info {
if (_eventEmitter != nullptr) {
std::dynamic_pointer_cast<const facebook::react::RNGoogleMobileAdsBannerViewEventEmitter>(
_eventEmitter)
->onNativeEvent(facebook::react::RNGoogleMobileAdsBannerViewEventEmitter::OnNativeEvent{
.type = "onAppEvent",
.name = std::string([name UTF8String]),
.data = std::string([info UTF8String])});
}
}

- (void)recordManualImpression {
if ([_banner class] == [GAMBannerView class]) {
[((GAMBannerView *)_banner) recordImpression];
}
}

@end
#endif
23 changes: 0 additions & 23 deletions ios/RNGoogleMobileAds/RNGoogleMobileAdsBannerViewManager.h

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,16 @@
*
*/

#import "RNGoogleMobileAdsBannerViewManager.h"
#import <React/RCTUIManager.h>
#import <React/RCTViewManager.h>
#ifdef RCT_NEW_ARCH_ENABLE

#else
#import "RNGoogleMobileAdsBannerComponent.h"
#endif

@interface RNGoogleMobileAdsBannerViewManager : RCTViewManager
@end

@implementation RNGoogleMobileAdsBannerViewManager

Expand Down Expand Up @@ -48,6 +55,9 @@ @implementation RNGoogleMobileAdsBannerViewManager
#endif
}

#ifdef RCT_NEW_ARCH_ENABLE

#else
@synthesize bridge = _bridge;

- (UIView *)view {
Expand All @@ -62,5 +72,6 @@ - (UIView *)view {
- (dispatch_queue_t)methodQueue {
return dispatch_get_main_queue();
}
#endif

@end
2 changes: 1 addition & 1 deletion ios/RNGoogleMobileAds/RNGoogleMobileAdsCommon.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@

#if !TARGET_OS_MACCATALYST

#import <GoogleMobileAds/GoogleMobileAds.h>
#import <React/RCTBridgeModule.h>
@import GoogleMobileAds;

@interface RNGoogleMobileAdsCommon : NSObject

Expand Down
10 changes: 9 additions & 1 deletion ios/RNGoogleMobileAds/RNGoogleMobileAdsModule.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,16 @@

#import <Foundation/Foundation.h>

#import <React/RCTBridgeModule.h>
#ifdef RCT_NEW_ARCH_ENABLED

#import <RNGoogleMobileAdsSpec/RNGoogleMobileAdsSpec.h>
@interface RNGoogleMobileAdsModule : NSObject <NativeGoogleMobileAdsModuleSpec>

#else

#import <React/RCTBridgeModule.h>
@interface RNGoogleMobileAdsModule : NSObject <RCTBridgeModule>

#endif

@end
Loading

0 comments on commit cdfd151

Please sign in to comment.