cordova-plugin-admob-nextgen 1.8.9 → 2.0.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.
- package/README.md +77 -16
- package/capacitor-hook-admob-ids.js +2 -2
- package/package.json +1 -1
- package/plugin.xml +5 -4
- package/src/android/ConsentExecutor.java +58 -7
- package/src/ios/ConsentExecutor.m +58 -7
package/README.md
CHANGED
|
@@ -115,7 +115,7 @@ This plugin is regularly updated to support the latest standards.
|
|
|
115
115
|
|
|
116
116
|
| Component | Platform | Version | Release Notes |
|
|
117
117
|
| :--- | :--- | :--- | :--- |
|
|
118
|
-
| **GMA Next-Gen SDK** | Android | **1.2.
|
|
118
|
+
| **GMA Next-Gen SDK** | Android | **1.2.1** | [View Notes](https://developers.google.com/admob/android/next-gen/rel-notes) |
|
|
119
119
|
| **UMP SDK** | Android | **4.0.0** | [View Notes](https://developers.google.com/admob/android/privacy/release-notes) |
|
|
120
120
|
| **Mobile Ads SDK** | iOS | **13.3.0** | [View Notes](https://developers.google.com/admob/ios/rel-notes) |
|
|
121
121
|
| **UMP SDK** | iOS | **3.1.0** | [View Notes](https://developers.google.com/ad-manager/mobile-ads-sdk/ios/privacy/download) |
|
|
@@ -147,6 +147,7 @@ Add this to your `config.xml` to restore the plugin automatically.
|
|
|
147
147
|
|
|
148
148
|
### Supporting Mediation: **[⚡ admob-mediation-suite ](https://github.com/swaplab-engine/admob-mediation-suite)** (Optional)
|
|
149
149
|
### Supporting Native ads: **[⚡ cordova-plugin-admob-nextgen-native ](https://github.com/swaplab-engine/cordova-plugin-admob-nextgen-native)** (Optional)
|
|
150
|
+
### New COPPA : **[⚡ cordova-plugin-play-age-signals ](https://github.com/swaplab-engine/cordova-plugin-play-age-signals)** (Optional)
|
|
150
151
|
|
|
151
152
|
---
|
|
152
153
|
|
|
@@ -163,13 +164,11 @@ Add this to your `config.xml` to restore the plugin automatically.
|
|
|
163
164
|
|
|
164
165
|
**IMPORTANT:** Configure Global Settings and handle Privacy Consent (UMP) **BEFORE** initializing the SDK.
|
|
165
166
|
|
|
166
|
-
### Step 1: Global Configuration (Run First)
|
|
167
|
-
|
|
168
167
|
// Optional: Mute ads globally
|
|
169
168
|
admobNextGen.setAppVolume(0.5);
|
|
170
169
|
admobNextGen.setAppMuted(true);
|
|
171
170
|
|
|
172
|
-
### Step
|
|
171
|
+
### Step 1: Request Consent (UMP) & Initialize
|
|
173
172
|
|
|
174
173
|
// 1. Request Consent Information
|
|
175
174
|
admobNextGen.requestConsentInfo({
|
|
@@ -214,7 +213,7 @@ Add this to your `config.xml` to restore the plugin automatically.
|
|
|
214
213
|
}
|
|
215
214
|
|
|
216
215
|
|
|
217
|
-
|
|
216
|
+
// 4. Privacy options
|
|
218
217
|
admobNextGen.showPrivacyOptionsForm(function() {
|
|
219
218
|
startSdk();
|
|
220
219
|
}, function(err) {
|
|
@@ -247,19 +246,81 @@ function checkAppTracking() {
|
|
|
247
246
|
// admobNextGen.getTrackingAuthorizationStatus(success, error);
|
|
248
247
|
```
|
|
249
248
|
|
|
250
|
-
### Step
|
|
251
|
-
|
|
249
|
+
### Step 2: Check Consent Status (Smart Analysis)
|
|
250
|
+
- Understanding Consent Flags (`getTCData`)
|
|
252
251
|
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
console.log("Personalized Allowed: " + data.isPersonalizedAllowed); // Boolean: true/false
|
|
256
|
-
console.log("Status: " + data.statusMessage);
|
|
252
|
+
*(See [Publisher integration with the IAB Europe TCF](https://support.google.com/admanager/answer/9805023?hl=en#consent-policies))*
|
|
253
|
+
>
|
|
257
254
|
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
255
|
+
When you call `admobNextGen.getTCData()`, the plugin returns a JSON object containing raw IAB TCF strings alongside pre-calculated boolean flags. To comply with AdMob's strict policies in GDPR regions, This plugin provide specific AdMob flags alongside the legacy flag.
|
|
256
|
+
|
|
257
|
+
| Flag | Description | GDPR Requirements Checked |
|
|
258
|
+
| :--- | :--- | :--- |
|
|
259
|
+
| `isAdMobPersonalizedAdsAllowed` | **(Recommended)** Returns `true` if the user has granted all necessary consents for AdMob to serve **Personalized Ads**. | Consent for Purposes 1, 3, 4 **AND** (Consent or Legitimate Interest) for Purposes 2, 7, 9, 10 **AND** Vendor 755 (Google). |
|
|
260
|
+
| `isAdMobNonPersonalizedAdsAllowed` | **(Recommended)** Returns `true` if the user has granted the minimum consent required for AdMob to serve **Non-Personalized Ads**. | Consent for Purpose 1 **AND** (Consent or Legitimate Interest) for Purposes 2, 7, 9, 10 **AND** Vendor 755 (Google). |
|
|
261
|
+
| `isPersonalizedAllowed` | **(Legacy)** Preserved for backward compatibility with older app versions. **Not recommended for strict AdMob policy compliance.** | Consent for Purpose 1 only. |
|
|
262
|
+
|
|
263
|
+
> **Note:** If the user is outside the GDPR region (e.g., USA, Indonesia), all of the ready-to-use flags above will return `true` by default.
|
|
264
|
+
|
|
265
|
+
### A: Standard Usage (Ready-to-use Flags)
|
|
266
|
+
For most users, relying on the built-in boolean flags is the easiest way to ensure AdMob compliance without parsing complex strings.
|
|
267
|
+
|
|
268
|
+
```javascript
|
|
269
|
+
// Request TC Data
|
|
270
|
+
admobNextGen.getTCData(function(tcData) {
|
|
271
|
+
|
|
272
|
+
|
|
273
|
+
console.log(tcData.adMobConsentStatus);
|
|
274
|
+
|
|
275
|
+
if (tcData.isAdMobPersonalizedAdsAllowed) {
|
|
276
|
+
console.log("Consent met: AdMob can serve Personalized Ads.");
|
|
277
|
+
// Proceed to load ads...
|
|
278
|
+
}
|
|
279
|
+
else if (tcData.isAdMobNonPersonalizedAdsAllowed) {
|
|
280
|
+
console.log("Consent met: AdMob will serve Non-Personalized Ads (Limited Ads).");
|
|
281
|
+
// Proceed to load ads...
|
|
282
|
+
}
|
|
283
|
+
else {
|
|
284
|
+
console.log("Consent insufficient: AdMob cannot serve any ads.");
|
|
285
|
+
// You might want to show the privacy options form again here
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
});
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
#### B: Advanced Usage (Raw Data Control)
|
|
292
|
+
Advanced users who want full control over the consent logic can completely ignore the built-in boolean flags. The plugin exposes the raw IAB TCF data directly from the device's local storage (`purposeConsents`, `purposeLegitimateInterests`, `vendorConsents`, etc.), allowing you to manipulate and build custom conditions based on your own specific requirements.
|
|
293
|
+
|
|
294
|
+
```javascript
|
|
295
|
+
admobNextGen.getTCData(function(tcData) {
|
|
296
|
+
|
|
297
|
+
// Ignore the built-in flags and parse the raw data yourself.
|
|
298
|
+
// Note: IAB TCF strings are 1-indexed, but JavaScript strings are 0-indexed.
|
|
299
|
+
// Index 0 represents Purpose 1, Index 2 represents Purpose 3, etc.
|
|
300
|
+
|
|
301
|
+
const purposes = tcData.purposeConsents || "";
|
|
302
|
+
const lis = tcData.purposeLegitimateInterests || "";
|
|
303
|
+
const vendors = tcData.vendorConsents || "";
|
|
304
|
+
|
|
305
|
+
// const tcs = tcData.tcString;
|
|
306
|
+
// const region = tcData.gdprApplies;
|
|
307
|
+
|
|
308
|
+
// Custom logic example: Check if Purpose 1 and Purpose 3 are explicitly granted
|
|
309
|
+
const hasPurpose1 = purposes.charAt(0) === '1';
|
|
310
|
+
const hasPurpose3 = purposes.charAt(2) === '1';
|
|
311
|
+
|
|
312
|
+
// Check if Vendor 755 (Google) is granted (Index 754)
|
|
313
|
+
const hasGoogleVendor = vendors.charAt(754) === '1';
|
|
314
|
+
|
|
315
|
+
if (hasPurpose1 && hasPurpose3 && hasGoogleVendor) {
|
|
316
|
+
console.log("Custom advanced condition met!");
|
|
317
|
+
// Your custom ad loading logic here
|
|
318
|
+
} else {
|
|
319
|
+
console.log("Custom advanced condition failed.");
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
});
|
|
323
|
+
```
|
|
263
324
|
|
|
264
325
|
---
|
|
265
326
|
|
|
@@ -158,7 +158,7 @@ function run() {
|
|
|
158
158
|
admob = {
|
|
159
159
|
APP_ID_ANDROID: appIdAndroid ? appIdAndroid[1] : "ca-app-pub-3940256099942544~3347511713",
|
|
160
160
|
APP_ID_IOS: appIdIos ? appIdIos[1] : "ca-app-pub-3940256099942544~1458002511",
|
|
161
|
-
NEXT_GEN_SDK_VERSION: sdk ? sdk[1] : "1.2.
|
|
161
|
+
NEXT_GEN_SDK_VERSION: sdk ? sdk[1] : "1.2.1",
|
|
162
162
|
UMP_VERSION: ump ? ump[1] : "4.0.0"
|
|
163
163
|
};
|
|
164
164
|
}
|
|
@@ -167,7 +167,7 @@ function run() {
|
|
|
167
167
|
injectExclusionRules();
|
|
168
168
|
if (admob?.NEXT_GEN_SDK_VERSION || admob?.UMP_VERSION) {
|
|
169
169
|
updateGradleDependencies(
|
|
170
|
-
admob.NEXT_GEN_SDK_VERSION || "1.2.
|
|
170
|
+
admob.NEXT_GEN_SDK_VERSION || "1.2.1",
|
|
171
171
|
admob.UMP_VERSION || "4.0.0"
|
|
172
172
|
);
|
|
173
173
|
}
|
package/package.json
CHANGED
package/plugin.xml
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<?xml version='1.0' encoding='utf-8'?>
|
|
2
2
|
<plugin id="cordova-plugin-admob-nextgen"
|
|
3
|
-
version="
|
|
3
|
+
version="2.0.0"
|
|
4
4
|
xmlns="http://apache.org/cordova/ns/plugins/1.0"
|
|
5
5
|
xmlns:android="http://schemas.android.com/apk/res/android">
|
|
6
6
|
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
<framework src="com.google.android.libraries.ads.mobile.sdk:ads-mobile-sdk:$NEXT_GEN_SDK_VERSION" />
|
|
35
35
|
<framework src="com.google.android.ump:user-messaging-platform:$UMP_VERSION" />
|
|
36
36
|
|
|
37
|
-
<!-- Android
|
|
37
|
+
<!-- Android Next-Gen Classical API -->
|
|
38
38
|
<source-file src="src/android/AdMobNextGen.java" target-dir="app/src/main/java/com/emi/cordova/admob/nextgen" />
|
|
39
39
|
<source-file src="src/android/BannerExecutor.java" target-dir="app/src/main/java/com/emi/cordova/admob/nextgen" />
|
|
40
40
|
<source-file src="src/android/NativeExecutor.java" target-dir="app/src/main/java/com/emi/cordova/admob/nextgen" />
|
|
@@ -44,7 +44,7 @@
|
|
|
44
44
|
<source-file src="src/android/RewardedInterstitialExecutor.java" target-dir="app/src/main/java/com/emi/cordova/admob/nextgen" />
|
|
45
45
|
<source-file src="src/android/ConsentExecutor.java" target-dir="app/src/main/java/com/emi/cordova/admob/nextgen" />
|
|
46
46
|
<source-file src="src/android/GlobalSettingsExecutor.java" target-dir="app/src/main/java/com/emi/cordova/admob/nextgen" />
|
|
47
|
-
<!--
|
|
47
|
+
<!-- Android Next-Gen New Preloading API -->
|
|
48
48
|
<source-file src="src/android/preloading/AppOpenAdPreloadExecutor.java" target-dir="app/src/main/java/com/emi/cordova/admob/nextgen/preloading" />
|
|
49
49
|
<source-file src="src/android/preloading/BannerPreloadExecutor.java" target-dir="app/src/main/java/com/emi/cordova/admob/nextgen/preloading" />
|
|
50
50
|
<source-file src="src/android/preloading/InterstitialPreloadExecutor.java" target-dir="src/com/emi/cordova/admob/nextgen/preloading" />
|
|
@@ -53,7 +53,7 @@
|
|
|
53
53
|
|
|
54
54
|
</platform>
|
|
55
55
|
|
|
56
|
-
<preference name="NEXT_GEN_SDK_VERSION" default="1.2.
|
|
56
|
+
<preference name="NEXT_GEN_SDK_VERSION" default="1.2.1" />
|
|
57
57
|
<preference name="UMP_VERSION" default="4.0.0" />
|
|
58
58
|
<!-- Sample AdMob app ID: ca-app-pub-3940256099942544~3347511713 -->
|
|
59
59
|
<preference name="APP_ID_ANDROID" default="ca-app-pub-3940256099942544~3347511713" />
|
|
@@ -142,6 +142,7 @@
|
|
|
142
142
|
</pods>
|
|
143
143
|
</podspec>
|
|
144
144
|
|
|
145
|
+
<!--IOS SDK API 13+ -->
|
|
145
146
|
<header-file src="src/ios/AdMobNextGen.h" />
|
|
146
147
|
<source-file src="src/ios/AdMobNextGen.m" />
|
|
147
148
|
<header-file src="src/ios/ConsentExecutor.h" />
|
|
@@ -130,41 +130,79 @@ public class ConsentExecutor {
|
|
|
130
130
|
|
|
131
131
|
String tcString = prefs.getString("IABTCF_TCString", "");
|
|
132
132
|
String purposeConsents = prefs.getString("IABTCF_PurposeConsents", "");
|
|
133
|
+
String purposeLegitimateInterests = prefs.getString("IABTCF_PurposeLegitimateInterests", "");
|
|
133
134
|
String vendorConsents = prefs.getString("IABTCF_VendorConsents", "");
|
|
134
135
|
int gdprApplies = prefs.getInt("IABTCF_gdprApplies", 0);
|
|
135
136
|
|
|
136
137
|
tcData.put("tcString", tcString);
|
|
137
138
|
tcData.put("purposeConsents", purposeConsents);
|
|
139
|
+
tcData.put("purposeLegitimateInterests", purposeLegitimateInterests);
|
|
138
140
|
tcData.put("vendorConsents", vendorConsents);
|
|
139
141
|
tcData.put("gdprApplies", gdprApplies);
|
|
140
142
|
|
|
141
143
|
boolean isPersonalizedAllowed = false;
|
|
142
144
|
String statusMessage = "Unknown";
|
|
143
145
|
|
|
146
|
+
boolean isAdMobPersonalizedAdsAllowed = false;
|
|
147
|
+
boolean isAdMobNonPersonalizedAdsAllowed = false;
|
|
148
|
+
String adMobConsentStatus = "Unknown";
|
|
149
|
+
|
|
144
150
|
if (gdprApplies == 0) {
|
|
145
151
|
|
|
146
152
|
isPersonalizedAllowed = true;
|
|
147
153
|
statusMessage = "Not GDPR region. Personalized Ads allowed by default.";
|
|
154
|
+
|
|
155
|
+
isAdMobPersonalizedAdsAllowed = true;
|
|
156
|
+
isAdMobNonPersonalizedAdsAllowed = true;
|
|
157
|
+
adMobConsentStatus = "Not GDPR region. AdMob ads allowed by default.";
|
|
148
158
|
} else {
|
|
149
159
|
|
|
150
160
|
if (purposeConsents != null && purposeConsents.length() > 0) {
|
|
151
161
|
char p1 = purposeConsents.charAt(0);
|
|
152
162
|
if (p1 == '1') {
|
|
153
163
|
isPersonalizedAllowed = true;
|
|
154
|
-
statusMessage = "Purpose 1 Granted.
|
|
164
|
+
statusMessage = "Purpose 1 Granted. Legacy check passed.";
|
|
155
165
|
} else {
|
|
156
166
|
isPersonalizedAllowed = false;
|
|
157
|
-
statusMessage = "Purpose 1 Denied.
|
|
167
|
+
statusMessage = "Purpose 1 Denied. Legacy check failed.";
|
|
158
168
|
}
|
|
159
|
-
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
boolean hasPurpose1 = checkConsent(purposeConsents, 1);
|
|
172
|
+
boolean hasPurpose3 = checkConsent(purposeConsents, 3);
|
|
173
|
+
boolean hasPurpose4 = checkConsent(purposeConsents, 4);
|
|
160
174
|
|
|
161
|
-
|
|
162
|
-
|
|
175
|
+
boolean hasRequiredLI_or_Consent =
|
|
176
|
+
hasConsentOrLI(purposeConsents, purposeLegitimateInterests, 2) &&
|
|
177
|
+
hasConsentOrLI(purposeConsents, purposeLegitimateInterests, 7) &&
|
|
178
|
+
hasConsentOrLI(purposeConsents, purposeLegitimateInterests, 9) &&
|
|
179
|
+
hasConsentOrLI(purposeConsents, purposeLegitimateInterests, 10);
|
|
180
|
+
|
|
181
|
+
boolean hasVendorGoogle = checkConsent(vendorConsents, 755);
|
|
182
|
+
|
|
183
|
+
if (hasPurpose1 && hasVendorGoogle && hasRequiredLI_or_Consent) {
|
|
184
|
+
isAdMobNonPersonalizedAdsAllowed = true;
|
|
185
|
+
|
|
186
|
+
if (hasPurpose3 && hasPurpose4) {
|
|
187
|
+
isAdMobPersonalizedAdsAllowed = true;
|
|
188
|
+
adMobConsentStatus = "Strict requirements met for Personalized Ads (Purposes 1,3,4 + LI 2,7,9,10 + Vendor 755).";
|
|
189
|
+
} else {
|
|
190
|
+
isAdMobPersonalizedAdsAllowed = false;
|
|
191
|
+
adMobConsentStatus = "Requirements met for Non-Personalized Ads only.";
|
|
192
|
+
}
|
|
193
|
+
} else {
|
|
194
|
+
isAdMobPersonalizedAdsAllowed = false;
|
|
195
|
+
isAdMobNonPersonalizedAdsAllowed = false;
|
|
196
|
+
adMobConsentStatus = "Insufficient strict consent (Missing P1, Vendor 755, or P2,7,9,10). Limited Ads only.";
|
|
163
197
|
}
|
|
164
198
|
}
|
|
165
199
|
|
|
166
|
-
tcData.put("isPersonalizedAllowed", isPersonalizedAllowed);
|
|
167
|
-
tcData.put("statusMessage", statusMessage);
|
|
200
|
+
tcData.put("isPersonalizedAllowed", isPersonalizedAllowed);
|
|
201
|
+
tcData.put("statusMessage", statusMessage);
|
|
202
|
+
|
|
203
|
+
tcData.put("isAdMobPersonalizedAdsAllowed", isAdMobPersonalizedAdsAllowed);
|
|
204
|
+
tcData.put("isAdMobNonPersonalizedAdsAllowed", isAdMobNonPersonalizedAdsAllowed);
|
|
205
|
+
tcData.put("adMobConsentStatus", adMobConsentStatus);
|
|
168
206
|
|
|
169
207
|
callbackContext.success(tcData);
|
|
170
208
|
} catch (Exception e) {
|
|
@@ -172,6 +210,19 @@ public class ConsentExecutor {
|
|
|
172
210
|
}
|
|
173
211
|
}
|
|
174
212
|
|
|
213
|
+
private boolean checkConsent(String consentString, int id) {
|
|
214
|
+
if (consentString == null || consentString.length() < id) {
|
|
215
|
+
return false;
|
|
216
|
+
}
|
|
217
|
+
return consentString.charAt(id - 1) == '1';
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
private boolean hasConsentOrLI(String consents, String lis, int id) {
|
|
221
|
+
boolean hasConsent = checkConsent(consents, id);
|
|
222
|
+
boolean hasLI = checkConsent(lis, id);
|
|
223
|
+
return hasConsent || hasLI;
|
|
224
|
+
}
|
|
225
|
+
|
|
175
226
|
private String getDeviceId() {
|
|
176
227
|
try {
|
|
177
228
|
Context context = cordova.getActivity();
|
|
@@ -100,12 +100,14 @@
|
|
|
100
100
|
|
|
101
101
|
NSString *tcString = [prefs stringForKey:@"IABTCF_TCString"] ?: @"";
|
|
102
102
|
NSString *purposeConsents = [prefs stringForKey:@"IABTCF_PurposeConsents"] ?: @"";
|
|
103
|
+
NSString *purposeLegitimateInterests = [prefs stringForKey:@"IABTCF_PurposeLegitimateInterests"] ?: @"";
|
|
103
104
|
NSString *vendorConsents = [prefs stringForKey:@"IABTCF_VendorConsents"] ?: @"";
|
|
104
105
|
NSString *additionalConsent = [prefs stringForKey:@"IABTCF_AddtlConsent"] ?: @"";
|
|
105
|
-
NSInteger gdprApplies = [prefs integerForKey:@"IABTCF_gdprApplies"];
|
|
106
|
+
NSInteger gdprApplies = [prefs integerForKey:@"IABTCF_gdprApplies"];
|
|
106
107
|
|
|
107
108
|
tcData[@"tcString"] = tcString;
|
|
108
109
|
tcData[@"purposeConsents"] = purposeConsents;
|
|
110
|
+
tcData[@"purposeLegitimateInterests"] = purposeLegitimateInterests;
|
|
109
111
|
tcData[@"vendorConsents"] = vendorConsents;
|
|
110
112
|
tcData[@"additionalConsent"] = additionalConsent;
|
|
111
113
|
tcData[@"gdprApplies"] = @(gdprApplies);
|
|
@@ -113,24 +115,55 @@
|
|
|
113
115
|
BOOL isPersonalizedAllowed = NO;
|
|
114
116
|
NSString *statusMessage = @"Unknown";
|
|
115
117
|
|
|
116
|
-
|
|
118
|
+
BOOL isAdMobPersonalizedAdsAllowed = NO;
|
|
119
|
+
BOOL isAdMobNonPersonalizedAdsAllowed = NO;
|
|
120
|
+
NSString *adMobConsentStatus = @"Unknown";
|
|
117
121
|
|
|
122
|
+
if (gdprApplies == 0) {
|
|
118
123
|
isPersonalizedAllowed = YES;
|
|
119
124
|
statusMessage = @"Not GDPR region. Personalized Ads allowed by default.";
|
|
125
|
+
|
|
126
|
+
isAdMobPersonalizedAdsAllowed = YES;
|
|
127
|
+
isAdMobNonPersonalizedAdsAllowed = YES;
|
|
128
|
+
adMobConsentStatus = @"Not GDPR region. AdMob ads allowed by default.";
|
|
120
129
|
} else {
|
|
121
130
|
|
|
122
131
|
if (purposeConsents.length > 0) {
|
|
123
|
-
|
|
124
132
|
if ([purposeConsents hasPrefix:@"1"]) {
|
|
125
133
|
isPersonalizedAllowed = YES;
|
|
126
|
-
statusMessage = @"Purpose 1 Granted.
|
|
134
|
+
statusMessage = @"Purpose 1 Granted. Legacy check passed.";
|
|
127
135
|
} else {
|
|
128
136
|
isPersonalizedAllowed = NO;
|
|
129
|
-
statusMessage = @"Purpose 1 Denied.
|
|
137
|
+
statusMessage = @"Purpose 1 Denied. Legacy check failed.";
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
BOOL hasPurpose1 = [self checkConsent:purposeConsents consentId:1];
|
|
142
|
+
BOOL hasPurpose3 = [self checkConsent:purposeConsents consentId:3];
|
|
143
|
+
BOOL hasPurpose4 = [self checkConsent:purposeConsents consentId:4];
|
|
144
|
+
|
|
145
|
+
BOOL hasRequiredLI_or_Consent =
|
|
146
|
+
[self hasConsentOrLI:purposeConsents lis:purposeLegitimateInterests consentId:2] &&
|
|
147
|
+
[self hasConsentOrLI:purposeConsents lis:purposeLegitimateInterests consentId:7] &&
|
|
148
|
+
[self hasConsentOrLI:purposeConsents lis:purposeLegitimateInterests consentId:9] &&
|
|
149
|
+
[self hasConsentOrLI:purposeConsents lis:purposeLegitimateInterests consentId:10];
|
|
150
|
+
|
|
151
|
+
BOOL hasVendorGoogle = [self checkConsent:vendorConsents consentId:755];
|
|
152
|
+
|
|
153
|
+
if (hasPurpose1 && hasVendorGoogle && hasRequiredLI_or_Consent) {
|
|
154
|
+
isAdMobNonPersonalizedAdsAllowed = YES;
|
|
155
|
+
|
|
156
|
+
if (hasPurpose3 && hasPurpose4) {
|
|
157
|
+
isAdMobPersonalizedAdsAllowed = YES;
|
|
158
|
+
adMobConsentStatus = @"Strict requirements met for Personalized Ads (Purposes 1,3,4 + LI 2,7,9,10 + Vendor 755).";
|
|
159
|
+
} else {
|
|
160
|
+
isAdMobPersonalizedAdsAllowed = NO;
|
|
161
|
+
adMobConsentStatus = @"Requirements met for Non-Personalized Ads only.";
|
|
130
162
|
}
|
|
131
163
|
} else {
|
|
132
|
-
|
|
133
|
-
|
|
164
|
+
isAdMobPersonalizedAdsAllowed = NO;
|
|
165
|
+
isAdMobNonPersonalizedAdsAllowed = NO;
|
|
166
|
+
adMobConsentStatus = @"Insufficient strict consent (Missing P1, Vendor 755, or P2,7,9,10). Limited Ads only.";
|
|
134
167
|
}
|
|
135
168
|
}
|
|
136
169
|
|
|
@@ -143,6 +176,10 @@
|
|
|
143
176
|
tcData[@"statusMessage"] = statusMessage;
|
|
144
177
|
tcData[@"isACVersion2"] = @(isACVersion2);
|
|
145
178
|
|
|
179
|
+
tcData[@"isAdMobPersonalizedAdsAllowed"] = @(isAdMobPersonalizedAdsAllowed);
|
|
180
|
+
tcData[@"isAdMobNonPersonalizedAdsAllowed"] = @(isAdMobNonPersonalizedAdsAllowed);
|
|
181
|
+
tcData[@"adMobConsentStatus"] = adMobConsentStatus;
|
|
182
|
+
|
|
146
183
|
if (command) {
|
|
147
184
|
CDVPluginResult* res = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:tcData];
|
|
148
185
|
[self.plugin.commandDelegate sendPluginResult:res callbackId:command.callbackId];
|
|
@@ -156,6 +193,20 @@
|
|
|
156
193
|
});
|
|
157
194
|
}
|
|
158
195
|
|
|
196
|
+
- (BOOL)checkConsent:(NSString *)consentString consentId:(NSInteger)consentId {
|
|
197
|
+
if (!consentString || consentString.length < consentId) {
|
|
198
|
+
return NO;
|
|
199
|
+
}
|
|
200
|
+
unichar c = [consentString characterAtIndex:(consentId - 1)];
|
|
201
|
+
return c == '1';
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
- (BOOL)hasConsentOrLI:(NSString *)consents lis:(NSString *)lis consentId:(NSInteger)consentId {
|
|
205
|
+
BOOL hasConsent = [self checkConsent:consents consentId:consentId];
|
|
206
|
+
BOOL hasLI = [self checkConsent:lis consentId:consentId];
|
|
207
|
+
return hasConsent || hasLI;
|
|
208
|
+
}
|
|
209
|
+
|
|
159
210
|
- (void)showPrivacyOptionsForm:(CDVInvokedUrlCommand *)command {
|
|
160
211
|
dispatch_async(dispatch_get_main_queue(), ^{
|
|
161
212
|
[UMPConsentForm presentPrivacyOptionsFormFromViewController:self.plugin.viewController completionHandler:^(NSError * _Nullable formError) {
|