Admob 用户消息平台的强制同意

hid*_*s02 27 android admob gdprconsentform user-messaging-platform

我从已弃用的 GDPR 同意库切换到新的用户消息传递平台,并使用了文档中所述的代码。

我注意到,当用户点击“管理选项”然后“确认选择”时,广告将完全停止显示(广告加载失败,没有广告配置),而且我无论如何也找不到检查用户是否同意使用个人资料。

这是有问题的,因为我的应用程序纯粹依赖于广告,如果广告不显示我就会赔钱,所以我想强制用户同意使用他们的个人数据,否则应用程序应该无法使用。

我在Github上做了一个测试项目,这样每个人都可以测试这个行为。如果您没有使用模拟器,则需要将“TEST_DEVICE_ID”更改为您的模拟器。

我怎样才能实现这个目标?

Tyl*_*r V 37

UMP 将其输出写入 中的一些属性,此处SharedPreferences概述。您可以编写一些辅助方法来查询这些属性,以了解用户给予的广告同意级别或用户是否属于 EEA,但您需要查看的不仅仅是字符串。VendorConsents

通常,您需要查找 5 个属性来确定是否投放广告:

  • IABTCF_gdprApplies- 一个整数(0 或 1),指示用户是否位于 EEA
  • IABTCF_PurposeConsents- 由 0 和 1 组成的字符串,最多 10 个条目,指示用户是否同意这 10 个不同的目的
  • IABTCF_PurposeLegitimateInterests- 由 0 和 1 组成的字符串,最多 10 个条目,指示应用程序是否具有 10 个不同目的的合法权益
  • IABTCF_VendorConsents- 任意长的 0 和 1 字符串,指示给定供应商是否已同意用于前述目的。每个供应商都有一个 ID,指示他们在字符串中的位置。例如,Google 的 ID 为 755,因此如果 Google 已获得同意,则该字符串中的第 755 个字符将是“1”。完整的供应商列表可在此处获取。
  • IABTCF_VendorLegitimateInterests- 与供应商同意字符串类似,但它表明供应商是否对先前指定的目的拥有合法权益。

根据此处的Google 文档,UMP 资助选择表格实际上只提供了一些与投放广告有关的实际结果:

  1. 用户点击“全部同意” - 上面的字符串将全部为 1,并且将显示个性化广告
  2. 用户点击了“不同意” - 根本不会显示任何广告
  3. 用户点击“管理”并选择存储同意(目的 1),然后滚动浏览非按字母顺序列出的供应商的巨大列表,还选择“Google” - 将显示非个性化广告
  4. 用户点击“管理”并执行了比之前步骤少的任何操作(例如,选择存储空间和基本广告,但没有从供应商列表中手动选择 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)
    }
}
Run Code Online (Sandbox Code Playgroud)

Note PreferenceManager.getDefaultSharedPreferences并未被弃用- 您只需要确保包含 androidx import ( import androidx.preference.PreferenceManager)。如果您添加了错误的 ( import android.preference.PreferenceManager),它将被标记为已弃用。

编辑:集成示例

ConsentHelper以下是用于管理调用 UMP SDK 和处理结果的方法的示例实现。这将在应用程序加载时调用(例如在 Activity 中onCreate

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)
    }
}
Run Code Online (Sandbox Code Playgroud)

这会处理在获得同意之前等待初始化 MobileAds SDK,然后在同意工作流程完成后使用回调开始加载广告。

ConsentHelper.obtainConsentAndShow(activity) {
    // add your code to load ads here
}
Run Code Online (Sandbox Code Playgroud)