react-native-google-mobile-ads 4.2.0 → 5.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (83) hide show
  1. package/RNGoogleMobileAds.podspec +16 -9
  2. package/__tests__/consent.test.ts +17 -9
  3. package/android/build.gradle +4 -3
  4. package/android/src/main/java/io/invertase/googlemobileads/ReactNativeGoogleMobileAdsConsentModule.java +111 -168
  5. package/android/src/main/java/io/invertase/googlemobileads/ReactNativeGoogleMobileAdsModule.java +1 -1
  6. package/docs/common-reasons-for-ads-not-showing.mdx +26 -24
  7. package/docs/displaying-ads-hook.mdx +99 -0
  8. package/docs/displaying-ads.mdx +3 -4
  9. package/docs/european-user-consent.mdx +67 -156
  10. package/docs/index.mdx +16 -16
  11. package/docs/migrating-to-v5.mdx +63 -0
  12. package/docs.json +4 -2
  13. package/ios/RNGoogleMobileAds/RNGoogleMobileAdsConsentModule.h +0 -1
  14. package/ios/RNGoogleMobileAds/RNGoogleMobileAdsConsentModule.m +83 -124
  15. package/ios_config.sh +8 -0
  16. package/lib/commonjs/AdsConsent.js +58 -98
  17. package/lib/commonjs/AdsConsent.js.map +1 -1
  18. package/lib/commonjs/AdsConsentPurposes.js +47 -0
  19. package/lib/commonjs/AdsConsentPurposes.js.map +1 -0
  20. package/lib/commonjs/AdsConsentSpecialFeatures.js +39 -0
  21. package/lib/commonjs/AdsConsentSpecialFeatures.js.map +1 -0
  22. package/lib/commonjs/AdsConsentStatus.js +4 -3
  23. package/lib/commonjs/AdsConsentStatus.js.map +1 -1
  24. package/lib/commonjs/hooks/useAppOpenAd.js +51 -0
  25. package/lib/commonjs/hooks/useAppOpenAd.js.map +1 -0
  26. package/lib/commonjs/hooks/useFullScreenAd.js +120 -0
  27. package/lib/commonjs/hooks/useFullScreenAd.js.map +1 -0
  28. package/lib/commonjs/hooks/useInterstitialAd.js +51 -0
  29. package/lib/commonjs/hooks/useInterstitialAd.js.map +1 -0
  30. package/lib/commonjs/hooks/useRewardedAd.js +51 -0
  31. package/lib/commonjs/hooks/useRewardedAd.js.map +1 -0
  32. package/lib/commonjs/index.js +40 -0
  33. package/lib/commonjs/index.js.map +1 -1
  34. package/lib/commonjs/types/AdStates.js +6 -0
  35. package/lib/commonjs/types/AdStates.js.map +1 -0
  36. package/lib/commonjs/version.js +1 -1
  37. package/lib/commonjs/version.js.map +1 -1
  38. package/lib/module/AdsConsent.js +56 -98
  39. package/lib/module/AdsConsent.js.map +1 -1
  40. package/lib/module/AdsConsentPurposes.js +39 -0
  41. package/lib/module/AdsConsentPurposes.js.map +1 -0
  42. package/lib/module/AdsConsentSpecialFeatures.js +31 -0
  43. package/lib/module/AdsConsentSpecialFeatures.js.map +1 -0
  44. package/lib/module/AdsConsentStatus.js +4 -3
  45. package/lib/module/AdsConsentStatus.js.map +1 -1
  46. package/lib/module/hooks/useAppOpenAd.js +38 -0
  47. package/lib/module/hooks/useAppOpenAd.js.map +1 -0
  48. package/lib/module/hooks/useFullScreenAd.js +109 -0
  49. package/lib/module/hooks/useFullScreenAd.js.map +1 -0
  50. package/lib/module/hooks/useInterstitialAd.js +38 -0
  51. package/lib/module/hooks/useInterstitialAd.js.map +1 -0
  52. package/lib/module/hooks/useRewardedAd.js +38 -0
  53. package/lib/module/hooks/useRewardedAd.js.map +1 -0
  54. package/lib/module/index.js +5 -0
  55. package/lib/module/index.js.map +1 -1
  56. package/lib/module/types/AdStates.js +2 -0
  57. package/lib/module/types/AdStates.js.map +1 -0
  58. package/lib/module/version.js +1 -1
  59. package/lib/module/version.js.map +1 -1
  60. package/lib/typescript/AdsConsentPurposes.d.ts +148 -0
  61. package/lib/typescript/AdsConsentSpecialFeatures.d.ts +22 -0
  62. package/lib/typescript/AdsConsentStatus.d.ts +10 -6
  63. package/lib/typescript/hooks/useAppOpenAd.d.ts +9 -0
  64. package/lib/typescript/hooks/useFullScreenAd.d.ts +5 -0
  65. package/lib/typescript/hooks/useInterstitialAd.d.ts +9 -0
  66. package/lib/typescript/hooks/useRewardedAd.d.ts +9 -0
  67. package/lib/typescript/index.d.ts +6 -1
  68. package/lib/typescript/types/AdStates.d.ts +85 -0
  69. package/lib/typescript/types/AdsConsent.interface.d.ts +229 -180
  70. package/lib/typescript/version.d.ts +1 -1
  71. package/package.json +10 -4
  72. package/src/AdsConsent.ts +91 -135
  73. package/src/AdsConsentPurposes.ts +182 -0
  74. package/src/AdsConsentSpecialFeatures.ts +48 -0
  75. package/src/AdsConsentStatus.ts +11 -6
  76. package/src/hooks/useAppOpenAd.ts +46 -0
  77. package/src/hooks/useFullScreenAd.ts +104 -0
  78. package/src/hooks/useInterstitialAd.ts +46 -0
  79. package/src/hooks/useRewardedAd.ts +46 -0
  80. package/src/index.ts +5 -0
  81. package/src/types/AdStates.ts +87 -0
  82. package/src/types/AdsConsent.interface.ts +230 -187
  83. package/src/version.ts +1 -1
