Android6.0运行时权限(基于RxPermission开源库)

版权声明:本文为博主原创文章,未经博主允许不得转载。

前言

  在6.0以前的系统,都是权限一刀切的处理方式,只要用户安装,Manifest申请的权限都会被赋予,并且安装后权限也撤销不了。

  Android 6.0 采用新的权限模型,只有在需要权限的时候,才告知用户是否授权;是在runtime时候授权,而不是在原来安装的时候 ,同时默认情况下每次在运行时打开页面时候,需要先检查是否有所需要的权限申请。

  判断是否是需要运行时权限的标记就是targetSDKVersion。

  当targetSDKVersion<23的时候,仅在安装时赋予权限,使用时将不被提醒;

  当targetSDKVersion≥23的时候才会使用新的运行时权限规则。

  运行时权限未适配可能会导致应用崩溃或者在SD卡中创建目录和文件不成功。

解决方案:

一、将targetSDKVersion人为地降到小于23,这样就变成了还是默认使用权限,但是这种并不是Google所推荐使用的。

二、实现APP支持运行时权限

那么,哪些权限属于运行时权限呢?

权限的分组

Android中有很多权限,但并非所有的权限都是敏感权限,于是6.0系统就对权限进行了分类,一般为下述几类

  • 正常(Normal Protection)权限
  • 危险(Dangerous)权限
  • 特殊(Particular)权限
  • 其他权限(一般很少用到)

正常权限

正常权限具有如下的几个特点

  • 对用户隐私没有较大影响或者不会带来安全问题。
  • 安装后就赋予这些权限,不需要显示提醒用户,用户也不能取消这些权限。

上述的权限基本设计的是关于网络,蓝牙,时区,快捷方式等方面,只要在AndroidManifest.xml指定了这些权限,就会被授予,并且不能撤销。

注意:直接在AndroidManifest.xml文件中声明权限即可。

特殊权限

这里讲特殊权限提前讲一下,因为这个相对来说简单一些。

特殊权限,顾名思义,就是一些特别敏感的权限,在Android系统中,主要由两个

  • SYSTEM_ALERT_WINDOW(设置悬浮窗,进行一些黑科技)
  • WRITE_SETTINGS (修改系统设置)

关于上面两个特殊权限的授权,做法是使用startActivityForResult启动授权界面来完成。

注意:关于这两个特殊权限,一般不建议应用申请。

危险权限

危险权限实际上才是运行时权限主要处理的对象,这些权限可能引起隐私问题或者影响其他程序运行。

Android中的危险权限可以归为以下几个分组:


权限组


权限列表


android.permission-group.CALENDAR


android.permission.READ_CALENDAR

(允许程序读取用户的日程信息)


android.permission-group.CAMERA


android.permission.CAMERA

(允许访问摄像头进行拍照)


android.permission-group.CONTACTS


android.permission.READ_CONTACTS

(允许应用访问联系人通讯录信息)

android.permission.WRITE_CONTACTS

(写入联系人,但不可读取)

android.permission.GET_ACCOUNTS

(访问GMail账户列表)


android.permission-group.LOCATION


android.permission.ACCESS_COARSE_LOCATION

(通过WiFi或移动基站的方式获取用户错略的经纬度信息,定位精度大概误差在30~1500米)

android.permission.ACCESS_FINE_LOCATION

(通过GPS芯片接收卫星的定位信息,定位精度达10米以内)


android.permission-group.MICROPHONE


android.permission.RECORD_AUDIO

(录制声音通过手机或耳机的麦克)


android.permission-group.PHONE


android.permission.READ_PHONE_STATE

(访问电话状态)

android.permission.CALL_PHONE

(允许程序从非系统拨号器里输入电话号码)

android.permission.READ_CALL_LOG

(允许应用程序读取用户的通话记录)

android.permission.WRITE_CALL_LOG

(允许一个程序写入(但不读取)用户的通话记录资料)

com.android.voicemail.permission.ADD_VOICEMAIL

(允许应用程序添加语音邮件进入系统)

android.permission.USE_SIP

(允许程序使用SIP视频服务)

android.permission.PROCESS_OUTGOING_CALLS

(允许程序监视,修改或放弃播出电话)


android.permission-group.SENSORS


android.permission.BODY_SENSORS

(允许从传感器,用户使用来衡量什么是他/她的身体内发生的事情,如心脏速率访问数据的应用程序)


android.permission-group.SMS


android.permission.SEND_SMS

(发送短信)

android.permission.RECEIVE_SMS

(接收短信)

android.permission.READ_SMS

(读取短信内容)

android.permission.RECEIVE_WAP_PUSH

(接收WAP PUSH信息)

