Обязательное согласие для платформы обмена сообщениями пользователей Admob
Я перешел с устаревшего
GDPR consent library
к новому
User Messaging Platform
, и использовал код, как указано в документации . Я заметил, что когда пользователь нажимает « Параметры управления», а затем « Подтвердить выбор» , реклама вообще перестает отображаться ( не удалось загрузить объявление, нет конфигурации рекламы ), и я не могу найти способ проверить, не дал ли пользователь согласие на использование личных данных. .
Это проблематично, поскольку мое приложение полагается исключительно на рекламу, и я буду терять деньги, если реклама не будет отображаться, поэтому я хочу сделать обязательным для пользователей согласие на использование личных данных, иначе приложение не будет использоваться.
Я сделал тестовый проект на Github, чтобы каждый мог проверить это поведение. Если вы не используете эмулятор, вам необходимо изменить "TEST_DEVICE_ID" на свой.
Как я могу этого добиться? Спасибо.
2 ответа
Я нашел обходной путь для этого, но это не окончательное официальное решение.
Кажется, что если пользователь дал согласие на использование персонализированной рекламы, строка в
SharedPreferences
, ключ которого IABTCF_VendorConsents , будет содержать единицы и нули, соответствующие некоторым поставщикам (я думаю). Если он не дал согласия, эта строка будет равна 0 .
private val sp = PreferenceManager.getDefaultSharedPreferences(appContext)
fun consentedToPersonalizedAds() = sp.getString("IABTCF_VendorConsents", null) != "0"
UMP записывает свой вывод в некоторые атрибуты в
SharedPreferences
, изложено здесь. Вы можете написать несколько вспомогательных методов для запроса этих атрибутов, чтобы узнать, какой уровень согласия на рекламу дал пользователь или находится ли пользователь в ЕЭЗ или нет, но вам нужно будет смотреть не только на
VendorConsents
нить.
Как правило, есть 5 атрибутов, на которые следует обращать внимание, чтобы определить, будет ли показываться реклама:
-
IABTCF_gdprApplies
- Целое число (0 или 1), указывающее, находится ли пользователь в ЕЭЗ. -
IABTCF_PurposeConsents
- Строка из 0 и 1 длиной до 10 записей, указывающая, дал ли пользователь согласие на 10 различных целей. -
IABTCF_PurposeLegitimateInterests
- Строка из 0 и 1 длиной до 10 записей, указывающая, имеет ли приложение законный интерес для 10 различных целей. -
IABTCF_VendorConsents
- Строка из нулей и единиц произвольной длины, указывающая, было ли дано согласие данному поставщику для ранее упомянутых целей. У каждого поставщика есть идентификатор, указывающий его позицию в строке. Например, идентификатор Google — 755, поэтому, если Google получил согласие, 755-й символ в этой строке будет «1». -
IABTCF_VendorLegitimateInterests
- Аналогично строке согласия поставщика, за исключением того, что она указывает, есть ли у поставщика законный интерес для ранее указанных целей.
Согласно документации Google здесь , на самом деле есть только несколько практических результатов из формы выбора финансирования UMP в отношении показа рекламы:
- Пользователь нажал «Согласие на все» — все строки выше будут равны 1, и будут показаны персонализированные объявления.
- Пользователь нажал «Согласиться с отказом» — реклама не будет показываться вообще.
- Пользователь нажал «Управление» и выбрал согласие на хранение (Цель 1) и прокрутил гигантский список поставщиков, перечисленных не в алфавитном порядке, чтобы также выбрать «Google» — будет показана неперсонализированная реклама.
- Пользователь нажал «Управление» и сделал что-то меньшее, чем предыдущий шаг (например, выбрал хранилище и базовую рекламу, но не выбрал вручную Google из списка поставщиков) — снова реклама не будет отображаться вообще.
Это довольно неидеальный набор вариантов, поскольку вариант 3 крайне маловероятен, а варианты 2 и 4 приводят к тому, что пользователь получает бесплатное приложение без рекламы. Для всех практических целей это удалило опцию «неперсонализированная реклама», которая была в устаревшем SDK согласия (и возможность приобрести приложение без рекламы), и заменила ее простым полным отключением рекламы.
Я написал несколько вспомогательных методов, чтобы, по крайней мере, вы могли запросить, что на самом деле выбрал пользователь, и действовать соответственно.
fun isGDPR(): Boolean {
val prefs = PreferenceManager.getDefaultSharedPreferences(applicationContext)
val gdpr = prefs.getInt("IABTCF_gdprApplies", 0)
return gdpr == 1
}
fun canShowAds(): Boolean {
val prefs = PreferenceManager.getDefaultSharedPreferences(applicationContext)
//https://github.com/InteractiveAdvertisingBureau/GDPR-Transparency-and-Consent-Framework/blob/master/TCFv2/IAB%20Tech%20Lab%20-%20CMP%20API%20v2.md#in-app-details
//https://support.google.com/admob/answer/9760862?hl=en&ref_topic=9756841
val purposeConsent = prefs.getString("IABTCF_PurposeConsents", "") ?: ""
val vendorConsent = prefs.getString("IABTCF_VendorConsents","") ?: ""
val vendorLI = prefs.getString("IABTCF_VendorLegitimateInterests","") ?: ""
val purposeLI = prefs.getString("IABTCF_PurposeLegitimateInterests","") ?: ""
val googleId = 755
val hasGoogleVendorConsent = hasAttribute(vendorConsent, index=googleId)
val hasGoogleVendorLI = hasAttribute(vendorLI, index=googleId)
// Minimum required for at least non-personalized ads
return hasConsentFor(listOf(1), purposeConsent, hasGoogleVendorConsent)
&& hasConsentOrLegitimateInterestFor(listOf(2,7,9,10), purposeConsent, purposeLI, hasGoogleVendorConsent, hasGoogleVendorLI)
}
fun canShowPersonalizedAds(): Boolean {
val prefs = PreferenceManager.getDefaultSharedPreferences(applicationContext)
//https://github.com/InteractiveAdvertisingBureau/GDPR-Transparency-and-Consent-Framework/blob/master/TCFv2/IAB%20Tech%20Lab%20-%20CMP%20API%20v2.md#in-app-details
//https://support.google.com/admob/answer/9760862?hl=en&ref_topic=9756841
val purposeConsent = prefs.getString("IABTCF_PurposeConsents", "") ?: ""
val vendorConsent = prefs.getString("IABTCF_VendorConsents","") ?: ""
val vendorLI = prefs.getString("IABTCF_VendorLegitimateInterests","") ?: ""
val purposeLI = prefs.getString("IABTCF_PurposeLegitimateInterests","") ?: ""
val googleId = 755
val hasGoogleVendorConsent = hasAttribute(vendorConsent, index=googleId)
val hasGoogleVendorLI = hasAttribute(vendorLI, index=googleId)
return hasConsentFor(listOf(1,3,4), purposeConsent, hasGoogleVendorConsent)
&& hasConsentOrLegitimateInterestFor(listOf(2,7,9,10), purposeConsent, purposeLI, hasGoogleVendorConsent, hasGoogleVendorLI)
}
// Check if a binary string has a "1" at position "index" (1-based)
private fun hasAttribute(input: String, index: Int): Boolean {
return input.length >= index && input[index-1] == '1'
}
// Check if consent is given for a list of purposes
private fun hasConsentFor(purposes: List<Int>, purposeConsent: String, hasVendorConsent: Boolean): Boolean {
return purposes.all { p -> hasAttribute(purposeConsent, p)} && hasVendorConsent
}
// Check if a vendor either has consent or legitimate interest for a list of purposes
private fun hasConsentOrLegitimateInterestFor(purposes: List<Int>, purposeConsent: String, purposeLI: String, hasVendorConsent: Boolean, hasVendorLI: Boolean): Boolean {
return purposes.all { p ->
(hasAttribute(purposeLI, p) && hasVendorLI) ||
(hasAttribute(purposeConsent, p) && hasVendorConsent)
}
}