安卓动态获取权限看这一篇就够了(想看具体流程的进)
为大家带来一篇安卓6.0动态获取权限的内容。看完后,你就能够掌握安卓动态获取权限的相关知识。而不是在面试官面前说我会用 RxPermission 等一些类库实现。为什么这样说,因为在之前我也是网上找找类库用用就行了。而如今工作中碰到发现还是需要自己去原生层处理。
为何需要主动获取权限
Google在 Android 6.0 开始将所有权限分成了正常权限和危险权限。所以如果应用的 targetSdkVersion >= 23 并且 申请了危险权限 但是仅仅在AndroidManifest 注册是不够的,相关运行时会出错,会提示没有相应的权限。如果不想申请,设置targetSdkVersion = 22或者更低,然后 return;
哪些是危险权限
危险权限有哪些,涉及到用户一些隐私的大体都属于。具体有以下
- 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
申请权限的几个步骤
- AndroidManifest.xml 中声明需要的权限
- 判断权限状态
- 判断用户是否上一次拒绝了权限并且勾选了 不再提示
- 申请权限 (用户运行 继续操作,用户拒绝 根据个人情景对应操作)
AndroidManifest.xml 中声明需要的权限
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
判断权限状态
/**
* 判断是否有权限
*
* @param permission
* @return
*/
protected boolean isHasPermission(String permission) {
return ContextCompat.checkSelfPermission(this, permission) != PackageManager.PERMISSION_GRANTED;
}
判断用户是否上一次拒绝了权限并且勾选了 不再提示
用户拒绝的时候,本地记录下,以方便下一次申请,判断上一次用户是否选择了不再提示。
requestRunTimePermission(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, new SimplePermissionListener() {
@Override
public void onGranted() {
Log.i(TAG, "存储权限 已经授权");
}
@Override
public void onDenied() {
super.onDenied();Log.i(TAG, "用户拒绝授予 存储 权限");
HelperUtils.setValues(MainActivity.this, SharePerfenceUtils.KEY_STORAGE_NOTIP);
}
});
shouldShowRequestPermissionRationale 返回false,并且上一次是拒绝了权限,所以给出提示,或者弹出对话框(用户自定义)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (shouldShowRequestPermissionRationale(Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
SharePerfenceUtils.clear(this, SharePerfenceUtils.KEY_STORAGE_NOTIP);
} else if (!shouldShowRequestPermissionRationale(Manifest.permission.WRITE_EXTERNAL_STORAGE) && HelperUtils.getValues(MainActivity.this, SharePerfenceUtils.KEY_STORAGE_NOTIP).equals("1")) {
//用户拒绝权限 并勾选了 不再提示 (这里 可以自定义 Dialog 让用户跳转 系统设置 去选择权限 跳转的方法在 HelperUtils 类中)
if(HelperUtils.getValues(MainActivity.this, SharePerfenceUtils.KEY_STORAGE_NOTIP_SHOWED).equals("1")){
// 用户拒绝权限 并勾选了 不再提示 后 已经提示过一次
return;
}
// 用户拒绝权限 并勾选了 不再提示 下一次获取权限 弹土司提示
Toast.makeText(this, "未取得存储权限,请在应用设置中打开权限", Toast.LENGTH_SHORT).show();
HelperUtils.setValues(MainActivity.this, SharePerfenceUtils.KEY_STORAGE_NOTIP_SHOWED);
return;
} else {
}
}
申请权限(这是我写在BaseActivity里的,接口回调方式回传,看不明白的,文章结束处可以去github上看)
/**
* 权限申请
*
* @param permissions 待申请的权限集合
* @param listener 申请结果监听事件
*/
protected void requestRunTimePermission(String[] permissions, PermissionListener listener) {
this.mlistener = listener;
// 用于存放未授权的权限
List<String> permissionList = new ArrayList<>();
// 遍历传递过来的权限集合
for (String permission : permissions) {
// 判断是否已经授权
if (isHasPermission(permission)) {
// 未授权,则加入待授权的权限集合中
permissionList.add(permission);
}
}
// 判断集合
if (!permissionList.isEmpty()) {
// 如果集合不为空,则需要去授权
ActivityCompat.requestPermissions(this, permissionList.toArray(new String[permissionList.size()]), 1);
} else {
// 为空,则已经全部授权
if (listener != null) {
listener.onGranted();
}
}
}
/**
* 权限申请结果
*
* @param requestCode 请求码
* @param permissions 所有的权限集合
* @param grantResults 授权结果集合
*/
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
switch (requestCode) {
case 1:
if (grantResults.length > 0) {
// 被用户拒绝的权限集合
List<String> deniedPermissions = new ArrayList<>();
// 用户通过的权限集合
List<String> grantedPermissions = new ArrayList<>();
for (int i = 0; i < grantResults.length; i++) {
// 获取授权结果,这是一个int类型的值
int grantResult = grantResults[i];
if (grantResult != PackageManager.PERMISSION_GRANTED) {
// 用户拒绝授权的权限
String permission = permissions[i];
deniedPermissions.add(permission);
} else {
// 用户同意的权限
String permission = permissions[i];
grantedPermissions.add(permission);
}
}
if (deniedPermissions.isEmpty()) {
// 用户拒绝权限为空
if (mlistener != null) {
mlistener.onGranted();
}
} else {
// 不为空
if (mlistener != null) {
// 回调授权成功的接口
mlistener.onGranted(grantedPermissions);
// 回调授权失败的接口
mlistener.onDenied(deniedPermissions);
mlistener.onDenied();
}
}
}
break;
default:
break;
}
}
public interface PermissionListener {
// 授权成功
void onGranted();
// 授权部分
void onGranted(List<String> grantedPermission);
// 拒绝授权
void onDenied(List<String> deniedPermission);
// 授权失败
void onDenied();
}
下面说两种特殊情况
- 危险权限 调用权限方法没反应 没系统弹窗
- 危险权限 安装时就已经赋予了权限,但是 是 空白通行证
没系统弹窗
在申请权限之前,先调下对应需要权限的方法并且 try catch。
try{
TelephonyManager TelephonyMgr = (TelephonyManager)this.getSystemService(this.TELEPHONY_SERVICE);
String ime = TelephonyMgr.getDeviceId();
}catch (SecurityException e){
e.printStackTrace();
}finally {
if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.M){
if(isHasPermission(Manifest.permission.READ_PHONE_STATE)){
requestRunTimePermission(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, new SimplePermissionListener() {
@Override
public void onGranted() {
}
@Override
public void onDenied() {
HelperUtils.setValues(MainActivity.this, SharePerfenceUtils.KEY_STORAGE_NOTIP);
}
});
}
}
}
空白通行证
开发中遇到,红米10 机型,安卓10 系统,获取 Phone_State 权限时。得到已经获取了权限,但是并没有拿到对应的内容。暂时没解决
最后附上github地址,欢迎一起学习(因为回调经常写了,所以看不惯的大佬们还请担待 安卓6.0动态获取权限)