Android AdMob(三) — GDPR相关处理

GDPR(General Data Protection Regulation)是欧盟针对数据保护和隐私权的一项法规。旨在加强个人数据保护,并为欧盟居民提供更多对其个人数据的控制权,该法规在2018年5月25日生效。

从2024年1月16日开始,使用AdManager或AdMob的发布者和开发者在向欧盟或英国的用户提供广告前,必须先使用由Google认证并集成了IAB's Transparency and Consent Framework的同意管理平台(CMP)获取用户授权。在获得授权后,才能使用用户信息进行个性化广告投放。

相关条例

User Messaging Platform(UMP)

针对新的限制条例,Google提供了User Messaging Platform(UMP)SDK,便于开发者在App中集成,实现获取用户同意功能。

UMP官方接入文档

在AdMob管理后台创建GDPR消息

官方指引文档

  • 在AdMob管理后台的隐私权与消息中选择创建GDPR信息。

  • 在GDPR消息创建页面中,首先需要选取使用该消息的App。需要注意的是,这里需要填入App使用的隐私政策对应的网址。

  • 根据需求调整弹窗样式以及此消息弹窗面向的人群后就可以发布。

添加UMP SDK

在项目app module的build.gradle中的dependencies中添加依赖:

scss 复制代码
dependencies {
    implementation("com.google.android.ump:user-messaging-platform:2.1.0")
}

配置AndroidManifest

设置APPLICATION_ID

AndroidManifest中的com.google.android.gms.ads.APPLICATION_ID配置为关联了GDPR消息的APPLICATION_ID。代码如下:

xml 复制代码
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">

    <application
        ......
        >

        <!--此id为官方demo的id,可以测试UMP效果-->
        <meta-data
            android:name="com.google.android.gms.ads.APPLICATION_ID"
            android:value="ca-app-pub-3940256099942544~3347511713" />

    </application>
</manifest>

延迟应用衡量

AdMob会在应用启动时初始化应用衡量并开始上报用户级事件,可以通过在AndroidManifest中配置<meta-data>延迟此行为。代码如下:

xml 复制代码
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">

    <application
        ......
        >

        <meta-data
            android:name="com.google.android.gms.ads.DELAY_APP_MEASUREMENT_INIT"
            android:value="true" />

    </application>
</manifest>

实现获取用户同意功能

请求同意信息

创建ConsentInformation对象然后通过requestConsentInfoUpdate()方法请求同意信息,代码如下:

kotlin 复制代码
class AdmobExampleActivity : AppCompatActivity() {

    private lateinit var binding: LayoutAdmobExampleActivityBinding

    private lateinit var consentInformation: ConsentInformation

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = LayoutAdmobExampleActivityBinding.inflate(layoutInflater).also {
            setContentView(it.root)
        }
        binding.includeTitle.tvTitle.text = "AdmobExample"

        val consentRequestParameters = ConsentRequestParameters.Builder()
            // 设置用户不会低于法定年龄
            .setTagForUnderAgeOfConsent(false)
            .build()
        consentInformation = UserMessagingPlatform.getConsentInformation(this)
        consentInformation.requestConsentInfoUpdate(
            this,
            consentRequestParameters,
            object : ConsentInformation.OnConsentInfoUpdateSuccessListener {
                override fun onConsentInfoUpdateSuccess() {
                    // 同意信息更新成功

                    if (consentInformation.isConsentFormAvailable) {
                        // 同意表单可用,加载并显示表单
                    } else {
                        // 同意表单不可用,验证一下是否可以使用广告
                        if (consentInformation.canRequestAds()) {
                            // 可以请求广告,开始初始化广告SDK
                        }
                    }
                }
            },
            object : ConsentInformation.OnConsentInfoUpdateFailureListener {
                override fun onConsentInfoUpdateFailure(formError: FormError) {
                    // 同意信息更新失败

                    // 获取错误码
                    val errorCode = formError.errorCode
                    // 获取错误信息
                    val errorMessage = formError.message

                    // 验证一下是否可以使用广告
                    if (consentInformation.canRequestAds()) {
                        // 可以请求广告,开始初始化广告SDK
                    }
                }
            })
    }
}