@@ -1,7 +1,8 @@
1
1
  require 'json'
2
2
  package = JSON.parse(File.read(File.join(__dir__, 'package.json')))
3
3
 
4
- google_ads_sdk_version = package['sdkVersions']['ios']['googleAds']
4
+ google_mobile_ads_sdk_version = package['sdkVersions']['ios']['googleMobileAds']
5
+ google_ump_sdk_version = package['sdkVersions']['ios']['googleUmp']
5
6
 
6
7
  Pod::Spec.new do |s|
7
8
  s.name = "RNGoogleMobileAds"
@@ -18,24 +19,30 @@ Pod::Spec.new do |s|
18
19
  s.social_media_url = 'http://twitter.com/invertaseio'
19
20
  s.ios.deployment_target = "10.0"
20
21
  s.source_files = 'ios/**/*.{h,m}'
22
+ s.frameworks = "AppTrackingTransparency"
21
23
 
22
24
  # React Native dependencies
23
25
  s.dependency 'React-Core'
24
26
 
25
27
  # Other dependencies
26
- s.dependency 'PersonalizedAdConsent', '~> 1.0.5'
28
+ if defined?($RNGoogleUmpSDKVersion)
29
+ Pod::UI.puts "#{s.name}: Using user specified Google UMP SDK version '#{$RNGoogleUmpSDKVersion}'"
30
+ google_ump_sdk_version = $RNGoogleUmpSDKVersion
31
+ end
32
+
33
+ s.dependency 'GoogleUserMessagingPlatform', google_ump_sdk_version
27
34
 
28
- if defined?($RNGoogleAdsSDKVersion)
29
- Pod::UI.puts "#{s.name}: Using user specified Google Mobile-Ads SDK version '#{$RNGoogleAdsSDKVersion}'"
30
- google_ads_sdk_version = $RNGoogleAdsSDKVersion
35
+ if defined?($RNGoogleMobileAdsSDKVersion)
36
+ Pod::UI.puts "#{s.name}: Using user specified Google Mobile-Ads SDK version '#{$RNGoogleMobileAdsSDKVersion}'"
37
+ google_mobile_ads_sdk_version = $RNGoogleMobileAdsSDKVersion
31
38
  end
32
39
 
33
40
  # AdMob dependencies
34
- s.dependency 'Google-Mobile-Ads-SDK', google_ads_sdk_version
41
+ s.dependency 'Google-Mobile-Ads-SDK', google_mobile_ads_sdk_version
35
42
 
36
- if defined?($RNGoogleAdsAsStaticFramework)
37
- Pod::UI.puts "#{s.name}: Using overridden static_framework value of '#{$RNGoogleAdsAsStaticFramework}'"
38
- s.static_framework = $RNGoogleAdsAsStaticFramework
43
+ if defined?($RNGoogleMobileAdsAsStaticFramework)
44
+ Pod::UI.puts "#{s.name}: Using overridden static_framework value of '#{$RNGoogleMobileAdsAsStaticFramework}'"
45
+ s.static_framework = $RNGoogleMobileAdsAsStaticFramework
39
46
  else
40
47
  s.static_framework = false
41
48
  end
@@ -2,23 +2,31 @@ import { AdsConsent } from '../src';
2
2
 
