- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
Consent SDK允许显示同意书,但目前只有英文版本(SDK 版本 1.0.3)。 SDK页面说:
To update consent text of the Google-rendered consent form, modify the consentform.html file included in the Consent SDK as required.
但是,consentform.html 作为 Assets 提供,我没有找到对其进行本地化的方法,尤其是使用 gradle。在这种情况下处理本地化的最佳方法是什么?为什么一开始没有这样做?欧洲不仅仅是英语。
最佳答案
由于 Google 的欧盟同意对话框不可本地化,因此我创建了自己的同意对话框,您可以像往常一样使用 strings.xml
进行翻译。它大致基于谷歌所做的事情。这将在没有中介的情况下使用:
您可以自由使用我的代码,但如果文本适合您,请咨询您的法律顾问。我无法就适合您的同意文本提供法律建议。
添加到您的 gradle 文件:
implementation 'com.google.android.ads.consent:consent-library:1.0.3'
添加成员变量:
public boolean mShowNonPersonalizedAdRequests = false;
private AlertDialog mEuDialog;
在onCreate()
中调用checkConsentStatus()
:
@Override
protected void onCreate(Bundle savedInstanceState) {
// ...
checkConsentStatus();
// ...
}
添加使用 Google Consent SDK 的 checkConsentStatus()
方法:
// 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);
}
});
}
添加showMyConsentDialog()
方法:
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();
}
});
}
这是同意布局,保存到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>
添加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();
}
在您的 AdMob 网络界面中选择您想要使用的广告技术提供商。我建议您不要选择超过 20 个(左右),因为我认为如果您选择太多提供程序,euMoreInfoDialog()
会变得非常慢。
添加到onDestroy()
以防止屏幕旋转时出现错误:
@Override
public void onDestroy(){
// ...
if (mEuDialog != null && mEuDialog.isShowing()) mEuDialog.cancel();
// ...
super.onDestroy();
}
当您发出广告请求时,请检查 mShowNonPersonalizedAdRequests
的值,并在必要时将 “npa”
添加到请求中:
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();
最后,将所有语言的字符串添加到 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>
就是这样!
(注意:log()
和 toast()
是我的方法,请将它们替换为您自己的方法。PRIVACY_URL
是您的 您的隐私政策的字符串
url。)
关于localization - GDPR - 同意 SDK - 同意书翻译,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50540538/
我的英语很差,抱歉 这是我的结构: bookstore ---author(app1) ---book(app2) 或者在代码中: from django.db import models from
我对antlr 的理解停留在非常基础的层面。浏览 Parr 博士的“权威 ANTLR 4 引用”。在第 4.2 节“使用访问者构建计算器”中列出了以下语法: grammar LabeledExpr;
我对antlr 的理解停留在非常基础的层面。浏览 Parr 博士的“权威 ANTLR 4 引用”。在第 4.2 节“使用访问者构建计算器”中列出了以下语法: grammar LabeledExpr;
我正在学习 1.1.0 的 rust book 教程,但尝试运行他们的代码时出现错误。 我有以下内容: extern crate rand; use std::io; use std::cmp::Or
关闭。这个问题是off-topic .它目前不接受答案。 想改进这个问题? Update the question所以它是on-topic对于堆栈溢出。 10年前关闭。 Improve this qu
按照目前的情况,这个问题不适合我们的问答形式。我们希望答案得到事实、引用或专业知识的支持,但这个问题可能会引发辩论、争论、投票或扩展讨论。如果您觉得这个问题可以改进并可能重新打开,visit the
我的帖子是书的代码。 void qsort(void *lineptr[], int left, int right, int (*comp)(void *, void *)); /*Why it
考虑到 Fluent NHibernate 已经有一段时间了,我想应该会有一本书可以买到,所以我在亚马逊和谷歌中搜索,但没有关于 fluent nhiberanet 的书籍。我是对的还是这本书已经存在
考虑到 DocBook 格式的书可以以“模块化”的方式完成,我希望我可以用 AsciiDoc 做类似的事情,并将章节和第一级部分拆分到单独的文件中。不幸的是,文档没有提及这一点。到目前为止,我看到的唯
已关闭。此问题旨在寻求有关书籍、工具、软件库等的建议。不符合Stack Overflow guidelines .它目前不接受答案。 我们不允许提问寻求书籍、工具、软件库等的推荐。您可以编辑问题,以
我目前正在使用 Jquery 使用 turn.js 制作一本书,进展顺利,但我需要一点帮助。你看,我正在尝试制作一本精装期刊类型的书,就像此处显示的示例一样 http://www.turnjs.com
我正在阅读 Bjarne S 的 C++ 编程语言。 在第 77 页,第 4.8 节中,我发现了这一点: "枚举器可以用常量表达式初始化(§C.5) 的整数类型 (§4.1.1)。这枚举的范围包含向上
为什么当我输入由空格分隔的字符串(在 while 循环之外)并且我尝试在屏幕上打印它们时,只有我输入的第一个出现,而在这个 while 循环中(见代码)它打印所有这些一个? //this one pr
按照目前的情况,这个问题不适合我们的问答形式。我们希望答案得到事实、引用或专业知识的支持,但这个问题可能会引发辩论、争论、投票或扩展讨论。如果您觉得这个问题可以改进并可能重新打开,visit the
我正在读这本书并被困在这里: public static class EventArgExtensions { public static void Raise(this TEventArgs
按照目前的情况,这个问题不适合我们的问答形式。我们希望答案得到事实、引用或专业知识的支持,但这个问题可能会引发辩论、争论、投票或扩展讨论。如果您觉得这个问题可以改进并可能重新打开,visit the
很难说出这里要问什么。这个问题模棱两可、含糊不清、不完整、过于宽泛或夸夸其谈,无法以目前的形式得到合理的回答。如需帮助澄清此问题以便重新打开,visit the help center . 关闭 1
我正在尝试使用 xlwt 创建具有多个选项卡的输出文件(.xlsx 格式)。我的Python版本号是2.7,IDE是Aptana Studio 3。 我以前使用过 xlwt 包,在相同的环境下执行相同
如何使用 Xcode 或 macOS 打开 Swift Playground Book?当我打开它时,我得到了这个: 最佳答案 在 Xcode 上,转到 Navigate > Reveal in Pr
嗨,我对 php 很陌生,我正在阅读 Murach PHP 书。我在单击类别部分中的链接时遇到问题,因为当它单击该链接时,它会广告 ?category_id=3 但问题是它在 add_product.
我是一名优秀的程序员,十分优秀!