Android6.0中对权限的处理

Android6.0中对权限的处理

Android6.0带来了新的权限管理方式,对于开发者来说,兼容android6.0是必须要做的事情了。本文的主要目的是展示一下Android的系统应用中对权限是怎么处理的。

一.Using Permission(使用权限)

一个新建的Android应用默认是没有权限的,这意味着它不能执行任何可能对用户体验有不利影响的操作或者访问设备数据。为了使用受保护的功能,你必须包含一个或者多个标签在你的app manifest中。

Android 6.0中权限分为两种,普通权限和危险权限(即运行时权限,下面统称运行时权限)。

1.1普通权限

如果你的应用manifest中只申明了普通权限(也就是说,这些权限对于用户隐私和设备操作不会造成太多危险),系统会自动授予这些权限。

1.2运行时权限

如果你的应用manifest中声明了运行时权限(也就是说,这些权限可能会影响用户隐私和设备的普通操作),系统会明确的让用户决定是否授予这些权限。系统请求用户授予这些权限的方式是由当前应用运行的系统版本来决定的。

1.2.1 Android6.0及以上的系统

如果你的设备运行的是Android6.0(API level 23)及以上的系统,并且你的应用的targetSdkVersion也是23或者更高,那么应用向用户请求这些权限是实时的。这意味着用户可以随时取消这些运行时权限的授权。所以应用在每次需要用到这些运行时权限的时候都需要去检查是否还有这些权限的授权。

1.2.2 Android 5.1及以下的系统

如果你的设备运行在Android5.1(API level 22)及以下的系统中,或者你的app的targetSdkVersion是22或者更低。系统会请求用户在apk安装的时候授予这些权限。

如果你的应用更新的时候添加了一个权限,系统会在用户更新应用的时候请求用户授予这个权限,一旦用户安装了这个应用,唯一可以取消授权的方式就是卸载掉这个应用。

如果app的targetSdkVersion是22或者以下,但是运行在android 6.0或以上版本的手机中,会发生什么?

安装过程中,会一起请求用户授予所有权限,如果用户拒绝,將不能安装这个app,只有用户全部同意这些授权,才能安装这个应用,但是问题来了,安装好了这个应用之后,android6.0以上的系统中,用户是可以去设置中取消授权的,而且是随时都可以取消,所以很多运行时权限可能也得不到,目前官方的做法是,如果用户取消该项授权,那么依赖该项授权的方法的返回值为null,所以你的app可能会报空指针异常。以后是否会针对22以下的app做改变还不得而知,毕竟crash是很难让人接受的,但是crash是由用户造成的,用户应该也可以理解。

二.Dangerous Permissions:

group:android.permission-group.CONTACTS
  permission:android.permission.WRITE_CONTACTS
  permission:android.permission.GET_ACCOUNTS
  permission:android.permission.READ_CONTACTS

group:android.permission-group.PHONE
  permission:android.permission.READ_CALL_LOG
  permission:android.permission.READ_PHONE_STATE
  permission:android.permission.CALL_PHONE
  permission:android.permission.WRITE_CALL_LOG
  permission:android.permission.USE_SIP
  permission:android.permission.PROCESS_OUTGOING_CALLS
  permission:com.android.voicemail.permission.ADD_VOICEMAIL

group:android.permission-group.CALENDAR
  permission:android.permission.READ_CALENDAR
  permission:android.permission.WRITE_CALENDAR

group:android.permission-group.CAMERA
  permission:android.permission.CAMERA

group:android.permission-group.SENSORS
  permission:android.permission.BODY_SENSORS

group:android.permission-group.LOCATION
  permission:android.permission.ACCESS_FINE_LOCATION
  permission:android.permission.ACCESS_COARSE_LOCATION

group:android.permission-group.STORAGE
  permission:android.permission.READ_EXTERNAL_STORAGE
  permission:android.permission.WRITE_EXTERNAL_STORAGE
  group:android.permission-group.MICROPHONE
  permission:android.permission.RECORD_AUDIO

group:android.permission-group.SMS
  permission:android.permission.READ_SMS
  permission:android.permission.RECEIVE_WAP_PUSH
  permission:android.permission.RECEIVE_MMS
  permission:android.permission.RECEIVE_SMS
  permission:android.permission.SEND_SMS
  permission:android.permission.READ_CELL_BROADCASTS

RECEIVE_SMS

READ_SMS

RECEIVE_WAP_PUSH

RECEIVE_MMS

STORAGE     
READ_EXTERNAL_STORAGE

WRITE_EXTERNAL_STORAGE
可以通过adb shell pm list permissions -d -g进行查看。

下面直接贴出源码中一段封装权限申请的代码:

