概述
在安卓6.0曾经,安卓使用的权限会在装置阶段向用户展现。可是在使用使用的阶段不需求再请求任何权限。
而在6.0今后,一般股权限只需求在清单文件里注册即可,可是风险权限,则除了注册在清单里之外,还需求在使用app时动态请求。
权限分类
一般权限
在程序运行时自动获取,只需求在清单文件里声明即可。比方 internet。
风险权限
App在一些操作中需求拜访用户的隐私信息,比方图库,通讯录。此刻安卓体系就会向用户展现所需的权限。
完好的权限请求流程
图示
解释说明
-
- 判别sdk版别是否低于23,假如是,则不需求请求权限,流程结束。不然往下。
-
- 调用
checkPermission
判别 权限是否已请求成功,假如回来true,流程结束。不然往下。
- 调用
-
- 调用
requestPermission
向体系自动发送请求权限的操作。
- 调用
可是在 requestPermission
之前,有一个 shouldShowRequestPermissionRationale
的判别
关键的 shouldShowRequestPermissionRationale
- 此判别假如回来了
true
,则说明,之前app现已测验请求过权限,可是用户点击了回绝
,可是并没有选择Never ask again
(今后不再提示).
这表明,用户没有永久回绝权限,app还能再次调用 requestPermission
测验请求。
- 假如回来了
false
, 有两种状况:- app从来没有请求过此权限
- 此刻,只需求 再次调用
requestPermission
测验请求
- 此刻,只需求 再次调用
- app请求过此权限,可是被用户回绝,并且勾选了
Never ask again
(永久回绝)- 此刻,只能弹出自定义对话框,提示用户此操作有必要具备权限之后才干持续,并且在点击某个按钮之后进入到 app的权限办理页面。
- app从来没有请求过此权限
特别留意,以上回来true的状况,在某些国产手机上被屏蔽,比方华为,小米,也就是说,这些手机上动态请求权限,只有两种状况,允许
,或许永久回绝
, 不存在介于两者中间的 暂时回绝
的选项。
规范代码示范
一般,我们需求按照 activity.requestPermissions()
传入 permissions权限数组,以及 requestCode回调码,然后在Activity内进行回调处理。
可是现在有了更优雅的方式,支撑我们在 恣意代码的位置,不限定activity内,支撑fragment,service,乃至一个一般类内进行处理。
基本思想为: 开启一个通明不行见的Activity作为请求权限的载体,请求的动作,以及 请求后的回调 全部放在此Activity内。首要代码如下:
权限请求成果接口
/**
* 权限请求成果接口
*/
public interface IPermissionCallback {
/**
* 颁发权限
*/
void granted(int requestCode);
/**
* 这次回绝,可是并没有勾选"今后不再提示"
*/
void denied(int requestCode);
/**
* 勾选"今后不再提示",并且回绝
*/
void deniedForever(int requestCode);
}
权限基本功能类
public class PermissionUtil {
/**
* 判别一切权限是否都赞同了,都赞同回来true 不然回来false
*
* @param context context
* @param permissions permission list
* @return return true if all permissions granted else false
*/
public static boolean hasSelfPermissions(Context context, String... permissions) {
for (String permission : permissions) {
if (!hasSelfPermission(context, permission)) {
return false;
}
}
return true;
}
/**
* 判别单个权限是否赞同
*
* @param context context
* @param permission permission
* @return return true if permission granted
*/
private static boolean hasSelfPermission(Context context, String permission) {
return ActivityCompat.checkSelfPermission(context, permission) == PackageManager.PERMISSION_GRANTED;
}
/**
* 查看是否都赋予权限
*
* @param grantResults grantResults
* @return 一切都赞同回来true 不然回来false
*/
public static boolean verifyPermissions(int... grantResults) {
if (grantResults.length == 0) return false;
for (int result : grantResults) {
if (result != PackageManager.PERMISSION_GRANTED) {
return false;
}
}
return true;
}
/**
* 查看所给权限List是否需求给提示
*
* @param activity Activity
* @param permissions 权限list
* @return 假如某个权限需求提示则回来true
*/
public static boolean shouldShowRequestPermissionRationale(Activity activity, String... permissions) {
for (String permission : permissions) {
if (ActivityCompat.shouldShowRequestPermissionRationale(activity, permission)) {
return true;
}
}
return false;
}
}
权限请求核心类,仅有入口
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.os.Build;
import android.os.Bundle;
import android.util.Log;
import org.jetbrains.annotations.Nullable;
public class PermissionAspectActivity extends Activity {
private final static String permissionsTag = "permissions";
private final static String requestCodeTag = "requestCode";
private static IPermissionCallback mCallback;
/**
* 发动当时这个Activity
*/
public static void startActivity(Context context, String[] permissions, int requestCode, IPermissionCallback callback) {
Log.d("PermissionAspectTag", "context is : " + context.getClass().getSimpleName());
if (context == null) return;
mCallback = callback;
//发动当时这个Activity并且取消切换动画
Intent intent = new Intent(context, PermissionAspectActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);//开启新的任务栈并且铲除栈顶...为何要铲除栈顶
intent.putExtra(permissionsTag, permissions);
intent.putExtra(requestCodeTag, requestCode);
context.startActivity(intent);//利用context发动activity
if (context instanceof Activity) {//并且,假如是activity发动的,那么还要屏蔽掉activity切换动画
((Activity) context).overridePendingTransition(0, 0);
}
}
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Intent intent = getIntent();
String[] permissions = intent.getStringArrayExtra(permissionsTag);
int requestCode = intent.getIntExtra(requestCodeTag, 0);
if (PermissionUtil.hasSelfPermissions(this, permissions)) {
mCallback.granted(requestCode);
finish();
overridePendingTransition(0, 0);
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
requestPermissions(permissions, requestCode);
}
}
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
// 现在拿到了权限的请求成果,那么如何处理,我这个Activity仅仅为了请求,然后把成果告诉外界,所以成果的处理只能是外界传进来
boolean granted = PermissionUtil.verifyPermissions(grantResults);
if (granted) {//假如用户给了权限
mCallback.granted(requestCode);
} else {
if (PermissionUtil.shouldShowRequestPermissionRationale(this, permissions)) { // 判别是否还能持续请求
mCallback.denied(requestCode);
} else { // 不能再次请求,用户现已彻底回绝
mCallback.deniedForever(requestCode);
}
}
this.finish();
overridePendingTransition(0, 0);
}
}
留意,此 PermissionAspectActivity 有必要在清单文件中注册
并且它的风格是通明的:
作用如下,恣意类中都能使用权限请求: