Android6.0 权限问题 详解

来源:互联网 发布:js判断 写法 编辑:程序博客网 时间:2024/06/05 19:50
今天看了一天郭神 的直播,边看边敲,最后总结了下知识点。算是比较详细
郭神直播地址——
http://edu.csdn.net/course/detail/3539
项目已经上传到Github了,方便大家观看视频,地址——
https://github.com/Foolwithgenius/PermissionDemo

API 23 之前都可以
     从android 1.0开始 至 android 5.1 关于android 权限机制 没有更改过。
     我们开发者只需要在AndroidManifest 中声明权限,就可以

 从 API 23 开始,android 权限分为运行时权限(危险权限),和 非运行时权限(安全权限),
非运行时权限,只需按照之前一样生命权限即可
运行时权限,必须在AndroidManifest声明一下,然后在代码中去申请下。才能正常运行功能。

知识点 1:
          运行时权限,在6.0手机中不去申请,并不一定会崩溃。 原因:如果在 gradle中 选定 TargetSDKversion 低于23 一下。
     就可以运行。

知识点 2:
          如果程序没有卸载,你更改了gradle中 TargetSDKversion 的指定23 或者高于23 版本,这时候运行时权限仍然不去申请,程序仍然不会崩溃,
     因为,程序向上兼容,程序从23版本之下,更改版本23 或者之上,android默认通过你所申请的权限  。

课外: 访问SD 卡的权限被列入 危险权限。 有一种方法可以不去申请 也可以写入一些文件,
Android- cache  文件放在这个目录下,你是不用去申请写入权限,也可以写入, 但是有一个缺点就是手机有一些清理文件可以被清理掉。

File file = getExternalCacheDir();
file.getPath();//可以拿到 目录文件

如果不想被清理掉的话,可以写入同目录下的files文件下,这个地方的文件被认为是重要文件,一般不会清理这个文件夹内的文件

File file = getExternalFilesDir("aaa");
//如果写入空字符的话,被写入文件会在fils根目录下
//向我这样写入  aaa  是在files 文件中新建一个文件夹
file.getPath();//可以拿到 目录文件


申请一个权限的时候的写法:

//这里是申请单个权限。
//检测应用 每个权限是否 已经开通。如果不开通之后 所做的判断
if (ContextCompat.checkSelfPermission(this, Manifest.permission.CALL_PHONE) != PackageManager.PERMISSION_GRANTED) {
    // 就是没有开通状态,需要去申请权限
    ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CALL_PHONE}, 1);
} else {
    makecall();
}



这里需要重写下OnRequestPermissionsResult 方法 (用户选择之后回调)
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    // requestCode 申请权限所传递状态吗
    // permissions 我认为 是所申请的权限
    // grantResults 所申请权限认证状态 是一个数组
    switch (requestCode) {
        case 1:
            // 首先判断返回状态数组长度是否为0, 如果不为0 ,在判断状态是否同意了
            if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                //同意权限
    makecall();
            } else {
                //不同意权限
            }
            break;
        default:
            break;
    }



同时申请多个权限时候,比较好的写法
//申请多个权限的写法
ArrayList<String> permission = new ArrayList<>();// 创建一个集合
//判断 某个权限是否开通, 如果没有开通 就把这个权限添加进入集合
if (ContextCompat.checkSelfPermission(this, Manifest.permission.CALL_PHONE) != PackageManager.PERMISSION_GRANTED) {
    permission.add(Manifest.permission.CALL_PHONE);
}
if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
    permission.add(Manifest.permission.WRITE_EXTERNAL_STORAGE);
}
if (!permission.isEmpty()) {
    //申请开通权限
    ActivityCompat.requestPermissions(this, permission.toArray(new String[permission.size()]), 1);
} else {
    //你所申请的权限都已经开启,可以运行你想要的操作了。
    makecall();
}

当然回调也需要更改下:

switch (requestCode) {
    case 1:
        if (grantResults.length > 0) {
            for (int grantResult : grantResults) {
                if (grantResult != PackageManager.PERMISSION_GRANTED) {
                    //  如果进来了,就说明 某个权限被关闭了。
                    return;
                }
            }
            //如果没有被return,说明你所申请的权限都已经被同意,可以去做想做的事情
            makecall();
        }
        break;
    default:
        break;
}



