点亮技能之Android6.0动态权限

一,写在前面

    在sdk23以前,用户安装应用时必须同意开发者添加的所有权限,否则应用无法安装成功。对于开发者来说,只需要在清单文件里添加功能模块需要的权限,非常方便。对于用户来说,却是灾难性的,数据隐私完全暴露在应用面前。

    于是,Google的Android团队在6.0版本推出了运行时权限系统,部分有关用户隐私的权限被划分为危险权限。对于开发者来说,普通权限的添加与以前并无两样,但危险权限不仅需要在清单文件中配置,还需要添加Java代码弹出对话框向用户请求权限。由于系统对动态权限已封装完善,咱们只需要调用新的API向用户请求权限即可,对话框也是系统提供,无需也不能自定义UI。

    本篇文章将会先介绍动态权限相关的四个方法,然后介绍如何使用这四个方法向用户申请动态权限。弹出权限请求的对话框后,用户可以同意权限拒绝权限拒绝权限并不再提示,APP要根据自己的业务需求,去处理用户的三种界面交互。在诸多应用中,腾讯公司的“微信”是一款用户体验较好的产品。因此,本篇文章会以微信的“扫一扫”功能需要的相机权限为例,模仿其界面交互的逻辑。


二,危险权限

关于危险权限的介绍,详细见官方文档。危险权限中有10个权限组,权限组在类Manifest的内部类permission_group中定义,详情见官方文档。每个权限组中包含几个权限,权限在类Manifest的内部类permission中定义,详情见官方文档;

危险权限,如下所示:

点亮技能之Android6.0动态权限_第1张图片


三,API介绍

检查应用是否拥有某一权限permission

ContextCompat类中:
public static int checkSelfPermission(@NonNull Context context, 
@NonNull String permission)

permission:权限对应的字符串,在Manifest.permission中定义
eg: 相机权限,第二个参数则传入Manifest.permission.CAMERA

返回值:int类型,有两种情况
PackageManager.PERMISSION_GRANTED:表示应用有该权限
PackageManager.PERMISSION_DENIED: 表示应用没有该权限

-------------------------------------------------------
向用户请求权限,此时系统会弹出对话框

ActivityCompat类中:
public static void requestPermissions(final @NonNull Activity activity,
final @NonNull String[] permissions, 
final @IntRange(from = 0) int requestCode)

permissions:字符串数组,批量向用户请求权限
requestCode:标记这次权限请求,常量可自定义

-------------------------------------------------------
用户与对话框交互后,处理权限请求的结果
一般需要重写该方法