android.permission.RECEIVE_MMS

(接收彩信)

android.permission.READ_CELL_BROADCASTS

()


android.permission-group.STORAGE


android.permission.READ_EXTERNAL_STORAGE

(允许程序读取外部存储,如SD卡读文件)

android.permission.WRITE_EXTERNAL_STORAGE

(允许程序写入外部存储,如SD卡上写文件)

效果图

代码分析

  • 基于Android Studio开发环境。
  • 基于RxPermission开源库。
  • 项目的最低sdk版本号(minSdkVersion)必须>=11。
  • 分为以下四种情况分析:

    A)  只有一个运行时权限申请的情况

    B)  同时请求多个权限(合并结果)的情况

    C)  同时请求多个权限(分别获取结果)的情况

    D)  条件触发获取权限(结合RxBinding使用)的情况

使用步骤

一、检查minSdkVersion值

当前项目的app/ build.gradle文件中的minSdkVersion值必须>=11

二、添加依赖开源库

在当前项目的app/ build.gradle文件中的dependencies{}里面添加以下代码:

普通情况【这个暂时不会用】

//运行时权限
compile ‘com.tbruyelle.rxpermissions:rxpermissions:[email protected]‘

项目中使用了RxJava2的的情况【建议使用这个--不论项目中是否使用了RxJava2】

//运行时权限
compile ‘com.tbruyelle.rxpermissions2:rxpermissions:[email protected]‘
compile ‘io.reactivex.rxjava2:rxjava:2.0.2‘

如果想要实现条件触发获取权限(结合RxBinding使用)的情况,则还需要依赖RxBinding开源库

compile ‘com.jakewharton.rxbinding2:rxbinding:2.0.0‘

例如,Demo中的依赖配置如下:

三、在AndroidManifest.xml文件中声明权限列表

<!-- ======================授权获取设备ANDROID_ID========================== -->
<!-- 访问电话状态 -->
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<!-- 允许程序读取外部存储文件 -->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<!-- 允许程序写入外部存储,如SD卡上写文件 -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"></uses-permission>
<uses-permission android:name="android.permission.CAMERA" />

四、运行时权限申请代码

注意:需要import的相关类如下:

import com.jakewharton.rxbinding2.view.RxView;
import com.tbruyelle.rxpermissions2.Permission;
import com.tbruyelle.rxpermissions2.RxPermissions;
import io.reactivex.functions.Action;
import io.reactivex.functions.Consumer;

4.1 只有一个运行时权限申请的情况

/**只有一个运行时权限申请的情况*/
private void onePermission(){
    RxPermissions rxPermissions = new RxPermissions(MainActivity.this); // where this is an Activity instance
    rxPermissions.request(Manifest.permission.READ_PHONE_STATE) //权限名称,多个权限之间逗号分隔开
            .subscribe(new Consumer<Boolean>() {
                @Override
                public void accept(Boolean granted) throws Exception {
                    Log.e(TAG, "{accept}granted=" + granted);//执行顺序——1【多个权限的情况,只有所有的权限均允许的情况下granted==true】
                    if (granted) { // 在android 6.0之前会默认返回true
                        // 已经获取权限
                        Toast.makeText(MainActivity.this, "已经获取权限", Toast.LENGTH_SHORT).show();
                        String deviceId = ((TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE)).getDeviceId();//根据不同的手机设备返回IMEI,MEID或者ESN码
                        Toast.makeText(MainActivity.this, "{accept}deviceId=" + deviceId, Toast.LENGTH_SHORT).show();
                    } else {
                        // 未获取权限
                        Toast.makeText(MainActivity.this, "您没有授权该权限,请在设置中打开授权", Toast.LENGTH_SHORT).show();
                    }
                }
            }, new Consumer<Throwable>() {
                @Override
                public void accept(Throwable throwable) throws Exception {
                    Log.e(TAG,"{accept}");//可能是授权异常的情况下的处理
                }
            }, new Action() {
                @Override
                public void run() throws Exception {
                    Log.e(TAG,"{run}");//执行顺序——2
                }
            });
}

在Activity的onCreate方法中调用即可:

打印的日志如下:

4.2 同时请求多个权限(合并结果)的情况