以上就是 申请 Android6.0权限  的时候的一般写法。但是有的时候,一个app需要在好多地方做一些写入的操作,不可能每次都要写这么多代码。
所以就要对这个工作做一些封装了、

权限对Activity的 耦合性是比较高的,因为每一个权限弹出是需要传入 Activity.this  并且重写的onRequestPermissionsResult.

 讨论的三种封装 
 
1、 因为申请权限 对 Activity的依赖比较高,那就开启一个透明的 Activity,这个activity不做其他操作,只是弹出 申请权限的弹框。
而这个activity 对用用户来说是完全不可见的。 对于我们开发者来说就开启一个activity 调用申请权限的方法。
缺点: 我就不能使用, 因为项目中访问网络的方法 我放在了 onRsume 中所以。。。。

2、RxPermissions 的写法。刚开的RxPermissions 的写法类似于第一种,但是之后更改过, 是把 申请权限,和 回调 监听放在 Fragment中,
然后把这个fragment 放在了你所传入的activity中,其实fragment中也提供了 申请权限的API。  (郭神 说这种写法很牛逼。我不是太懂)
一会亲自看下RxPermissions 的源码。

3、封装在BaseActivity

public class BaseActivity extends AppCompatActivity {
    private static PermissionListener mListtener;

    public static void requestRuntimePermissions(String[] permissions, PermissionListener listener) {
        mListtener = listener;
        Activity topActivity = ActivityCollector.getTopActivity();
        if (topActivity == null) {
            return;
        } else {
            ArrayList<String> permissionsList = new ArrayList<>();// 创建一个集合
            for (String permission : permissions) {
                if (ContextCompat.checkSelfPermission(topActivity, permission) != PackageManager.PERMISSION_GRANTED) {
                    permissionsList.add(permission);
                }
            }
            if (!permissionsList.isEmpty()) {
                //申请开通权限
                ActivityCompat.requestPermissions(topActivity, permissionsList.toArray(new String[permissionsList.size()]), 1);
            } else {
                //你所申请的权限都已经开启,可以运行你想要的操作了。
                mListtener.onGrande();
            }
        }
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);

        switch (requestCode) {
            case 1:
                if (grantResults.length > 0) {
                    List<String> deniedPermissions = new ArrayList<>();
                    for (int i = 0; i < grantResults.length; i++) {
                        int grantResult = grantResults[i];
                        String permission = permissions[i];
                        if (grantResult != PackageManager.PERMISSION_GRANTED) {
                            deniedPermissions.add(permission);
                        }
                    }
                    if (!deniedPermissions.isEmpty()) {
                        mListtener.onGrande();
                    } else {
                        mListtener.onDenied(deniedPermissions);
                    }
                    //如果没有被return,说明你所申请的权限都已经被同意,可以去做想做的事情
                }
                break;
            default:
                break;
        }

    }
}

可以任何类中使用

public class SendActivity extends BaseActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }

    public void ButtonClick(View view) {
        requestRuntimePermissions(new String[]{Manifest.permission.CALL_PHONE, Manifest.permission.WRITE_EXTERNAL_STORAGE}, new PermissionListener() {
            @Override
            public void onGrande() {
                //权限申请通过
            }

            @Override
            public void onDenied(List<String> deniedPermissions) {
                for (String deniedPermission :
                        deniedPermissions
                        ) {
                    //                  deniedPermission  权限没有申请通过
                }
            }
        });
    }
}

ActivityCollector这是一个activity管理类。郭神的第一行代码第二章

public class ActivityCollector {
    public static ArrayList<Activity> activitys = new ArrayList<>();

    public static void addActivity(Activity activity) {
        activitys.add(activity);
    }

    ;

    public static void removeActivity(Activity activity) {
        activitys.remove(activity);
    }

    public static Activity getTopActivity() {
        if (activitys.isEmpty()) {
            return null;
        } else {
            return activitys.get(activitys.size() - 1);
        }
    }

}











1 0
原创粉丝点击