1.由于laya底层代码调用获取设备信息,导致原先启动laya引擎后才去弹出隐私政策条款的功能是过不了审核的,所以需要在android的设计一个隐私条款的弹窗,玩家同意条款后才启动laya引擎:
(1)定义隐私条款弹窗的xml文件:在layout文件夹下创建?activity_privacy_policy.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginLeft="50dp"
android:layout_marginTop="100dp"
android:layout_marginRight="50dp"
android:layout_marginBottom="100dp"
android:background="@drawable/dialog_privacy_bg"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_above="@+id/ll_btn_bottom"
android:layout_marginBottom="35dp"
android:gravity="center"
android:orientation="vertical"
tools:ignore="UnknownId">
<TextView
android:id="@+id/tv_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:layout_marginBottom="10dp"
android:text="用户使用协议"
android:autoLink="all"
android:textColor="@color/colorBlack"
android:textSize="18sp" />
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginLeft="5dp"
android:layout_marginRight="5dp"
android:layout_marginBottom="15dp"
android:fadingEdgeLength="60dp"
android:requiresFadingEdge="horizontal">
<TextView
android:id="@+id/tv_content"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="10dp"
android:singleLine="false"
android:text=""
android:textColor="@color/colorBlack"
/>
</ScrollView>
<TextView
android:id="@+id/url_href"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="20dp"
android:layout_marginTop="-238dp"
android:singleLine="false"
android:autoLink="all" //添加下划线
android:text="《产品隐私说明》"
android:textColor="@color/color_accent" />
</LinearLayout>
<LinearLayout
android:id="@+id/BtnView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:layout_alignParentBottom="true"
android:gravity="bottom">
<Button
android:id="@+id/btn_exit"
android:layout_width="0dp"
android:layout_height="32dp"
android:layout_weight="1"
android:background="@color/colorWhite"
android:text="@string/privacy_exit"
android:textColor="@color/colorGray"
android:textSize="16sp"
android:textStyle="bold" />
<View
android:layout_width="0.25dp"
android:layout_height="40dp"
android:background="@color/colorGray" />
<Button
android:id="@+id/btn_enter"
android:layout_width="0dp"
android:layout_height="32dp"
android:layout_weight="1"
android:background="@color/colorWhite"
android:text="@string/privacy_agree"
android:textColor="@color/colorOrange"
android:textSize="16sp"
android:textStyle="bold" />
</LinearLayout>
</RelativeLayout>
(2)既然有弹出界面,那就有弹出界面的bg代码,所以在drawable目录下创建一个? dialog_privacy_bg.xml
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<!--填充设置-->
<solid android:color="@android:color/white" />
<!--圆角设置-->
<corners android:radius="6dp" />
</shape>
(3)然后少不了颜色设置啦,直接在values目录下的?colors.xml里面补上填充颜色:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="colorPrimary">#008577</color>
<color name="colorPrimaryDark">#00574B</color>
<color name="colorAccent">#D81B60</color>
<color name="colorWhite">#FFFFFFFF</color>
<color name="colorBlack">#FF000000</color>
<color name="colorGray">#878787</color>
<color name="colorOrange">#FFE26C25</color>
<color name="colorBlue">#FF036EB8</color>
</resources>
(4)颜色有了,少不了文字,所以在?values目录下的?strings.xml?里面按钮文字之类的 :
<string name="privacy_exit">退出</string>
<string name="privacy_agree">同意</string>
2.实现隐私弹窗的前提内容已经准备好了,那就少不了开始调用隐私弹窗了,在代码层面:
(1)既然只需要显示一次,那就需要保持数据,直接上保存数据的工具类:
package demo;//包名我就隐藏了
import android.content.Context;
import android.content.SharedPreferences;
import java.util.Map;
/**
* 数据缓存到本地
* **/
public class DataUtils {
/**
* 保存在手机里的SP文件名
*/
public static final String FILE_NAME = "privacy_sp";
/**
* 保存数据
*/
public static void put(Context context, String key, Object obj) {
SharedPreferences sp = context.getSharedPreferences(FILE_NAME, context.MODE_PRIVATE);
SharedPreferences.Editor editor = sp.edit();
if (obj instanceof Boolean) {
editor.putBoolean(key, (Boolean) obj);
} else if (obj instanceof Float) {
editor.putFloat(key, (Float) obj);
} else if (obj instanceof Integer) {
editor.putInt(key, (Integer) obj);
} else if (obj instanceof Long) {
editor.putLong(key, (Long) obj);
} else {
editor.putString(key, (String) obj);
}
editor.commit();
}
public static boolean isKeep(Context context, String key, Object defaultObj){
SharedPreferences sp = context.getSharedPreferences(FILE_NAME, context.MODE_PRIVATE);
if(sp.contains(key))
{
}
return false;
}
/**
* 获取指定数据
*/
@org.jetbrains.annotations.Nullable
public static Object get(Context context, String key, Object defaultObj) {
SharedPreferences sp = context.getSharedPreferences(FILE_NAME, context.MODE_PRIVATE);
if (defaultObj instanceof Boolean) {
return sp.getBoolean(key, (Boolean) defaultObj);
} else if (defaultObj instanceof Float) {
return sp.getFloat(key, (Float) defaultObj);
} else if (defaultObj instanceof Integer) {
return sp.getInt(key, (Integer) defaultObj);
} else if (defaultObj instanceof Long) {
return sp.getLong(key, (Long) defaultObj);
} else if (defaultObj instanceof String) {
return sp.getString(key, (String) defaultObj);
}
return null;
}
/**
* 删除指定数据
*/
public static void remove(Context context, String key) {
SharedPreferences sp = context.getSharedPreferences(FILE_NAME, context.MODE_PRIVATE);
SharedPreferences.Editor editor = sp.edit();
editor.remove(key);
editor.commit();
}
/**
* 返回所有键值对
*/
public static Map<String, ?> getAll(Context context) {
SharedPreferences sp = context.getSharedPreferences(FILE_NAME, context.MODE_PRIVATE);
Map<String, ?> map = sp.getAll();
return map;
}
/**
* 删除所有数据
*/
public static void clear(Context context) {
SharedPreferences sp = context.getSharedPreferences(FILE_NAME, context.MODE_PRIVATE);
SharedPreferences.Editor editor = sp.edit();
editor.clear();
editor.commit();
}
/**
* 检查key对应的数据是否存在
*/
public static boolean contains(Context context, String key) {
SharedPreferences sp = context.getSharedPreferences(FILE_NAME, context.MODE_PRIVATE);
return sp.contains(key);
}
}
(2)接下来在 MainActivity.java中,onCreate方法中,判断?是否?需要拉起隐私弹窗:
/**当前表现的隐私类型:
* 1:个人信息隐私
* 2:使用条款
* 注意:一个是用户协议记录状态,一个是隐私协议记录状态。至于那个,你们自己定也可以看我的。
* **/
private int prviacyType = 1; //在onCreate之前声明变量
/**
* 既然是保存第一次数据的。所以,执行调用隐私前,必须拿到是否同意哪个隐私内容了
* */
String isPrivacy = DataUtils.get(MainActivity.this,"privacy","0").toString();
if(isPrivacy.equals("1") )
{
//同意过隐私政策了,直接跳过隐私弹窗处理
Log.e("showPrivacy", "同意了,直接跳过隐私弹窗处理");
onAgreed(); //下次进游戏同意过隐私政策的用户直接启动laya引擎
}else if(isPrivacy.equals("0"))
{
Log.e("showPrivacy", "显示用户个人信息隐私");
prviacyType = 1;
//这里需要在assets文件夹下,创建一个隐私政策的文本,代码通过读取这个文件,显示隐私政策的内容在界面
showPrivacy("privacy.txt","隐私协议");
}
(3)当同意隐私政策后,拉取权限申请代码,和启动laya引擎的代码:
public void onAgreed(){
checkAndRequestPermissions(); //申请权限
MiCommplatform.getInstance().onUserAgreed(this); //小米接口同意隐私政策 告知SDK??是否同意隐私协议
MMApplication mApplication = (MMApplication) getApplication();
mApplication.initSDK(this); //调用小米登录以及初始化广告sdk
checkApkUpdate(this); //启动laya引擎
}
/**声明权限申请相关的变量**/
private List<String> mNeedRequestPMSList = new ArrayList<>();
private static final int REQUEST_PERMISSIONS_CODE = 100;
/**
* 申请 SDK 运行需要的权限
* 注意:READ_PHONE_STATE 权限是必须权限,没有这个权限 SDK 无法正常获得广告。
* WRITE_EXTERNAL_STORAGE 、ACCESS_FINE_LOCATION 是可选权限;没有不影响 SDK 获取
广告;但是如果应用申请到该权限,会显著提升应用的广告收益。
*/
private void checkAndRequestPermissions() {
/**
* Android Q 以下 READ_PHONE_STATE 权限是必须权限,没有这个权限 SDK 无法正常获得
广告。
*/
mNeedRequestPMSList.add(Manifest.permission.READ_PHONE_STATE);
mNeedRequestPMSList.add(Manifest.permission.READ_EXTERNAL_STORAGE);
mNeedRequestPMSList.add(Manifest.permission.READ_PHONE_STATE);
mNeedRequestPMSList.add(Manifest.permission.GET_ACCOUNTS);
mNeedRequestPMSList.add(Manifest.permission.INTERNET);
mNeedRequestPMSList.add(Manifest.permission.WRITE_EXTERNAL_STORAGE);
mNeedRequestPMSList.add(Manifest.permission.INTERNET);
mNeedRequestPMSList.add(Manifest.permission.ACCESS_NETWORK_STATE);
mNeedRequestPMSList.add(Manifest.permission.ACCESS_WIFI_STATE);
mNeedRequestPMSList.add(Manifest.permission.ACCESS_FINE_LOCATION);
mNeedRequestPMSList.add(Manifest.permission.REQUEST_INSTALL_PACKAGES);
//
if (0 == mNeedRequestPMSList.size()) {
/**
* 权限都已经有了,那么直接调用 SDK 请求广告。
*/
} else {
/**
* 有权限需要申请,主动申请。
*/
String[] temp = new String[mNeedRequestPMSList.size()];
mNeedRequestPMSList.toArray(temp);
ActivityCompat.requestPermissions(this, temp,
REQUEST_PERMISSIONS_CODE);
}
}
(4)显示?隐私弹窗:
/**
* 前置内容都设定了,那就开始调用弹出隐私,并且根据调用的隐私内容去加载隐私内容回来并且展示出来。
* */
public void showPrivacy(String privacyFileName,String title) {
//加载当前要显示的隐私内容文本
String str = initAssets(privacyFileName);
//布局ui界面信息
final View inflate = LayoutInflater.from(this).inflate(R.layout.activity_privacy_policy, null);
TextView tv_title = (TextView) inflate.findViewById(R.id.tv_title);
//设置隐私内容抬头
tv_title.setText(title);
//显示隐私内容,因为文本布局,需要美观,所以内容用需要使用换行符,但加载回来的内容用\n的话无法真正做到换行,只能在文本中用<br/>作为换行符,然后进行替换成\n
TextView tv_content = (TextView) inflate.findViewById(R.id.tv_content);
tv_content.setText(str.replace("<br/>", "\n"));
tv_content.setText(Html.fromHtml(str)); //这里把读取的str按照html格式显示出来
//获取同意和退出两个按钮并且添加事件
TextView url_href = (TextView) inflate.findViewById(R.id.url_href);
TextView btn_exit = (TextView) inflate.findViewById(R.id.btn_exit);
TextView btn_enter = (TextView) inflate.findViewById(R.id.btn_enter);
Log.e("showPrivacy", "开始弹出隐私界面111");
//开始弹出隐私界面
final Dialog dialog = new AlertDialog
.Builder(this)
.setView(inflate)
.show();
//对话框弹出后点击或按返回键不消失
dialog.setCancelable(false);
Log.e("showPrivacy", "开始弹出隐私界面2222");
WindowManager m = getWindowManager();
Display defaultDisplay = m.getDefaultDisplay();
final WindowManager.LayoutParams params = dialog.getWindow().getAttributes();
params.width = (int) (defaultDisplay.getWidth() * 0.90);
dialog.getWindow().setAttributes(params);
dialog.getWindow().setBackgroundDrawableResource(android.R.color.transparent);
url_href.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Log.e("showPrivacy", "点击跳转url界面");
//打开一下新的Activity
Intent intent = new Intent(MainActivity.this,SecretUrlActivity.class) ;
startActivity(intent);
}
});
//退出按钮事件
btn_exit.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
dialog.dismiss();
exitGame();
finish();
}
});
//同意按钮事件
btn_enter.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
dialog.dismiss();
// if(prviacyType == 1)
// {
// prviacyType = 2;
// //保存隐私同意状态
// DataUtils.put(MainActivity.this,"privacy","1");
// //显示下一个隐私内容
// showPrivacy("policy.txt","使用条款");
// }else if(prviacyType == 2)
// {
// DataUtils.put(MainActivity.this,"policy","1");
// //两个隐私内容都确定后,开始执行下一步
// onAgreed();
// }
DataUtils.put(MainActivity.this,"privacy","1");
//两个隐私内容都确定后,开始执行下一步
onAgreed();
}
});
}
这里需要在assets文件夹下,创建一个隐私政策的文本,代码通过读取这个文件,显示隐私政策的内容在界面中:
(5)读取txt文件的代码如下:
/**
* 从assets下的txt文件中读取数据
*/
public String initAssets(String fileName) {
Log.e("initAssets", "从assets下的txt文件中读取数据");
String str = null;
try {
InputStream inputStream = getAssets().open(fileName);
str = getString(inputStream);
} catch (IOException e1) {
e1.printStackTrace();
}
return str;
}
public static String getString(InputStream inputStream) {
InputStreamReader inputStreamReader = null;
try {
inputStreamReader = new InputStreamReader(inputStream, "UTF-8");
} catch (UnsupportedEncodingException e1) {
e1.printStackTrace();
}
BufferedReader reader = new BufferedReader(inputStreamReader);
StringBuffer sb = new StringBuffer("");
String line;
try {
while ((line = reader.readLine()) != null) {
sb.append(line);
sb.append("");
}
} catch (IOException e) {
e.printStackTrace();
}
return sb.toString();
}
(6)另外在点击?xml中的一个 TextView元素的时候,这里注册了一个点击事件,会打开新的Activity,这个新的Activity是一个用于显示隐私条款详情的?网页:
TextView url_href = (TextView) inflate.findViewById(R.id.url_href);
url_href.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Log.e("showPrivacy", "点击跳转url界面");
Intent intent = new Intent(MainActivity.this,SecretUrlActivity.class) ;
startActivity(intent);
}
});
(7)这个新的Activity,SecretUrlActivity.java 代码如下:
package demo;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.view.ViewGroup;
import com.cszs.jgdnc.mi.R;
import demo.SecretUrlView;
public class SecretUrlActivity extends Activity {
public ViewGroup urlView_container;
private SecretUrlView urlView = null;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.url_layout) ;
InitUrlSecretView();
}
public void InitUrlSecretView(){
if(urlView!=null){
urlView.showUrlView();
return;
}
// final View inflate2 = LayoutInflater.from(this).inflate(R.layout.url_layout,null);
// this.urlView_container = (ViewGroup)inflate2.findViewById(R.id.view_url_container);
this.urlView_container = findViewById(R.id.view_url_container);
urlView = new SecretUrlView(this);
}
public void toMainActivity(){
Intent intent = new Intent(SecretUrlActivity.this,MainActivity.class) ;
startActivity(intent) ;
}
}
(8)这个SecretUrlActivity对应的布局文件,在layout文件夹中创建url_layout.xml,如下:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto">
<FrameLayout
android:id="@+id/view_url_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginLeft="0dp"
android:layout_marginTop="0dp"
android:layout_marginRight="0dp"
android:layout_marginBottom="0dp"
android:background="#FFFFFF">
<WebView
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:id="@+id/wv"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_alignParentTop="true" />
<ImageView
android:id="@+id/view_url_close"
android:layout_width="32dp"
android:layout_height="32dp"
android:layout_marginStart="9dp"
android:layout_marginTop="20dp"
android:layout_marginEnd="400dp"
android:contentDescription="关闭按钮"
android:src="@drawable/float_hide_tip_sel"
app:layout_constraintBottom_toTopOf="@+id/view_feedBox_image"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.78"
app:layout_constraintStart_toEndOf="@+id/view_feedBox_image"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.0" />
</FrameLayout>
</RelativeLayout>
(9)这个新的Activity,也就是 SecretUrlActivity,创建一个View类 SecretUrlView.java:用于显示网页
package demo;
import android.content.Intent;
import android.view.View;
import android.view.ViewGroup;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import com.cszs.jgdnc.mi.R;
import demo.Constants;
import demo.MainActivity;
import demo.SecretUrlActivity;
public class SecretUrlView {
private SecretUrlActivity sActivity;
private static String TAG = "SecretUrlView";
private View mView;
private WebView wv;
public SecretUrlView(SecretUrlActivity sActivity) {
this.sActivity = sActivity;
this.init();
}
public void init(){
mView = (ViewGroup) sActivity.urlView_container;
wv=(WebView)mView.findViewById(R.id.wv);
WebSettings ws=wv.getSettings();
ws.setJavaScriptEnabled(true);
wv.loadUrl("https://res.wqop2018.com/app/web/privacy/v3/privacy.html?app_name=" + Constants.APP_NAME + "&company="+Constants.COMPANY+"&package_name="+Constants.PACKAGE_NAME);
wv.setWebViewClient(new WebViewClient());
mView.findViewById(R.id.view_url_close).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//点击关闭后隐藏该界面
mView.setVisibility(View.GONE);
sActivity.toMainActivity();
}
});
}
public void showUrlView(){
mView.setVisibility(View.VISIBLE);
}
public void hideUrlView(){
mView.setVisibility(View.GONE);
}
}