如何正确实施UMP SDK以获得欧盟同意?

Pat*_*tic 6 android admob mobile-ad-mediation gdprconsentform user-messaging-platform

我对 UMP SDK 的实现有很多困惑。除了谷歌之外,我没有找到太多信息或完整教程。我正在关注这个这个,但无法理解以下问题:

  1. MobileAds.initialize()征得同意后需要打电话吗?如果是这样,那么它应该在哪里调用?获得同意后可能会调用:

    public void onConsentFormLoadSuccess(ConsentForm consentForm) {
        if(consentInformation.getConsentStatus() == ConsentInformation.ConsentStatus.OBTAINED) {
    }
    }
    
    Run Code Online (Sandbox Code Playgroud)
  2. 我如何检查用户是否来自欧洲经济区?我想根据用户位置请求同意或初始化移动广告。在Consent SDK 中,有一个 method isRequestLocationInEeaOrUnknown(),但此 SDK 已弃用。我在 UMP SDK 中没有找到类似的东西。一种方法可能是始终requestConsentInfoUpdate调用isConsentFormAvailableinside onConsentInfoUpdateSuccess。如果用户不是来自 EEA,则此方法返回 false。

  3. 我总是得到同意类型consentInformation.getConsentType()0 或未知。我尝试过不同的组合,但总是 0。

  4. 是否需要将同意信息转发给 AdMob SDK 或 SDK 会处理。

  5. 关于调解,我需要同意信息,但不知道如何获取。从文档:The UMP SDK writes consent status information to local storage

  6. 在 AdMob -> 欧盟用户同意中,我的中介合作伙伴之一未包含在Commonly used set of ad technology providers. 如果我使用Custom set of ad technology providers,是否需要包括所有Commonly used set of ad technology providers198 家广告技术提供商。或者在 Funding Choices 中包含广告技术提供商就足够了。

Tyl*_*r V 33

我自己一直在解决这个问题,虽然我没有回答你所有的问题,但我已经找到了其中的一些问题。

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

  1. 如何检查用户是否是 EEA?您可以检查IABTCF_gdprAppliesSharedPreferences 中的整数,如果为 1,则用户是 EEA。如果为 0,则用户不是。

  2. 如何获得同意类型?这部分变得更加复杂。此处的Google 文档概述了个性化和非个性化广告所需的权限。要获得此结果,您需要查看 SharedPreference 中的 4 个字符串:IABTCF_PurposeConsentsIABTCF_PurposeLegitimateInterests和。正如其他人所指出的,用户几乎不可能实际选择非个性化广告配置,因为他们不仅必须选择“在设备上存储信息”,而且还要滚动浏览数百个非按字母顺序组织的供应商以查找并选择“Google”(这些字符串中的供应商 ID 755)。这意味着,出于所有实际目的,他们要么选择个性化广告(全部同意),要么免费拥有一个不错的无广告应用程序。您至少可以使用这些检查来设置付费专区、禁用云功能或以其他方式处理您认为合适的情况。IABTCF_VendorConsentsIABTCF_VendorLegitimateInterests

我做了一些辅助方法来查找这些状态。

科特林

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),它将被标记为已弃用。

迅速

func isGDPR() -> Bool {
    let settings = UserDefaults.standard
    let gdpr = settings.integer(forKey: "IABTCF_gdprApplies")
    return gdpr == 1
}

// Check if a binary string has a "1" at position "index" (1-based)    
private func hasAttribute(input: String, index: Int) -> Bool {
    return input.count >= index && String(Array(input)[index-1]) == "1"
}

// Check if consent is given for a list of purposes
private func hasConsentFor(_ purposes: [Int], _ purposeConsent: String, _ hasVendorConsent: Bool) -> Bool {
    return purposes.allSatisfy { i in hasAttribute(input: purposeConsent, index: i) } && hasVendorConsent
}

// Check if a vendor either has consent or legitimate interest for a list of purposes
private func hasConsentOrLegitimateInterestFor(_ purposes: [Int], _ purposeConsent: String, _ purposeLI: String, _ hasVendorConsent: Bool, _ hasVendorLI: Bool) -> Bool {
    return purposes.allSatisfy { i in
        (hasAttribute(input: purposeLI, index: i) && hasVendorLI) ||
        (hasAttribute(input: purposeConsent, index: i) && hasVendorConsent)
    }
}

