android 6.0权限demo,GitHub - alidili/PermissionDemo: Android 6.0运行时权限详解

PermissionDemo

Android 6.0运行时权限详解

1.介绍

Android 6.0之前,权限在应用安装过程中只询问一次,以列表的形式展现给用户,然而大多数用户并不会注意到这些,直接就下一步了,应用安装成功后就会被赋予清单文件中的所有权限,应用就可以在用户不知情的情况下进行非法操作(比如偷偷的上传用户数据)。

Android 6.0版本中运行时权限的出现解决了这一问题,一些高危权限会在应用的运行过程中动态申请,这样用户就可以选择是否允许,比如一个单机游戏要获取通讯录权限,那肯定要禁止了。

并不是所有的权限都需要动态申请,需要申请的权限如下表所示:

注意:同一组内的任何一个权限被授权了,其他权限也自动被授权。例如,一旦READ_CALENDAR被授权了,应用也有WRITE_CALENDAR权限了。

2.运行时权限处理

通过一个Demo来了解运行时权限的处理,先上图

第一次申请权限,拒绝后再次申请,申请成功

201ff0d391ceb245898c87d318594dab.gif

多次拒绝后,点击不再提示

6476a7b4d9422121205ebcdfcc9f20d3.gif

二话不说,上代码

package com.yang.permissiondemo;

import android.Manifest;

import android.annotation.TargetApi;

import android.content.DialogInterface;

import android.content.pm.PackageManager;

import android.graphics.Color;

import android.os.Build;

import android.os.Bundle;

import android.support.v4.app.ActivityCompat;

import android.support.v4.content.ContextCompat;

import android.support.v7.app.AlertDialog;

import android.support.v7.app.AppCompatActivity;

import android.widget.TextView;

import android.widget.Toast;

import butterknife.Bind;

import butterknife.ButterKnife;

import butterknife.OnClick;

public class RuntimePermissionsActivity extends AppCompatActivity {

@Bind(R.id.tv_permission_status)

TextView tvPermissionStatus;

private final int CAMERA_REQUEST_CODE = 1;

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_permission);

ButterKnife.bind(this);

}

@OnClick(R.id.btn_request_permission)

public void onClick() {

requestPermission();

}

@TargetApi(Build.VERSION_CODES.M)

private void requestPermission() {

if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA)

!= PackageManager.PERMISSION_GRANTED) {

// 第一次请求权限时,用户如果拒绝,下一次请求shouldShowRequestPermissionRationale()返回true

// 向用户解释为什么需要这个权限

if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.CAMERA)) {

new AlertDialog.Builder(this)

.setMessage("申请相机权限")

.setPositiveButton("确定", new DialogInterface.OnClickListener() {

@Override

public void onClick(DialogInterface dialog, int which) {

//申请相机权限

ActivityCompat.requestPermissions(RuntimePermissionsActivity.this,

new String[]{Manifest.permission.CAMERA}, CAMERA_REQUEST_CODE);

}

})

.show();

} else {

//申请相机权限

ActivityCompat.requestPermissions(this,

new String[]{Manifest.permission.CAMERA}, CAMERA_REQUEST_CODE);

}

} else {

tvPermissionStatus.setTextColor(Color.GREEN);

tvPermissionStatus.setText("相机权限已申请");

}

}

@Override

public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {

super.onRequestPermissionsResult(requestCode, permissions, grantResults);

if (requestCode == CAMERA_REQUEST_CODE) {

if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {

tvPermissionStatus.setTextColor(Color.GREEN);

tvPermissionStatus.setText("相机权限已申请");

} else {

//用户勾选了不再询问

//提示用户手动打开权限

if (!ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.CAMERA)) {

Toast.makeText(this, "相机权限已被禁止", Toast.LENGTH_SHORT).show();

}

}

}

}

}

首先来看requestPermission方法

1>首先判断当前应用有没有CAMERA权限,如果没有则进行申请。

if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA)

!= PackageManager.PERMISSION_GRANTED)

2>如果没有CAMERA权限,进行如下判断,当第一次申请权限时shouldShowRequestPermissionRationale返回false,第一次用户拒绝,再次申请的时候返回true,在此判断中提示用户为什么要申请这个权限。

if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.CAMERA))

3>如果用户点击了允许,则调用requestPermissions方法申请权限,注意里面接收的参数是一个String数组,也就是说可以同时申请多个权限,不过不建议这么做。

//申请相机权限

ActivityCompat.requestPermissions(this,

new String[]{Manifest.permission.CAMERA}, CAMERA_REQUEST_CODE);

onRequestPermissionsResult回调方法

此方法是权限申请的回调方法,在此方法中处理权限申请成功或失败后的操作。

1>因为可以同时申请多个权限,所以回调的结果是以数组方式返回的,如果用户点击允许的话,此判断为true,可以在里面处理打开摄像头的操作。

if (grantResults[0] == PackageManager.PERMISSION_GRANTED)

2>当多次(两次或两次以上)请求操作时,会有不再提示的选择框,如果用户选择了不再提示,shouldShowRequestPermissionRationale为false,在此判断中提示用户权限已被禁止,需要在应用管理中自行打开。

if (!ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.CAMERA)) {

Toast.makeText(this, "相机权限已被禁止", Toast.LENGTH_SHORT).show();

}

shouldShowRequestPermissionRationale()说明

