@ququplay/admob 8.2.0 → 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.
- package/android/src/main/java/com/getcapacitor/community/admob/AdMob.java +2 -0
- package/android/src/main/java/com/getcapacitor/community/admob/consent/AdConsentExecutor.java +51 -0
- package/ios/Sources/AdMobPlugin/AdMobPlugin.swift +2 -0
- package/ios/Sources/AdMobPlugin/Consent/ConsentExecutor.swift +26 -0
- package/package.json +1 -1
|
@@ -72,6 +72,8 @@ public class AdMob extends Plugin {
|
|
|
72
72
|
@PluginMethod
|
|
73
73
|
public void initialize(final PluginCall call) {
|
|
74
74
|
this.setRequestConfiguration(call);
|
|
75
|
+
// The Unity Ads adapter starts Unity Ads here: give it the stored consent answer first.
|
|
76
|
+
adConsentExecutor.passConsentToUnityAds();
|
|
75
77
|
|
|
76
78
|
try {
|
|
77
79
|
MobileAds.initialize(
|
package/android/src/main/java/com/getcapacitor/community/admob/consent/AdConsentExecutor.java
CHANGED
|
@@ -17,10 +17,14 @@ import com.google.android.ump.ConsentInformation;
|
|
|
17
17
|
import com.google.android.ump.ConsentRequestParameters;
|
|
18
18
|
import com.google.android.ump.UserMessagingPlatform;
|
|
19
19
|
import java.util.ArrayList;
|
|
20
|
+
import java.util.Arrays;
|
|
20
21
|
import java.util.List;
|
|
21
22
|
|
|
22
23
|
public class AdConsentExecutor extends Executor {
|
|
23
24
|
|
|
25
|
+
// Unity Ads in the IAB TCF Global Vendor List ("Unity Technologies SF").
|
|
26
|
+
private static final int UNITY_ADS_VENDOR_ID = 1549;
|
|
27
|
+
|
|
24
28
|
private ConsentInformation consentInformation;
|
|
25
29
|
|
|
26
30
|
public AdConsentExecutor(
|
|
@@ -74,6 +78,7 @@ public class AdConsentExecutor extends Executor {
|
|
|
74
78
|
.remove("IABTCF_PurposeLegitimateInterests")
|
|
75
79
|
.remove("IABTCF_VendorLegitimateInterests")
|
|
76
80
|
.remove("IABTCF_gdprApplies") // Force SDK to reassess context
|
|
81
|
+
.remove("IABTCF_AddtlConsent")
|
|
77
82
|
.apply();
|
|
78
83
|
Log.w(logTag, "Successfully purged all IABTCF tracking variables from SharedPreferences.");
|
|
79
84
|
}
|
|
@@ -137,6 +142,49 @@ public class AdConsentExecutor extends Executor {
|
|
|
137
142
|
return false;
|
|
138
143
|
}
|
|
139
144
|
|
|
145
|
+
private boolean gdprApplies(SharedPreferences prefs) {
|
|
146
|
+
try {
|
|
147
|
+
return prefs.getInt("IABTCF_gdprApplies", 0) == 1;
|
|
148
|
+
} catch (ClassCastException ex) {
|
|
149
|
+
return false;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
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) {
|
|
155
|
+
try {
|
|
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));
|
|
159
|
+
} catch (ClassCastException ex) {
|
|
160
|
+
return false;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* Tells Unity Ads the player's answer, so it never shows its own consent dialog. The AdMob adapter passes it only
|
|
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.
|
|
168
|
+
*/
|
|
169
|
+
public void passConsentToUnityAds() {
|
|
170
|
+
Context context = contextSupplier.get();
|
|
171
|
+
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context.getApplicationContext());
|
|
172
|
+
if (!gdprApplies(prefs)) {
|
|
173
|
+
return;
|
|
174
|
+
}
|
|
175
|
+
boolean consent = unityAdsConsent(prefs);
|
|
176
|
+
try {
|
|
177
|
+
Class<?> metaDataClass = Class.forName("com.unity3d.ads.metadata.MetaData");
|
|
178
|
+
Object metaData = metaDataClass.getConstructor(Context.class).newInstance(context.getApplicationContext());
|
|
179
|
+
metaDataClass.getMethod("set", String.class, Object.class).invoke(metaData, "gdpr.consent", consent);
|
|
180
|
+
metaDataClass.getMethod("commit").invoke(metaData);
|
|
181
|
+
} catch (ClassNotFoundException ex) {
|
|
182
|
+
// No Unity Ads in this app.
|
|
183
|
+
} catch (ReflectiveOperationException ex) {
|
|
184
|
+
Log.w(logTag, "Could not pass consent to Unity Ads", ex);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
140
188
|
public boolean canShowAds() {
|
|
141
189
|
Context context = contextSupplier.get();
|
|
142
190
|
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context.getApplicationContext());
|
|
@@ -204,6 +252,7 @@ public class AdConsentExecutor extends Executor {
|
|
|
204
252
|
// Check (and possibly purge) outdated consent before reading the
|
|
205
253
|
// remaining values, so they reflect the post-cleanup state.
|
|
206
254
|
boolean isConsentOutdated = isConsentOutdated();
|
|
255
|
+
passConsentToUnityAds();
|
|
207
256
|
|
|
208
257
|
JSObject consentInfo = new JSObject();
|
|
209
258
|
consentInfo.put("status", getConsentStatusString(consentInformation.getConsentStatus()));
|
|
@@ -236,6 +285,7 @@ public class AdConsentExecutor extends Executor {
|
|
|
236
285
|
if (formError != null) {
|
|
237
286
|
call.reject("Error when show privacy form", formError.getMessage());
|
|
238
287
|
} else {
|
|
288
|
+
passConsentToUnityAds();
|
|
239
289
|
call.resolve();
|
|
240
290
|
}
|
|
241
291
|
})
|
|
@@ -268,6 +318,7 @@ public class AdConsentExecutor extends Executor {
|
|
|
268
318
|
// Check (and possibly purge) outdated consent before reading the
|
|
269
319
|
// remaining values, so they reflect the post-cleanup state.
|
|
270
320
|
boolean isConsentOutdated = isConsentOutdated();
|
|
321
|
+
passConsentToUnityAds();
|
|
271
322
|
|
|
272
323
|
JSObject consentFormInfo = new JSObject();
|
|
273
324
|
consentFormInfo.put("status", getConsentStatusString(consentInformation.getConsentStatus()));
|
|
@@ -56,6 +56,8 @@ public class AdMobPlugin: CAPPlugin, CAPBridgedPlugin {
|
|
|
56
56
|
self.adInterstitialExecutor.plugin = self
|
|
57
57
|
self.consentExecutor.plugin = self
|
|
58
58
|
self.setRequestConfiguration(call)
|
|
59
|
+
// The Unity Ads adapter starts Unity Ads here: give it the stored consent answer first.
|
|
60
|
+
self.consentExecutor.passConsentToUnityAds()
|
|
59
61
|
|
|
60
62
|
MobileAds.shared.start(completionHandler: nil)
|
|
61
63
|
call.resolve([:])
|
|
@@ -6,6 +6,9 @@ import UserMessagingPlatform
|
|
|
6
6
|
class ConsentExecutor: NSObject {
|
|
7
7
|
weak var plugin: AdMobPlugin?
|
|
8
8
|
|
|
9
|
+
// Unity Ads in the IAB TCF Global Vendor List ("Unity Technologies SF").
|
|
10
|
+
private let unityAdsVendorId = 1549
|
|
11
|
+
|
|
9
12
|
func requestConsentInfo(_ call: CAPPluginCall, _ debugGeography: Int, _ testDeviceIdentifiers: [String], _ tagForUnderAgeOfConsent: Bool) {
|
|
10
13
|
let parameters = RequestParameters()
|
|
11
14
|
let debugSettings = DebugSettings()
|
|
@@ -37,6 +40,7 @@ class ConsentExecutor: NSObject {
|
|
|
37
40
|
Task {
|
|
38
41
|
do {
|
|
39
42
|
try await ConsentForm.presentPrivacyOptionsForm(from: rootViewController)
|
|
43
|
+
passConsentToUnityAds()
|
|
40
44
|
call.resolve()
|
|
41
45
|
} catch {
|
|
42
46
|
call.reject("Failed to show privacy options form: \(error.localizedDescription)")
|
|
@@ -74,6 +78,7 @@ class ConsentExecutor: NSObject {
|
|
|
74
78
|
// Check (and possibly purge) outdated consent before reading the
|
|
75
79
|
// remaining values, so they reflect the post-cleanup state.
|
|
76
80
|
let isConsentOutdated = isConsentOutdated()
|
|
81
|
+
passConsentToUnityAds()
|
|
77
82
|
|
|
78
83
|
return [
|
|
79
84
|
"status": getConsentStatusString(ConsentInformation.shared.consentStatus),
|
|
@@ -173,6 +178,7 @@ class ConsentExecutor: NSObject {
|
|
|
173
178
|
settings.removeObject(forKey: "IABTCF_PurposeLegitimateInterests")
|
|
174
179
|
settings.removeObject(forKey: "IABTCF_VendorLegitimateInterests")
|
|
175
180
|
settings.removeObject(forKey: "IABTCF_gdprApplies") // Force SDK to reassess context
|
|
181
|
+
settings.removeObject(forKey: "IABTCF_AddtlConsent")
|
|
176
182
|
NSLog("AdMob: Successfully purged all IABTCF tracking variables from UserDefaults.")
|
|
177
183
|
}
|
|
178
184
|
|
|
@@ -229,6 +235,26 @@ class ConsentExecutor: NSObject {
|
|
|
229
235
|
|
|
230
236
|
return false
|
|
231
237
|
}
|
|
238
|
+
|
|
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))
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
/// Tells Unity Ads the player's answer, so it never shows its own consent dialog. The AdMob adapter passes it only
|
|
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.
|
|
249
|
+
func passConsentToUnityAds() {
|
|
250
|
+
guard isGDPR(), let metaDataClass = NSClassFromString("UADSMetaData") as? NSObject.Type else {
|
|
251
|
+
return
|
|
252
|
+
}
|
|
253
|
+
let consent = unityAdsConsent(UserDefaults.standard)
|
|
254
|
+
let metaData = metaDataClass.init()
|
|
255
|
+
_ = metaData.perform(NSSelectorFromString("set:value:"), with: "gdpr.consent", with: NSNumber(value: consent))
|
|
256
|
+
_ = metaData.perform(NSSelectorFromString("commit"))
|
|
257
|
+
}
|
|
232
258
|
func getPrivacyOptionsRequirementStatus(_ requirementStatus: PrivacyOptionsRequirementStatus) -> String {
|
|
233
259
|
switch requirementStatus {
|
|
234
260
|
case PrivacyOptionsRequirementStatus.required:
|