public class RequestPermissionsActivity extends Activity {

    private static final String TAG = "RequestPermissionsActivity";
    private static final String PREVIOUS_INTENT = "previous_intent";
    private static final int REQUEST_ALL_PERMISSIONS = 1;
    private Intent mPreviousIntent;

    private static final String[] REQUIRED_PERMISSIONS = new String[] {
            permission.READ_EXTERNAL_STORAGE,
            permission.WRITE_EXTERNAL_STORAGE };

    public static boolean startPermissionActivity(Activity activity) {
        return startRequestPermissionActivity(activity,REQUIRED_PERMISSIONS,
                RequestPermissionsActivity.class);
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mPreviousIntent = (Intent) getIntent().getExtras().get(
                PREVIOUS_INTENT);

        if (savedInstanceState == null) {
            requestPermissions();
        }
    }

    @Override
    public void onRequestPermissionsResult(int requestCode,
            String permissions[], int[] grantedResults) {
        if (permissions != null && permissions.length > 0
                && arePermissionsGranted(permissions, grantedResults)) {
            mPreviousIntent.setFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
            startActivity(mPreviousIntent);
            finish();
        } else {
            Toast.makeText(this, "You have disabled a required permission",Toast.LENGTH_SHORT).show();
            finish();
        }
    }

    protected static boolean startRequestPermissionActivity(Activity activity,
            String[] requiredPermissions, Class<?> newActivityClass) {
        if (!RequestPermissionsActivity.checkPermissions(activity,
                requiredPermissions)) {
            final Intent intent = new Intent(activity, newActivityClass);
            intent.putExtra(PREVIOUS_INTENT, activity.getIntent());
            activity.startActivity(intent);
            activity.finish();
            return true;
        }
        return false;
    }
    private static boolean checkPermissions(Context context, String[] permissions) {
        for (String permission : permissions) {
            if (context.checkSelfPermission(permission) != PackageManager.PERMISSION_GRANTED) {
                return false;
            }
        }
        return true;
    }

    private boolean arePermissionsGranted(String permissions[], int[] grantResult) {
        for (int i = 0; i < permissions.length; i++) {
            if (grantResult[i] != PackageManager.PERMISSION_GRANTED
                    && Arrays.asList(REQUIRED_PERMISSIONS).contains(permissions[i])) {
                return false;
            }
        }
        return true;
    }

    private void requestPermissions() {
        final ArrayList<String> noGrantedPermissions = new ArrayList<>();
        for (String permission : REQUIRED_PERMISSIONS) {
            if (checkSelfPermission(permission)
                    != PackageManager.PERMISSION_GRANTED) {
                noGrantedPermissions.add(permission);
            }
        }
        if (noGrantedPermissions.size() == 0) {
            Log.e(TAG, "Request permission activity was called even"
                    + " though all permissions are satisfied.");
        }
        requestPermissions(noGrantedPermissions.toArray(new String[noGrantedPermissions.size()]),
                REQUEST_ALL_PERMISSIONS);
    }
}

调用方式非常简单,在你的MainActivity的Oncreate()中加上如下代码:

protected void onCreate(Bundle state) {
        super.onCreate(state);
        if (RequestPermissionsActivity.startPermissionActivity(this)) {
            finish();//这里可以换成你自己的逻辑,如果你的App不是必须要这些权限的话
            return;
        }
 }

if里面应该还加上Build.VERSION.SDK_INT>= Build.VERSION_CODES.M判断。解释一下,这里为什么有个return。这里的return不是多余的,因为执行finish( )是一个异步过程,你的Oncreate方法并不会立马终止,试着打下log就会发现你的Oncreate方法中接下来的代码会继续执行,所以如果你下面的代码中有显示Dialog这样的操作时,你的程序就会抛异常了,这时return就能起到一个很好的作用。

相关API的使用就不一一述说了,看一下方法名就知道这个方法是干什么用的了,这里主要是体现如何快速的去使用RequestPermissionsActivity 这个类去兼容6.0,只要把RequestPermissionsActivity的REQUIRED_PERMISSIONS数组 里面的权限换成你自己需要申请的权限,就可以在第一次启动的时候一次性去向用户申请你所有需要用到的危险权限。

当然,如果你需要申请的危险权限很多,并且不是全部都必要的话,也可以把这个RequestPermissionsActivity设为抽象类,在需要调用的地方去实现。

在Android6.0源码中的拨号和联系人模块里面就是这样做的,将RequestPermissionsActivity设为一个抽象类,然后在几个需要申请权限的地方去分别申请权限。

第一次写博客呀,欢迎大家指出错误,谢谢!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值