小米手机小游戏隐私问题解决方案

news/2024/5/18 9:59:24 标签: android-studio, 安卓, 游戏程序

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);
    }

}


http://www.niftyadmin.cn/n/5293497.html

相关文章

如何解决网站显示不安全

1. 为何网站显示不安全&#xff1f; 这种情况通常发生在网站未启用SSL证书的情况下。SSL证书是一种安全套接字层协议&#xff0c;通过在用户的浏览器和您的网站之间建立加密连接&#xff0c;保护用户和网站之间的数据传输。当网站未启用SSL时&#xff0c;数据可能以明文形式传输…

HBuilder常用的快捷键

查看专栏目录 Network 灰鸽宝典专栏主要关注服务器的配置&#xff0c;前后端开发环境的配置&#xff0c;编辑器的配置&#xff0c;网络服务的配置&#xff0c;网络命令的应用与配置&#xff0c;windows常见问题的解决等。 文章目录 常用快捷键分9项快捷键1.文件(4)2.编辑(13)3.…

Vue中Render函数、_ref属性、_props配置的使用

Render函数 由于导入的vue为vue.runtime.xxx.js是运行版的vue.只包含&#xff1a;核心功能&#xff1a;没有模板解析器 完整版的Vue为vue.js包含&#xff1a;核心功能模板解析器 vue.runtime.esm.js中的esm为ES6的模块化 //导入的vue并非完整的vue&#xff0c;这样做的好处是…

golang第五卷---包以及常用内置包归纳

包以及常用内置包归纳 包的概念math包time包sync包 Go 语言官方的包文档网站&#xff1a;包文档 包的概念 Go语言是使用包来组织源代码的&#xff0c;包&#xff08;package&#xff09;是多个 Go 源码的集合&#xff0c;是一种高级的代码复用方案。 任何源代码文件必须属于某…

Java学习——设计模式——结构型模式1

文章目录 结构型模式代理模式适配器模式 结构型模式 结构型模式主要涉及如何组合各种对象以便获得更好、更灵活的结构。虽然面向对象的继承机制提供了最基本的子类扩展父类的功能&#xff0c;但结构型模式不仅仅简单地使用继承&#xff0c;而更多地通过组合与运行期的动态组合来…

git 常用基本命令, reset 回退撤销commit,解决gitignore无效,忽略记录或未记录远程仓库的文件,删除远程仓库文件

git 基本命令 reset 撤销commit https://blog.csdn.net/a704397849/article/details/135220091 idea 中 rest 撤销commit过程如下&#xff1a; Git -> Rest Head… 在To Commit中的HEAD后面加上^&#xff0c;点击Reset即可撤回最近一次的尚未push的commit Reset Type 有三…

最新最详细的linux当中安装mongodb教程

什么是mongoDB 1.MongoDB是一个开源的NoSQL数据库&#xff0c;采用了文档型存储方式。它是面向文档的数据库&#xff0c;意味着数据以文档的形式存储在数据库中&#xff0c;而不是以传统的行-列方式存储。每个文档是一个可自包含的数据结构&#xff0c;类似于JSON格式&#xff…

Linux、Windows命令行查看服务、进程是否存在、存活

Linux 服务 查看服务状态 systemctl is-active <serviceName>示例 [rootcurry platform]# systemctl is-active mysqld active [rootcurry platform]# systemctl is-active mysqld1 unknown返回状态 active failed unknown 不存在此服务 进程 查看所有进程名称 …