private func canShowAds() -> Bool {
    let settings = UserDefaults.standard
    
    //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
    
    let purposeConsent = settings.string(forKey: "IABTCF_PurposeConsents") ?? ""
    let vendorConsent = settings.string(forKey: "IABTCF_VendorConsents") ?? ""
    let vendorLI = settings.string(forKey: "IABTCF_VendorLegitimateInterests") ?? ""
    let purposeLI = settings.string(forKey: "IABTCF_PurposeLegitimateInterests") ?? ""
    
    let googleId = 755
    let hasGoogleVendorConsent = hasAttribute(input: vendorConsent, index: googleId)
    let hasGoogleVendorLI = hasAttribute(input: vendorLI, index: googleId)
    
    // Minimum required for at least non-personalized ads
    return hasConsentFor([1], purposeConsent, hasGoogleVendorConsent)
        && hasConsentOrLegitimateInterestFor([2,7,9,10], purposeConsent, purposeLI, hasGoogleVendorConsent, hasGoogleVendorLI)
                         
}

private func canShowPersonalizedAds() -> Bool {
    let settings = UserDefaults.standard
            
    //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
          
    // required for personalized ads
    let purposeConsent = settings.string(forKey: "IABTCF_PurposeConsents") ?? ""
    let vendorConsent = settings.string(forKey: "IABTCF_VendorConsents") ?? ""
    let vendorLI = settings.string(forKey: "IABTCF_VendorLegitimateInterests") ?? ""
    let purposeLI = settings.string(forKey: "IABTCF_PurposeLegitimateInterests") ?? ""
    
    let googleId = 755
    let hasGoogleVendorConsent = hasAttribute(input: vendorConsent, index: googleId)
    let hasGoogleVendorLI = hasAttribute(input: vendorLI, index: googleId)
    
    return hasConsentFor([1,3,4], purposeConsent, hasGoogleVendorConsent)
        && hasConsentOrLegitimateInterestFor([2,7,9,10], purposeConsent, purposeLI, hasGoogleVendorConsent, hasGoogleVendorLI)
}
Run Code Online (Sandbox Code Playgroud)

编辑:集成示例