3
3
  describe('Google Mobile Ads AdsConsent', function () {
4
4
  describe('requestInfoUpdate', function () {
5
- it('throws if publisherIds is not an array', function () {
5
+ it('throws if options are not an object', function () {
6
6
  // @ts-ignore
7
- expect(() => AdsConsent.requestInfoUpdate('pub-123')).toThrowError(
8
- "AdsConsent.requestInfoUpdate(*) 'publisherIds' expected an array of string values.",
7
+ expect(() => AdsConsent.requestInfoUpdate('123')).toThrowError(
8
+ "AdsConsent.requestInfoUpdate(*) 'options' expected an object value.",
9
9
  );
10
10
  });
11
11
 
12
- it('throws if publisherIds is empty array', function () {
13
- expect(() => AdsConsent.requestInfoUpdate([])).toThrowError(
14
- "AdsConsent.requestInfoUpdate(*) 'publisherIds' list of publisher IDs cannot be empty.",
12
+ it('throws if options.debugGeography is not a valid value.', function () {
13
+ // @ts-ignore
14
+ expect(() => AdsConsent.requestInfoUpdate({ debugGeography: -1 })).toThrowError(
15
+ "AdsConsent.requestInfoUpdate(*) 'options.debugGeography' expected one of AdsConsentDebugGeography.DISABLED, AdsConsentDebugGeography.EEA or AdsConsentDebugGeography.NOT_EEA.",
16
+ );
17
+ });
18
+
19
+ it('throws if options.tagForUnderAgeOfConsent is not a boolean.', function () {
20
+ // @ts-ignore
21
+ expect(() => AdsConsent.requestInfoUpdate({ tagForUnderAgeOfConsent: '123' })).toThrowError(
22
+ "AdsConsent.requestInfoUpdate(*) 'options.tagForUnderAgeOfConsent' expected a boolean value.",
15
23
  );
16
24
  });
17
25
 
18
- it('throws if publisherIds contains non-string values', function () {
26
+ it('throws if options.testDeviceIdentifiers is not an array', function () {
19
27
  // @ts-ignore
20
- expect(() => AdsConsent.requestInfoUpdate(['foo', 123])).toThrowError(
21
- "AdsConsent.requestInfoUpdate(*) 'publisherIds[1]' expected a string value.",
28
+ expect(() => AdsConsent.requestInfoUpdate({ testDeviceIdentifiers: '123' })).toThrowError(
29
+ "AdsConsent.requestInfoUpdate(*) 'options.testDeviceIdentifiers' expected an array of string values.",
22
30
  );
23
31
  });
24
32
  });
@@ -22,6 +22,7 @@ plugins {
22
22
 
23
23
  def packageJson = PackageJson.getForProject(project)
24
24
  def googleMobileAdsVersion = packageJson['sdkVersions']['android']['googleMobileAds']
25
+ def googleUmpVersion = packageJson['sdkVersions']['android']['googleUmp']
25
26
  def jsonMinSdk = packageJson['sdkVersions']['android']['minSdk']
26
27
  def jsonTargetSdk = packageJson['sdkVersions']['android']['targetSdk']
27
28
  def jsonCompileSdk = packageJson['sdkVersions']['android']['compileSdk']
@@ -44,7 +45,7 @@ project.ext {
44
45
  ],
45
46
 
46
47
  ads : [
47
- consent: "1.0.6"
48
+ consent: googleUmpVersion,
48
49
  ],
49
50
  ],
50
51
  ])
@@ -88,8 +89,8 @@ repositories {
88
89
  }
89
90
 
90
91
  dependencies {
91
- implementation("com.google.android.gms:play-services-ads:20.5.0") { force = true; }
92
- implementation "com.google.android.ads.consent:consent-library:${ReactNative.ext.getVersion("ads", "consent")}"
92
+ implementation("com.google.android.gms:play-services-ads:${googleMobileAdsVersion}") { force = true; }
93
+ api "com.google.android.ump:user-messaging-platform:${googleUmpVersion}"
93
94
  }
94
95
 
95
96
  ReactNative.shared.applyPackageVersion()
@@ -16,211 +16,154 @@ package io.invertase.googlemobileads;
16
16
  * limitations under the License.
17
17
  *
18
18
  */
19
-
19
+ import android.content.SharedPreferences;
20
+ import android.preference.PreferenceManager;
20
21
  import com.facebook.react.bridge.Arguments;
21
22
  import com.facebook.react.bridge.Promise;
22
23
  import com.facebook.react.bridge.ReactApplicationContext;
23
24
  import com.facebook.react.bridge.ReactMethod;
24
25
  import com.facebook.react.bridge.ReadableArray;
25
26
  import com.facebook.react.bridge.ReadableMap;
26
- import com.facebook.react.bridge.WritableArray;
27
27
  import com.facebook.react.bridge.WritableMap;
28
- import com.google.ads.consent.AdProvider;
29
- import com.google.ads.consent.ConsentForm;
30
- import com.google.ads.consent.ConsentFormListener;
31
- import com.google.ads.consent.ConsentInfoUpdateListener;
32
- import com.google.ads.consent.ConsentInformation;
33
- import com.google.ads.consent.ConsentStatus;
34
- import com.google.ads.consent.DebugGeography;
28
+ import com.google.android.ump.ConsentDebugSettings;
29
+ import com.google.android.ump.ConsentInformation;
30
+ import com.google.android.ump.ConsentRequestParameters;
31
+ import com.google.android.ump.UserMessagingPlatform;
35
32
  import io.invertase.googlemobileads.common.ReactNativeModule;
36
- import java.net.MalformedURLException;
37
- import java.net.URL;
38
- import java.util.List;
33
+ import javax.annotation.Nonnull;
39
34
 
40
35
  public class ReactNativeGoogleMobileAdsConsentModule extends ReactNativeModule {
36
+
41
37
  private static final String TAG = "RNGoogleMobileAdsConsentModule";
42
38
  private ConsentInformation consentInformation;
43
- private ConsentForm consentForm;
44
39
 
45
40
  public ReactNativeGoogleMobileAdsConsentModule(ReactApplicationContext reactContext) {
46
41
  super(reactContext, TAG);
47
- consentInformation = ConsentInformation.getInstance(reactContext);
42
+ consentInformation = UserMessagingPlatform.getConsentInformation(reactContext);
48
43
  }
49
44
 
50
- private int getConsentStatusInt(ConsentStatus consentStatus) {
45
+ private String getConsentStatusString(int consentStatus) {
51
46
  switch (consentStatus) {
52
- case NON_PERSONALIZED:
53
- return 1;
54
- case PERSONALIZED:
55
- return 2;
56
- case UNKNOWN:
47
+ case ConsentInformation.ConsentStatus.REQUIRED:
48
+ return "REQUIRED";
49
+ case ConsentInformation.ConsentStatus.NOT_REQUIRED:
50
+ return "NOT_REQUIRED";
51
+ case ConsentInformation.ConsentStatus.OBTAINED:
52
+ return "OBTAINED";
53
+ case ConsentInformation.ConsentStatus.UNKNOWN:
57
54
  default:
58
- return 0;
55
+ return "UNKNOWN";
59
56
  }
60
57
  }
61
58
 
62
59
  @ReactMethod
63
- public void requestInfoUpdate(ReadableArray publisherIds, Promise promise) {
64
- @SuppressWarnings("SuspiciousToArrayCall")
65
- String[] publisherIdsArray = publisherIds.toArrayList().toArray(new String[0]);
66
-
67
- consentInformation.requestConsentInfoUpdate(
68
- publisherIdsArray,
69
- new ConsentInfoUpdateListener() {
70
- @Override
71
- public void onConsentInfoUpdated(ConsentStatus consentStatus) {
60
+ public void requestInfoUpdate(@Nonnull final ReadableMap options, final Promise promise) {
61
+ try {
62
+ ConsentRequestParameters.Builder paramsBuilder = new ConsentRequestParameters.Builder();
63
+ ConsentDebugSettings.Builder debugSettingsBuilder =
64
+ new ConsentDebugSettings.Builder(getApplicationContext());
65
+
66
+ if (options.hasKey("testDeviceIdentifiers")) {
67
+ ReadableArray devices = options.getArray("testDeviceIdentifiers");
68
+
69
+ for (int i = 0; i < devices.size(); i++) {
70
+ debugSettingsBuilder.addTestDeviceHashedId(devices.getString(i));
71
+ }
72
+ }
73
+
74
+ if (options.hasKey("debugGeography")) {
75
+ debugSettingsBuilder.setDebugGeography(options.getInt("debugGeography"));
76
+ }
77
+
78
+ paramsBuilder.setConsentDebugSettings(debugSettingsBuilder.build());
79
+
80
+ if (options.hasKey("tagForUnderAgeOfConsent")) {
81
+ paramsBuilder.setTagForUnderAgeOfConsent(options.getBoolean("tagForUnderAgeOfConsent"));
82
+ }
83
+
84
+ ConsentRequestParameters consentRequestParameters = paramsBuilder.build();
85
+
86
+ if (getCurrentActivity() == null) {
87
+ rejectPromiseWithCodeAndMessage(
88
+ promise,
89
+ "null-activity",
90
+ "Attempted to request a consent info update but the current Activity was null.");
91
+ return;
92
+ }
93
+
94
+ consentInformation.requestConsentInfoUpdate(
95
+ getCurrentActivity(),
96
+ consentRequestParameters,
97
+ () -> {
72
98
  WritableMap requestInfoMap = Arguments.createMap();
73
- requestInfoMap.putInt("status", getConsentStatusInt(consentStatus));
99
+ requestInfoMap.putString(
100
+ "status", getConsentStatusString(consentInformation.getConsentStatus()));
74
101
  requestInfoMap.putBoolean(
75
- "isRequestLocationInEeaOrUnknown",
76
- consentInformation.isRequestLocationInEeaOrUnknown());
102
+ "isConsentFormAvailable", consentInformation.isConsentFormAvailable());
77
103
  promise.resolve(requestInfoMap);
78
- }
79
-
80
- @Override
81
- public void onFailedToUpdateConsentInfo(String reason) {
82
- rejectPromiseWithCodeAndMessage(promise, "consent-update-failed", reason);
83
- }
84
- });
85
- }
86
-
87
- @ReactMethod
88
- public void showForm(ReadableMap options, Promise promise) {
89
- if (getCurrentActivity() == null) {
90
- rejectPromiseWithCodeAndMessage(
91
- promise,
92
- "null-activity",
93
- "Consent form attempted to show but the current Activity was null.");
94
- return;
95
- }
96
- getCurrentActivity()
97
- .runOnUiThread(
98
- () -> {
99
- URL privacyUrl = null;
100
-
101
- try {
102
- privacyUrl = new URL(options.getString("privacyPolicy"));
103
- } catch (MalformedURLException e) {
104
- // Validated in JS land
105
- }
106
-
107
- ConsentFormListener listener =
108
- new ConsentFormListener() {
109
- @Override
110
- public void onConsentFormLoaded() {
111
- try {
112
- consentForm.show();
113
- } catch (Exception e) {
114
- rejectPromiseWithCodeAndMessage(
115
- promise, "consent-form-error", e.toString());
116
- }
117
- }
118
-
119
- @Override
120
- public void onConsentFormClosed(
121
- ConsentStatus consentStatus, Boolean userPrefersAdFree) {
122
- WritableMap consentFormMap = Arguments.createMap();
123
- consentFormMap.putInt("status", getConsentStatusInt(consentStatus));
124
- consentFormMap.putBoolean("userPrefersAdFree", userPrefersAdFree);
125
- promise.resolve(consentFormMap);
126
- }
127
-
128
- @Override
129
- public void onConsentFormError(String reason) {
130
- rejectPromiseWithCodeAndMessage(promise, "consent-form-error", reason);
131
- }
132
- };
133
-
134
- ConsentForm.Builder builder =
135
- new ConsentForm.Builder(getCurrentActivity(), privacyUrl).withListener(listener);
136
-
137
- if (options.hasKey("withPersonalizedAds")
138
- && options.getBoolean("withPersonalizedAds")) {
139
- builder = builder.withPersonalizedAdsOption();
140
- }
141
-
142
- if (options.hasKey("withNonPersonalizedAds")
143
- && options.getBoolean("withNonPersonalizedAds")) {
144
- builder = builder.withNonPersonalizedAdsOption();
145
- }
146
-
147
- if (options.hasKey("withAdFree") && options.getBoolean("withAdFree")) {
148
- builder = builder.withAdFreeOption();
149
- }
150
-
151
- consentForm = builder.build();
152
- consentForm.load();
153
- });
154
- }
155
-
156
- @ReactMethod
157
- public void getStatus(Promise promise) {
158
- ConsentStatus status = consentInformation.getConsentStatus();
159
- promise.resolve(getConsentStatusInt(status));
160
- }
161
-
162
- @ReactMethod
163
- public void setStatus(int status, Promise promise) {
164
- ConsentStatus consentStatus = ConsentStatus.UNKNOWN;
165
-
166
- switch (status) {
167
- case 0:
168
- consentStatus = ConsentStatus.UNKNOWN;
169
- break;
170
- case 1:
171
- consentStatus = ConsentStatus.NON_PERSONALIZED;
172
- break;
173
- case 2:
174
- consentStatus = ConsentStatus.PERSONALIZED;
175
- break;
104
+ },
105
+ formError ->
106
+ rejectPromiseWithCodeAndMessage(
107
+ promise, "consent-update-failed", formError.getMessage()));
108
+ } catch (Exception e) {
109
+ rejectPromiseWithCodeAndMessage(promise, "consent-update-failed", e.toString());
176
110
  }
177
-
178
- consentInformation.setConsentStatus(consentStatus);
179
- promise.resolve(null);
180
111
  }
181
112
 
182
113
  @ReactMethod
183
- public void getAdProviders(Promise promise) {
184
- List<AdProvider> providers = consentInformation.getAdProviders();
185
-
186
- WritableArray formattedAdProviders = Arguments.createArray();
187
-
188
- for (AdProvider provider : providers) {
189
- WritableMap formattedProvider = Arguments.createMap();
190
- formattedProvider.putString("companyName", provider.getName());
191
- formattedProvider.putString("companyId", provider.getId());
192
- formattedProvider.putString("privacyPolicyUrl", provider.getPrivacyPolicyUrlString());
193
- formattedAdProviders.pushMap(formattedProvider);
114
+ public void showForm(final Promise promise) {
115
+ try {
116
+ if (getCurrentActivity() == null) {
117
+ rejectPromiseWithCodeAndMessage(
118
+ promise,
119
+ "null-activity",
120
+ "Consent form attempted to show but the current Activity was null.");
121
+ return;
122
+ }
123
+ getCurrentActivity()
124
+ .runOnUiThread(
125
+ () ->
126
+ UserMessagingPlatform.loadConsentForm(
127
+ getReactApplicationContext(),
128
+ consentForm ->
129
+ consentForm.show(
130
+ getCurrentActivity(),
131
+ formError -> {
132
+ if (formError != null) {
133
+ rejectPromiseWithCodeAndMessage(
134
+ promise, "consent-form-error", formError.getMessage());
135
+ } else {
136
+ WritableMap consentFormMap = Arguments.createMap();
137
+ consentFormMap.putString(
138
+ "status",
139
+ getConsentStatusString(
140
+ consentInformation.getConsentStatus()));
141
+ promise.resolve(consentFormMap);
142
+ }
143
+ }),
144
+ formError ->
145
+ rejectPromiseWithCodeAndMessage(
146
+ promise, "consent-form-error", formError.getMessage())));
147
+ } catch (Exception e) {
148
+ rejectPromiseWithCodeAndMessage(promise, "consent-form-error", e.toString());
194
149
  }
195
-
196
- promise.resolve(formattedAdProviders);
197
150
  }
198
151
 
199
152
  @ReactMethod
200
- public void setTagForUnderAgeOfConsent(boolean tag, Promise promise) {
201
- consentInformation.setTagForUnderAgeOfConsent(tag);
202
- promise.resolve(null);
203
- }
204
-
205
- @ReactMethod
206
- public void setDebugGeography(int geography, Promise promise) {
207
- if (geography == 0) {
208
- consentInformation.setDebugGeography(DebugGeography.DEBUG_GEOGRAPHY_DISABLED);
209
- } else if (geography == 1) {
210
- consentInformation.setDebugGeography(DebugGeography.DEBUG_GEOGRAPHY_EEA);
211
- } else if (geography == 2) {
212
- consentInformation.setDebugGeography(DebugGeography.DEBUG_GEOGRAPHY_NOT_EEA);
213
- }
214
-
215
- promise.resolve(null);
153
+ public void reset() {
154
+ consentInformation.reset();
216
155
  }
217
156
 
218
157
  @ReactMethod
219
- public void addTestDevices(ReadableArray deviceIds, Promise promise) {
220
- List<Object> devices = deviceIds.toArrayList();
221
- for (Object device : devices) {
222
- consentInformation.addTestDevice((String) device);
158
+ public void getTCString(Promise promise) {
159
+ try {
160
+ SharedPreferences prefs =
161
+ PreferenceManager.getDefaultSharedPreferences(getReactApplicationContext());
162
+ // https://github.com/InteractiveAdvertisingBureau/GDPR-Transparency-and-Consent-Framework/blob/master/TCFv2/IAB%20Tech%20Lab%20-%20CMP%20API%20v2.md#in-app-details
163
+ String tcString = prefs.getString("IABTCF_TCString", null);
164
+ promise.resolve(tcString);
165
+ } catch (Exception e) {
166
+ rejectPromiseWithCodeAndMessage(promise, "consent-string-error", e.toString());
223
167
  }
224
- promise.resolve(null);
225
168
  }
226
169
  }
@@ -117,7 +117,7 @@ public class ReactNativeGoogleMobileAdsModule extends ReactNativeModule {
117
117
  @ReactMethod
118
118
  public void initialize(Promise promise) {
119
119
  MobileAds.initialize(
120
- getContext(),
120
+ getApplicationContext(),
121
121
  new OnInitializationCompleteListener() {
122
122
  @Override
123
123
  public void onInitializationComplete(InitializationStatus initializationStatus) {
@@ -13,6 +13,7 @@ You'll be notified of approval or rejection via email after review.
13
13
 
14
14
  New apps and ad units take some time to activate.
15
15
  Here are common reasons you may not see live impressions immediately:
16
+
16
17
  - It usually takes at least an hour after you create an app or ad unit
17
18
  - Sometimes it can take a few days for ads to appear in new apps or ad units
18
19
  - New iOS apps will not show Google ads until they’re listed in the Apple App Store
@@ -35,6 +36,7 @@ Test devices can either be added in the AdMob UI or programmatically using the G
35
36
  Follow the steps below to add your device as a test device.
36
37
 
37
38
  #### Add your test device in the AdMob UI
39
+
38
40
  For a simple, non-programmatic way to add a test device and test new or existing app builds, use the AdMob UI.
39
41
  [Learn how](https://support.google.com/admob/answer/9691433).
40
42
 
@@ -48,39 +50,39 @@ If you want to test ads in your app as you're developing, follow the steps below
48
50
 
49
51
  3. Check the console for a message that looks like this:
50
52
 
51
- ```
52
- GADMobileAds.sharedInstance.requestConfiguration.testDeviceIdentifiers =
53
- @[ @"2077ef9a63d2b398840261c8221a0c9b" ]; // Sample device ID
54
- ```
53
+ ```
54
+ GADMobileAds.sharedInstance.requestConfiguration.testDeviceIdentifiers =
55
+ @[ @"2077ef9a63d2b398840261c8221a0c9b" ]; // Sample device ID
56
+ ```
55
57
 
56
- Copy your test device ID to your clipboard.
58
+ Copy your test device ID to your clipboard.
57
59
 
58
60
  4. Check the logcat output for a message that looks like the one below, which shows you your device ID and how to add it as a test device:
59
61
 
60
- ```
61
- I/Ads: Use RequestConfiguration.Builder.setTestDeviceIds(Arrays.asList("33BE2250B43518CCDA7DE426D04EE231"))
62
- to get test ads on this device."
63
- ```
62
+ ```
63
+ I/Ads: Use RequestConfiguration.Builder.setTestDeviceIds(Arrays.asList("33BE2250B43518CCDA7DE426D04EE231"))
64
+ to get test ads on this device."
65
+ ```
64
66
 
65
- Copy your test device ID to your clipboard.
67
+ Copy your test device ID to your clipboard.
66
68
 
67
69
  5. Modify your code to set the test device ID through testDeviceIdentifiers
68
70
 
69
- ```js
70
- import mobileAds from 'react-native-google-mobile-ads';
71
+ ```js
72
+ import mobileAds from 'react-native-google-mobile-ads';
71
73
 
72
- mobileAds()
73
- .setRequestConfiguration({
74
- // An array of test device IDs to add to the allow list.
75
- testDeviceIdentifiers: ["2077ef9a63d2b398840261c8221a0c9b", "EMULATOR"]
76
- })
77
- .then(() => {
78
- // Request config successfully set!
79
- });
80
- ```
74
+ mobileAds()
75
+ .setRequestConfiguration({
76
+ // An array of test device IDs to add to the allow list.
77
+ testDeviceIdentifiers: ['2077ef9a63d2b398840261c8221a0c9b', 'EMULATOR'],
78
+ })
79
+ .then(() => {
80
+ // Request config successfully set!
81
+ });
82
+ ```
81
83
 
82
- 5. Re-run your app. If the ad is a Google ad, you'll see a Test Ad label centered at the top of the ad.
83
- Ads with this Test Ad label are safe to click. Requests, impressions, and clicks on test ads will not show up in your account's reports.
84
+ 6. Re-run your app. If the ad is a Google ad, you'll see a Test Ad label centered at the top of the ad.
85
+ Ads with this Test Ad label are safe to click. Requests, impressions, and clicks on test ads will not show up in your account's reports.
84
86
 
85
87
  ## Emulator vs real device
86
88
 
@@ -89,4 +91,4 @@ In some cases ads won't show up on an emulator but will show up while testing on
89
91
  ## Extra links
90
92
 
91
93
  - Mobile Ads SDK [iOS](https://developers.google.com/admob/ios/quick-start), [Android](https://developers.google.com/admob/android/quick-start)
92
- - [Common reasons for ads not showing](https://support.google.com/admob/answer/9469204)
94
+ - [Common reasons for ads not showing](https://support.google.com/admob/answer/9469204)
@@ -0,0 +1,99 @@
1
+ # Hooks
2
+
3
+ The AdMob package provides hooks to help you to display ads in a functional component with tiny code. The supported ad formats are full-screen ads: App open, Interstitial & Rewarded.
4
+
5
+ ## Load an ad
6
+
7
+ You can create a new ad by adding a corresponding ad type's hook to your component.
8
+
9
+ The first argument of the hook is the "Ad Unit ID".
10
+ For testing, we can use a Test ID, however for production the ID from the
11
+ Google AdMob dashboard under "Ad units" should be used:
12
+
13
+ ```tsx {4-8}
14
+ import { useInterstitialAd, TestIds } from 'react-native-google-mobile-ads';
15
+
16
+ export default function App() {
17
+ const interstitialAd = useInterstitialAd(TestIds.Interstitial, {
18
+ requestNonPersonalizedAdsOnly: true,
19
+ });
20
+
21
+ return <View>{/* ... */}</View>;
22
+ }
23
+ ```
24
+
25
+ > The `adUnitid` parameter can also be used to manage creation and destruction of an ad instance.
26
+ > If `adUnitid` is set or changed, new ad instance will be created and previous ad instance will be destroyed if exists.
27
+ > If `adUnitid` is set to `null`, no ad instance will be created and previous ad instance will be destroyed if exists.
28
+
29
+ The second argument is an additional optional request options object to be sent whilst loading an advert, such as keywords & location.
30
+ Setting additional request options helps AdMob choose better tailored ads from the network. View the [`RequestOptions`](/reference/admob/requestoptions)
31
+ documentation to view the full range of options available.
32
+
33
+ ## Show the ad
34
+
35
+ The hook returns several states and functions to control ad.
36
+
37
+ ```tsx
38
+ import { useInterstitialAd, TestIds } from 'react-native-google-mobile-ads';
39
+
40
+ export default function App({ navigation }) {
41
+ const { isLoaded, isClosed, load, show } = useInterstitialAd(TestIds.Interstitial, {
42
+ requestNonPersonalizedAdsOnly: true,
43
+ });
44
+
45
+ useEffect(() => {
46
+ // Start loading the interstitial straight away
47
+ load();
48
+ }, [load]);
49
+
50
+ useEffect(() => {
51
+ if (isClosed) {
52
+ // Action after the ad is closed
53
+ navigation.navigate('NextScreen');
54
+ }
55
+ }, [isClosed, navigation]);
56
+
57
+ return (
58
+ <View>
59
+ <Button
60
+ title="Navigate to next screen"
61
+ onPress={() => {
62
+ if (isLoaded) {
63
+ show();
64
+ } else {
65
+ // No advert ready to show yet
66
+ navigation.navigate('NextScreen');
67
+ }
68
+ }}
69
+ />
70
+ </View>
71
+ );
72
+ }
73
+ ```
74
+
75
+ The code above immediately starts to load a new advert from the network (via `load()`).
76
+ When user presses button, it checks if the ad is loaded via `isLoaded` value,
77
+ then the `show` function is called and the advert is shown over-the-top of your application.
78
+ Otherwise, if the ad is not loaded, the `navigation.navigate` method is called to navigate to the next screen without showing the ad.
79
+ After the ad is closed, the `isClosed` value is set to `true` and the `navigation.navigate` method is called to navigate to the next screen.
80
+
81
+ If needed, you can reuse the existing hook to load more adverts and show them when required. The states are initialized when the `load` function is called.
82
+
83
+ Return values of the hook are:
84
+
85
+ | Name | Type | Description |
86
+ | :------------- | :--------------------------------- | :----------------------------------------------------------------------------------------------------------------- |
87
+ | isLoaded | boolean | Whether the ad is loaded and ready to to be shown to the user. |
88
+ | isOpened | boolean | Whether the ad is opened. The value is remained `true` even after the ad is closed unless **new ad is requested**. |
89
+ | isClosed | boolean | Whether your ad is dismissed. |
90
+ | isShowing | boolean | Whether your ad is showing. The value is equal with `isOpened && !isClosed`. |
91
+ | error | Error \| undefined | `Error` object throwed during ad load. |
92
+ | reward | [RewardedAdReward](#) \| undefined | Loaded reward item of the Rewarded Ad. Available only in RewardedAd. |
93
+ | isEarnedReward | boolean | Whether the user earned the reward by Rewarded Ad. |
94
+ | load | Function | Start loading the advert with the provided RequestOptions. |
95
+ | show | Function | Show the loaded advert to the user. |
96
+
97
+ > Note that `isOpened` value remains `true` even after the ad is closed.
98
+ > The value changes to `false` when ad is initialized via calling `load()`.
99
+ > To determine whether the ad is currently showing, use `isShowing` value.
@@ -27,11 +27,10 @@ const appOpenAd = AppOpenAd.createForAdRequest(adUnitId, {
27
27
  });
28
28
 
29
29
  // Preload an app open ad
30
- appOpenAd.load()
30
+ appOpenAd.load();
31
31
 
32
32
  // Show the app open ad when user brings the app to the foreground.
33
- appOpenAd.show()
34
-
33
+ appOpenAd.show();
35
34
  ```
36
35
 
37
36
  ### Consider ad expiration
@@ -159,7 +158,7 @@ The purpose of a rewarded ad is to reward users with _something_ after completin
159
158
  as watching a video or submitting an option via an interactive form. If the user completes the action, you can reward them
160
159
  with something (e.g. in-game currency).
161
160
 
162
- To create a new interstitial, call the `createForAdRequest` method from the `RewardedAd` class. The first argument
161
+ To create a new rewarded ad, call the `createForAdRequest` method from the `RewardedAd` class. The first argument
163
162
  of the method is the "Ad Unit ID". For testing, we can use a Test ID, however for production the ID from the
164
163
  Google AdMob dashboard under "Ad units" should be used:
165
164