Activity类中
public void onRequestPermissionsResult(int requestCode, 
@NonNull String[] permissions, @NonNull int[] grantResults) {

requestCode: 对应requestPermissions方法中的requestCode
permissions: 对应requestPermissions方法中的permissions
grantResults:权限请求的结果

权限请求的结果有两种值:
PackageManager.PERMISSION_GRANTED:表示用户同意请求
PackageManager.PERMISSION_DENIED: 表示用户拒绝请求

--------------------------------------------------------
用户是否选择对话框中“禁止后不再询问”

ActivityCompat类中
public static boolean shouldShowRequestPermissionRationale(@NonNull Activity activity,
@NonNull String permission)

参数比较简单,不再介绍
返回值:
true:  没有勾选“禁止后不再询问”,下次请求权限,仍弹出对话框
false: 已经勾选“禁止后不再询问”,下次请求权限,不会弹出对话框

四,实践

定义一些权限,并过滤掉应用已获取的权限,代码如下

    private String[] permissions = {Manifest.permission.CAMERA,Manifest.permission.WRITE_EXTERNAL_STORAGE};

    private ArrayList needToPermissions = new ArrayList();

    private void getNotAgreePermission() {
        for (String p : permissions) {
            if (ContextCompat.checkSelfPermission(this, p) != PackageManager.PERMISSION_GRANTED) {
                //如果权限没有被授予
                needToPermissions.add(p);
            }
        }
    }

提供一个requestPermissions方法向用户发起权限请求,代码如下

    private static final int REQUEST_CODE_PERMMISSIONS = 1;
    
    private void requestPermissions() {
        //过滤掉已拥有的权限
        getNotAgreePermission();

        //如果已获得所有权限
        if (needToPermissions.size() <= 0)
            return;
        ActivityCompat.requestPermissions(
                this,
                //集合转化为数组
                needToPermissions.toArray(new String[needToPermissions.size()]),
                //int值标识这次权限请求
                REQUEST_CODE_PERMMISSIONS);
    }

此时,用户界面会弹出系统权限请求的对话框。

我们需要先在“设置-应用-微信-权限”中将微信的相机权限关闭,打开微信的扫一扫,研究对话框的交互逻辑。在微信的扫一扫中,只要用户点击“禁止”,不管是否勾选“禁止后不再询问”,都会弹出一个对话框提示用户在设置里手动开启权限。

以微信的扫一扫权限请求的逻辑为例,继续处理与用户交互的结果(实际情况以具体业务需求为准);

系统回调onRequestPermissionsResult方法,代码如下

    //处理权限请求的对话框逻辑:同意/拒绝
    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        //requestCode :请求的唯一标识
        //permissions: 请求的权限
        //grantResults:请求的结果
        
        //打印参数中的数据
        for (int i = 0; i < grantResults.length; i++) {
            Log.e("wcc", "requestCode : " + requestCode);
            Log.e("wcc", "permissions : " + permissions[i]);
            Log.e("wcc", "result : " + grantResults[i]);
        }

        //仅以申请相机权限为例
        if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
            //用户同意授权
            //do something...
            Log.e("wcc", "request success");
        } else {
            //用户不同意授权
            if (ActivityCompat.shouldShowRequestPermissionRationale(this, permissions[0])) {
                //仅仅拒绝
                //以微信的扫一扫为例:弹出对话框
                Log.e("wcc", "request failed and still remind next time");
                showDialog();
            } else {
                //不仅拒绝,还不再提醒
                //以微信的扫一扫为例:弹出对话框
                Log.e("wcc", "request failed and never remind");
                showDialog();
            }
        }
    }

    private AlertDialog dialog;

    //模仿微信交互方式,禁止后弹出对话框
    private void showDialog() {
        dialog = new AlertDialog.Builder(this)
                .setTitle("权限申请")
                .setMessage("在设置-应用-微信-权限中开启相机权限,以正常使用拍照,小视频,扫一扫等功能")
                .setCancelable(false)
                .setPositiveButton("去设置", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        Toast.makeText(getApplicationContext(), "start Settings", Toast.LENGTH_SHORT).show();
                        //startActivity ...  and enter Setting
                        finish();
                    }
                })
                .setNegativeButton("取消", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        Toast.makeText(getApplicationContext(), "cancel", Toast.LENGTH_SHORT).show();
                        finish();
                    }
                })
                .show();
    }

在Activity的onCreate方法中,调用requestPermissions方法向用户请求权限;

代码如下

public class MainActivity extends Activity {
    private TextView text;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        text = findViewById(R.id.text);
        requestPermissions();
    }

    //... code

    @Override
    protected void onDestroy() {
        if (dialog != null) {
            dialog.cancel();
        }
        super.onDestroy();
    }

}

每次onCreate方法被调用,都会尝试向用户请求权限。

在此之前,如果用户点击“禁止”按钮,并勾选了“禁止后不再询问”。那么,在调用ActivityCompat$requestPermissions向用户请求时,不会弹出对话框,且仍会回调onRequestPermissionsResult方法,grantResults参数的值是PERMISSION_DENIED,默认用户禁止获取该权限。

 

最后,本篇文章到此结束啦~

                                                                                                  O(∩_∩)O

 

 

 

 

 

 

你可能感兴趣的:(android)