Android AdMob(三) — GDPR相关处理

1,049 阅读5分钟

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信息。
image.png image.png
  • 在GDPR消息创建页面中,首先需要选取使用该消息的App。需要注意的是,这里需要填入App使用的隐私政策对应的网址。
image.png image.png
  • 根据需求调整弹窗样式以及此消息弹窗面向的人群后就可以发布。
image.png image.png

添加UMP SDK

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

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 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 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()方法请求同意信息,代码如下:

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个月导致失效。

加载同意表单并显示。

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

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。代码如下:

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的日志,如下:

image.png

  1. 调整ConsentRequestParameters配置。

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

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. 在需要时撤销同意授权,代码如下:
class AdmobExampleActivity : AppCompatActivity() {

    private lateinit var consentInformation: ConsentInformation

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

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

效果演示与示例代码

最终效果如下图:

Screen_recording_202 -big-original.gif

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

ExampleDemo github

ExampleDemo gitee