ConsentHelper以下是用于管理调用 UMP SDK 和处理结果的方法(在 Kotlin 中)的示例实现。这将在应用程序加载时调用(例如在 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,然后在同意工作流程完成后使用回调开始加载广告。

func isGDPR() -> Bool {
    let settings = UserDefaults.standard
    let gdpr = settings.integer(forKey: "IABTCF_gdprApplies")
    return gdpr == 1
}

// Check if a binary string has a "1" at position "index" (1-based)    
private func hasAttribute(input: String, index: Int) -> Bool {
    return input.count >= index && String(Array(input)[index-1]) == "1"
}

// Check if consent is given for a list of purposes
private func hasConsentFor(_ purposes: [Int], _ purposeConsent: String, _ hasVendorConsent: Bool) -> Bool {
    return purposes.allSatisfy { i in hasAttribute(input: purposeConsent, index: i) } && hasVendorConsent
}

// Check if a vendor either has consent or legitimate interest for a list of purposes
private func hasConsentOrLegitimateInterestFor(_ purposes: [Int], _ purposeConsent: String, _ purposeLI: String, _ hasVendorConsent: Bool, _ hasVendorLI: Bool) -> Bool {
    return purposes.allSatisfy { i in
        (hasAttribute(input: purposeLI, index: i) && hasVendorLI) ||
        (hasAttribute(input: purposeConsent, index: i) && hasVendorConsent)
    }
}

private func canShowAds() -> Bool {
    let settings = UserDefaults.standard
    
    //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
    
    let purposeConsent = settings.string(forKey: "IABTCF_PurposeConsents") ?? ""
    let vendorConsent = settings.string(forKey: "IABTCF_VendorConsents") ?? ""
    let vendorLI = settings.string(forKey: "IABTCF_VendorLegitimateInterests") ?? ""
    let purposeLI = settings.string(forKey: "IABTCF_PurposeLegitimateInterests") ?? ""
    
    let googleId = 755
    let hasGoogleVendorConsent = hasAttribute(input: vendorConsent, index: googleId)
    let hasGoogleVendorLI = hasAttribute(input: vendorLI, index: googleId)
    
    // Minimum required for at least non-personalized ads
    return hasConsentFor([1], purposeConsent, hasGoogleVendorConsent)
        && hasConsentOrLegitimateInterestFor([2,7,9,10], purposeConsent, purposeLI, hasGoogleVendorConsent, hasGoogleVendorLI)
                         
}

private func canShowPersonalizedAds() -> Bool {
    let settings = UserDefaults.standard
            
    //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
          
    // required for personalized ads
    let purposeConsent = settings.string(forKey: "IABTCF_PurposeConsents") ?? ""
    let vendorConsent = settings.string(forKey: "IABTCF_VendorConsents") ?? ""
    let vendorLI = settings.string(forKey: "IABTCF_VendorLegitimateInterests") ?? ""
    let purposeLI = settings.string(forKey: "IABTCF_PurposeLegitimateInterests") ?? ""
    
    let googleId = 755
    let hasGoogleVendorConsent = hasAttribute(input: vendorConsent, index: googleId)
    let hasGoogleVendorLI = hasAttribute(input: vendorLI, index: googleId)
    
    return hasConsentFor([1,3,4], purposeConsent, hasGoogleVendorConsent)
        && hasConsentOrLegitimateInterestFor([2,7,9,10], purposeConsent, purposeLI, hasGoogleVendorConsent, hasGoogleVendorLI)
}
Run Code Online (Sandbox Code Playgroud)


YAQ*_*YAQ 15

据我的经验/了解,通过用户消息传递平台的谷歌资助选择(实际上甚至不清楚为什么有两个不同的名称)在欧盟内完全没有用。

\n

欢迎您纠正我,但正如我在 2021 年 3 月 8 日的经历:

\n

如果用户单击\xe2\x80\x9c管理选项\xe2\x80\x9d,然后单击\xe2\x80\x9c提交\xe2\x80\x9d并保留\xe2\x80\x9c在设备\xe2\上存储和/或访问信息x80\x9d 关闭后 AdMob 不会向用户显示任何广告。因此,您最终可能需要支付资源(云服务、员工等)费用才能向用户提供免费应用程序。\n根据问题出现的开始日期(我在本主题中看到的帖子和评论的日期),对于 Google 和/或 AdMob 来说,这是一个低优先级问题。\nconsentInformation.getConsentType() 始终返回值 0。实际上证明(或者至少我认为)这个问题在他们的列表中的优先级有多低。至少可以通过此 getter 来检查用户是否同意提供非个性化广告。然后我们可以向他展示如何正确选择退出并让他免费使用该应用程序的说明。不过,这似乎是出于开发商的利益。

\n

再次欢迎大家纠正我,也许只有我有过这样的负面经历。

\n

  • 在我看来,这使得 UMP 在大多数情况下毫无用处。我检查了 [android UMP SDK 发行说明](https://developers.google.com/admob/ump/android/release-notes),两天前他们进行了更新(12 个月后)。我想使用 UMP 的主要原因是向 (GDPR) 用户显示广告技术供应商列表。但是不...我只会下载供应商列表并将其发布在网站和/或应用程序中...浪费了 UMP 的最后 3 天时间。在这种情况下,谷歌的支持非常荒谬:[示例](https://groups.google.com/g/google-admob-ads-sdk/c/KUXEPzh1o_A)(检查日期) (4认同)
  • 我有完全相同的经历。难以理解的是,即使在谷歌的支持论坛上,他们也建议使用其他同意框架。我有感觉UMP是死胎。 (3认同)
  • 我也有同样的经历。。现在对你有用吗? (2认同)
  • 自 2021 年 3 月 8 日起我就没有尝试过。您可以尝试搜索其他同意管理平台(例如用于 Xamarin 的 Tealium),也可以将 AdMob 换成其竞争对手之一。这是迫使公司生产优质产品的最佳方式之一;-) (2认同)

小智 0

我有同样的疑问,特别是在第 3 点上,即使在我的情况下,同意类型始终为 0。我在这个视频中看到,根据该值初始化了不同的 adRequest

关于第2点,我使用没有EEA的用户设置Consentdebugsettings(DEBUG_GEOGRAPHY_NOT_EEA,与官方指南上所做的略有不同)并且方法consentInformation.isConsentFormAvailable()返回false