• Android6.0-运行时权限处理


    为什么需要有运行时权限?

    大家都知道在Android6.0之前,权限在应用安装过程中只询问一次,以列表的形式展现给用户,如果点击取消(即不认可应用所申请的权限),则会取消应用的安装。而用户出于安装应用的需求,一般都会点击同意,而应用就有可能在后台进行一些非法操作。(同时,因为这个原因,应用可能会出现申请一大堆权限的情况,说不定以后有用呢,hhhhh)

    而正是认识到这个问题,在Android6.0版本以后,推出了运行时权限功能。即用户不需要在安装应用的时候一次性授权,而是可以在应用的使用过程中对某一项权限进行授权。

    当然并不是所有的权限都不需要手动动态申请,Android将权限分为了普通权限和高危权限。对于普通权限,系统会自动完成授权,我们只需要处理高危权限的授权即可。下面就是Android的危险权限表。

    注意:表格中的每一个危险权限都属于一个权限组,我们在进行运行时权限处理时使用的是权限名,但当用户一旦同意授权,那么该权限所对应的权限组的所有其他权限都会被同时授权。

    即一旦READ_CALENDAR被授权了,应用也有WRITE_CALENDAR权限了。

    2.运行时权限处理

      对于运行在API23系统的应用,如果它的targetAPI大于等于23,则需要对运行时权限进行申请,否则会出现抛出异常,导致程序crash。

      而在现有的 代码中加入运行时权限处理也很简单,只需要在需要申请危险权限的地方嵌套权限申请的代码即可,下面就是一个典型的运行时权限申请的代码。

      

    package com.pignet.runtimepermissiondemo;
    
    import android.Manifest;
    import android.content.DialogInterface;
    import android.content.Intent;
    import android.content.pm.PackageManager;
    import android.net.Uri;
    import android.support.annotation.NonNull;
    import android.support.v7.app.AlertDialog;
    import android.support.v7.app.AppCompatActivity;
    import android.os.Bundle;
    import android.view.View;
    import android.widget.Button;
    import android.widget.Toast;
    
    
    public class MainActivity extends AppCompatActivity {
        private final static String CALL_PERMISSION=Manifest.permission.CALL_PHONE;
        private final static int REQUEST_CODE_ASK_PERMISSIONS = 1;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            Button btnCall= (Button) findViewById(R.id.btn_call);
            btnCall.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                   callWrapper();
                }
            });
        }
    
        /**
         * 若没有权限,则申请,否则调用call
         */
        private void callWrapper() {
            if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
                int hasCallPhonePermission = checkSelfPermission(CALL_PERMISSION);
                //是否已经拥有指定权限
                if(hasCallPhonePermission!=PackageManager.PERMISSION_GRANTED){
    
                    /**
                     * 检查是否需要弹出请求权限的提示对话框
                     * shouldShowRequestPermissionRationale(permission)默认返回false
                     * 当用户拒绝赋予权限后,返回值为true,这里的思路就是当用户拒绝了一次权限后
                     * 需要弹出一个提示框,告诉用户这个权限的用途,以更好地申请到权限
                     */
    
                    if(shouldShowRequestPermissionRationale(CALL_PERMISSION)){
                        showMessageOKCancel("您需要允许拨打电话的权限", new DialogInterface.OnClickListener() {
                            @Override
                            public void onClick(DialogInterface dialog, int which) {
                                requestPermissions(new String[]{CALL_PERMISSION},REQUEST_CODE_ASK_PERMISSIONS);
                            }
                        });
                        return;
    
                    }
    
                    requestPermissions(new String[]{CALL_PERMISSION},REQUEST_CODE_ASK_PERMISSIONS);
                    return;
                }
                call();
            }else
                call();
    
        }
        private void showMessageOKCancel(String message, DialogInterface.OnClickListener okListener) {
            new AlertDialog.Builder(MainActivity.this)
                    .setMessage(message)
                    .setPositiveButton("OK", okListener)
                    .setNegativeButton("Cancel", null)
                    .create()
                    .show();
        }
    
        /**
         * 要完成的操作
         */
        private void call() {
            try{
                Intent intent = new Intent(Intent.ACTION_CALL);
                intent.setData(Uri.parse("tel:110"));
                startActivity(intent);
            }catch (SecurityException e){
                e.printStackTrace();
            }
        }
    
        /**
         *
         * @param requestCode 权限申请请求码 这边对应前面的1
         * @param permissions 需要申请的权限
         * @param grantResults 请求结果   -1:Denied  0:Granted
         */
        @Override
        public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    
            switch (requestCode){
                case 1:
                    if(grantResults.length>0&&grantResults[0]==PackageManager.PERMISSION_GRANTED)
                        call();
                    else
                        //当用户第一次选择拒绝授权后,再次申请权限时,这时授权对话框会多一个”不再提醒“的提示,如果选择了拒绝授权
                        //并且勾选了不再授权,那么在下次读取时就不会去申请授权,而是直接在回调中说明用户已经拒绝授权
                        //所以在这边给出提示,提示用户去“设置”里手动授权,或者可以发一个广播打开设置界面。
                        Toast.makeText(this,"您没有授予该权限,请在设置中打开授权",Toast.LENGTH_SHORT).show();
                    break;
                default:
                    super.onRequestPermissionsResult(requestCode, permissions, grantResults);
                    break;
            }
        }
    
    
    }

    注意:正如前面提到的,申请了一个权限后,会获得这个权限组中的所有权限。

    github地址:https://github.com/pignet/RuntimePermissionDemo

  • 相关阅读:
    搜索自动提示的简单模拟JQuery
    log4j+AOP 记录错误日志信息到文件中
    利用firebug 查看JS方法, JS 调试
    Blog 使用Jsoup解析出html中的img元素
    jquery操作select(取值,设置选中)
    C++解析(20):智能指针与类型转换函数
    C++解析(19):函数对象、关于赋值和string的疑问
    C++解析(18):C++标准库与字符串类
    C++解析(17):操作符重载
    C++解析(16):友元与类中的函数重载
  • 原文地址:https://www.cnblogs.com/hustzhb/p/6932242.html
Copyright © 2020-2023  润新知