Since Google's EU Consent dialog is not localizable, I created my own consent dialog which you can translate as usual with strings.xml
. It's loosely based on what Google did. This is to be used without mediation:
You are free to use my code, however consult your legal advisor, if the text is appropriate for you. I cannot provide legal advice on the consent text that is appropriate for you.
Add to your gradle file:
implementation 'com.google.android.ads.consent:consent-library:1.0.3'
Add member variables:
public boolean mShowNonPersonalizedAdRequests = false;
private AlertDialog mEuDialog;
In onCreate()
call checkConsentStatus()
:
@Override
protected void onCreate(Bundle savedInstanceState) {
// ...
checkConsentStatus();
// ...
}
Add checkConsentStatus()
method which uses Google's Consent SDK:
// https://developers.google.com/admob/android/eu-consent
private void checkConsentStatus(){
ConsentInformation consentInformation = ConsentInformation.getInstance(this);
ConsentInformation.getInstance(this).addTestDevice("YOUR-DEVICE-ID"); // enter your device id, if you need it for testing
String[] publisherIds = {"pub-YOUR-ADMOB-PUB-ID"}; // enter your admob pub-id
consentInformation.requestConsentInfoUpdate(publisherIds, new ConsentInfoUpdateListener() {
@Override
public void onConsentInfoUpdated(ConsentStatus consentStatus) {
log("User's consent status successfully updated: " +consentStatus);
if (ConsentInformation.getInstance(MainActivity.this).isRequestLocationInEeaOrUnknown()){
log("User is from EU");
/////////////////////////////
// TESTING - reset the choice
//ConsentInformation.getInstance(MainActivity.this).setConsentStatus(ConsentStatus.UNKNOWN);
/////////////////////////////
// If the returned ConsentStatus is UNKNOWN, collect user's consent.
if (consentStatus == ConsentStatus.UNKNOWN) {
showMyConsentDialog(false);
}
// If the returned ConsentStatus is PERSONALIZED or NON_PERSONALIZED
// the user has already provided consent. Forward consent to the Google Mobile Ads SDK.
else if (consentStatus == ConsentStatus.NON_PERSONALIZED) {
mShowNonPersonalizedAdRequests = true;
// The default behavior of the Google Mobile Ads SDK is to serve personalized ads.
// If a user has consented to receive only non-personalized ads, you can configure
// an AdRequest object with the following code to specify that only non-personalized
// ads should be returned.
}
} else {
log("User is NOT from EU");
// we don't have to do anything
}
}
@Override
public void onFailedToUpdateConsentInfo(String errorDescription) {
log("User's consent status failed to update: " +errorDescription);
}
});
}
Add showMyConsentDialog()
method:
public void showMyConsentDialog(boolean showCancel) {
AlertDialog.Builder alertDialog = new AlertDialog.Builder(MainActivity.this, R.style.MyAlertDialogStyle);
LayoutInflater inflater = getLayoutInflater();
View eu_consent_dialog = inflater.inflate(R.layout.eu_consent, null);
alertDialog.setView(eu_consent_dialog)
.setCancelable(false);
if (showCancel) alertDialog.setPositiveButton(R.string.dialog_close, null);
mEuDialog = alertDialog.create();
mEuDialog.show();
Button btn_eu_consent_yes = eu_consent_dialog.findViewById(R.id.btn_eu_consent_yes);
Button btn_eu_consent_no = eu_consent_dialog.findViewById(R.id.btn_eu_consent_no);
Button btn_eu_consent_remove_ads = eu_consent_dialog.findViewById(R.id.btn_eu_consent_remove_ads);
btn_eu_consent_yes.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mEuDialog.cancel();
toast(getString(R.string.thank_you), MainActivity.this);
ConsentInformation.getInstance(MainActivity.this).setConsentStatus(ConsentStatus.PERSONALIZED);
mShowNonPersonalizedAdRequests = false;
}
});
btn_eu_consent_no.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mEuDialog.cancel();
toast(getString(R.string.thank_you), MainActivity.this);
ConsentInformation.getInstance(MainActivity.this).setConsentStatus(ConsentStatus.NON_PERSONALIZED);
mShowNonPersonalizedAdRequests = true;
}
});
btn_eu_consent_remove_ads.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mEuDialog.cancel();
IAP_buyAdsFree(); // YOUR REMOVE ADS METHOD
}
});
TextView tv_eu_learn_more = eu_consent_dialog.findViewById(R.id.tv_eu_learn_more);
tv_eu_learn_more.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
euMoreInfoDialog();
}
});
}
This is the consent layout, save to eu_consent.xml
:
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<LinearLayout
android:id="@+id/ll_eu_consent"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="@dimen/activity_horizontal_margin"
>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/eu_consent_text"
android:textSize="14sp"
android:paddingBottom="6dp"
/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/eu_consent_question"
android:textSize="14sp"
android:paddingBottom="6dp"
android:textStyle="bold"
/>
<Button
android:id="@+id/btn_eu_consent_yes"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/eu_consent_yes"
android:textSize="13sp"
/>
<Button
android:id="@+id/btn_eu_consent_no"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/eu_consent_no"
android:textSize="13sp"
android:layout_marginTop="6dp"
android:layout_marginBottom="6dp"
/>
<Button
android:id="@+id/btn_eu_consent_remove_ads"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/action_remove_ads"
android:textSize="13sp"
/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/eu_consent_change_setting"
android:textSize="14sp"
android:paddingTop="6dp"
android:paddingBottom="6dp"
/>
<TextView
android:id="@+id/tv_eu_learn_more"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/learn_more"
android:textSize="14sp"
android:ellipsize="marquee"
android:fadingEdge="horizontal"
android:paddingTop="6dp"
android:paddingBottom="6dp"
android:textColor="@color/blue"
style="@style/SelectableItem"
/>
</LinearLayout>
</ScrollView>
Add euMoreInfoDialog()
:
private void euMoreInfoDialog(){
AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this, R.style.MyAlertDialogStyle);
ScrollView sv = new ScrollView(this);
LinearLayout ll = new LinearLayout(this);
ll.setOrientation(LinearLayout.VERTICAL);
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.MATCH_PARENT,
LinearLayout.LayoutParams.WRAP_CONTENT);
params.setMargins(40, 20, 40, 20);
TextView tv_my_privacy_policy = new TextView(this);
String link = "<a href="+PRIVACY_URL+">"+getResources().getString(R.string.app_name)+"</a>";
tv_my_privacy_policy.setText(Html.fromHtml(link));
tv_my_privacy_policy.setMovementMethod(LinkMovementMethod.getInstance());
ll.addView(tv_my_privacy_policy, params);
TextView tv_google_partners = new TextView(this);
tv_google_partners.setText(R.string.google_partners);
tv_google_partners.setPadding(40,40,40,20);
ll.addView(tv_google_partners);
List<AdProvider> adProviders = ConsentInformation.getInstance(this).getAdProviders();
for (AdProvider adProvider : adProviders) {
//log("adProvider: " +adProvider.getName()+ " " +adProvider.getPrivacyPolicyUrlString());
link = "<a href="+adProvider.getPrivacyPolicyUrlString()+">"+adProvider.getName()+"</a>";
TextView tv_adprovider = new TextView(this);
tv_adprovider.setText(Html.fromHtml(link));
tv_adprovider.setMovementMethod(LinkMovementMethod.getInstance());
ll.addView(tv_adprovider, params);
}
sv.addView(ll);
builder.setTitle(R.string.privacy_policy)
.setView(sv)
.setPositiveButton(R.string.dialog_close, null);
final AlertDialog createDialog = builder.create();
createDialog.show();
}
In your AdMob web interface select the ad technology providers you wish to use. I suggest you don't select more than 20 (or so), because I assume the euMoreInfoDialog()
will become very slow if you select too many providers.
Add to onDestroy()
to prevent errors on screen rotate:
@Override
public void onDestroy(){
// ...
if (mEuDialog != null && mEuDialog.isShowing()) mEuDialog.cancel();
// ...
super.onDestroy();
}
When you make an ad request, check the value of mShowNonPersonalizedAdRequests
and add "npa"
to the request if necessary:
Bundle extras = new Bundle();
if (mShowNonPersonalizedAdRequests)
extras.putString("npa", "1");
AdRequest adRequest = new AdRequest.Builder()
.addTestDevice(AdRequest.DEVICE_ID_EMULATOR)
.addTestDevice("YOUR-DEVICE-ID-GOES-HERE") // insert your device id
.addNetworkExtrasBundle(AdMobAdapter.class, extras)
.build();
And lastly, add strings for all your languages to strings.xml
:
<!-- EU GDPR Consent texts -->
<string name="eu_consent_text">Dear user!\n\nWe use Google Admob to show ads. Ads support our work, and enable further development of this app. In line with the new European Data Protection Regulation (GDPR), we need your consent to serve ads tailored for you.</string>
<string name="eu_consent_question">Can your data be used to show ads tailored for you?</string>
<string name="learn_more">Learn how your data is used</string>
<string name="google_partners">Google and its partners:</string>
<string name="eu_consent_yes">Yes, continue to show relevant ads</string>
<string name="eu_consent_no">No, show ads that are irrelevant</string>
<string name="eu_consent_change_setting">You can change this setting anytime in the \"About\" window.</string>
<string name="thank_you">Thank you!</string>
That's it!
(Note: log()
and toast()
are my methods, replace them with your own. PRIVACY_URL
is your String
url to your privacy policy.)