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"><LinearLayoutandroid: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"><TextViewandroid: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" /><ScrollViewandroid: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"><TextViewandroid: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><TextViewandroid: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><LinearLayoutandroid:id="@+id/BtnView"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_alignParentStart="true"android:layout_alignParentBottom="true"android:gravity="bottom"><Buttonandroid: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" /><Viewandroid:layout_width="0.25dp"android:layout_height="40dp"android:background="@color/colorGray" /><Buttonandroid: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.Nullablepublic 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); //调用小米登录以及初始化广告sdkcheckApkUpdate(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/>作为换行符,然后进行替换成\nTextView 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() {@Overridepublic void onClick(View v) {Log.e("showPrivacy", "点击跳转url界面");//打开一下新的ActivityIntent intent = new Intent(MainActivity.this,SecretUrlActivity.class) ;startActivity(intent);}});//退出按钮事件btn_exit.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {dialog.dismiss();exitGame();finish();}});//同意按钮事件btn_enter.setOnClickListener(new View.OnClickListener() {@Overridepublic 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() {@Overridepublic 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;@Overrideprotected 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"><FrameLayoutandroid: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"><WebViewandroid: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" /><ImageViewandroid: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() {@Overridepublic void onClick(View v) {//点击关闭后隐藏该界面mView.setVisibility(View.GONE);sActivity.toMainActivity();}});}public void showUrlView(){mView.setVisibility(View.VISIBLE);}public void hideUrlView(){mView.setVisibility(View.GONE);}}