@ququplay/admob 8.2.1 → 8.2.2

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.
@@ -22,12 +22,8 @@ import java.util.List;
22
22
 
23
23
  public class AdConsentExecutor extends Executor {
24
24
 
25
- // Unity Ads in Google's Additional Consent list (https://storage.googleapis.com/tcfac/additional-consent-providers.csv).
26
- private static final String UNITY_ADS_PROVIDER_ID = "3234";
27
-
28
- // Consent last updated before this date (2026-10-27) may not mention Unity Ads, which joined the ad partners in
29
- // October 2026. Newer consent is never asked for again on this account.
30
- private static final long UNITY_ADS_CONSENT_SINCE_MILLIS = 1793059200000L;
25
+ // Unity Ads in the IAB TCF Global Vendor List ("Unity Technologies SF").
26
+ private static final int UNITY_ADS_VENDOR_ID = 1549;
31
27
 
32
28
  private ConsentInformation consentInformation;
33
29
 
@@ -143,33 +139,9 @@ public class AdConsentExecutor extends Executor {
143
139
  return true;
144
140
  }
145
141
 
146
- // 6. Consent that does not mention Unity Ads makes Unity Ads ask in its own dialog, inside an ad.
147
- // Ask once more, with Unity Ads now among the ad partners.
148
- long lastUpdated = lastUpdatedMillis(tcString, base64);
149
- if (gdprApplies(prefs) && lastUpdated >= 0 && lastUpdated < UNITY_ADS_CONSENT_SINCE_MILLIS && unityAdsConsent(prefs) == null) {
150
- clearAllTCFPreferences(prefs);
151
- return true;
152
- }
153
-
154
142
  return false;
155
143
  }
156
144
 