获取同意信息可能出现几种情况,需要做出对应的处理,如下:

  • 更新信息成功且同意表单可用,此时应该加载并显示表单。
  • 更新信息成功但表单不可用,此时应该通过canRequestAds()检测是否可以请求广告。
  • 更新信息失败,此时也应该通过canRequestAds()检测是否可以请求广告。

另外,需要注意的是,为了符合IAB TCF的标准,官方建议在每次运行App时都执行requestConsentInfoUpdate()方法,避免用户上一次授权的同意信息已经超过13个月导致失效。

加载同意表单并显示。

在成功更新完同意信息后,如果同意表单可用,那么此时应该加载同意表单并显示。代码如下:

kotlin 复制代码
class AdmobExampleActivity : AppCompatActivity() {

    private lateinit var binding: LayoutAdmobExampleActivityBinding

    private lateinit var consentInformation: ConsentInformation

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = LayoutAdmobExampleActivityBinding.inflate(layoutInflater).also {
            setContentView(it.root)
        }
        binding.includeTitle.tvTitle.text = "AdmobExample"

        val consentRequestParameters = ConsentRequestParameters.Builder()
            .setTagForUnderAgeOfConsent(false)
            .build()
        consentInformation = UserMessagingPlatform.getConsentInformation(this)
        consentInformation.requestConsentInfoUpdate(
            this,
            consentRequestParameters,
            object : ConsentInformation.OnConsentInfoUpdateSuccessListener {
                override fun onConsentInfoUpdateSuccess() {
                    if (consentInformation.isConsentFormAvailable) {
                        loadAndShowConsentFormIfRequired()
                    } 
                    ......
                }
            },
            object : ConsentInformation.OnConsentInfoUpdateFailureListener {
                override fun onConsentInfoUpdateFailure(formError: FormError) {
                    ......
                }
            })
    }
    
    fun loadAndShowConsentFormIfRequired() {
        UserMessagingPlatform.loadAndShowConsentFormIfRequired(this, object : ConsentForm.OnConsentFormDismissedListener {
            override fun onConsentFormDismissed(formError: FormError?) {
                // 表单加载失败时回调此方法。
                // 表单加载完并显示成功,用户操作完表单后回调此方法。
                // 验证一下是否可以使用广告
                if (consentInformation.canRequestAds()) {
                    // 可以请求广告,开始初始化广告SDK
                }
            }
        })
    }
}

onConsentFormDismissed()会在表单加载失败或者表单被用户关闭之后(不论用户选择同意或不同意)回调。此时同样应该通过canRequestAds()检测是否可以请求广告。

允许撤销授权

根据GDPR法规,用户可以随时撤销同意授权,因此需要在App中提供撤销授权功能。UMP为此提供了Privacy Options API,在requestConsentInfoUpdate()回调成功后,可以通过ConsentInformationgetPrivacyOptionsRequirementStatus()方法获取是否需要使用Privacy Options。如果需要的话,通过UserMessagingPlatformshowPrivacyOptionsForm()方法显示Privacy Options。代码如下:

kotlin 复制代码
class AdmobExampleActivity : AppCompatActivity() {

    private lateinit var binding: LayoutAdmobExampleActivityBinding

    private lateinit var consentInformation: ConsentInformation

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = LayoutAdmobExampleActivityBinding.inflate(layoutInflater).also {
            setContentView(it.root)
        }
        binding.includeTitle.tvTitle.text = "AdmobExample"
        binding.btnShowPrivacyOptions.setOnClickListener { showPrivacyOptionsForm() }

