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

相关推荐
沐言人生2 小时前
Android10 Framework—Init进程-9.服务端属性值初始化
android·android studio·android jetpack
追光天使2 小时前
【Mac】和【安卓手机】 通过有线方式实现投屏
android·macos·智能手机·投屏·有线
小雨cc5566ru2 小时前
uniapp+Android智慧居家养老服务平台 0fjae微信小程序
android·微信小程序·uni-app
一切皆是定数3 小时前
Android车载——VehicleHal初始化(Android 11)
android·gitee
一切皆是定数3 小时前
Android车载——VehicleHal运行流程(Android 11)
android
problc3 小时前
Android 组件化利器:WMRouter 与 DRouter 的选择与实践
android·java
图王大胜4 小时前
Android SystemUI组件(11)SystemUIVisibility解读
android·framework·systemui·visibility
服装学院的IT男8 小时前
【Android 13源码分析】Activity生命周期之onCreate,onStart,onResume-2
android
Arms2068 小时前
android 全面屏最底部栏沉浸式
android
服装学院的IT男8 小时前
【Android 源码分析】Activity生命周期之onStop-1
android