157
- /** The TC string's "last updated" date (characters 7 to 12), or -1 when it is unreadable. */
158
- private long lastUpdatedMillis(String tcString, String base64) {
159
- if (tcString.length() < 13) {
160
- return -1;
161
- }
162
- long deciseconds = 0L;
163
- for (char c : tcString.substring(7, 13).toCharArray()) {
164
- int value = base64.indexOf(c);
165
- if (value == -1) {
166
- return -1;
167
- }
168
- deciseconds = deciseconds * 64 + value;
169
- }
170
- return deciseconds * 100;
171
- }
172
-
173
145
  private boolean gdprApplies(SharedPreferences prefs) {
174
146
  try {
175
147
  return prefs.getInt("IABTCF_gdprApplies", 0) == 1;
@@ -178,31 +150,21 @@ public class AdConsentExecutor extends Executor {
178
150
  }
179
151
  }
180
152
 
181
- /**
182
- * Unity Ads' answer in Google's Additional Consent string ("2~consented ids~dv.disclosed ids"):
183
- * true or false, or null when the string does not mention Unity Ads.
184
- */
185
- private Boolean unityAdsConsent(SharedPreferences prefs) {
186
- String additionalConsent;
153
+ /** Whether the player agreed to personalized ads (purposes 1, 3 and 4) from Unity Ads in the TC string. */
154
+ private boolean unityAdsConsent(SharedPreferences prefs) {
187
155
  try {
188
- additionalConsent = prefs.getString("IABTCF_AddtlConsent", "");
156
+ String purposeConsent = prefs.getString("IABTCF_PurposeConsents", "");
157
+ String vendorConsent = prefs.getString("IABTCF_VendorConsents", "");
158
+ return hasConsentFor(Arrays.asList(1, 3, 4), purposeConsent, hasAttribute(vendorConsent, UNITY_ADS_VENDOR_ID));
189
159
  } catch (ClassCastException ex) {
190
- return null;
191
- }
192
- String[] parts = additionalConsent == null ? new String[0] : additionalConsent.split("~");
193
- if (parts.length > 1 && Arrays.asList(parts[1].split("\\.")).contains(UNITY_ADS_PROVIDER_ID)) {
194
- return true;
195
- }
196
- if (parts.length > 2 && Arrays.asList(parts[2].split("\\.")).contains(UNITY_ADS_PROVIDER_ID)) {
197
160
  return false;
198
161
  }
199
- return null;
200
162
  }
201
163
 
202
164
  /**
203
165
  * Tells Unity Ads the player's answer, so it never shows its own consent dialog. The AdMob adapter passes it only
204
- * when the Additional Consent string mentions Unity Ads: here not mentioned counts as no. Apps without Unity Ads
205
- * skip this.
166
+ * when Google's Additional Consent string mentions Unity Ads, which Google's consent form never does: it records
167
+ * Unity Ads as an IAB vendor. Apps without Unity Ads skip this.
206
168
  */
207
169
  public void passConsentToUnityAds() {
208
170
  Context context = contextSupplier.get();
@@ -210,7 +172,7 @@ public class AdConsentExecutor extends Executor {
210
172
  if (!gdprApplies(prefs)) {
211
173
  return;
212
174
  }
213
- boolean consent = Boolean.TRUE.equals(unityAdsConsent(prefs));
175
+ boolean consent = unityAdsConsent(prefs);
214
176
  try {
215
177
  Class<?> metaDataClass = Class.forName("com.unity3d.ads.metadata.MetaData");
216
178
  Object metaData = metaDataClass.getConstructor(Context.class).newInstance(context.getApplicationContext());
@@ -6,12 +6,8 @@ import UserMessagingPlatform
6
6
  class ConsentExecutor: NSObject {
7
7
  weak var plugin: AdMobPlugin?
8
8
 
9
- // Unity Ads in Google's Additional Consent list (https://storage.googleapis.com/tcfac/additional-consent-providers.csv).
10
- private let unityAdsProviderId = "3234"
11
-
12
- // Consent last updated before this date (2026-10-27) may not mention Unity Ads, which joined the ad partners in
13
- // October 2026. Newer consent is never asked for again on this account.
14
- private let unityAdsConsentSinceMillis: Int64 = 1793059200000
9
+ // Unity Ads in the IAB TCF Global Vendor List ("Unity Technologies SF").
10
+ private let unityAdsVendorId = 1549
15
11
 
16
12
  func requestConsentInfo(_ call: CAPPluginCall, _ debugGeography: Int, _ testDeviceIdentifiers: [String], _ tagForUnderAgeOfConsent: Bool) {
17
13
  let parameters = RequestParameters()
@@ -237,53 +233,24 @@ class ConsentExecutor: NSObject {
237
233
  return true
238
234
  }
239
235
 
240
- // 6. Consent that does not mention Unity Ads makes Unity Ads ask in its own dialog, inside an ad.
241
- // Ask once more, with Unity Ads now among the ad partners.
242
- if let lastUpdated = lastUpdatedMillis(tcString, base64),
243
- isGDPR() && lastUpdated < unityAdsConsentSinceMillis && unityAdsConsent(settings) == nil {
244
- clearAllTCFPreferences(settings)
245
- return true
246
- }
247
-
248
236
  return false
249
237
  }
250
238
 
251
- /// The TC string's "last updated" date (characters 7 to 12), or nil when it is unreadable.
252
- private func lastUpdatedMillis(_ tcString: String, _ base64: String) -> Int64? {
253
- guard tcString.count >= 13 else {
254
- return nil
255
- }
256
- var deciseconds: Int64 = 0
257
- for char in tcString.dropFirst(7).prefix(6) {
258
- guard let value = base64.firstIndex(of: char) else {
259
- return nil
260
- }
261
- deciseconds = deciseconds * 64 + Int64(value.utf16Offset(in: base64))
262
- }
263
- return deciseconds * 100
264
- }
265
-
266
- /// Unity Ads' answer in Google's Additional Consent string ("2~consented ids~dv.disclosed ids"):
267
- /// true or false, or nil when the string does not mention Unity Ads.
268
- private func unityAdsConsent(_ settings: UserDefaults) -> Bool? {
269
- let parts = (settings.string(forKey: "IABTCF_AddtlConsent") ?? "").components(separatedBy: "~")
270
- if parts.count > 1 && parts[1].components(separatedBy: ".").contains(unityAdsProviderId) {
271
- return true
272
- }
273
- if parts.count > 2 && parts[2].components(separatedBy: ".").contains(unityAdsProviderId) {
274
- return false
275
- }
276
- return nil
239
+ /// Whether the player agreed to personalized ads (purposes 1, 3 and 4) from Unity Ads in the TC string.
240
+ private func unityAdsConsent(_ settings: UserDefaults) -> Bool {
241
+ let purposeConsent = settings.string(forKey: "IABTCF_PurposeConsents") ?? ""
242
+ let vendorConsent = settings.string(forKey: "IABTCF_VendorConsents") ?? ""
243
+ return hasConsentFor([1, 3, 4], purposeConsent, hasAttribute(input: vendorConsent, index: unityAdsVendorId))
277
244
  }
278
245
 
279
246
  /// Tells Unity Ads the player's answer, so it never shows its own consent dialog. The AdMob adapter passes it only
280
- /// when the Additional Consent string mentions Unity Ads: here not mentioned counts as no. Apps without Unity Ads
281
- /// skip this.
247
+ /// when Google's Additional Consent string mentions Unity Ads, which Google's consent form never does: it records
248
+ /// Unity Ads as an IAB vendor. Apps without Unity Ads skip this.
282
249
  func passConsentToUnityAds() {
283
250
  guard isGDPR(), let metaDataClass = NSClassFromString("UADSMetaData") as? NSObject.Type else {
284
251
  return
285
252
  }
286
- let consent = unityAdsConsent(UserDefaults.standard) == true
253
+ let consent = unityAdsConsent(UserDefaults.standard)
287
254
  let metaData = metaDataClass.init()
288
255
  _ = metaData.perform(NSSelectorFromString("set:value:"), with: "gdpr.consent", with: NSNumber(value: consent))
289
256
  _ = metaData.perform(NSSelectorFromString("commit"))
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ququplay/admob",
3
- "version": "8.2.1",
3
+ "version": "8.2.2",
4
4
  "description": "A native plugin for AdMob",
5
5
  "main": "dist/plugin.cjs.js",
6
6
  "module": "dist/esm/index.js",