/**同时请求多个权限(合并结果)的情况*/
    private void MultPermission(){
        RxPermissions rxPermissions = new RxPermissions(MainActivity.this); // where this is an Activity instance
        rxPermissions.request(Manifest.permission.READ_PHONE_STATE,
                Manifest.permission.READ_EXTERNAL_STORAGE)//权限名称,多个权限之间逗号分隔开
                .subscribe(new Consumer<Boolean>() {
                    @Override
                    public void accept(Boolean granted) throws Exception {
                        Log.e(TAG, "{accept}granted=" + granted);//执行顺序——1【多个权限的情况,只有所有的权限均允许的情况下granted==true】
                        if (granted) { // 在android 6.0之前会默认返回true
                            // 已经获取权限
                            Toast.makeText(MainActivity.this, "已经获取权限", Toast.LENGTH_SHORT).show();
                        } else {
                            // 未获取权限
                            Toast.makeText(MainActivity.this, "您没有授权该权限,请在设置中打开授权", Toast.LENGTH_SHORT).show();
                        }
                    }
                }, new Consumer<Throwable>() {
                    @Override
                    public void accept(Throwable throwable) throws Exception {
                        Log.e(TAG,"{accept}");//可能是授权异常的情况下的处理
                    }
                }, new Action() {
                    @Override
                    public void run() throws Exception {
                        Log.e(TAG,"{run}");//执行顺序——2
                    }
                });
    }

在Activity的onCreate方法中调用即可:

打印的日志如下:

4.3 同时请求多个权限(分别获取结果)的情况

/**同时请求多个权限(分别获取结果)的情况*/
    private void MultPermission2(){
        RxPermissions rxPermissions = new RxPermissions(MainActivity.this); // where this is an Activity instance
        rxPermissions.requestEach(Manifest.permission.READ_PHONE_STATE,
                Manifest.permission.READ_EXTERNAL_STORAGE)//权限名称,多个权限之间逗号分隔开
                .subscribe(new Consumer<Permission>(){
                    @Override
                    public void accept(Permission permission) throws Exception {
                        Log.e(TAG, "{accept}permission.name=" + permission.name);
                        Log.e(TAG, "{accept}permission.granted=" + permission.granted);
                        if(permission.name.equals(Manifest.permission.READ_PHONE_STATE) && permission.granted){
                            // 已经获取权限
                            Toast.makeText(MainActivity.this, "已经获取权限", Toast.LENGTH_SHORT).show();
                            String deviceId = ((TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE)).getDeviceId();//根据不同的手机设备返回IMEI,MEID或者ESN码
                            Toast.makeText(MainActivity.this, "{accept}deviceId=" + deviceId, Toast.LENGTH_SHORT).show();
                        }
                    }
                });
    }

在Activity的onCreate方法中调用即可:

打印的日志如下:

4.4 条件触发获取权限(结合RxBinding使用)的情况

/**条件触发获取权限(结合RxBinding使用)的情况*/
    private void clickPermission(View view){
        RxPermissions rxPermissions = new RxPermissions(MainActivity.this); // where this is an Activity instance
        RxView.clicks(view)
                .compose(rxPermissions.ensure(Manifest.permission.CAMERA))
                .subscribe(new Consumer<Boolean>() {
                    @Override
                    public void accept(Boolean granted) {
                        Log.e(TAG, "{accept}granted=" + granted);//【多个权限的情况,只有所有的权限均允许的情况下granted==true】
                        if (granted) { // 在android 6.0之前会默认返回true
                            // 已经获取权限
                            Toast.makeText(MainActivity.this, "已经获取CAMERA权限", Toast.LENGTH_SHORT).show();
                        } else {
                            // 未获取权限
                            Toast.makeText(MainActivity.this, "您没有授权该权限,请在设置中打开授权", Toast.LENGTH_SHORT).show();
                        }
                    }
                });
    }

在activity的onCreate方法中调用:

打印的日志如下:

其中,点击事件对应的控件如下:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.why.project.runtime.MainActivity">

    <Button
        android:id="@+id/btn_getpermission"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="手动获取权限"
        android:layout_centerInParent="true"/>
</RelativeLayout>

混淆配置

参考资料

聊一聊 Android 6.0 的运行时权限

https://blog.coding.net/blog/understanding-marshmallow-runtime-permission

Android权限管理之Android 6.0运行时权限及解决办法

http://www.cnblogs.com/whoislcj/p/6064710.html

Android 6.0 运行时权限处理完全解析

http://blog.csdn.net/lmj623565791/article/details/50709663

Manifest.permission

https://developer.android.google.cn/reference/android/Manifest.permission.html

android权限大全

http://www.cnblogs.com/classic/archive/2011/06/20/2085055.html

RxPermissions开源库github地址:

https://github.com/tbruyelle/RxPermissions

项目demo下载地址

链接:http://pan.baidu.com/s/1mi9et1Q 密码:qru3

时间: 2024-10-12 09:09:22

Android6.0运行时权限(基于RxPermission开源库)的相关文章

1.Android6.0运行时权限简介_2.Android6.0权限适配之WRITE_EXTERNAL_STORAGE(SD卡写入)3_.Android 6.0 运行时权限理解

