diff --git a/docs/modules/admob.md b/docs/modules/admob.md index c18d4ffe..1c2b6b11 100644 --- a/docs/modules/admob.md +++ b/docs/modules/admob.md @@ -282,7 +282,7 @@ adverts (e.g. Interstitial) they're available via the `on` method. ##### onAdLoaded(config: `Object`) !> The config is not provided for Interstitial or Rewarded Video adverts. -On successful response from the AdMob servers. +On successful response from the AdMob servers. This is also called when a new banner is automatically loaded from the AdMob servers if the current one expires. Returns an object of config data related to the loaded advert: ```js diff --git a/ios/RNFirebase/admob/BannerComponent.h b/ios/RNFirebase/admob/BannerComponent.h index 4924fbe1..d9df7a0d 100644 --- a/ios/RNFirebase/admob/BannerComponent.h +++ b/ios/RNFirebase/admob/BannerComponent.h @@ -21,7 +21,7 @@ @end #else -@interface RNFirebaseAdMobBanner : NSObject { +@interface BannerComponent : NSObject { } @end diff --git a/ios/RNFirebase/admob/NativeExpressComponent.h b/ios/RNFirebase/admob/NativeExpressComponent.h new file mode 100644 index 00000000..0e0b16eb --- /dev/null +++ b/ios/RNFirebase/admob/NativeExpressComponent.h @@ -0,0 +1,31 @@ +#import +#import + +#if __has_include() + +#import "GoogleMobileAds/GADNativeExpressAdView.h" +#import "GoogleMobileAds/GADVideoControllerDelegate.h" + +@interface NativeExpressComponent : UIView + +@property GADNativeExpressAdView *banner; +//@property(nonatomic, weak) IBOutlet GADNativeExpressAdView *banner; +@property (nonatomic, assign) BOOL requested; + +@property (nonatomic, copy) NSString *size; +@property (nonatomic, copy) NSString *unitId; +@property (nonatomic, copy) NSDictionary *request; +@property (nonatomic, copy) NSDictionary *video; + +@property (nonatomic, copy) RCTBubblingEventBlock onBannerEvent; + +- (void)requestAd; + +@end +#else + +@interface NativeExpressComponent : NSObject { +} +@end + +#endif diff --git a/ios/RNFirebase/admob/NativeExpressComponent.m b/ios/RNFirebase/admob/NativeExpressComponent.m new file mode 100644 index 00000000..6ffaa72b --- /dev/null +++ b/ios/RNFirebase/admob/NativeExpressComponent.m @@ -0,0 +1,96 @@ +#import "NativeExpressComponent.h" +#import "RNFirebaseAdMob.h" +#import "React/UIView+React.h" + +@implementation NativeExpressComponent + +- (void)initBanner:(GADAdSize)adSize { + if (_requested) { + [_banner removeFromSuperview]; + } + _banner = [[GADNativeExpressAdView alloc] initWithAdSize:adSize]; + _banner.rootViewController = [UIApplication sharedApplication].delegate.window.rootViewController; + _banner.delegate = self; + _banner.videoController.delegate = self; +} + +- (void)setUnitId:(NSString *)unitId { + _unitId = unitId; + [self requestAd]; +} + +- (void)setSize:(NSString *)size { + _size = size; + [self requestAd]; +} + +- (void)setRequest:(NSDictionary *)request { + _request = request; + [self requestAd]; +} + +- (void)setVideo:(NSDictionary *)video { + _video = video; + [self requestAd]; +} + +- (void)requestAd { + if (_unitId == nil || _size == nil || _request == nil || _video == nil) { + [self setRequested:NO]; + return; + } + + [self initBanner:[RNFirebaseAdMob stringToAdSize:_size]]; + [self addSubview:_banner]; + + [self sendEvent:@"onSizeChange" payload:@{ + @"width": @(_banner.bounds.size.width), + @"height": @(_banner.bounds.size.height), + }]; + + _banner.adUnitID = _unitId; + [self setRequested:YES]; + [_banner setAdOptions:@[[RNFirebaseAdMob buildVideoOptions:_video]]]; + [_banner loadRequest:[RNFirebaseAdMob buildRequest:_request]]; +} + +- (void)sendEvent:(NSString *)type payload:(NSDictionary *_Nullable)payload { + self.onBannerEvent(@{ + @"type": type, + @"payload": payload != nil ? payload : [NSNull null], + }); +} + +- (void)nativeExpressAdViewDidReceiveAd:(GADNativeExpressAdView *)adView { + [self sendEvent:@"onAdLoaded" payload:@{ + @"width": @(adView.bounds.size.width), + @"height": @(adView.bounds.size.height), + @"hasVideoContent": @(adView.videoController.hasVideoContent), + }]; +} + +- (void)nativeExpressAdView:(nonnull GADNativeExpressAdView *)nativeExpressAdView didFailToReceiveAdWithError:(nonnull GADRequestError *)error { + [self sendEvent:@"onAdFailedToLoad" payload:[RNFirebaseAdMob errorCodeToDictionary:error]]; +} + +- (void)nativeExpressAdViewWillPresentScreen:(GADNativeExpressAdView *)adView { + [self sendEvent:@"onAdOpened" payload:nil]; +} + +- (void)nativeExpressAdViewWillDismissScreen:(GADNativeExpressAdView *)adView { + // not in use +} + +- (void)nativeExpressAdViewDidDismissScreen:(GADNativeExpressAdView *)adView { + [self sendEvent:@"onAdClosed" payload:nil]; +} + +- (void)nativeExpressAdViewWillLeaveApplication:(GADNativeExpressAdView *)adView { + [self sendEvent:@"onAdLeftApplication" payload:nil]; +} + +- (void)videoControllerDidEndVideoPlayback:(GADVideoController *)videoController { + [self sendEvent:@"onVideoEnd" payload:nil]; +} + +@end \ No newline at end of file diff --git a/ios/RNFirebase/admob/RNFirebaseAdMob.h b/ios/RNFirebase/admob/RNFirebaseAdMob.h index 016ed169..6ac1f772 100644 --- a/ios/RNFirebase/admob/RNFirebaseAdMob.h +++ b/ios/RNFirebase/admob/RNFirebaseAdMob.h @@ -17,6 +17,7 @@ @property NSMutableDictionary *rewardedVideos; + (GADRequest *)buildRequest:(NSDictionary *)request; ++ (GADVideoOptions *)buildVideoOptions:(NSDictionary *)options; + (NSDictionary *)errorCodeToDictionary:(NSError *)error; + (GADAdSize)stringToAdSize:(NSString *)value; @end diff --git a/ios/RNFirebase/admob/RNFirebaseAdMob.m b/ios/RNFirebase/admob/RNFirebaseAdMob.m index e778631f..04eaf119 100644 --- a/ios/RNFirebase/admob/RNFirebaseAdMob.m +++ b/ios/RNFirebase/admob/RNFirebaseAdMob.m @@ -88,8 +88,8 @@ RCT_EXPORT_METHOD(rewardedVideoShowAd: if (request[@"keywords"]) builder.keywords = request[@"keywords"]; if (request[@"testDevices"]) { - NSArray * devices = request[@"testDevices"]; - NSMutableArray * testDevices = [[NSMutableArray alloc] init]; + NSArray *devices = request[@"testDevices"]; + NSMutableArray *testDevices = [[NSMutableArray alloc] init]; for (id device in devices) { if ([device isEqual:@"DEVICE_ID_EMULATOR"]) { @@ -117,6 +117,12 @@ RCT_EXPORT_METHOD(rewardedVideoShowAd: return builder; } ++ (GADVideoOptions *)buildVideoOptions:(NSDictionary *)options { + GADVideoOptions *builder = [[GADVideoOptions alloc] init]; + builder.startMuted = (BOOL) options[@"startMuted"]; + return builder; +} + + (NSDictionary *)errorCodeToDictionary:(NSError *)error { NSString *code; NSString *message; @@ -162,6 +168,22 @@ RCT_EXPORT_METHOD(rewardedVideoShowAd: } + (GADAdSize)stringToAdSize:(NSString *)value { + NSError *error = nil; + NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:@"([0-9]+)x([0-9]+)" options:0 error:&error]; + NSArray *matches = [regex matchesInString:value options:0 range:NSMakeRange(0, [value length])]; + + for (NSTextCheckingResult *match in matches) { + NSString *matchText = [value substringWithRange:[match range]]; + if (matchText) { + NSArray *values = [matchText componentsSeparatedByString:@"x"]; + CGFloat width = (CGFloat)[values[0] intValue]; + CGFloat height = (CGFloat)[values[1] intValue]; + return GADAdSizeFromCGSize(CGSizeMake(width, height)); + } + } + + value = [value uppercaseString]; + if ([value isEqualToString:@"BANNER"]) { return kGADAdSizeBanner; } else if ([value isEqualToString:@"LARGE_BANNER"]) { diff --git a/ios/RNFirebase/admob/RNFirebaseAdMobNativeExpressManager.h b/ios/RNFirebase/admob/RNFirebaseAdMobNativeExpressManager.h new file mode 100644 index 00000000..90948041 --- /dev/null +++ b/ios/RNFirebase/admob/RNFirebaseAdMobNativeExpressManager.h @@ -0,0 +1,5 @@ +#import + +@interface RNFirebaseAdMobNativeExpressManager : RCTViewManager + +@end \ No newline at end of file diff --git a/ios/RNFirebase/admob/RNFirebaseAdMobNativeExpressManager.m b/ios/RNFirebase/admob/RNFirebaseAdMobNativeExpressManager.m new file mode 100644 index 00000000..a428cfb7 --- /dev/null +++ b/ios/RNFirebase/admob/RNFirebaseAdMobNativeExpressManager.m @@ -0,0 +1,28 @@ +#import "RNFirebaseAdMobNativeExpressManager.h" +#import "NativeExpressComponent.h" + +@implementation RNFirebaseAdMobNativeExpressManager + +RCT_EXPORT_MODULE(); + +@synthesize bridge = _bridge; + +- (UIView *)view +{ + return [[NativeExpressComponent alloc] init]; +} + +- (dispatch_queue_t)methodQueue +{ + return dispatch_get_main_queue(); +} + + +RCT_EXPORT_VIEW_PROPERTY(size, NSString); +RCT_EXPORT_VIEW_PROPERTY(unitId, NSString); +RCT_EXPORT_VIEW_PROPERTY(request, NSDictionary); +RCT_EXPORT_VIEW_PROPERTY(video, NSDictionary); + +RCT_EXPORT_VIEW_PROPERTY(onBannerEvent, RCTBubblingEventBlock); + +@end \ No newline at end of file diff --git a/lib/modules/admob/NativeExpress.js b/lib/modules/admob/NativeExpress.js index 8da233d4..7c429444 100644 --- a/lib/modules/admob/NativeExpress.js +++ b/lib/modules/admob/NativeExpress.js @@ -1,5 +1,4 @@ import React from 'react'; -import { requireNativeComponent } from 'react-native'; import AdMobComponent from './AdMobComponent'; function NativeExpress({ ...props }) { @@ -14,7 +13,8 @@ function NativeExpress({ ...props }) { NativeExpress.propTypes = AdMobComponent.propTypes; NativeExpress.defaultProps = { - unitId: 'ca-app-pub-3940256099942544/2177258514', + // unitId: 'ca-app-pub-3940256099942544/2177258514', + unitId: 'ca-app-pub-3940256099942544/8897359316', size: 'SMART_BANNER', };