diff --git a/android/src/main/java/com/ammarahmed/rnadmob/nativeads/EventEmitter.java b/android/src/main/java/com/ammarahmed/rnadmob/nativeads/EventEmitter.java index c4f2cd8..cf765c6 100644 --- a/android/src/main/java/com/ammarahmed/rnadmob/nativeads/EventEmitter.java +++ b/android/src/main/java/com/ammarahmed/rnadmob/nativeads/EventEmitter.java @@ -2,6 +2,7 @@ import androidx.annotation.Nullable; +import com.facebook.react.bridge.Arguments; import com.facebook.react.bridge.ReactContext; import com.facebook.react.bridge.WritableMap; import com.facebook.react.modules.core.DeviceEventManagerModule; @@ -9,7 +10,7 @@ public class EventEmitter { public static void sendEvent(ReactContext reactContext, String eventName, @Nullable WritableMap params) { - reactContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class).emit(eventName, params); + reactContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class).emit(eventName, params != null ? params : Arguments.createMap()); } } \ No newline at end of file diff --git a/android/src/main/java/com/ammarahmed/rnadmob/nativeads/RNAdMobUnifiedAdQueueWrapper.java b/android/src/main/java/com/ammarahmed/rnadmob/nativeads/RNAdMobUnifiedAdQueueWrapper.java index c207f56..4bf4b57 100644 --- a/android/src/main/java/com/ammarahmed/rnadmob/nativeads/RNAdMobUnifiedAdQueueWrapper.java +++ b/android/src/main/java/com/ammarahmed/rnadmob/nativeads/RNAdMobUnifiedAdQueueWrapper.java @@ -81,19 +81,20 @@ public void onAdFailedToLoad(LoadAdError adError) { error.putInt("code", adError.getCode()); error.putString("domain", adError.getDomain()); event.putMap("error", error); - EventEmitter.sendEvent((ReactContext) mContext, CacheManager.EVENT_AD_PRELOAD_ERROR + ":" + name, event); + + EventEmitter.sendEvent(mContext, CacheManager.EVENT_AD_PRELOAD_ERROR + ":" + name, event); notifyOnAdsLoadFailed(adError); return; } if (retryCount >= totalRetryCount) { - WritableMap event = Arguments.createMap(); + WritableMap event = getDefaultEventData(); WritableMap error = Arguments.createMap(); error.putString("message", "reach maximum retry"); error.putInt("code", AdRequest.ERROR_CODE_INTERNAL_ERROR); error.putString("domain", ""); event.putMap("error", error); - EventEmitter.sendEvent((ReactContext) mContext, CacheManager.EVENT_AD_PRELOAD_ERROR + ":" + name, event); + EventEmitter.sendEvent( mContext, CacheManager.EVENT_AD_PRELOAD_ERROR + ":" + name, event); notifyOnAdsLoadFailed(adError); return; } @@ -110,29 +111,29 @@ public void run() { @Override public void onAdImpression() { super.onAdImpression(); - EventEmitter.sendEvent((ReactContext) mContext, CacheManager.EVENT_AD_IMPRESSION + ":" + name, null); + EventEmitter.sendEvent(mContext, CacheManager.EVENT_AD_IMPRESSION + ":" + name, getDefaultEventData()); } @Override public void onAdClosed() { super.onAdClosed(); - EventEmitter.sendEvent((ReactContext) mContext, CacheManager.EVENT_AD_CLOSED + ":" + name, null); + WritableMap map = Arguments.createMap(); + EventEmitter.sendEvent(mContext, CacheManager.EVENT_AD_CLOSED + ":" + name, getDefaultEventData()); } @Override public void onAdOpened() { super.onAdOpened(); - EventEmitter.sendEvent((ReactContext) mContext, CacheManager.EVENT_AD_OPEN + ":" + name, null); + EventEmitter.sendEvent(mContext, CacheManager.EVENT_AD_OPEN + ":" + name, getDefaultEventData()); } @Override public void onAdClicked() { super.onAdClicked(); - Log.d("RNADMOB", CacheManager.EVENT_AD_CLICKED + ":" + name); - EventEmitter.sendEvent((ReactContext) mContext, CacheManager.EVENT_AD_CLICKED + ":" + name, null); + EventEmitter.sendEvent(mContext, CacheManager.EVENT_AD_CLICKED + ":" + name, getDefaultEventData()); } @@ -140,6 +141,8 @@ public void onAdClicked() { public void onAdLoaded() { super.onAdLoaded(); + EventEmitter.sendEvent(mContext, CacheManager.EVENT_AD_PRELOAD_LOADED + ":" + name, getDefaultEventData()); + retryCount = 0; if (mediation) { loadingAdRequestCount--; @@ -154,7 +157,13 @@ public void onAdLoaded() { }; setConfiguration(config); + } + private WritableMap getDefaultEventData() { + WritableMap map = Arguments.createMap(); + map.putString("adUnitId", adUnitId); + map.putString("repo", name); + return map; } private void notifyOnAdsLoadFailed(LoadAdError adError){ diff --git a/android/src/main/java/com/ammarahmed/rnadmob/nativeads/RNAdmobNativeView.java b/android/src/main/java/com/ammarahmed/rnadmob/nativeads/RNAdmobNativeView.java index bcfe78f..36ec72e 100644 --- a/android/src/main/java/com/ammarahmed/rnadmob/nativeads/RNAdmobNativeView.java +++ b/android/src/main/java/com/ammarahmed/rnadmob/nativeads/RNAdmobNativeView.java @@ -1,11 +1,9 @@ package com.ammarahmed.rnadmob.nativeads; import android.content.Context; -import android.graphics.Color; import android.os.Handler; import android.view.LayoutInflater; import android.view.View; -import android.view.ViewGroup; import android.widget.LinearLayout; import androidx.annotation.NonNull; @@ -18,7 +16,6 @@ import com.facebook.react.bridge.WritableArray; import com.facebook.react.bridge.WritableMap; import com.facebook.react.bridge.WritableNativeArray; -import com.facebook.react.bridge.WritableNativeMap; import com.facebook.react.uimanager.events.RCTEventEmitter; import com.google.android.gms.ads.AdListener; import com.google.android.gms.ads.AdLoader; @@ -26,7 +23,6 @@ import com.google.android.gms.ads.MediaContent; import com.google.android.gms.ads.VideoOptions; import com.google.android.gms.ads.admanager.AdManagerAdRequest; -import com.google.android.gms.ads.nativead.AdChoicesView; import com.google.android.gms.ads.nativead.MediaView; import com.google.android.gms.ads.nativead.NativeAd; import com.google.android.gms.ads.nativead.NativeAdOptions; @@ -67,7 +63,6 @@ public class RNAdmobNativeView extends LinearLayout { private Handler handler; AdListener adListener = new AdListener() { - @Override public void onAdFailedToLoad(@NonNull LoadAdError loadAdError) { super.onAdFailedToLoad(loadAdError); @@ -126,11 +121,6 @@ public void onNativeAdLoaded(NativeAd ad) { if (nativeAd != null) { nativeAd.destroy(); } - - if (ad != null) { - nativeAd = ad; - setNativeAd(); - } loadingAd = false; setNativeAdToJS(ad); } @@ -185,9 +175,10 @@ private Method getDeclaredMethod(Object obj, String name) { return null; } - private void setNativeAdToJS(NativeAd nativeAd) { - + private void setNativeAdToJS(NativeAd ad) { try { + nativeAd = ad; + setNativeAd(); WritableMap args = Arguments.createMap(); args.putString("headline", nativeAd.getHeadline()); args.putString("tagline", nativeAd.getBody()); @@ -307,12 +298,13 @@ private void getAdFromRepository() { unifiedNativeAdContainer = CacheManager.instance.getNativeAd(adRepo); if (unifiedNativeAdContainer != null) { + if (nativeAd != null) { + nativeAd.destroy(); + } nativeAd = unifiedNativeAdContainer.unifiedNativeAd; - nativeAdView.setNativeAd(nativeAd); if (mediaView != null) { nativeAdView.setMediaView(mediaView); mediaView.requestLayout(); - setNativeAd(); } setNativeAdToJS(nativeAd); } @@ -394,6 +386,9 @@ public void setNativeAd() { mediaView.setMedia(nativeAd.getMediaContent()); } } + handler.postDelayed(() -> { + nativeAdView.getRootView().requestLayout(); + }, 1000); } } diff --git a/example/App.js b/example/App.js index 8f1dcaa..4242ab2 100644 --- a/example/App.js +++ b/example/App.js @@ -16,7 +16,10 @@ import List from "./src/List"; import { routes } from "./src/utils"; import Icon from "react-native-vector-icons/MaterialCommunityIcons"; const App = () => { - const [currentRoute, setCurrentRoute] = useState(null); + const [currentRoute, setCurrentRoute] = useState({ + type: "banner", + index: 0 + }); const [loading, setLoading] = useState(true); useEffect(() => { diff --git a/example/index.js b/example/index.js index 338874e..0cfb86a 100644 --- a/example/index.js +++ b/example/index.js @@ -50,12 +50,12 @@ AdManager.registerRepository({ console.log('registered: ', result); }); -AdManager.subscribe('imageAd', 'onAdPreloadClicked', () => { - console.log('click', 'imageAd'); +AdManager.subscribe('imageAd', 'onAdPreloadClicked', (event) => { + console.log('click', 'imageAd', event); }); -AdManager.subscribe("imageAd", "onAdPreloadImpression", () => { - console.log('impression recorded', 'imageAd'); +AdManager.subscribe("imageAd", "onAdPreloadImpression", (event) => { + console.log('impression recorded', 'imageAd', event); }); AppRegistry.registerComponent(appName, () => App); diff --git a/example/src/AdView.js b/example/src/AdView.js index 76add5c..8becd18 100644 --- a/example/src/AdView.js +++ b/example/src/AdView.js @@ -1,10 +1,9 @@ -import React, {useCallback, useEffect, useRef, useState} from 'react'; +import React, { useEffect, useRef, useState } from 'react'; import { ActivityIndicator, - DeviceEventEmitter, Platform, Text, - View, + View } from 'react-native'; import NativeAdView, { AdvertiserView, @@ -13,11 +12,10 @@ import NativeAdView, { IconView, StarRatingView, StoreView, - TaglineView, - TestIds, + TaglineView } from 'react-native-admob-native-ads'; -import {MediaView} from './MediaView'; -import {Events, Logger} from './utils'; +import { MediaView } from './MediaView'; +import { Logger } from './utils'; export const AdView = React.memo(({index, media, type, loadOnMount = true}) => { const [aspectRatio, setAspectRatio] = useState(1.5); @@ -101,8 +99,8 @@ export const AdView = React.memo(({index, media, type, loadOnMount = true}) => { mediationOptions={{ nativeBanner: true, }} - adUnitID={type === 'image' ? TestIds.Image : TestIds.Video} // REPLACE WITH NATIVE_AD_VIDEO_ID for video ads. - // repository={type === 'image' ? 'imageAd' : 'videoAd'} + // adUnitID={type === 'image' ? TestIds.Image : TestIds.Video} // REPLACE WITH NATIVE_AD_VIDEO_ID for video ads. + repository={type === 'image' ? 'imageAd' : 'videoAd'} > & @@ -255,8 +255,8 @@ type NativeAdViewProps = { targetingOptions?: TargetingOptions; enableSwipeGestureOptions: { tapsAllowed?: boolean; - swipeGestureDirection?: "right" | "left" | "up" | "down"; - } + swipeGestureDirection?: "right" | "left" | "up" | "down"; + }; testDevices?: Array; onAdOpened?: () => void; @@ -267,7 +267,6 @@ type NativeAdViewProps = { onAdLoaded?: () => void; onNativeAdLoaded?: (event: NativeAd) => void; onAdFailedToLoad?: (error: { message: string }) => void; - adBadgeProps: NestedTextProps }; type SimpleViewProps = { @@ -415,11 +414,19 @@ declare module "react-native-admob-native-ads" { | "onAdPreloadClosed" | "onAdPreloadClicked" | "onAdPreloadImpression", - listener + listener: (event: { + adUnitId: string; + repo: string; + error?: { + message: string; + code: number; + domain: string; + }; + }) => void ) => EmitterSubscription; openAdInspector: () => void; - openDebugMenu: (adUnitId: string) => void + openDebugMenu: (adUnitId: string) => void; }; export const AdOptions: options; diff --git a/ios/RNAdMobManager/EventEmitter.m b/ios/RNAdMobManager/EventEmitter.m index 5d48bb2..125b52a 100644 --- a/ios/RNAdMobManager/EventEmitter.m +++ b/ios/RNAdMobManager/EventEmitter.m @@ -53,7 +53,7 @@ - (void)sendEvent:(NSString *) name dict:(NSDictionary *)dict { if (hasListeners) { // Only send events if anyone is listening - [self sendEventWithName:name body:dict]; + [self sendEventWithName:name body:dict ? dict : [NSDictionary dictionary]]; } } @end diff --git a/ios/RNAdMobManager/RNAdMobUnifiedAdQueueWrapper.m b/ios/RNAdMobManager/RNAdMobUnifiedAdQueueWrapper.m index fedcaab..f3b84bf 100644 --- a/ios/RNAdMobManager/RNAdMobUnifiedAdQueueWrapper.m +++ b/ios/RNAdMobManager/RNAdMobUnifiedAdQueueWrapper.m @@ -19,12 +19,13 @@ @implementation RNAdMobUnifiedAdQueueWrapper{ GADAdLoader* adLoader; GAMRequest* adRequest; - + NSMutableSet>* attachedAdListeners; UnifiedNativeAdLoadedListener* unifiedNativeAdLoadedListener; GADVideoOptions* adVideoOptions; GADNativeAdMediaAdLoaderOptions* adMediaOptions; GADNativeAdViewAdOptions* adPlacementOptions; + GADNativeAdCustomClickGestureOptions *clickGestureOptions; NSDictionary* targetingOptions; int loadingAdRequestCount; int retryDelay; @@ -45,10 +46,10 @@ -(instancetype)initWithConfig:(NSDictionary *)config repo:(NSString *)repo{ adVideoOptions = [[GADVideoOptions alloc]init]; adMediaOptions = [[GADNativeAdMediaAdLoaderOptions alloc] init]; adPlacementOptions = [[GADNativeAdViewAdOptions alloc]init]; - + attachedAdListeners = [[NSMutableSet> alloc] init]; } - + //Set repository settings _adUnitId = [config objectForKey:@"adUnitId"] ; _name = repo; @@ -58,21 +59,21 @@ -(instancetype)initWithConfig:(NSDictionary *)config repo:(NSString *)repo{ if ([config objectForKey:@"totalRetryCount"]){ totalRetryCount = ((NSNumber *)[config objectForKey:@"totalRetryCount"]).boolValue; } - + if ([config objectForKey:@"retryDelay"]){ retryDelay = ((NSNumber *)[config objectForKey:@"retryDelay"]).boolValue; } - + _nativeAds = [[NSMutableArray alloc]init]; - + if ([config objectForKey:@"expirationPeriod"]){ _expirationInterval = ((NSNumber *)[config objectForKey:@"expirationPeriod"]).intValue; } if ([config objectForKey:@"mediationEnabled"]){ _isMediationEnabled = ((NSNumber *)[config objectForKey:@"mediationEnabled"]).boolValue; } - - + + //Set request options if ([config objectForKey:@"adChoicesPlacement"]){ [adPlacementOptions setPreferredAdChoicesPosition:((NSNumber *)[config objectForKey:@"adChoicesPlacement"]).intValue]; @@ -80,7 +81,7 @@ -(instancetype)initWithConfig:(NSDictionary *)config repo:(NSString *)repo{ if ([config objectForKey:@"mediaAspectRatio"]){ [adMediaOptions setMediaAspectRatio:((NSNumber *)[config objectForKey:@"mediaAspectRatio"]).intValue]; } - + if ([config objectForKey:@"videoOptions"]){ [self configVideoOptions:[config objectForKey:@"videoOptions"]]; } @@ -90,15 +91,38 @@ -(instancetype)initWithConfig:(NSDictionary *)config repo:(NSString *)repo{ if ([config objectForKey:@"targetingOptions"]){ [self configTargetOptions:[config objectForKey:@"targetingOptions"]]; } - - + + if ([config valueForKey:@"swipeGestureDirection"]) { + + clickGestureOptions = [[GADNativeAdCustomClickGestureOptions alloc] initWithSwipeGestureDirection:UISwipeGestureRecognizerDirectionUp tapsAllowed:false]; + + int direction = ((NSNumber *)[config objectForKey:@"swipeGestureDirection"]).intValue; + + if (direction == 1) { + [clickGestureOptions setSwipeGestureDirection:UISwipeGestureRecognizerDirectionRight]; + } else if (direction == 2) { + [clickGestureOptions setSwipeGestureDirection:UISwipeGestureRecognizerDirectionLeft]; + } else if (direction == 4) { + [clickGestureOptions setSwipeGestureDirection:UISwipeGestureRecognizerDirectionUp]; + } else if (direction == 8) { + [clickGestureOptions setSwipeGestureDirection:UISwipeGestureRecognizerDirectionDown]; + } + + if ([config valueForKey:@"tapsAllowed"]) { + [clickGestureOptions setTapsAllowed:[config valueForKey:@"tapsAllowed"]]; + } + } + + + + if ([config objectForKey:@"requestNonPersonalizedAdsOnly"]){ GADCustomEventExtras *extras = [[GADCustomEventExtras alloc] init]; bool npa = ((NSNumber *)[config objectForKey:@"requestNonPersonalizedAdsOnly"]).boolValue; [extras setExtras:@{@"npa": @([NSNumber numberWithInt:npa].intValue)} forLabel:@"npa"]; [adRequest registerAdNetworkExtras:extras]; } - + unifiedNativeAdLoadedListener = [[UnifiedNativeAdLoadedListener alloc]initWithRepo:repo nativeAds:_nativeAds tAds:_totalAds]; return self; } @@ -114,14 +138,19 @@ -(void) detachAdListener:(id) listener{ if use mediation,you can't use GADMultipleAdsAdLoaderOptions for load ads */ -(void) fillAds{ - + int require2fill = _totalAds-((int)_nativeAds.count); - + if ( [self isLoading] || require2fill<=0){ return; } + NSMutableArray* options = [NSMutableArray arrayWithArray:@[adMediaOptions,adVideoOptions,adPlacementOptions]]; - + + if (clickGestureOptions) { + [options addObject:clickGestureOptions]; + } + if (!_isMediationEnabled) { GADMultipleAdsAdLoaderOptions* multipleAdsOptions = [[GADMultipleAdsAdLoaderOptions alloc] init]; multipleAdsOptions.numberOfAds = MAX(require2fill,0); @@ -129,7 +158,7 @@ -(void) fillAds{ } adLoader = [[GADAdLoader alloc] initWithAdUnitID:_adUnitId rootViewController:nil adTypes:@[GADAdLoaderAdTypeNative] options:options]; [adLoader setDelegate:self]; - + loadingAdRequestCount = require2fill; if(_isMediationEnabled){ printf("admob request count:",MIN(require2fill,5)); @@ -144,14 +173,14 @@ -(void) fillAds{ -(RNAdMobUnifiedAdContainer*) getAd{ long long now = (long long)([[NSDate date] timeIntervalSince1970] * 1000.0); RNAdMobUnifiedAdContainer *ad = nil; - + if (!(_nativeAds.count == 0)){ //sortAds [_nativeAds sortUsingComparator:^NSComparisonResult(id _Nonnull obj1, id _Nonnull obj2) { return [obj1 compareTo:obj2] > 0; //find lowest showCount }]; - + NSMutableArray *discardedItems = [NSMutableArray array]; for (RNAdMobUnifiedAdContainer *item in self.nativeAds) { if (item != nil && (now - item.loadTime) < _expirationInterval) { @@ -188,46 +217,53 @@ - (void)adLoader:(nonnull GADAdLoader *)adLoader didReceiveNativeAd:(nonnull GAD loadingAdRequestCount--; retryCount = 0; [unifiedNativeAdLoadedListener adLoader:adLoader didReceiveNativeAd:nativeAd]; - + //to prevent a crash (check the link below), first copy attachedAdListeners into a new array //link:https://stackoverflow.com/questions/44648610/collection-nsarraym-was-mutated-while-being-enumerated for (id listener in [attachedAdListeners copy]){ [listener didAdLoaded:nativeAd]; } - [EventEmitter.sharedInstance sendEvent:[CacheManager EVENT_AD_PRELOAD_LOADED:_name] dict:nil]; - + [EventEmitter.sharedInstance sendEvent:[CacheManager EVENT_AD_PRELOAD_LOADED:_name] dict:[self getDefaultEventData]]; + if (loadingAdRequestCount == 0){ [self fillAds];//fill up repository if need } // The adLoader has finished loading ads, and a new request can be sent. } +- (NSMutableDictionary *)getDefaultEventData { + NSMutableDictionary *dict = [NSMutableDictionary dictionary]; + [dict setValue:@"adUnitId" forKey:_adUnitId]; + [dict setValue:@"repo" forKey:_name]; + return dict; +} + - (void)nativeAdDidRecordClick:(GADNativeAd *)nativeAd { - [EventEmitter.sharedInstance sendEvent:[CacheManager EVENT_AD_CLICKED:_name] dict:nil]; + [EventEmitter.sharedInstance sendEvent:[CacheManager EVENT_AD_CLICKED:_name] dict:[self getDefaultEventData]]; } - (void)nativeAdDidRecordImpression:(GADNativeAd *)nativeAd { - [EventEmitter.sharedInstance sendEvent:[CacheManager EVENT_AD_IMPRESSION:_name] dict:nil]; + [EventEmitter.sharedInstance sendEvent:[CacheManager EVENT_AD_IMPRESSION:_name] dict:[self getDefaultEventData]]; } - (void)nativeAdWillPresentScreen:(GADNativeAd *)nativeAd { - [EventEmitter.sharedInstance sendEvent:[CacheManager EVENT_AD_OPEN:_name] dict:nil]; + [EventEmitter.sharedInstance sendEvent:[CacheManager EVENT_AD_OPEN:_name] dict:[self getDefaultEventData]]; } - (void)nativeAdDidDismissScreen:(GADNativeAd *)nativeAd { - [EventEmitter.sharedInstance sendEvent:[CacheManager EVENT_AD_CLOSED:_name] dict:nil]; + [EventEmitter.sharedInstance sendEvent:[CacheManager EVENT_AD_CLOSED:_name] dict:[self getDefaultEventData]]; } - (void)adLoader:(nonnull GADAdLoader *)adLoader didFailToReceiveAdWithError:(nonnull NSError *)error { - if(_isMediationEnabled){ - loadingAdRequestCount--; - }else{ - loadingAdRequestCount = 0; - } - + if(_isMediationEnabled){ + loadingAdRequestCount--; + }else{ + loadingAdRequestCount = 0; + } + [unifiedNativeAdLoadedListener adLoader:adLoader didFailToReceiveAdWithError:error]; - - + + BOOL stopPreloading = false; switch (error.code) { case GADErrorInternalError: @@ -235,42 +271,47 @@ - (void)adLoader:(nonnull GADAdLoader *)adLoader didFailToReceiveAdWithError:(no stopPreloading = true; break; } - + if (stopPreloading) { + NSDictionary *errorDic = @{ - @"domain":error.domain, - @"message":error.localizedDescription, - @"code":@(error.code).stringValue - }; - NSDictionary *event = @{ - @"error":errorDic, - }; - - [EventEmitter.sharedInstance sendEvent:[CacheManager EVENT_AD_PRELOAD_ERROR:_name] dict:event]; + @"domain":error.domain, + @"message":error.localizedDescription, + @"code":@(error.code).stringValue + }; + + NSMutableDictionary *dict = [self getDefaultEventData]; + [dict addEntriesFromDictionary:@{ + @"error":errorDic, + }]; + + [EventEmitter.sharedInstance sendEvent:[CacheManager EVENT_AD_PRELOAD_ERROR:_name] dict:dict]; - for (id listener in [attachedAdListeners copy]){ - [listener didFailToReceiveAdWithError:error]; - } - return; + for (id listener in [attachedAdListeners copy]){ + [listener didFailToReceiveAdWithError:error]; + } + return; } - + if (retryCount >= totalRetryCount){ NSDictionary *errorDic = @{ - @"domain":@"", - @"message":@"reach max retry", - @"code":@"" - }; - NSDictionary *event = @{ - @"error":errorDic, - }; - [EventEmitter.sharedInstance sendEvent:[CacheManager EVENT_AD_PRELOAD_ERROR:_name] dict:event]; + @"domain":@"", + @"message":@"reach max retry", + @"code":@"" + }; + NSMutableDictionary *dict = [self getDefaultEventData]; + [dict addEntriesFromDictionary:@{ + @"error":errorDic, + }]; + + [EventEmitter.sharedInstance sendEvent:[CacheManager EVENT_AD_PRELOAD_ERROR:_name] dict:dict]; for (id listener in [attachedAdListeners copy]){ - [listener didFailToReceiveAdWithError:error]; - } + [listener didFailToReceiveAdWithError:error]; + } return; } - - + + if (loadingAdRequestCount == 0) { retryCount++; __weak typeof(self) weakSelf = self; @@ -279,21 +320,21 @@ - (void)adLoader:(nonnull GADAdLoader *)adLoader didFailToReceiveAdWithError:(no [weakSelf fillAds]; }); } - + } -(void)configVideoOptions:(NSDictionary *)config{ - + if ([config objectForKey:@"mute"]) { bool muted = ((NSNumber *)[config objectForKey:@"mute"]).boolValue; [adVideoOptions setStartMuted:muted]; } - + if ([config objectForKey:@"clickToExpand"]) { bool clickToExpand = ((NSNumber *)[config objectForKey:@"clickToExpand"]).boolValue; [adVideoOptions setClickToExpandRequested:clickToExpand]; } - + if ([config objectForKey:@"customControlsRequested"]) { bool customControlsRequested = ((NSNumber *)[config objectForKey:@"customControlsRequested"]).boolValue; [adVideoOptions setCustomControlsRequested:customControlsRequested]; @@ -301,20 +342,20 @@ -(void)configVideoOptions:(NSDictionary *)config{ } -(void)configTargetOptions:(NSDictionary *)config{ - + if ([config objectForKey:@"targets"]){ NSArray* targets = (NSArray *)[config objectForKey:@"targets"]; for (NSDictionary* target in targets){ - [adRequest setCustomTargeting:target]; + [adRequest setCustomTargeting:target]; } - + if ([config objectForKey:@"categoryExclusions"]){ [adRequest setCategoryExclusions:(NSArray *)[config objectForKey:@"categoryExclusions"]]; } if ([config objectForKey:@"publisherId"]){ [adRequest setPublisherProvidedID:(NSString *)[config objectForKey:@"publisherId"]]; } - + if ([config objectForKey:@"requestAgent"]){ [adRequest setRequestAgent:(NSString *)[config objectForKey:@"requestAgent"]]; } @@ -327,23 +368,23 @@ -(void)configTargetOptions:(NSDictionary *)config{ if ([config objectForKey:@"neighboringContentUrls"]){ [adRequest setNeighboringContentURLStrings:(NSArray *)[config objectForKey:@"neighboringContentUrls"]]; } - + } } -(void)configMediationOptions:(NSDictionary *)config{ #ifdef MEDIATION_FACEBOOK - GADFBNetworkExtras * extras = [[GADFBNetworkExtras alloc] init]; - - if ([config valueForKey:@"nativeBanner"]) { - extras.nativeAdFormat = GADFBAdFormatNative; - } else { - extras.nativeAdFormat = GADFBAdFormatNativeBanner; - } - - [adRequest registerAdNetworkExtras:extras]; + GADFBNetworkExtras * extras = [[GADFBNetworkExtras alloc] init]; + + if ([config valueForKey:@"nativeBanner"]) { + extras.nativeAdFormat = GADFBAdFormatNative; + } else { + extras.nativeAdFormat = GADFBAdFormatNativeBanner; + } + + [adRequest registerAdNetworkExtras:extras]; #endif - + } @end diff --git a/ios/RNAdMobManager/RNGADMediaView.m b/ios/RNAdMobManager/RNGADMediaView.m index cc973a1..14c82b8 100644 --- a/ios/RNAdMobManager/RNGADMediaView.m +++ b/ios/RNAdMobManager/RNGADMediaView.m @@ -59,6 +59,8 @@ - (void)videoControllerDidEndVideoPlayback:(GADVideoController *)videoController } } + + - (void)getCurrentProgress { diff --git a/ios/RNAdMobManager/RNGADNativeView.h b/ios/RNAdMobManager/RNGADNativeView.h index 357769f..95c2d93 100755 --- a/ios/RNAdMobManager/RNGADNativeView.h +++ b/ios/RNAdMobManager/RNGADNativeView.h @@ -32,6 +32,7 @@ GADNativeAdDelegate> @property (nonatomic, copy) NSDictionary *mediationOptions; @property (nonatomic, copy) NSDictionary *targetingOptions; @property (nonatomic, copy) NSDictionary *videoOptions; +@property (nonatomic, copy) NSDictionary *enableSwipeGestureOptions; - (instancetype)initWithBridge:(RCTBridge *)bridge; diff --git a/ios/RNAdMobManager/RNGADNativeView.m b/ios/RNAdMobManager/RNGADNativeView.m index a651998..3ce8a5d 100755 --- a/ios/RNAdMobManager/RNGADNativeView.m +++ b/ios/RNAdMobManager/RNGADNativeView.m @@ -40,7 +40,7 @@ @implementation RNGADNativeView : GADNativeAdView GADNativeAdViewAdOptions *adPlacementOptions; GADNativeAdMediaAdLoaderOptions *adMediaOptions; - +GADNativeAdCustomClickGestureOptions *clickGestureOptions; GAMRequest *adRequest; GADVideoOptions *adVideoOptions; @@ -79,6 +79,29 @@ - (void) willMoveToSuperview: (UIView *) newSuperview{ } } +- (void) setEnableSwipeGestureOptions:(NSDictionary *)enableSwipeGestureOptions { + + clickGestureOptions = [[GADNativeAdCustomClickGestureOptions alloc] initWithSwipeGestureDirection:UISwipeGestureRecognizerDirectionUp tapsAllowed:false]; + + if ([enableSwipeGestureOptions valueForKey:@"swipeGestureDirection"]) { + int direction = ((NSNumber *)[enableSwipeGestureOptions objectForKey:@"swipeGestureDirection"]).intValue; + + if (direction == 1) { + [clickGestureOptions setSwipeGestureDirection:UISwipeGestureRecognizerDirectionRight]; + } else if (direction == 2) { + [clickGestureOptions setSwipeGestureDirection:UISwipeGestureRecognizerDirectionLeft]; + } else if (direction == 4) { + [clickGestureOptions setSwipeGestureDirection:UISwipeGestureRecognizerDirectionUp]; + } else if (direction == 8) { + [clickGestureOptions setSwipeGestureDirection:UISwipeGestureRecognizerDirectionDown]; + } + } + + if ([enableSwipeGestureOptions valueForKey:@"tapsAllowed"]) { + [clickGestureOptions setTapsAllowed:[enableSwipeGestureOptions valueForKey:@"tapsAllowed"]]; + } +} + - (void)setMediationOptions:(NSDictionary *)mediationOptions { NSArray *allKeys = [mediationOptions allKeys]; if ([allKeys containsObject:@"nativeBanner"]) { @@ -479,10 +502,17 @@ - (void)loadAd - (void) requestAd{ if (isLoading == TRUE) return; isLoading = TRUE; + + NSMutableArray* options = [NSMutableArray arrayWithArray:@[adMediaOptions,adVideoOptions,adPlacementOptions]]; + + if (clickGestureOptions) { + [options addObject:clickGestureOptions]; + } + self.adLoader = [[GADAdLoader alloc] initWithAdUnitID:adUnitId rootViewController:self.reactViewController adTypes:@[ GADAdLoaderAdTypeNative ] - options:@[adMediaOptions,adPlacementOptions,adVideoOptions]]; + options:options]; self.adLoader.delegate = self; diff --git a/ios/RNAdMobManager/RNGADNativeViewManager.m b/ios/RNAdMobManager/RNGADNativeViewManager.m index a978f0e..dfff9e2 100755 --- a/ios/RNAdMobManager/RNGADNativeViewManager.m +++ b/ios/RNAdMobManager/RNGADNativeViewManager.m @@ -59,6 +59,7 @@ -(UIView *)view RCT_EXPORT_VIEW_PROPERTY(requestNonPersonalizedAdsOnly, BOOL) RCT_EXPORT_VIEW_PROPERTY(adChoicesPlacement, NSNumber) RCT_EXPORT_VIEW_PROPERTY(repository, NSString) +RCT_EXPORT_VIEW_PROPERTY(enableSwipeGestureOptions, NSDictionary) RCT_EXPORT_VIEW_PROPERTY(onSizeChange, RCTDirectEventBlock) RCT_EXPORT_VIEW_PROPERTY(onAppEvent, RCTDirectEventBlock) diff --git a/package.json b/package.json index d4de097..a46e129 100755 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "react-native-admob-native-ads", - "version": "0.7.2", + "version": "0.7.3", "description": "A simple and robust library for creating & displaying Admob Native Ads in your React Native App using Native Views", "author": "Ammar Ahmed ", "main": "index.js", diff --git a/src/AdBadge.js b/src/AdBadge.js index c2eb6e6..b4ebf59 100644 --- a/src/AdBadge.js +++ b/src/AdBadge.js @@ -1,29 +1,44 @@ import React from "react"; -import { StyleSheet, Text } from "react-native"; +import { View, Text, StyleSheet } from "react-native"; const AdBadge = ({allCaps,textStyle,style}) => { return ( - - {allCaps ? 'AD' : 'AD'} - + + + {allCaps ? 'AD' : 'AD'} + + ); }; export default AdBadge; const styles = StyleSheet.create({ + container: { + height: 17, + width: 21, + borderWidth: 1, + borderRadius: 2.5, + left: 0, + top: 0, + justifyContent:'center', + alignItems:'center', + paddingHorizontal: 1, + position:"absolute", + + }, text: { - color: "green", - fontSize: 10, - fontWeight:"bold", - position:"absolute", - left: 1, - top: 1, - zIndex: 999 + fontSize: 12, + fontWeight:"bold" } }) diff --git a/src/AdManager.js b/src/AdManager.js index eddcaf5..4672009 100644 --- a/src/AdManager.js +++ b/src/AdManager.js @@ -53,6 +53,7 @@ async function resetCache() { } function subscribe(repo, eventName, listener) { + console.log('subscribed: ', `${eventName}:${repo}`); return DeviceEventEmitter.addListener(`${eventName}:${repo}`, listener); } diff --git a/src/Wrapper.js b/src/Wrapper.js index 5175611..8bd77d7 100644 --- a/src/Wrapper.js +++ b/src/Wrapper.js @@ -1,51 +1,12 @@ -import React, { useContext, useEffect, useRef, useState } from "react"; -import { ScrollView, StyleSheet } from "react-native"; -import { NativeAdContext } from "./context"; +import React from "react"; +import { View } from "react-native"; const Wrapper = (props) => { - const [height, setHeight] = useState(0); - const ref = useRef(); - const { nativeAd } = useContext(NativeAdContext); - - useEffect(() => { - setTimeout(() => { - if (nativeAd && ref.current !== null) { - ref.current?.scrollTo({ - x: 0, - y: 1, - animated: true, - }); - } - }, 1000); - }, [nativeAd]); - return ( - { - props.onLayout?.(event); - const height = event.nativeEvent.layout.height; - setTimeout(() => setHeight(height)); - }} - style={[ - { - height: height === 0 ? "auto" : height, - }, - styles.container, - ]} - contentContainerStyle={{ - height: height === 0 ? "auto" : height + 1, - }} - scrollEnabled={false} /> ); }; export default Wrapper; - -const styles = StyleSheet.create({ - container: { - backgroundColor: "transparent", - }, -}); diff --git a/src/index.js b/src/index.js index 24f32fc..624475c 100644 --- a/src/index.js +++ b/src/index.js @@ -83,17 +83,16 @@ export class NativeAdView extends Component { } }; - _onAdLefApplication = (event) => { + _onAdLeftApplication = (event) => { if (this.props.onAdLeftApplication) this.props.onAdLeftApplication(event.nativeEvent); }; updateAd() { - if (this.componentMounted) { - this.setState({ - nativeAd: this.ad, - }); - } + if (!this.componentMounted) return; + this.setState({ + nativeAd: this.ad, + }); } componentDidMount() { @@ -154,9 +153,7 @@ export class NativeAdView extends Component { AdOptions.adChoicesPlacement[this.props.adChoicesPlacement] } > - { this.setState({ nativeAdView: this.nativeAdRef, @@ -186,5 +183,4 @@ NativeAdView.defaultProps = { NativeAdView.simulatorId = "SIMULATOR"; - export default NativeAdView;