Android6.0运行时权限简介:http://unclechen.github.io/2016/03/05/Android6.0%E8%BF%90%E8%A1%8C%E6%97%B6%E6%9D%83%E9%99%90%E7%AE%80%E4%BB%8B/ Android6.0权限适配之WRITE_EXTERNAL_STORAGE(SD卡写入):https://blog.csdn.net/xiechengfa/article/details/52699233 Android 6.0 运行时权

Android6.0运行时权限管理

自从Android6.0发布以来,在权限上做出了很大的变动,不再是之前的只要在manifest设置就可以任意获取权限,而是更加的注重用户的隐私和体验,不会再强迫用户因拒绝不该拥有的权限而导致的无法安装的事情,也不会再不征求用户授权的情况下,就可以任意的访问用户隐私,而且即使在授权之后也可以及时的更改权限.这就是6.0版本做出的更拥护和注重用户的一大体现. 一.认知 今天我们就来学习下Android6.0的权限管理. Android6.0系统把权限分为两个级别: 一个是Normal Permiss

Android6.0运行时权限

从 Android 6.0(API 级别 23)开始,用户在使用软件时向其授予权限,而不是在安装时授权.这个方法可以简化安装过程,用户在安装或者更新软件时不需要授予权限.它还能让用户对应用的功能进行控制.例如一个摄影应用,他使用摄像头权限是正常的,但是用户无法理解这个应用要读取联系人信息. 系统权限分为两类:正常权限跟危险权限 正常权限不会直接给用户隐私权带来风险.在AndroidManifest.xml中注册就行. 危险权限会授予应用访问用户机密数据的权限.在AndroidManifest.x

Android6.0运行时权限的处理Demo

MainActivity.java package com.loaderman.permissionsdemo; import android.Manifest; import android.content.pm.PackageManager; import android.os.Bundle; import android.support.v4.app.ActivityCompat; import android.support.v7.app.AppCompatActivity; impor

Android 6.0+ 运行时权限

1.权限被分为了普通和危险两种 2.打电话的Demo import android.Manifest; import android.app.Activity; import android.content.Intent; import android.content.pm.PackageManager; import android.net.Uri; import android.os.Bundle; import android.provider.Settings; import andro

Android 6.0 运行时权限管理最佳实践

Android 6.0 运行时权限管理最佳实践 版权声明:转载必须注明本文转自严振杰的博客: http://blog.yanzhenjie.com 这是一篇迟来的博客,Android M已经发布一年多了(6.0的变化),在Android M中权限系统被重新设计,发生了颠覆性的变化,很多人把握不好这个变化,一是对这个权限策略和套路还没有摸透,二是没有一个很好的实践来支撑,在我的技术开发群里很多人问我关于权限的问题,往往我都没有直接回答,因为这个问题不是一两句说的清楚的,这几点是今天我写这篇博客的原

Android6.0执行时权限解析,RxPermissions的使用,自己封装一套权限框架

Android6.0执行时权限解析,RxPermissions的使用.自己封装一套权限框架 在Android6.0中,新添加了一个执行时的权限,我相信非常多人都已经知道了.预计也知道怎么用了,这篇博客非常easy.就是告诉大家怎样去申请执行时权限和RxPermission这个权限框架的使用.同一时候依据现有的技术封装思想,去封装一个自己可用的权限框架,好的,我们继续往下看 一.Android M 执行时权限介绍 关于Android M的更新变化,我就不啰嗦了,有兴趣的能够看下Android M更

Android 6.0 运行时权限处理

运行时权限介绍 Android 6.0在我们原有的AndroidManifest.xml声明权限的基础上,又新增了运行时权限动态检测,以下权限都需要在运行时判断: 身体传感器 日历 摄像头 通讯录 地理位置 麦克风 电话 短信 存储空间 运行时权限处理 Android6.0系统默认为targetSdkVersion小于23的应用默认授予了所申请的所有权限,所以如果你以前的APP设置的targetSdkVersion低于23,在运行时也不会崩溃,但这也只是一个临时的救急策略,用户还是可以在设置中取

Android 6.0 运行时权限处理完全解析

一.概述 随着Android 6.0发布以及普及,我们开发者所要应对的主要就是新版本SDK带来的一些变化,首先关注的就是权限机制的变化.对于6.0的几个主要的变化,查看查看官网的这篇文章http://developer.android.com/intl/zh-cn/about/versions/marshmallow/android-6.0-changes.html,其中当然包含Runtime Permissions. ok,本篇文章目的之一就是对运行时权限处理的一个介绍,以及对目前权限相关的库