        val consentRequestParameters = ConsentRequestParameters.Builder()
            .setTagForUnderAgeOfConsent(false)
            .build()
        consentInformation = UserMessagingPlatform.getConsentInformation(this)
        consentInformation.requestConsentInfoUpdate(
            this,
            consentRequestParameters,
            object : ConsentInformation.OnConsentInfoUpdateSuccessListener {
                override fun onConsentInfoUpdateSuccess() {
                    if (consentInformation.privacyOptionsRequirementStatus == ConsentInformation.PrivacyOptionsRequirementStatus.REQUIRED) {
                        // 需要显示Privacy Options,显示对应的按钮
                        binding.btnShowPrivacyOptions.visibility = View.VISIBLE
                    }
                    ......
                }
            },
            object : ConsentInformation.OnConsentInfoUpdateFailureListener {
                override fun onConsentInfoUpdateFailure(formError: FormError) {
                    ......
                }
            })
    }

    private fun showPrivacyOptionsForm() {
        UserMessagingPlatform.showPrivacyOptionsForm(this, object : ConsentForm.OnConsentFormDismissedListener {
            override fun onConsentFormDismissed(formError: FormError?) {
                // 表单加载失败时回调此方法。
                // 表单加载完并显示成功,用户操作完表单后回调此方法。
            }
        })
    }
}

测试

UMP提供了一些测试方法,可以模拟App在欧盟或英国区域时的情况和快速撤销同意授权,使用步骤如下:

  1. 获取设备的测试ID。

调用requestConsentInfoUpdate()方法后,在Logcat中过滤tag为UserMessagingPlatform的日志,如下:

  1. 调整ConsentRequestParameters配置。

在创建ConsentRequestParameters时设置获取到的TestDeviceHashedId以及地理位置信息,代码如下:

kotlin 复制代码
class AdmobExampleActivity : AppCompatActivity() {

    private lateinit var consentInformation: ConsentInformation

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        val consentRequestParameters = ConsentRequestParameters.Builder()
            .setTagForUnderAgeOfConsent(false)
            .setConsentDebugSettings(ConsentDebugSettings.Builder(this)
                .setDebugGeography(ConsentDebugSettings.DebugGeography.DEBUG_GEOGRAPHY_EEA)
                .addTestDeviceHashedId("9E190127A33E1387D56E000EEF479712")
                .build())
            .build()
        consentInformation.requestConsentInfoUpdate(
            this,
            consentRequestParameters,
            object : ConsentInformation.OnConsentInfoUpdateSuccessListener {
                override fun onConsentInfoUpdateSuccess() {
                    ......
                }
            },
            object : ConsentInformation.OnConsentInfoUpdateFailureListener {
                override fun onConsentInfoUpdateFailure(formError: FormError) {
                    ......
                }
            })
    }
}
  1. 在需要时撤销同意授权,代码如下:
kotlin 复制代码
class AdmobExampleActivity : AppCompatActivity() {

    private lateinit var consentInformation: ConsentInformation

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        consentInformation = UserMessagingPlatform.getConsentInformation(this)
        consentInformation.reset()
    }
}

效果演示与示例代码

最终效果如下图:

演示代码已在示例Demo中添加。

ExampleDemo github

ExampleDemo gitee

相关推荐
darkb1rd28 分钟前
五、PHP类型转换与类型安全
android·安全·php
gjxDaniel1 小时前
Kotlin编程语言入门与常见问题
android·开发语言·kotlin
csj501 小时前
安卓基础之《(22)—高级控件(4)碎片Fragment》
android
峥嵘life2 小时前
Android16 【CTS】CtsMediaCodecTestCases等一些列Media测试存在Failed项
android·linux·学习
stevenzqzq2 小时前
Compose 中的状态可变性体系
android·compose
似霰3 小时前
Linux timerfd 的基本使用
android·linux·c++
darling3315 小时前
mysql 自动备份以及远程传输脚本,异地备份
android·数据库·mysql·adb
你刷碗5 小时前
基于S32K144 CESc生成随机数
android·java·数据库
TheNextByte15 小时前
Android上的蓝牙文件传输:跨设备无缝共享
android
言之。6 小时前
Kotlin快速入门
android·开发语言·kotlin