shouldShowRequestPermissionRationale() 默认返回 false。

第一次请求权限时,如果用户拒绝了,再次请求时 shouldShowRequestPermissionRationale() 返回 true。

多次请求权限(超过一次),用户如果选择了不再提醒并拒绝,shouldShowRequestPermissionRationale() 返回 false。

设备的策略禁止当前应用获取这个权限的授权,shouldShowRequestPermissionRationale() 返回 false。

3.第三方库PermissionsDispatcher

PermissionsDispatcher通过注解的方式,动态生成类处理运行时权限。配合插件使用,可自动生成代码。

使用方法如下:

1>将下面这段代码添加到project的build.gradle文件中。

buildscript {

dependencies {

classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'

}

}

2>将下面的代码添加到app module的build.gradle文件中,${latest.version}填写最新的版本号,目前为2.1.3。

apply plugin: 'android-apt'

dependencies {

compile 'com.github.hotchemi:permissionsdispatcher:${latest.version}'

apt 'com.github.hotchemi:permissionsdispatcher-processor:${latest.version}'

}

3>在Android Studio中选择File——Setting——Plugins,搜索PermissionsDispatcher,点击install安装,如下图所示:

d3f7774c9e98a02e022bae76a23df70e.png

4>准备工作已经完成了,下面来进行代码的生成,在Android Studio中选择Code——Generate——Generate Runtime Permissions,如下图所示:

ca65097d9bf4535e83e0b80261587047.png

@NeedsPermission

当申请的权限被用户允许后,调用此方法。

@OnShowRationale

当第一次申请权限时,用户选择拒绝,再次申请时调用此方法,在此方法中提示用户为什么需要这个权限。

@OnPermissionDenied

当申请的权限被用户拒绝后,调用此方法

@OnNeverAskAgain

当用户点击不再询问后,调用此方法。

代码处理如下:

package com.yang.permissiondemo;

import android.Manifest;

import android.annotation.TargetApi;

import android.content.DialogInterface;

import android.graphics.Color;

import android.os.Build;

import android.os.Bundle;

import android.support.v7.app.AlertDialog;

import android.support.v7.app.AppCompatActivity;

import android.widget.TextView;

import android.widget.Toast;

import butterknife.Bind;

import butterknife.ButterKnife;

import butterknife.OnClick;

import permissions.dispatcher.NeedsPermission;

import permissions.dispatcher.OnNeverAskAgain;

import permissions.dispatcher.OnPermissionDenied;

import permissions.dispatcher.OnShowRationale;

import permissions.dispatcher.PermissionRequest;

import permissions.dispatcher.RuntimePermissions;

@RuntimePermissions

public class PermissionsDispatcherActivity extends AppCompatActivity {

@Bind(R.id.tv_permission_status)

TextView tvPermissionStatus;

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_permission);

ButterKnife.bind(this);

}

@OnClick(R.id.btn_request_permission)

public void onClick() {

requestPermission();

}

@TargetApi(Build.VERSION_CODES.M)

private void requestPermission() {

//申请权限

PermissionsDispatcherActivityPermissionsDispatcher.openCameraWithCheck(this);

}

@NeedsPermission(Manifest.permission.CAMERA)

void openCamera() {

tvPermissionStatus.setTextColor(Color.GREEN);

tvPermissionStatus.setText("相机权限已申请");

}

@OnShowRationale(Manifest.permission.CAMERA)

void showRationale(final PermissionRequest request) {

new AlertDialog.Builder(this)

.setMessage("申请相机权限")

.setPositiveButton("确定", new DialogInterface.OnClickListener() {

@Override

public void onClick(DialogInterface dialog, int which) {

//再次执行请求

request.proceed();

}

})

.show();

}

@OnPermissionDenied(Manifest.permission.CAMERA)

void permissionDenied() {

Toast.makeText(this, "权限被拒绝", Toast.LENGTH_SHORT).show();

}

@OnNeverAskAgain(Manifest.permission.CAMERA)

void neverAskAgain() {

Toast.makeText(this, "不再询问", Toast.LENGTH_SHORT).show();

}

@Override

public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {

super.onRequestPermissionsResult(requestCode, permissions, grantResults);

PermissionsDispatcherActivityPermissionsDispatcher.onRequestPermissionsResult(this, requestCode, grantResults);

}

}

4.兼容性

为了保持兼容性建议使用v4包的兼容方法:

ContextCompat.checkSelfPermission()

ActivityCompat.requestPermissions()

ActivityCompat.OnRequestPermissionsResultCallback

ActivityCompat.shouldShowRequestPermissionRationale()

当targetSdkVersion小于23,但是设备是6.0系统时:

设备权限模型使用老的版本

清单文件中列出的权限只会在安装时询问

用户可以在设置列表中编辑相关权限,这对应用能否正常运行有很大影响

当targetSdkVersion大于等于23,但是设备系统小于6.0时:

设备权限模型使用老的版本

清单文件中列出的权限只会在安装时询问

我把使用运行时权限遇到的一些问题汇总到了一篇博客中,欢迎点击查看《Android 6.0运行时权限问题汇总》。

License

Copyright (C) 2017 YangLe

Licensed under the Apache License, Version 2.0 (the "License");

you may not use this file except in compliance with the License.

You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software

distributed under the License is distributed on an "AS IS" BASIS,

WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

See the License for the specific language governing permissions and

limitations under the License.

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值