diff --git a/android/src/main/java/io/invertase/firebase/admob/RNFirebaseAdMob.java b/android/src/main/java/io/invertase/firebase/admob/RNFirebaseAdMob.java index 9c7f1651..4eaae2ed 100644 --- a/android/src/main/java/io/invertase/firebase/admob/RNFirebaseAdMob.java +++ b/android/src/main/java/io/invertase/firebase/admob/RNFirebaseAdMob.java @@ -66,6 +66,11 @@ public class RNFirebaseAdMob extends ReactContextBaseJavaModule { rewardedVideo.show(); } + /** + * + * @param adUnit + * @return + */ private RNFirebaseAdmobInterstitial getOrCreateInterstitial(String adUnit) { if (interstitials.containsKey(adUnit)) { return interstitials.get(adUnit); @@ -75,6 +80,11 @@ public class RNFirebaseAdMob extends ReactContextBaseJavaModule { return interstitial; } + /** + * + * @param adUnit + * @return + */ private RNFirebaseRewardedVideo getOrCreateRewardedVideo(String adUnit) { if (rewardedVideos.containsKey(adUnit)) { return rewardedVideos.get(adUnit); diff --git a/android/src/main/java/io/invertase/firebase/admob/RNFirebaseAdmobInterstitial.java b/android/src/main/java/io/invertase/firebase/admob/RNFirebaseAdmobInterstitial.java index 25b532a8..2373f33b 100644 --- a/android/src/main/java/io/invertase/firebase/admob/RNFirebaseAdmobInterstitial.java +++ b/android/src/main/java/io/invertase/firebase/admob/RNFirebaseAdmobInterstitial.java @@ -99,7 +99,7 @@ class RNFirebaseAdmobInterstitial { void sendEvent(String type, final @Nullable WritableMap payload) { WritableMap map = Arguments.createMap(); map.putString("type", type); - map.putString("adunit", adUnit); + map.putString("adUnit", adUnit); if (payload != null) { map.putMap("payload", payload); diff --git a/android/src/main/java/io/invertase/firebase/admob/RNFirebaseRewardedVideo.java b/android/src/main/java/io/invertase/firebase/admob/RNFirebaseRewardedVideo.java index 136d8d7b..3eeaf286 100644 --- a/android/src/main/java/io/invertase/firebase/admob/RNFirebaseRewardedVideo.java +++ b/android/src/main/java/io/invertase/firebase/admob/RNFirebaseRewardedVideo.java @@ -6,9 +6,7 @@ import android.support.annotation.Nullable; import com.facebook.react.bridge.Arguments; import com.facebook.react.bridge.WritableMap; -import com.google.android.gms.ads.AdListener; import com.google.android.gms.ads.AdRequest; -import com.google.android.gms.ads.InterstitialAd; import com.google.android.gms.ads.MobileAds; import com.google.android.gms.ads.reward.RewardItem; import com.google.android.gms.ads.reward.RewardedVideoAd; @@ -28,11 +26,23 @@ public class RNFirebaseRewardedVideo implements RewardedVideoAdListener { adMob = adMobInstance; rewardedVideo = MobileAds.getRewardedVideoAdInstance(adMob.getContext()); - rewardedVideo.setRewardedVideoAdListener(this); + + Activity activity = adMob.getActivity(); + final RNFirebaseRewardedVideo _this = this; + + if (activity != null) { + activity.runOnUiThread(new Runnable() { + @Override + public void run() { + rewardedVideo.setRewardedVideoAdListener(_this); + } + }); + } } /** * Load an Ad with a AdRequest instance + * * @param adRequest */ void loadAd(final AdRequest adRequest) { @@ -66,33 +76,36 @@ public class RNFirebaseRewardedVideo implements RewardedVideoAdListener { @Override public void onRewarded(RewardItem reward) { - sendEvent("onRewarded", null); + WritableMap payload = Arguments.createMap(); + payload.putInt("amount", reward.getAmount()); + payload.putString("type", reward.getType()); + sendEvent("onRewarded", payload); } @Override public void onRewardedVideoAdLeftApplication() { - sendEvent("onRewardedVideoAdLeftApplication", null); + sendEvent("onAdLeftApplication", null); } @Override public void onRewardedVideoAdClosed() { - sendEvent("onRewardedVideoAdClosed", null); + sendEvent("onAdClosed", null); } @Override public void onRewardedVideoAdFailedToLoad(int errorCode) { WritableMap payload = RNFirebaseAdMobUtils.errorCodeToMap(errorCode); - sendEvent("onRewardedVideoAdFailedToLoad", payload); + sendEvent("onAdFailedToLoad", payload); } @Override public void onRewardedVideoAdLoaded() { - sendEvent("onRewardedVideoAdLoaded", null); + sendEvent("onAdLoaded", null); } @Override public void onRewardedVideoAdOpened() { - sendEvent("onRewardedVideoAdOpened", null); + sendEvent("onAdOpened", null); } @Override @@ -104,13 +117,14 @@ public class RNFirebaseRewardedVideo implements RewardedVideoAdListener { /** * Send a native event over the bridge with a type and optional payload + * * @param type * @param payload */ void sendEvent(String type, final @Nullable WritableMap payload) { WritableMap map = Arguments.createMap(); map.putString("type", type); - map.putString("adunit", adUnit); + map.putString("adUnit", adUnit); if (payload != null) { map.putMap("payload", payload); diff --git a/lib/modules/admob/AdRequest.js b/lib/modules/admob/AdRequest.js index 217db457..e2a3a8db 100644 --- a/lib/modules/admob/AdRequest.js +++ b/lib/modules/admob/AdRequest.js @@ -3,6 +3,9 @@ export default class AdRequest { constructor() { this._props = { keywords: [], + contentUrl: null, + isDesignedForFamilies: null, + tagForChildDirectedTreatment: null, }; } @@ -15,8 +18,38 @@ export default class AdRequest { return this; } - addKeyword(word: string) { - this._props.keywords.push(word); + addKeyword(keyword: string) { + this._props.keywords.push(keyword); + return this; + } + + setBirthday() { + // TODO + } + + setContentUrl(url: string) { + this._props.contentUrl = url; + } + + setGender() { + // TODO + } + + setLocation() { + // TODO + } + + setRequestAgent() { + // TODO + } + + setIsDesignedForFamilies(isDesignedForFamilies: boolean) { + this._props.isDesignedForFamilies = isDesignedForFamilies; + return this; + } + + tagForChildDirectedTreatment(tagForChildDirectedTreatment: boolean) { + this._props.tagForChildDirectedTreatment = tagForChildDirectedTreatment; return this; } } diff --git a/lib/modules/admob/Interstitial.js b/lib/modules/admob/Interstitial.js index c8b20116..8076044f 100644 --- a/lib/modules/admob/Interstitial.js +++ b/lib/modules/admob/Interstitial.js @@ -6,11 +6,11 @@ const FirebaseAdMob = NativeModules.RNFirebaseAdmob; export default class Interstitial { - constructor(admob: Object, adunit: string) { + constructor(admob: Object, adUnit: string) { this.admob = admob; - this.adUnit = adunit; + this.adUnit = adUnit; this.loaded = false; - this.admob.on(`interstitial_${adunit}`, this._onInterstitialEvent.bind(this)); + this.admob.on(`interstitial_${adUnit}`, this._onInterstitialEvent.bind(this)); } /** diff --git a/lib/modules/admob/RewardedVideo.js b/lib/modules/admob/RewardedVideo.js new file mode 100644 index 00000000..fc9142f7 --- /dev/null +++ b/lib/modules/admob/RewardedVideo.js @@ -0,0 +1,82 @@ +import { NativeModules } from 'react-native'; +import { statics } from './'; +import { nativeToJSError } from '../../utils'; + +const FirebaseAdMob = NativeModules.RNFirebaseAdmob; + +export default class RewardedVideo { + + constructor(admob: Object, adunit: string) { + this.admob = admob; + this.adUnit = adunit; + this.loaded = false; + this.admob.on(`rewarded_video_${adunit}`, this._onRewardedVideoEvent.bind(this)); + } + + /** + * Handle a JS emit event + * @param event + * @private + */ + _onRewardedVideoEvent(event) { + const eventType = `rewarded_video:${this.adUnit}:${event.type}`; + + let emitData = Object.assign({}, event); + + switch (event.type) { + case 'onAdLoaded': + this.loaded = true; + break; + case 'onAdFailedToLoad': + emitData = nativeToJSError(event.payload.code, event.payload.message); + emitData.type = event.type; + break; + default: + } + + this.admob.emit(eventType, emitData); + this.admob.emit(`rewarded_video:${this.adUnit}:*`, emitData); + } + + /** + * Load an ad with an instance of AdRequest + * @param request + * @returns {*} + */ + loadAd(request: AdRequest) { + return FirebaseAdMob.rewardedVideoLoadAd(this.adUnit, request); + } + + /** + * Return a local instance of isLoaded + * @returns {boolean} + */ + isLoaded() { + return this.loaded; + } + + /** + * Show the advert - will only show if loaded + * @returns {*} + */ + show() { + if (this.loaded) { + FirebaseAdMob.rewardedVideoShowAd(this.adUnit); + } + } + + /** + * Listen to an Ad event + * @param eventType + * @param listenerCb + * @returns {null} + */ + on(eventType, listenerCb) { + if ((eventType !== 'onRewarded' || eventType !== 'onRewardedVideoStarted') && !statics.EventTypes[eventType]) { + console.warn(`Invalid event type provided, must be one of: ${Object.keys(statics.EventTypes).join(', ')}, onRewarded, onRewardedVideoStarted`); + return null; + } + + return this.admob.on(`rewarded_video:${this.adUnit}:${eventType}`, listenerCb); + } +} diff --git a/lib/modules/admob/index.js b/lib/modules/admob/index.js index 9490689e..41b69b2e 100644 --- a/lib/modules/admob/index.js +++ b/lib/modules/admob/index.js @@ -2,6 +2,7 @@ import { NativeModules, NativeEventEmitter } from 'react-native'; import { nativeSDKMissing } from './../../utils'; import Interstitial from './Interstitial'; +import RewardedVideo from './RewardedVideo'; import AdRequest from './AdRequest'; import Banner from './Banner'; import { Base } from './../base'; @@ -18,11 +19,23 @@ export default class Admob extends Base { } FirebaseAdMobEvt.addListener('interstitial_event', this._onInterstitialEvent.bind(this)); + FirebaseAdMobEvt.addListener('rewarded_video_event', this._onRewardedVideoEvent.bind(this)); } _onInterstitialEvent(event) { - const { adunit } = event; - const jsEventType = `interstitial_${adunit}`; + const { adUnit } = event; + const jsEventType = `interstitial_${adUnit}`; + + if (!this.hasListeners(jsEventType)) { + // TODO + } + + this.emit(jsEventType, event); + } + + _onRewardedVideoEvent(event) { + const { adUnit } = event; + const jsEventType = `rewarded_video_${adUnit}`; if (!this.hasListeners(jsEventType)) { // TODO @@ -35,6 +48,10 @@ export default class Admob extends Base { return new Interstitial(this, adUnit); } + rewarded(adUnit: string) { + return new RewardedVideo(this, adUnit); + } + static get statics() { return statics; } @@ -50,13 +67,4 @@ export const statics = { onAdClosed: 'onAdClosed', onAdFailedToLoad: 'onAdFailedToLoad', }, - RewardedEventTypes: { - onRewarded: 'onRewarded', - onRewardedVideoAdLeftApplication: 'onRewardedVideoAdLeftApplication', - onRewardedVideoAdClosed: 'onRewardedVideoAdClosed', - onRewardedVideoAdFailedToLoad: 'onRewardedVideoAdFailedToLoad', - onRewardedVideoAdLoaded: 'onRewardedVideoAdLoaded', - onRewardedVideoAdOpened: 'onRewardedVideoAdOpened', - onRewardedVideoStarted: 'onRewardedVideoStarted', - }, };