From b2fa0cd97b87ed45a6790a3304b2789736a90007 Mon Sep 17 00:00:00 2001 From: ehesp Date: Tue, 13 Aug 2019 09:10:00 +0100 Subject: [PATCH] - --- packages/admob/RNFBAdmob.podspec | 2 + .../android/src/main/AndroidManifest.xml | 1 + ...ativeFirebaseAdMobBannerAdViewManager.java | 97 +++++++++++ .../admob/ReactNativeFirebaseAdMobCommon.java | 14 +- ...ReactNativeFirebaseAdMobConsentModule.java | 1 + ...NativeFirebaseAdMobInterstitialModule.java | 8 +- ...eactNativeFirebaseAdMobRewardedModule.java | 1 + .../ReactNativeFirebaseAdmobPackage.java | 5 +- packages/admob/ios/RNFBAdmob.podspec | 3 + .../ios/RNFBAdmob.xcodeproj/project.pbxproj | 42 ++++- .../admob/ios/RNFBAdmob/RNFBAdMobCommon.h | 58 +++++++ .../admob/ios/RNFBAdmob/RNFBAdMobCommon.m | 150 ++++++++++++++++++ .../ios/RNFBAdmob/RNFBAdMobConsentModule.m | 29 ++-- .../RNFBAdmob/RNFBAdMobInterstitialDelegate.h | 34 ++++ .../RNFBAdmob/RNFBAdMobInterstitialDelegate.m | 69 ++++++++ .../RNFBAdmob/RNFBAdMobInterstitialModule.h | 26 +++ .../RNFBAdmob/RNFBAdMobInterstitialModule.m | 102 ++++++++++++ .../{RNFBAdmobModule.h => RNFBAdMobModule.h} | 2 +- .../{RNFBAdmobModule.m => RNFBAdMobModule.m} | 4 +- .../ios/RNFBAdmob/RNFBAdMobRewardedDelegate.h | 36 +++++ .../ios/RNFBAdmob/RNFBAdMobRewardedDelegate.m | 76 +++++++++ .../ios/RNFBAdmob/RNFBAdMobRewardedModule.h | 25 +++ .../ios/RNFBAdmob/RNFBAdMobRewardedModule.m | 114 +++++++++++++ packages/admob/lib/AdsConsent.js | 2 +- packages/admob/lib/TestIds.js | 33 ++++ packages/admob/lib/ads/BannerAd.js | 29 ++++ packages/admob/lib/ads/RewardedAd.js | 2 +- packages/admob/lib/index.d.ts | 1 + packages/admob/lib/index.js | 13 +- .../admob/lib/validateAdRequestOptions.js | 14 +- .../ios/RNFBMessaging/RNFBMessagingDelegate.h | 1 - tests/app.admob.js | 90 ++++++----- tests/ios/Podfile.lock | 13 +- tests/ios/testing/Info.plist | 4 + 34 files changed, 1020 insertions(+), 81 deletions(-) create mode 100644 packages/admob/android/src/main/java/io/invertase/firebase/admob/ReactNativeFirebaseAdMobBannerAdViewManager.java create mode 100644 packages/admob/ios/RNFBAdmob/RNFBAdMobCommon.h create mode 100644 packages/admob/ios/RNFBAdmob/RNFBAdMobCommon.m create mode 100644 packages/admob/ios/RNFBAdmob/RNFBAdMobInterstitialDelegate.h create mode 100644 packages/admob/ios/RNFBAdmob/RNFBAdMobInterstitialDelegate.m create mode 100644 packages/admob/ios/RNFBAdmob/RNFBAdMobInterstitialModule.h create mode 100644 packages/admob/ios/RNFBAdmob/RNFBAdMobInterstitialModule.m rename packages/admob/ios/RNFBAdmob/{RNFBAdmobModule.h => RNFBAdMobModule.h} (92%) rename packages/admob/ios/RNFBAdmob/{RNFBAdmobModule.m => RNFBAdMobModule.m} (94%) create mode 100644 packages/admob/ios/RNFBAdmob/RNFBAdMobRewardedDelegate.h create mode 100644 packages/admob/ios/RNFBAdmob/RNFBAdMobRewardedDelegate.m create mode 100644 packages/admob/ios/RNFBAdmob/RNFBAdMobRewardedModule.h create mode 100644 packages/admob/ios/RNFBAdmob/RNFBAdMobRewardedModule.m create mode 100644 packages/admob/lib/TestIds.js create mode 100644 packages/admob/lib/ads/BannerAd.js diff --git a/packages/admob/RNFBAdmob.podspec b/packages/admob/RNFBAdmob.podspec index ce759e6a..9f5054e4 100644 --- a/packages/admob/RNFBAdmob.podspec +++ b/packages/admob/RNFBAdmob.podspec @@ -17,6 +17,8 @@ Pod::Spec.new do |s| s.source_files = 'ios/**/*.{h,m}' s.dependency 'React' s.dependency 'Firebase/Core', '~> 6.5.0' + s.dependency 'Firebase/Analytics', '~> 6.5.0' + s.dependency 'Firebase/AdMob', '~> 6.5.0' s.dependency 'PersonalizedAdConsent' s.dependency 'RNFBApp' s.static_framework = true diff --git a/packages/admob/android/src/main/AndroidManifest.xml b/packages/admob/android/src/main/AndroidManifest.xml index f26f5c49..8bf31efd 100644 --- a/packages/admob/android/src/main/AndroidManifest.xml +++ b/packages/admob/android/src/main/AndroidManifest.xml @@ -5,6 +5,7 @@ + { + + public static final String REACT_CLASS = "RNFBBannerAd"; + private AdView adView; + + @Nonnull + @Override + public String getName() { + return REACT_CLASS; + } + + @Nonnull + @Override + protected ReactViewGroup createViewInstance(@Nonnull ThemedReactContext reactContext) { + ReactViewGroup viewGroup = new ReactViewGroup(reactContext); + adView = new AdView(reactContext); + + adView.setAdUnitId("ca-app-pub-3940256099942544/6300978111"); + + adView.setAdSize(AdSize.SMART_BANNER); + AdRequest adRequest = new AdRequest.Builder().build(); + + adView.setAdListener(new AdListener() { + @Override + public void onAdLoaded() { + Log.d("ELLIOT", "LOADED"); + // Code to be executed when an ad finishes loading. + } + + @Override + public void onAdFailedToLoad(int errorCode) { + Log.d("ELLIOT", "ERROR"); + // Code to be executed when an ad request fails. + } + + @Override + public void onAdOpened() { + Log.d("ELLIOT", "OPENED"); + // Code to be executed when an ad opens an overlay that + // covers the screen. + } + + @Override + public void onAdClicked() { + // Code to be executed when the user clicks on an ad. + } + + @Override + public void onAdLeftApplication() { + // Code to be executed when the user has left the app. + } + + @Override + public void onAdClosed() { + // Code to be executed when the user is about to return + // to the app after tapping on an ad. + } + }); + + adView.loadAd(adRequest); + + viewGroup.addView(adView); + + return viewGroup; + } +} diff --git a/packages/admob/android/src/main/java/io/invertase/firebase/admob/ReactNativeFirebaseAdMobCommon.java b/packages/admob/android/src/main/java/io/invertase/firebase/admob/ReactNativeFirebaseAdMobCommon.java index 208b54b9..f347c274 100644 --- a/packages/admob/android/src/main/java/io/invertase/firebase/admob/ReactNativeFirebaseAdMobCommon.java +++ b/packages/admob/android/src/main/java/io/invertase/firebase/admob/ReactNativeFirebaseAdMobCommon.java @@ -18,10 +18,10 @@ package io.invertase.firebase.admob; */ +import android.location.Location; import android.os.Bundle; import com.facebook.react.bridge.Arguments; -import com.facebook.react.bridge.Promise; import com.facebook.react.bridge.ReadableArray; import com.facebook.react.bridge.ReadableMap; import com.facebook.react.bridge.WritableMap; @@ -37,8 +37,6 @@ import javax.annotation.Nullable; import io.invertase.firebase.common.ReactNativeFirebaseEventEmitter; import io.invertase.firebase.database.ReactNativeFirebaseAdMobEvent; -import static io.invertase.firebase.common.ReactNativeFirebaseModule.rejectPromiseWithCodeAndMessage; - public class ReactNativeFirebaseAdMobCommon { static public AdRequest buildAdRequest(ReadableMap adRequestOptions) { @@ -90,8 +88,12 @@ public class ReactNativeFirebaseAdMobCommon { } if (adRequestOptions.hasKey("location")) { - ReadableArray location = adRequestOptions.getArray("location"); - // todo how? https://developer.android.com/reference/android/location/Location.html + ReadableArray locationArray = adRequestOptions.getArray("location"); + Location location = new Location(""); + location.setLatitude(Objects.requireNonNull(locationArray).getDouble(0)); + location.setLongitude(Objects.requireNonNull(locationArray).getDouble(1)); + + builder.setLocation(location); } if (adRequestOptions.hasKey("requestAgent")) { @@ -143,7 +145,7 @@ public class ReactNativeFirebaseAdMobCommon { static public String[] getCodeAndMessageFromAdErrorCode(int errorCode) { String code = "unknown"; - String message = "An unknown error occurred"; + String message = "An unknown error occurred."; switch (errorCode) { case AdRequest.ERROR_CODE_INTERNAL_ERROR: diff --git a/packages/admob/android/src/main/java/io/invertase/firebase/admob/ReactNativeFirebaseAdMobConsentModule.java b/packages/admob/android/src/main/java/io/invertase/firebase/admob/ReactNativeFirebaseAdMobConsentModule.java index cfecb4bf..4bfc577f 100644 --- a/packages/admob/android/src/main/java/io/invertase/firebase/admob/ReactNativeFirebaseAdMobConsentModule.java +++ b/packages/admob/android/src/main/java/io/invertase/firebase/admob/ReactNativeFirebaseAdMobConsentModule.java @@ -65,6 +65,7 @@ public class ReactNativeFirebaseAdMobConsentModule extends ReactNativeFirebaseMo @ReactMethod public void requestInfoUpdate(ReadableArray publisherIds, Promise promise) { @SuppressWarnings("SuspiciousToArrayCall") + String[] publisherIdsArray = publisherIds.toArrayList().toArray(new String[0]); consentInformation.requestConsentInfoUpdate(publisherIdsArray, new ConsentInfoUpdateListener() { diff --git a/packages/admob/android/src/main/java/io/invertase/firebase/admob/ReactNativeFirebaseAdMobInterstitialModule.java b/packages/admob/android/src/main/java/io/invertase/firebase/admob/ReactNativeFirebaseAdMobInterstitialModule.java index 9eb3bd76..98baaa58 100644 --- a/packages/admob/android/src/main/java/io/invertase/firebase/admob/ReactNativeFirebaseAdMobInterstitialModule.java +++ b/packages/admob/android/src/main/java/io/invertase/firebase/admob/ReactNativeFirebaseAdMobInterstitialModule.java @@ -121,8 +121,12 @@ public class ReactNativeFirebaseAdMobInterstitialModule extends ReactNativeFireb interstitialAd.setImmersiveMode(false); } - interstitialAd.show(); - promise.resolve(null); + if (interstitialAd.isLoaded()) { + interstitialAd.show(); + promise.resolve(null); + } else { + rejectPromiseWithCodeAndMessage(promise, "not-ready", "Interstitial ad attempted to show but was not ready."); + } }); } } diff --git a/packages/admob/android/src/main/java/io/invertase/firebase/admob/ReactNativeFirebaseAdMobRewardedModule.java b/packages/admob/android/src/main/java/io/invertase/firebase/admob/ReactNativeFirebaseAdMobRewardedModule.java index e7705e07..21a43c17 100644 --- a/packages/admob/android/src/main/java/io/invertase/firebase/admob/ReactNativeFirebaseAdMobRewardedModule.java +++ b/packages/admob/android/src/main/java/io/invertase/firebase/admob/ReactNativeFirebaseAdMobRewardedModule.java @@ -11,6 +11,7 @@ import com.facebook.react.bridge.ReactApplicationContext; import com.facebook.react.bridge.ReactMethod; import com.facebook.react.bridge.ReadableMap; import com.facebook.react.bridge.WritableMap; +import com.google.android.gms.ads.reward.RewardedVideoAd; import com.google.android.gms.ads.rewarded.RewardItem; import com.google.android.gms.ads.rewarded.RewardedAd; import com.google.android.gms.ads.rewarded.RewardedAdCallback; diff --git a/packages/admob/android/src/main/java/io/invertase/firebase/admob/ReactNativeFirebaseAdmobPackage.java b/packages/admob/android/src/main/java/io/invertase/firebase/admob/ReactNativeFirebaseAdmobPackage.java index 4d45daf5..4e987734 100644 --- a/packages/admob/android/src/main/java/io/invertase/firebase/admob/ReactNativeFirebaseAdmobPackage.java +++ b/packages/admob/android/src/main/java/io/invertase/firebase/admob/ReactNativeFirebaseAdmobPackage.java @@ -23,6 +23,7 @@ import com.facebook.react.bridge.ReactApplicationContext; import com.facebook.react.uimanager.ViewManager; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.List; @@ -40,6 +41,8 @@ public class ReactNativeFirebaseAdmobPackage implements ReactPackage { @Override public List createViewManagers(ReactApplicationContext reactContext) { - return Collections.emptyList(); + return Collections.singletonList( + new ReactNativeFirebaseAdMobBannerAdViewManager() + ); } } diff --git a/packages/admob/ios/RNFBAdmob.podspec b/packages/admob/ios/RNFBAdmob.podspec index 5cd26430..652ffe38 100644 --- a/packages/admob/ios/RNFBAdmob.podspec +++ b/packages/admob/ios/RNFBAdmob.podspec @@ -17,6 +17,9 @@ Pod::Spec.new do |s| s.source_files = 'RNFBAdmob/**/*.{h,m}' s.dependency 'React' s.dependency 'Firebase/Core', '~> 6.5.0' + s.dependency 'Firebase/Core', '~> 6.5.0' + s.dependency 'Firebase/Analytics', '~> 6.5.0' + s.dependency 'Firebase/AdMob', '~> 6.5.0' s.dependency 'PersonalizedAdConsent' s.dependency 'RNFBApp' s.static_framework = true diff --git a/packages/admob/ios/RNFBAdmob.xcodeproj/project.pbxproj b/packages/admob/ios/RNFBAdmob.xcodeproj/project.pbxproj index 39994a12..1bdeebbf 100644 --- a/packages/admob/ios/RNFBAdmob.xcodeproj/project.pbxproj +++ b/packages/admob/ios/RNFBAdmob.xcodeproj/project.pbxproj @@ -7,8 +7,13 @@ objects = { /* Begin PBXBuildFile section */ - 2744B98621F45429004F8E3F /* RNFBAdmobModule.m in Sources */ = {isa = PBXBuildFile; fileRef = 2744B98521F45429004F8E3F /* RNFBAdmobModule.m */; }; + 2744B98621F45429004F8E3F /* RNFBAdMobModule.m in Sources */ = {isa = PBXBuildFile; fileRef = 2744B98521F45429004F8E3F /* RNFBAdMobModule.m */; }; 8B06D41B22FEC8B800A5B542 /* RNFBAdMobConsentModule.m in Sources */ = {isa = PBXBuildFile; fileRef = 8B06D41A22FEC8B800A5B542 /* RNFBAdMobConsentModule.m */; }; + 8B06D41F230063ED00A5B542 /* RNFBAdMobCommon.m in Sources */ = {isa = PBXBuildFile; fileRef = 8B06D41E230063ED00A5B542 /* RNFBAdMobCommon.m */; }; + 8B4E497523017EB400587275 /* RNFBAdMobInterstitialModule.m in Sources */ = {isa = PBXBuildFile; fileRef = 8B4E497423017EB400587275 /* RNFBAdMobInterstitialModule.m */; }; + 8B4E497823017ED300587275 /* RNFBAdMobRewardedModule.m in Sources */ = {isa = PBXBuildFile; fileRef = 8B4E497723017ED300587275 /* RNFBAdMobRewardedModule.m */; }; + 8B4E497E2301BE2C00587275 /* RNFBAdMobInterstitialDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 8B4E497D2301BE2C00587275 /* RNFBAdMobInterstitialDelegate.m */; }; + 8BC10E6223029CAE00209FF9 /* RNFBAdMobRewardedDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 8BC10E6123029CAE00209FF9 /* RNFBAdMobRewardedDelegate.m */; }; /* End PBXBuildFile section */ /* Begin PBXCopyFilesBuildPhase section */ @@ -25,10 +30,20 @@ /* Begin PBXFileReference section */ 2744B98221F45429004F8E3F /* libRNFBAdmob.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libRNFBAdmob.a; sourceTree = BUILT_PRODUCTS_DIR; }; - 2744B98421F45429004F8E3F /* RNFBAdmobModule.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = RNFBAdmobModule.h; path = RNFBAdmob/RNFBAdmobModule.h; sourceTree = SOURCE_ROOT; }; - 2744B98521F45429004F8E3F /* RNFBAdmobModule.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = RNFBAdmobModule.m; path = RNFBAdmob/RNFBAdmobModule.m; sourceTree = SOURCE_ROOT; }; + 2744B98421F45429004F8E3F /* RNFBAdMobModule.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = RNFBAdMobModule.h; path = RNFBAdmob/RNFBAdMobModule.h; sourceTree = SOURCE_ROOT; }; + 2744B98521F45429004F8E3F /* RNFBAdMobModule.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = RNFBAdMobModule.m; path = RNFBAdmob/RNFBAdMobModule.m; sourceTree = SOURCE_ROOT; }; 8B06D41922FEC8AE00A5B542 /* RNFBAdMobConsentModule.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RNFBAdMobConsentModule.h; sourceTree = ""; }; 8B06D41A22FEC8B800A5B542 /* RNFBAdMobConsentModule.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RNFBAdMobConsentModule.m; sourceTree = ""; }; + 8B06D41D230063E200A5B542 /* RNFBAdMobCommon.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RNFBAdMobCommon.h; sourceTree = ""; }; + 8B06D41E230063ED00A5B542 /* RNFBAdMobCommon.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RNFBAdMobCommon.m; sourceTree = ""; }; + 8B4E497323017EA600587275 /* RNFBAdMobInterstitialModule.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RNFBAdMobInterstitialModule.h; sourceTree = ""; }; + 8B4E497423017EB400587275 /* RNFBAdMobInterstitialModule.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RNFBAdMobInterstitialModule.m; sourceTree = ""; }; + 8B4E497623017ECA00587275 /* RNFBAdMobRewardedModule.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RNFBAdMobRewardedModule.h; sourceTree = ""; }; + 8B4E497723017ED300587275 /* RNFBAdMobRewardedModule.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RNFBAdMobRewardedModule.m; sourceTree = ""; }; + 8B4E497C2301BE1500587275 /* RNFBAdMobInterstitialDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RNFBAdMobInterstitialDelegate.h; sourceTree = ""; }; + 8B4E497D2301BE2C00587275 /* RNFBAdMobInterstitialDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RNFBAdMobInterstitialDelegate.m; sourceTree = ""; }; + 8BC10E6023029CA500209FF9 /* RNFBAdMobRewardedDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RNFBAdMobRewardedDelegate.h; sourceTree = ""; }; + 8BC10E6123029CAE00209FF9 /* RNFBAdMobRewardedDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RNFBAdMobRewardedDelegate.m; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -53,10 +68,20 @@ 2744B98321F45429004F8E3F /* RNFBAdmob */ = { isa = PBXGroup; children = ( - 2744B98421F45429004F8E3F /* RNFBAdmobModule.h */, - 2744B98521F45429004F8E3F /* RNFBAdmobModule.m */, + 2744B98421F45429004F8E3F /* RNFBAdMobModule.h */, + 2744B98521F45429004F8E3F /* RNFBAdMobModule.m */, 8B06D41922FEC8AE00A5B542 /* RNFBAdMobConsentModule.h */, 8B06D41A22FEC8B800A5B542 /* RNFBAdMobConsentModule.m */, + 8B06D41D230063E200A5B542 /* RNFBAdMobCommon.h */, + 8B06D41E230063ED00A5B542 /* RNFBAdMobCommon.m */, + 8B4E497323017EA600587275 /* RNFBAdMobInterstitialModule.h */, + 8B4E497423017EB400587275 /* RNFBAdMobInterstitialModule.m */, + 8B4E497623017ECA00587275 /* RNFBAdMobRewardedModule.h */, + 8B4E497723017ED300587275 /* RNFBAdMobRewardedModule.m */, + 8B4E497C2301BE1500587275 /* RNFBAdMobInterstitialDelegate.h */, + 8B4E497D2301BE2C00587275 /* RNFBAdMobInterstitialDelegate.m */, + 8BC10E6023029CA500209FF9 /* RNFBAdMobRewardedDelegate.h */, + 8BC10E6123029CAE00209FF9 /* RNFBAdMobRewardedDelegate.m */, ); path = RNFBAdmob; sourceTree = ""; @@ -128,8 +153,13 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 8B4E497E2301BE2C00587275 /* RNFBAdMobInterstitialDelegate.m in Sources */, + 8B4E497823017ED300587275 /* RNFBAdMobRewardedModule.m in Sources */, 8B06D41B22FEC8B800A5B542 /* RNFBAdMobConsentModule.m in Sources */, - 2744B98621F45429004F8E3F /* RNFBAdmobModule.m in Sources */, + 8B4E497523017EB400587275 /* RNFBAdMobInterstitialModule.m in Sources */, + 8B06D41F230063ED00A5B542 /* RNFBAdMobCommon.m in Sources */, + 2744B98621F45429004F8E3F /* RNFBAdMobModule.m in Sources */, + 8BC10E6223029CAE00209FF9 /* RNFBAdMobRewardedDelegate.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/packages/admob/ios/RNFBAdmob/RNFBAdMobCommon.h b/packages/admob/ios/RNFBAdmob/RNFBAdMobCommon.h new file mode 100644 index 00000000..3c599a3a --- /dev/null +++ b/packages/admob/ios/RNFBAdmob/RNFBAdMobCommon.h @@ -0,0 +1,58 @@ +// +/** + * Copyright (c) 2016-present Invertase Limited & Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this library except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#import +#import + +@interface RNFBAdMobCommon : NSObject + ++ (GADRequest *)buildAdRequest:(NSDictionary *)adRequestOptions; + ++ (NSDictionary *)getCodeAndMessageFromAdError:(GADRequestError *)error; + ++ (void)sendAdEvent:(NSString *)event + requestId:(NSNumber *)requestId + type:(NSString *)type + adUnitId:(NSString *)adUnitId + error:(nullable NSDictionary *)error + data:(nullable NSDictionary *)data; + +@end + +@interface RNFBGADInterstitial : GADInterstitial +@property(nonatomic) NSNumber *requestId; +- (void)setRequestId:(NSNumber *)requestId; +@end + +@interface RNFBGADRewarded : GADRewardedAd +@property(nonatomic) NSNumber *requestId; +- (void)setRequestId:(NSNumber *)requestId; +@end + +extern NSString *const EVENT_INTERSTITIAL; +extern NSString *const EVENT_REWARDED; + +extern NSString *const ADMOB_EVENT_LOADED; +extern NSString *const ADMOB_EVENT_ERROR; +extern NSString *const ADMOB_EVENT_OPENED; +extern NSString *const ADMOB_EVENT_CLICKED; +extern NSString *const ADMOB_EVENT_LEFT_APPLICATION; +extern NSString *const ADMOB_EVENT_CLOSED; + +extern NSString *const ADMOB_EVENT_REWARDED_LOADED; +extern NSString *const ADMOB_EVENT_REWARDED_EARNED_REWARD; diff --git a/packages/admob/ios/RNFBAdmob/RNFBAdMobCommon.m b/packages/admob/ios/RNFBAdmob/RNFBAdMobCommon.m new file mode 100644 index 00000000..dacba959 --- /dev/null +++ b/packages/admob/ios/RNFBAdmob/RNFBAdMobCommon.m @@ -0,0 +1,150 @@ +// +/** + * Copyright (c) 2016-present Invertase Limited & Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this library except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#import "RNFBAdMobCommon.h" +#import "RNFBRCTEventEmitter.h" + +NSString *const EVENT_INTERSTITIAL = @"admob_interstitial_event"; +NSString *const EVENT_REWARDED = @"admob_rewarded_event"; +NSString *const ADMOB_EVENT_LOADED = @"loaded"; +NSString *const ADMOB_EVENT_ERROR = @"error"; +NSString *const ADMOB_EVENT_OPENED = @"opened"; +NSString *const ADMOB_EVENT_CLICKED = @"clicked"; +NSString *const ADMOB_EVENT_LEFT_APPLICATION = @"left_application"; +NSString *const ADMOB_EVENT_CLOSED = @"closed"; +NSString *const ADMOB_EVENT_REWARDED_LOADED = @"rewarded_loaded"; +NSString *const ADMOB_EVENT_REWARDED_EARNED_REWARD = @"rewarded_earned_reward"; + + +@implementation RNFBGADInterstitial : GADInterstitial +- (void)setRequestId:(NSNumber *)requestId { + _requestId = requestId; +} +@end + +@implementation RNFBGADRewarded : GADRewardedAd +- (void)setRequestId:(NSNumber *)requestId { + _requestId = requestId; +} +@end + +@implementation RNFBAdMobCommon + ++ (GADRequest *)buildAdRequest:(NSDictionary *)adRequestOptions { + GADRequest *request = [GADRequest request]; + NSMutableDictionary *extras = [@{} mutableCopy]; + + if (adRequestOptions[@"requestNonPersonalizedAdsOnly"]) { + extras[@"npa"] = @"1"; + } + + if (adRequestOptions[@"networkExtras"]) { + for (NSString *key in adRequestOptions[@"networkExtras"]) { + NSString *value = adRequestOptions[@"networkExtras"][key]; + extras[key] = value; + } + } + + GADExtras *networkExtras = [[GADExtras alloc] init]; + networkExtras.additionalParameters = extras; + [request registerAdNetworkExtras:networkExtras]; + + if (adRequestOptions[@"keywords"]) { + request.keywords = adRequestOptions[@"keywords"]; + } + + if (adRequestOptions[@"testDevices"]) { + NSMutableArray *devices = [@[] mutableCopy]; + for (NSString *key in adRequestOptions[@"testDevices"]) { + if ([key isEqualToString:@"EMULATOR"]) { + [devices addObject:kGADSimulatorID]; + } else { + [devices addObject:adRequestOptions[@"testDevices"][key]]; + } + } + request.testDevices = devices; + } + + if (adRequestOptions[@"location"]) { +// TODO + // NSArray *location = adRequestOptions[@"location"]; +// CGFloat *latitude = +// +// [request setLocationWithLatitude:location[0] longitude:<#(CGFloat)longitude#> accuracy:<#(CGFloat)accuracyInMeters#>]; + } + + if (adRequestOptions[@"requestAgent"]) { + request.keywords = adRequestOptions[@"requestAgent"]; + } + + return request; +} + ++ (NSDictionary *)getCodeAndMessageFromAdError:(GADRequestError *)error { + NSString *code = @"unknown"; + NSString *message = @"An unknown error occurred."; + + if (error.code == kGADErrorInvalidRequest) { + code = @"invalid-request"; + message = @"The ad request was invalid; for instance, the ad unit ID was incorrect."; + } else if (error.code == kGADErrorNoFill) { + code = @"no-fill"; + message = @"The ad request was successful, but no ad was returned due to lack of ad inventory."; + } else if (error.code == kGADErrorNetworkError) { + code = @"network-error"; + message = @"The ad request was unsuccessful due to network connectivity."; + } else if (error.code == kGADErrorInternalError) { + code = @"internal-error"; + message = @"Something happened internally; for instance, an invalid response was received from the ad server."; + } + + return @{ + @"code": code, + @"message": message, + }; +} + ++ (void)sendAdEvent:(NSString *)event + requestId:(NSNumber *)requestId + type:(NSString *)type + adUnitId:(NSString *)adUnitId + error:(nullable NSDictionary *)error + data:(nullable NSDictionary *)data { + NSMutableDictionary *body = [@{ + @"type": type, + } mutableCopy]; + + if (error != nil) { + body[@"error"] = error; + } + + if (data != nil) { + body[@"data"] = data; + } + + NSMutableDictionary *payload = [@{ + @"eventName": type, + @"requestId": requestId, + @"adUnitId": adUnitId, + @"body": body, + } mutableCopy]; + + [[RNFBRCTEventEmitter shared] sendEventWithName:event body:payload]; +} + +@end diff --git a/packages/admob/ios/RNFBAdmob/RNFBAdMobConsentModule.m b/packages/admob/ios/RNFBAdmob/RNFBAdMobConsentModule.m index 6c2a694b..17b1489d 100644 --- a/packages/admob/ios/RNFBAdmob/RNFBAdMobConsentModule.m +++ b/packages/admob/ios/RNFBAdmob/RNFBAdMobConsentModule.m @@ -41,9 +41,12 @@ RCT_EXPORT_METHOD(requestInfoUpdate: ) { PACConsentInformation *consentInformation = [PACConsentInformation sharedInstance]; - id completionHandler = ^(NSError *error) { + id completionHandler = ^(NSError *_Nullable error) { if (error != nil) { - // todo error + [RNFBSharedUtils rejectPromiseWithUserInfo:reject userInfo:[@{ + @"code": @"consent-update-failed", + @"message": error.localizedDescription, + } mutableCopy]]; } else { resolve(@{ @"status": @(consentInformation.consentStatus), @@ -77,7 +80,10 @@ RCT_EXPORT_METHOD(showForm: id dismissCompletionBlock = ^(NSError *error, BOOL userPrefersAdFree) { if (error != nil) { - // todo error + [RNFBSharedUtils rejectPromiseWithUserInfo:reject userInfo:[@{ + @"code": @"consent-form-error", + @"message": error.localizedDescription, + } mutableCopy]]; } else { resolve(@{ @"status": @(PACConsentInformation.sharedInstance.consentStatus), @@ -88,7 +94,10 @@ RCT_EXPORT_METHOD(showForm: [form loadWithCompletionHandler:^(NSError *error) { if (error != nil) { - // todo error + [RNFBSharedUtils rejectPromiseWithUserInfo:reject userInfo:[@{ + @"code": @"consent-form-error", + @"message": error.localizedDescription, + } mutableCopy]]; } else { [form presentFromViewController:[UIApplication sharedApplication].delegate.window.rootViewController dismissCompletion:dismissCompletionBlock]; } @@ -110,11 +119,11 @@ RCT_EXPORT_METHOD(setStatus ) { PACConsentStatus consentStatus = PACConsentStatusUnknown; - if (status == @0) { + if ([status integerValue] == [@0 integerValue]) { consentStatus = PACConsentStatusUnknown; - } else if (status == @1) { + } else if ([status integerValue] == [@1 integerValue]) { consentStatus = PACConsentStatusNonPersonalized; - } else if (status == @2) { + } else if ([status integerValue] == [@2 integerValue]) { consentStatus = PACConsentStatusPersonalized; } @@ -157,11 +166,11 @@ RCT_EXPORT_METHOD(setDebugGeography ) { PACDebugGeography debugGeography = PACDebugGeographyDisabled; - if (geography == @0) { + if ([geography integerValue] == [@0 integerValue]) { debugGeography = PACDebugGeographyDisabled; - } else if (geography == @1) { + } else if ([geography integerValue] == [@1 integerValue]) { debugGeography = PACDebugGeographyEEA; - } else if (geography == @2) { + } else if ([geography integerValue] == [@2 integerValue]) { debugGeography = PACDebugGeographyNotEEA; } diff --git a/packages/admob/ios/RNFBAdmob/RNFBAdMobInterstitialDelegate.h b/packages/admob/ios/RNFBAdmob/RNFBAdMobInterstitialDelegate.h new file mode 100644 index 00000000..68320626 --- /dev/null +++ b/packages/admob/ios/RNFBAdmob/RNFBAdMobInterstitialDelegate.h @@ -0,0 +1,34 @@ +/** + * Copyright (c) 2016-present Invertase Limited & Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this library except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#import + +#import +#import + +#import "RNFBAdMobCommon.h" + +@interface RNFBAdMobInterstitialDelegate : NSObject + ++ (_Nonnull instancetype)sharedInstance; + ++ (void)sendInterstitialEvent:(NSString *)type + requestId:(NSNumber *)requestId + adUnitId:(NSString *)adUnitId + error:(nullable NSDictionary *)error; + +@end \ No newline at end of file diff --git a/packages/admob/ios/RNFBAdmob/RNFBAdMobInterstitialDelegate.m b/packages/admob/ios/RNFBAdmob/RNFBAdMobInterstitialDelegate.m new file mode 100644 index 00000000..149c69ca --- /dev/null +++ b/packages/admob/ios/RNFBAdmob/RNFBAdMobInterstitialDelegate.m @@ -0,0 +1,69 @@ +/** + * Copyright (c) 2016-present Invertase Limited & Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this library except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#import "RNFBAdMobInterstitialDelegate.h" + + +@implementation RNFBAdMobInterstitialDelegate + ++ (instancetype)sharedInstance { + static dispatch_once_t once; + static RNFBAdMobInterstitialDelegate *sharedInstance; + dispatch_once(&once, ^{ + sharedInstance = [[RNFBAdMobInterstitialDelegate alloc] init]; + }); + return sharedInstance; +} + +#pragma mark - +#pragma mark Helper Methods + ++ (void)sendInterstitialEvent:(NSString *)type + requestId:(NSNumber *)requestId + adUnitId:(NSString *)adUnitId + error:(nullable NSDictionary *)error { + [RNFBAdMobCommon sendAdEvent:EVENT_INTERSTITIAL requestId:requestId type:type adUnitId:adUnitId error:error data:nil]; +} + + +#pragma mark - +#pragma mark GADInterstitialDelegate Methods + +- (void)interstitialDidReceiveAd:(GADInterstitial *)ad { + [RNFBAdMobInterstitialDelegate sendInterstitialEvent:ADMOB_EVENT_LOADED requestId:[(RNFBGADInterstitial *) ad requestId] adUnitId:ad.adUnitID error:nil]; +} + +- (void)interstitial:(GADInterstitial *)ad didFailToReceiveAdWithError:(GADRequestError *)error { + NSDictionary *codeAndMessage = [RNFBAdMobCommon getCodeAndMessageFromAdError:error]; + [RNFBAdMobInterstitialDelegate sendInterstitialEvent:ADMOB_EVENT_ERROR requestId:[(RNFBGADInterstitial *) ad requestId] adUnitId:ad.adUnitID error:codeAndMessage]; +} + +- (void)interstitialWillPresentScreen:(GADInterstitial *)ad { + [RNFBAdMobInterstitialDelegate sendInterstitialEvent:ADMOB_EVENT_OPENED requestId:[(RNFBGADInterstitial *) ad requestId] adUnitId:ad.adUnitID error:nil]; +} + +- (void)interstitialDidDismissScreen:(GADInterstitial *)ad { + [RNFBAdMobInterstitialDelegate sendInterstitialEvent:ADMOB_EVENT_CLOSED requestId:[(RNFBGADInterstitial *) ad requestId] adUnitId:ad.adUnitID error:nil]; +} + +- (void)interstitialWillLeaveApplication:(GADInterstitial *)ad { + [RNFBAdMobInterstitialDelegate sendInterstitialEvent:ADMOB_EVENT_CLICKED requestId:[(RNFBGADInterstitial *) ad requestId] adUnitId:ad.adUnitID error:nil]; + [RNFBAdMobInterstitialDelegate sendInterstitialEvent:ADMOB_EVENT_LEFT_APPLICATION requestId:[(RNFBGADInterstitial *) ad requestId] adUnitId:ad.adUnitID error:nil]; +} + + +@end diff --git a/packages/admob/ios/RNFBAdmob/RNFBAdMobInterstitialModule.h b/packages/admob/ios/RNFBAdmob/RNFBAdMobInterstitialModule.h new file mode 100644 index 00000000..eb4ef761 --- /dev/null +++ b/packages/admob/ios/RNFBAdmob/RNFBAdMobInterstitialModule.h @@ -0,0 +1,26 @@ +// +/** + * Copyright (c) 2016-present Invertase Limited & Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this library except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + + +#import + +#import + +@interface RNFBAdMobInterstitialModule : NSObject + +@end diff --git a/packages/admob/ios/RNFBAdmob/RNFBAdMobInterstitialModule.m b/packages/admob/ios/RNFBAdmob/RNFBAdMobInterstitialModule.m new file mode 100644 index 00000000..4f5de6b6 --- /dev/null +++ b/packages/admob/ios/RNFBAdmob/RNFBAdMobInterstitialModule.m @@ -0,0 +1,102 @@ +// +/** + * Copyright (c) 2016-present Invertase Limited & Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this library except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#import + +#import "RNFBAdMobInterstitialModule.h" +#import "RNFBAdMobCommon.h" +#import "RNFBSharedUtils.h" +#import "RNFBAdMobInterstitialDelegate.h" + +static __strong NSMutableDictionary *interstitialMap; + +@implementation RNFBAdMobInterstitialModule +#pragma mark - +#pragma mark Module Setup + +RCT_EXPORT_MODULE(); + +- (dispatch_queue_t)methodQueue { + return dispatch_get_main_queue(); +} + +- (id)init { + self = [super init]; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + interstitialMap = [[NSMutableDictionary alloc] init]; + }); + return self; +} + ++ (BOOL)requiresMainQueueSetup { + return YES; +} + +- (void)dealloc { + [self invalidate]; +} + +- (void)invalidate { + for (NSNumber *id in [interstitialMap allKeys]) { + RNFBGADInterstitial * ad = interstitialMap[id]; + [ad setRequestId:@-1]; + [interstitialMap removeObjectForKey:id]; + } +} + +#pragma mark - +#pragma mark Firebase AdMob Methods + +RCT_EXPORT_METHOD(interstitialLoad + : + (nonnull + NSNumber *)requestId + :(NSString *)adUnitId + :(NSDictionary *)adRequestOptions +) { + RNFBGADInterstitial *interstitial = [[RNFBGADInterstitial alloc] initWithAdUnitID:adUnitId]; + [interstitial setRequestId:requestId]; + [interstitial loadRequest:[RNFBAdMobCommon buildAdRequest:adRequestOptions]]; + interstitial.delegate = [RNFBAdMobInterstitialDelegate sharedInstance]; + interstitialMap[requestId] = interstitial; +} + +RCT_EXPORT_METHOD(interstitialShow + : + (nonnull + NSNumber *)requestId + :(NSDictionary *)showOptions + :(RCTPromiseResolveBlock) resolve + :(RCTPromiseRejectBlock) reject +) { + GADInterstitial *interstitial = interstitialMap[requestId]; + if (interstitial.isReady) { + [interstitial presentFromRootViewController:RCTSharedApplication().delegate.window.rootViewController]; + resolve([NSNull null]); + } else { + [RNFBSharedUtils rejectPromiseWithUserInfo:reject userInfo:[@{ + @"code": @"not-ready", + @"message": @"Interstitial ad attempted to show but was not ready.", + } mutableCopy]]; + } +} + + + +@end diff --git a/packages/admob/ios/RNFBAdmob/RNFBAdmobModule.h b/packages/admob/ios/RNFBAdmob/RNFBAdMobModule.h similarity index 92% rename from packages/admob/ios/RNFBAdmob/RNFBAdmobModule.h rename to packages/admob/ios/RNFBAdmob/RNFBAdMobModule.h index 77d50309..a786b280 100644 --- a/packages/admob/ios/RNFBAdmob/RNFBAdmobModule.h +++ b/packages/admob/ios/RNFBAdmob/RNFBAdMobModule.h @@ -19,6 +19,6 @@ #import -@interface RNFBAdmobModule : NSObject +@interface RNFBAdMobModule : NSObject @end diff --git a/packages/admob/ios/RNFBAdmob/RNFBAdmobModule.m b/packages/admob/ios/RNFBAdmob/RNFBAdMobModule.m similarity index 94% rename from packages/admob/ios/RNFBAdmob/RNFBAdmobModule.m rename to packages/admob/ios/RNFBAdmob/RNFBAdMobModule.m index f276a759..d6fcea3b 100644 --- a/packages/admob/ios/RNFBAdmob/RNFBAdmobModule.m +++ b/packages/admob/ios/RNFBAdmob/RNFBAdMobModule.m @@ -17,11 +17,11 @@ #import -#import "RNFBAdmobModule.h" +#import "RNFBAdMobModule.h" #import "RNFBApp/RNFBSharedUtils.h" -@implementation RNFBAdmobModule +@implementation RNFBAdMobModule #pragma mark - #pragma mark Module Setup diff --git a/packages/admob/ios/RNFBAdmob/RNFBAdMobRewardedDelegate.h b/packages/admob/ios/RNFBAdmob/RNFBAdMobRewardedDelegate.h new file mode 100644 index 00000000..1c8d509b --- /dev/null +++ b/packages/admob/ios/RNFBAdmob/RNFBAdMobRewardedDelegate.h @@ -0,0 +1,36 @@ +// +/** + * Copyright (c) 2016-present Invertase Limited & Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this library except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#import + +#import +#import + +#import "RNFBAdMobCommon.h" + +@interface RNFBAdMobRewardedDelegate : NSObject + ++ (_Nonnull instancetype)sharedInstance; + ++ (void)sendRewardedEvent:(NSString *)type + requestId:(NSNumber *)requestId + adUnitId:(NSString *)adUnitId + error:(nullable NSDictionary *)error + data:(nullable NSDictionary *)data; + +@end diff --git a/packages/admob/ios/RNFBAdmob/RNFBAdMobRewardedDelegate.m b/packages/admob/ios/RNFBAdmob/RNFBAdMobRewardedDelegate.m new file mode 100644 index 00000000..4e246a63 --- /dev/null +++ b/packages/admob/ios/RNFBAdmob/RNFBAdMobRewardedDelegate.m @@ -0,0 +1,76 @@ +// +/** + * Copyright (c) 2016-present Invertase Limited & Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this library except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#import "RNFBAdMobRewardedDelegate.h" + +@implementation RNFBAdMobRewardedDelegate + ++ (instancetype)sharedInstance { + static dispatch_once_t once; + static RNFBAdMobRewardedDelegate *sharedInstance; + dispatch_once(&once, ^{ + sharedInstance = [[RNFBAdMobRewardedDelegate alloc] init]; + }); + return sharedInstance; +} + +#pragma mark - +#pragma mark Helper Methods + ++ (void)sendRewardedEvent:(NSString *)type + requestId:(NSNumber *)requestId + adUnitId:(NSString *)adUnitId + error:(nullable NSDictionary *)error + data:(nullable NSDictionary *)data { + [RNFBAdMobCommon sendAdEvent:EVENT_REWARDED requestId:requestId type:type adUnitId:adUnitId error:error data:data]; +} + + +#pragma mark - +#pragma mark GADInterstitialDelegate Methods + +/// Tells the delegate that the user earned a reward. +- (void)rewardedAd:(GADRewardedAd *)ad userDidEarnReward:(GADAdReward *)reward { + NSDictionary *data = @{ + @"type": reward.type, + @"amount": reward.amount, + }; + [RNFBAdMobRewardedDelegate sendRewardedEvent:ADMOB_EVENT_REWARDED_EARNED_REWARD requestId:[(RNFBGADRewarded *) ad requestId] adUnitId:ad.adUnitID error:nil data:data]; +} + +/// Tells the delegate that the rewarded ad was presented. +- (void)rewardedAdDidPresent:(GADRewardedAd *)ad { + [RNFBAdMobRewardedDelegate sendRewardedEvent:ADMOB_EVENT_OPENED requestId:[(RNFBGADRewarded *) ad requestId] adUnitId:ad.adUnitID error:nil data:nil]; +} + +/// Tells the delegate that the rewarded ad failed to present. +- (void)rewardedAd:(GADRewardedAd *)ad didFailToPresentWithError:(NSError *)error { + NSMutableDictionary *userError = [@{ + @"code": @"unknown", + @"message": error.localizedDescription, + } mutableCopy]; + [RNFBAdMobRewardedDelegate sendRewardedEvent:ADMOB_EVENT_ERROR requestId:[(RNFBGADRewarded *) ad requestId] adUnitId:ad.adUnitID error:userError data:nil]; +} + +/// Tells the delegate that the rewarded ad was dismissed. +- (void)rewardedAdDidDismiss:(GADRewardedAd *)ad { + [RNFBAdMobRewardedDelegate sendRewardedEvent:ADMOB_EVENT_CLOSED requestId:[(RNFBGADRewarded *) ad requestId] adUnitId:ad.adUnitID error:nil data:nil]; +} + +@end + diff --git a/packages/admob/ios/RNFBAdmob/RNFBAdMobRewardedModule.h b/packages/admob/ios/RNFBAdmob/RNFBAdMobRewardedModule.h new file mode 100644 index 00000000..5d61364b --- /dev/null +++ b/packages/admob/ios/RNFBAdmob/RNFBAdMobRewardedModule.h @@ -0,0 +1,25 @@ +// +/** + * Copyright (c) 2016-present Invertase Limited & Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this library except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#import + +#import + +@interface RNFBAdMobRewardedModule : NSObject + +@end \ No newline at end of file diff --git a/packages/admob/ios/RNFBAdmob/RNFBAdMobRewardedModule.m b/packages/admob/ios/RNFBAdmob/RNFBAdMobRewardedModule.m new file mode 100644 index 00000000..a1a74988 --- /dev/null +++ b/packages/admob/ios/RNFBAdmob/RNFBAdMobRewardedModule.m @@ -0,0 +1,114 @@ +// +/** + * Copyright (c) 2016-present Invertase Limited & Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this library except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#import + +#import "RNFBAdMobRewardedModule.h" +#import "RNFBAdMobRewardedDelegate.h" +#import "RNFBAdMobCommon.h" +#import "RNFBSharedUtils.h" +#import + +static __strong NSMutableDictionary *rewardedMap; + +@implementation RNFBAdMobRewardedModule +#pragma mark - +#pragma mark Module Setup + +RCT_EXPORT_MODULE(); + +- (dispatch_queue_t)methodQueue { + return dispatch_get_main_queue(); +} + +- (id)init { + self = [super init]; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + rewardedMap = [[NSMutableDictionary alloc] init]; + }); + return self; +} + ++ (BOOL)requiresMainQueueSetup { + return YES; +} + +- (void)dealloc { + [self invalidate]; +} + +- (void)invalidate { + for (NSNumber *id in [rewardedMap allKeys]) { + RNFBGADRewarded * ad = rewardedMap[id]; + [ad setRequestId:@-1]; + [rewardedMap removeObjectForKey:id]; + } +} + +#pragma mark - +#pragma mark Firebase AdMob Methods + +RCT_EXPORT_METHOD(rewardedLoad + : + (nonnull + NSNumber *)requestId + :(NSString *)adUnitId + :(NSDictionary *)adRequestOptions +) { + RNFBGADRewarded *rewarded = [[RNFBGADRewarded alloc] initWithAdUnitID:adUnitId]; + [rewarded setRequestId:requestId]; + GADRequest *request = [RNFBAdMobCommon buildAdRequest:adRequestOptions]; + rewardedMap[requestId] = rewarded; + [rewarded loadRequest:request completionHandler:^(GADRequestError *error) { + if (error != nil) { + NSDictionary *codeAndMessage = [RNFBAdMobCommon getCodeAndMessageFromAdError:error]; + [RNFBAdMobRewardedDelegate sendRewardedEvent:ADMOB_EVENT_ERROR requestId:requestId adUnitId:adUnitId error:codeAndMessage data:nil]; + } else { + GADAdReward *reward = rewarded.reward; + NSDictionary *data = @{ + @"type": reward.type, + @"amount": reward.amount, + }; + [RNFBAdMobRewardedDelegate sendRewardedEvent:ADMOB_EVENT_REWARDED_LOADED requestId:requestId adUnitId:adUnitId error:nil data:data]; + } + }]; +} + +RCT_EXPORT_METHOD(rewardedShow + : + (nonnull + NSNumber *)requestId + :(NSDictionary *)showOptions + :(RCTPromiseResolveBlock) resolve + :(RCTPromiseRejectBlock) reject +) { + GADRewardedAd *rewarded = rewardedMap[requestId]; + if (rewarded.isReady) { + [rewarded presentFromRootViewController:RCTSharedApplication().delegate.window.rootViewController delegate:[RNFBAdMobRewardedDelegate sharedInstance]]; + resolve([NSNull null]); + } else { + [RNFBSharedUtils rejectPromiseWithUserInfo:reject userInfo:[@{ + @"code": @"not-ready", + @"message": @"Rewarded ad attempted to show but was not ready.", + } mutableCopy]]; + } +} + +@end + diff --git a/packages/admob/lib/AdsConsent.js b/packages/admob/lib/AdsConsent.js index 201cd205..63023ccc 100644 --- a/packages/admob/lib/AdsConsent.js +++ b/packages/admob/lib/AdsConsent.js @@ -21,7 +21,7 @@ import { hasOwnProperty, isArray, isBoolean, isObject, isString, isUndefined } f import AdsConsentDebugGeography from './AdsConsentDebugGeography'; import AdsConsentStatus from './AdsConsentStatus'; -const native = NativeModules.RNFBAdmobConsentModule; +const native = NativeModules.RNFBAdMobConsentModule; export default { /** diff --git a/packages/admob/lib/TestIds.js b/packages/admob/lib/TestIds.js new file mode 100644 index 00000000..01f97277 --- /dev/null +++ b/packages/admob/lib/TestIds.js @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2016-present Invertase Limited & Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this library except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +import { Platform } from 'react-native'; + +export default { + ...Platform.select({ + android: { + BANNER: 'ca-app-pub-3940256099942544/6300978111', + INTERSTITIAL: 'ca-app-pub-3940256099942544/1033173712', + REWARDED: 'ca-app-pub-3940256099942544/5224354917', + }, + ios: { + BANNER: 'ca-app-pub-3940256099942544/2934735716', + INTERSTITIAL: 'ca-app-pub-3940256099942544/4411468910', + REWARDED: 'ca-app-pub-3940256099942544/1712485313', + }, + }), +}; diff --git a/packages/admob/lib/ads/BannerAd.js b/packages/admob/lib/ads/BannerAd.js new file mode 100644 index 00000000..3d222ae8 --- /dev/null +++ b/packages/admob/lib/ads/BannerAd.js @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2016-present Invertase Limited & Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this library except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +import React from 'react'; +import { requireNativeComponent } from 'react-native'; + +class BannerAd extends React.Component { + render() { + return ; + } +} + +const RNFBBannerAd = requireNativeComponent('RNFBBannerAd', BannerAd); + +export default BannerAd; diff --git a/packages/admob/lib/ads/RewardedAd.js b/packages/admob/lib/ads/RewardedAd.js index b19540ab..9ad5fdc2 100644 --- a/packages/admob/lib/ads/RewardedAd.js +++ b/packages/admob/lib/ads/RewardedAd.js @@ -75,6 +75,6 @@ export default class RewardedAd extends MobileAd { }; // todo validate options? common validator or local? - return this._admob.native.rewardedShow(this._requestId, this._adUnitId, options); + return this._admob.native.rewardedShow(this._requestId, options); } } diff --git a/packages/admob/lib/index.d.ts b/packages/admob/lib/index.d.ts index 3a1ac986..2563dd47 100644 --- a/packages/admob/lib/index.d.ts +++ b/packages/admob/lib/index.d.ts @@ -98,6 +98,7 @@ export namespace Admob { OPENED = 'opened', + // android only CLICKED = 'clicked', LEFT_APPLICATION = 'left_application', diff --git a/packages/admob/lib/index.js b/packages/admob/lib/index.js index 84f7a76b..c495ec55 100644 --- a/packages/admob/lib/index.js +++ b/packages/admob/lib/index.js @@ -24,7 +24,8 @@ import { import version from './version'; import AdsConsentDebugGeography from './AdsConsentDebugGeography'; import AdsConsentStatus from './AdsConsentStatus'; -import MaxAdContentRating from './MaxAdContentRating' +import MaxAdContentRating from './MaxAdContentRating'; +import TestIds from './TestIds'; import AdEventType from './AdEventType'; import RewardedAdEventType from './RewardedAdEventType'; @@ -36,12 +37,9 @@ const statics = { AdsConsentDebugGeography, AdsConsentStatus, AdEventType, + RewardedAdEventType, MaxAdContentRating, - TestIds: { - BANNER: 'ca-app-pub-3940256099942544/6300978111', - INTERSTITIAL: 'ca-app-pub-3940256099942544/1033173712', - REWARDED: 'ca-app-pub-3940256099942544/5224354917', - }, + TestIds, }; const namespace = 'admob'; @@ -54,6 +52,7 @@ class FirebaseAdMobModule extends FirebaseModule { super(...args); this.emitter.addListener('admob_interstitial_event', (event) => { + console.log(event) this.emitter.emit( `admob_interstitial_event:${event.adUnitId}:${event.requestId}`, event, @@ -116,6 +115,7 @@ export const firebase = getFirebaseRoot(); export AdsConsentDebugGeography from './AdsConsentDebugGeography'; export AdsConsentStatus from './AdsConsentStatus'; export MaxAdContentRating from './MaxAdContentRating'; +export TestIds from './TestIds'; export AdEventType from './AdEventType'; export RewardedAdEventType from './RewardedAdEventType'; @@ -123,4 +123,5 @@ export AdsConsent from './AdsConsent'; export InterstitialAd from './ads/InterstitialAd'; export RewardedAd from './ads/RewardedAd'; +export BannerAd from './ads/BannerAd'; diff --git a/packages/admob/lib/validateAdRequestOptions.js b/packages/admob/lib/validateAdRequestOptions.js index 4dc4aa47..b3ea6475 100644 --- a/packages/admob/lib/validateAdRequestOptions.js +++ b/packages/admob/lib/validateAdRequestOptions.js @@ -18,7 +18,7 @@ import { hasOwnProperty, isArray, - isBoolean, + isBoolean, isNumber, isObject, isString, isUndefined, @@ -106,16 +106,18 @@ export default function validateAdRequestOptions(options) { } if (options.location) { + const error = new Error("'options.location' expected an array value containing a latitude & longitude number value."); + if (!isArray(options.location)) { - // todo + throw error; } - if (!isString(options.location[0])) { - // todo + if (!isNumber(options.location[0])) { + throw error; } - if (!isString(options.location[1])) { - // todo + if (!isNumber(options.location[1])) { + throw error; } out.location = [options[0], options[1]]; diff --git a/packages/messaging/ios/RNFBMessaging/RNFBMessagingDelegate.h b/packages/messaging/ios/RNFBMessaging/RNFBMessagingDelegate.h index 3fe5ae06..1baf8ea3 100644 --- a/packages/messaging/ios/RNFBMessaging/RNFBMessagingDelegate.h +++ b/packages/messaging/ios/RNFBMessaging/RNFBMessagingDelegate.h @@ -1,4 +1,3 @@ -// /** * Copyright (c) 2016-present Invertase Limited & Contributors * diff --git a/tests/app.admob.js b/tests/app.admob.js index 5031bd30..e21ea669 100755 --- a/tests/app.admob.js +++ b/tests/app.admob.js @@ -19,22 +19,27 @@ import React, { useEffect, Component } from 'react'; import { AppRegistry, Image, StyleSheet, View, Text } from 'react-native'; -import { AdsConsent, InterstitialAd, RewardedAd } from '@react-native-firebase/admob'; +import { AdsConsent, InterstitialAd, RewardedAd, BannerAd, TestIds } from '@react-native-firebase/admob'; import firebase from '@react-native-firebase/app'; function Root() { async function init() { // await AdsConsent.setDebugGeography(1); + // + // const foo = await AdsConsent.requestInfoUpdate(['pub-4406399463942824']); + // console.warn(foo); + // const r = await AdsConsent.showForm({ + // privacyPolicy: 'https://invertase.io/privacy-policy', + // withPersonalizedAds: true, + // withNonPersonalizedAds: false, + // withAdFree: false, + // }); + // console.log(r); + // // const p = await AdsConsent.getAdProviders(); - // console.warn(p); - await AdsConsent.requestInfoUpdate(['pub-6189033257628751']); - const r = await AdsConsent.showForm({ - privacyPolicy: 'https://invertase.io/privacy-policy', - withPersonalizedAds: false, - withNonPersonalizedAds: false, - withAdFree: false, - }); + // console.warn('p', p); + // console.log(Interstitial) // await Interstitial.request('ca-app-pub-3940256099942544/1033173712', { // listener(event, error) { @@ -42,41 +47,52 @@ function Root() { // }, // }); + const options = { + requestNonPersonalizedAdsOnly: true, + networkExtras: { + user: '123', + foo: 'bar', + npa: '1', + }, + keywords: ['foo'], + testDevices: ['EMULATOR'], + location: [53.481073, -2.237074], + requestAgent: 'CoolAds', + }; - // const rewardedAd = RewardedAd.createForAdRequest('ca-app-pub-3940256099942544/5224354917', { - // requestNonPersonalizedAdsOnly: true, - // keywords: ['foo'], - // testDevices: ['EMULATOR'], + + const rewardedAd = RewardedAd.createForAdRequest(TestIds.REWARDED); // - // }); - // - // rewardedAd.onAdEvent(async (type, error, data) => { - // console.log('>>>', type, error, data); - // - // if (type === 'rewarded_loaded') { - // rewardedAd.show(); - // } - // }); + // rewardedAd.onAdEvent(console.log); // // rewardedAd.load(); + rewardedAd.onAdEvent(async (type, error, data) => { + console.log('>>>', type, error, data); + + if (type === 'rewarded_loaded') { + await rewardedAd.show(); + } + }); + // + rewardedAd.load(); + } + // testing ssh - not sure the name -// const interstitialAd = InterstitialAd.createForAdRequest('ca-app-pub-3940256099942544/1033173712', { +// const interstitialAd = InterstitialAd.createForAdRequest(TestIds.INTERSTITIAL, { // // // }); - - // interstitialAd.onAdEvent(async (type, error) => { - // console.log('>>>', type, error); - // if (type === 'loaded') { - // console.log('!!!!! show') - // await interstitialAd.show(); - // } - // }); - // - // setTimeout(() => { - // interstitialAd.load(); - // }, 1); - } +// await interstitialAd.show(); +// +// interstitialAd.onAdEvent(async (type, error) => { +// console.log('>>>', type, error); +// if (type === 'loaded') { +// console.log('!!!!! show') +// } +// }); +// +// interstitialAd.load(); +// } useEffect(() => { init().catch(console.error); @@ -84,7 +100,7 @@ function Root() { return ( - Admob + Hello ); } diff --git a/tests/ios/Podfile.lock b/tests/ios/Podfile.lock index 7f90a138..2611daf1 100644 --- a/tests/ios/Podfile.lock +++ b/tests/ios/Podfile.lock @@ -10,6 +10,11 @@ PODS: - Fabric (~> 1.9.0) - DoubleConversion (1.1.6) - Fabric (1.9.0) + - Firebase/AdMob (6.5.0): + - Firebase/CoreOnly + - Google-Mobile-Ads-SDK (~> 7.47) + - Firebase/Analytics (6.5.0): + - Firebase/Core - Firebase/Auth (6.5.0): - Firebase/CoreOnly - FirebaseAuth (~> 6.2.1) @@ -208,6 +213,8 @@ PODS: - DoubleConversion - glog - glog (0.3.5) + - Google-Mobile-Ads-SDK (7.47.0): + - GoogleAppMeasurement (~> 6.0) - GoogleAPIClientForREST/Core (1.3.9): - GTMSessionFetcher (>= 1.1.7) - GoogleAPIClientForREST/Vision (1.3.9): @@ -365,6 +372,8 @@ PODS: - React-Core (= 0.60.4) - React-fishhook (= 0.60.4) - RNFBAdmob (0.1.5): + - Firebase/AdMob (~> 6.5.0) + - Firebase/Analytics (~> 6.5.0) - Firebase/Core (~> 6.5.0) - PersonalizedAdConsent - React @@ -534,6 +543,7 @@ SPEC REPOS: - FirebasePerformance - FirebaseRemoteConfig - FirebaseStorage + - Google-Mobile-Ads-SDK - GoogleAPIClientForREST - GoogleAppMeasurement - GoogleMobileVision @@ -666,6 +676,7 @@ SPEC CHECKSUMS: FirebaseStorage: 618dd8fd886b30adf6e5d1915b1f5c18cb5c3944 Folly: 30e7936e1c45c08d884aa59369ed951a8e68cf51 glog: 1f3da668190260b06b429bb211bfbee5cd790c28 + Google-Mobile-Ads-SDK: a10b30f4a51a3283df7df3c9ea7e84553b508e4b GoogleAPIClientForREST: 44c7b678cbab11d26a47eab7309d6179b1a61f0c GoogleAppMeasurement: 183bd916af7f80deb67c01888368f1108d641832 GoogleMobileVision: 31cfb4319fd0c03d80105680abd9eae9da5e3b47 @@ -697,7 +708,7 @@ SPEC CHECKSUMS: React-RCTText: e0f224898b13af9aa036ea7cb3d438daa68c1044 React-RCTVibration: 0bea40cd51bd089bd591a8f74c86e91fdf2666c5 React-RCTWebSocket: 163873f4cdd5f1058a9483443404fc3801581cb6 - RNFBAdmob: d15e6ed11ded6a9521a4fbbd9178efd36c1fd6ce + RNFBAdmob: 138be145a3a80bd7cd3ebc0bda2cd12da9108b44 RNFBAnalytics: a878332b39d9794094173783c679dce0b2642c89 RNFBApp: 11a392342b99b20903922714462a8019cd230b56 RNFBAuth: 33c1a022fd8584d742f2763a80f5d02f65cc27ba diff --git a/tests/ios/testing/Info.plist b/tests/ios/testing/Info.plist index 00dfa5d9..2d972af3 100755 --- a/tests/ios/testing/Info.plist +++ b/tests/ios/testing/Info.plist @@ -82,5 +82,9 @@ rnfirebase_meta_testing_string abc + GADApplicationIdentifier + ca-app-pub-4406399463942824~1625911479 + GADDelayAppMeasurementInit +