权限申请结果只能在活动(指activity/fragment)里面获取,在非活动里面是获取不到的,所以需要一个透明的activity进行requestPermissions申请权限、onRequestPermissionsResult请求权限结果并回调回去。
一开始尝试封装在非活动类里面获取申请结果,查找资料后有人说只要用如下方法:
注:此方法是行不通的,走不到onRequestPermissionsResult里面
public class PermissionTestUtils implements ActivityCompat.OnRequestPermissionsResultCallback {
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
if (requestCode == 申请权限的requestCode) {
//处理判断权限是否授权的逻辑
}
}
}
思路:上层申请权限(带结果回调授权成功、拒绝、拒绝且不再询问,具体要什么回调按需求来)——》校验权限是否都存在——》不存在则弹出提示用户需要申请什么权限,为什么要申请。用户同意后——》申请权限,把申请结果回调回去,若是用户选择了拒绝且不再询问则引导用户去设置页开启什么权限。
在开始前,需要了解到几个重要方法:
1.ContextCompat.checkSelfPermission(context, permission)校验权限是否已授权 2.ActivityCompat.requestPermissions(this, permissions, request_permissions_code申请权限 3.ActivityCompat.shouldShowRequestPermissionRationale(activity, permission)是否勾选不再询问,在onRequestPermissionsResult中用
/**
* onDenied、onAskAgain某些情况会回都回调,申请多个权限ABCD,第一次我拒绝且不再询问权限A,后面拒绝BCD任何一个,
* 所以上层一般不处理拒绝的回调,统一处理“拒绝且不再询问”后去引导用户设置
*/
public interface PermissionTestListener {
void onGranted(String[] grPermission);//授权(全部权限都授权时才回调)
void onDenied(List dePermissions);//拒绝
void onAskAgain(List asPermissions);//拒绝且不再询问
}
public class PermissionTestUtils {
private static String TAG = PermissionTestUtils.class.getSimpleName();
/**
* 校验权限是否都授权(只要有一个没有授权就是false)
*
* @param context
* @param permissions
* @return
*/
public static boolean checkSelPermission(Context context, String... permissions) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) { // 判断sdk版本
return true;
}
for (String permission : permissions) {
//没有授权:PackageManager.PERMISSION_DENIED;已授权:PackageManager.PERMISSION_GRANTED;用PERMISSION_GRANTED来判断
if (ContextCompat.checkSelfPermission(context, permission) != PackageManager.PERMISSION_GRANTED) {
return false;
}
}
return true;
}
/**
* 校验权限是否都授权
*
* @param context
* @param permissions
* @return 返回没有授权的string[]
*/
public static String[] checkSelPermissionStr(Context context, String... permissions) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) { // 判断sdk版本
return null;
}
List stringList = new ArrayList<>();
//循环遍历所申请的所有权限,看看是否都申请到了;但凡有一个没有申请,那就立即去申请
for (String permission : permissions) {
//没有授权:PackageManager.PERMISSION_DENIED;已授权:PackageManager.PERMISSION_GRANTED
if (ContextCompat.checkSelfPermission(context, permission) != PackageManager.PERMISSION_GRANTED) {//这个权限没有申请到
stringList.add(permission);
}
}
if (stringList != null || stringList.size() > 0) {
String[] permissionDenied = new String[stringList.size()];//没有权限的数组
for (int i = 0; i < stringList.size(); i++) {
permissionDenied[i] = stringList.get(i);
}
return permissionDenied;
} else {
return null;
}
}
/**
* 检验权限结果是否都授权(onRequestPermissionsResult()里面调用)
*
* @param grantResults
* @return 有一个没有授权成功就返回false
*/
public static boolean checkGrantResults(int[] grantResults) {
boolean grant = true;
if (grantResults != null && grantResults.length > 0) {
for (int grantResult : grantResults) {
//没有授权:PackageManager.PERMISSION_DENIED;已授权:PackageManager.PERMISSION_GRANTED
if (grantResult != PackageManager.PERMISSION_GRANTED) {
grant = false;
break;
}
}
}
return grant;
}
/**
* 判断用户是否勾选不再提示 返回false
* true:之前请求过此权限但拒绝了,但是没有勾选不再提示;
* false:1.之前请求拒绝了且勾选不再提示(那就不能再提示了);2.之前没有拒绝过即第一次申请(两种情况都返回false)
* 所以在onRequestPermissionsResult()方法里面用,不在requestPermissions()申请权限前用,因无法判断false具体是哪个
*/
public static boolean checkShouldShowRequestPermissionRationale(Activity activity, @NonNull String permission) {
return ActivityCompat.shouldShowRequestPermissionRationale(activity, permission);
}
/**
* 权限申请统一入口
* @param context
* @param listener
* @param permissions
*/
public static void requestPermissions(Context context, PermissionTestListener listener, String... permissions) {
String[] deniedPermission = checkSelPermissionStr(context, permissions);
if (deniedPermission != null && deniedPermission.length > 0) {
//优化:写个弹窗,告诉用户申请这些权限是用来做什么的(只提示没有授权的),当用户点击确定后再requestPermissionsStart,点击取消后可回调拒绝或不处理
requestPermissionsStart(context, listener, deniedPermission);//送没有授权的权限
} else {
listener.onGranted(permissions);
}
}
/**
* 权限申请
* @param context
* @param listener
* @param permissions
*/
public static void requestPermissionsStart(Context context, final PermissionTestListener listener, final String... permissions) {
//授权成功,拒绝,拒绝且不再询问的逻辑处理都由上层处理,则使用这个
// PermissionTestHelp.getInstance().requestPermissionsStart(context,listener,permissions);
/**
*统一处理:拒绝且不再询问,弹窗引导用户去设置,用这个(推荐)
* 那么修改传进来的Listener就不要用PermissionTestListener,换个**Listener
* 上层只处理授权成功的业务那**Listener里面只实现onGranted方法
* 处理授权成功和拒绝的业务**Listener里面实现onGranted、onDenied两个方法
* 注:onDenied、onAskAgain某些情况会回都回调,申请多个权限ABCD,第一次我拒绝且不再询问权限A,后面拒绝BCD任何一个,
* 所以上层一般不处理拒绝的回调,统一处理“拒绝且不再询问”后去引导用户设置
*/
PermissionTestHelp.getInstance().requestPermissionsStart(context, new PermissionTestListener() {
@Override
public void onGranted(String[] grPermission) {
LogUtil.i(TAG, "授权成功" + grPermission.length);
listener.onGranted(grPermission);
}
@Override
public void onDenied(List dePermissions) {
LogUtil.i(TAG, "拒绝:" + dePermissions.size());
listener.onDenied(dePermissions);
}
@Override
public void onAskAgain(List asPermissions) {
LogUtil.i(TAG, "拒绝且不再询问:" + asPermissions.size());
//优化:弹窗提示用户需要什么权限(必须要开启,否者影响使用的这种权限),引导用户去设置开启
listener.onAskAgain(asPermissions);
}
}, permissions);
}
}
public class PermissionTestHelp {
private static PermissionTestHelp permissionTestHelp = null;
private PermissionTestListener listener;
public synchronized static PermissionTestHelp getInstance() {
if (permissionTestHelp == null) {
permissionTestHelp = new PermissionTestHelp();
}
return permissionTestHelp;
}
//重点,后面透明activity就是通过这个方法得到listener进行回调
public PermissionTestListener getListener() {
return listener;
}
public void requestPermissionsStart(Context context, PermissionTestListener listener, String... permissions) {
this.listener = listener;
Intent intent = new Intent(context, PermissionTransparentActivity.class);
intent.putExtra("permissions", permissions);
context.startActivity(intent);
}
}
/**
* 透明的activity,用于发起权限申请,获得权限申请结果并回调到上层(因以下原因,所以才有这个activity)
*
* 权限申请结果必须在活动(activity/fragment)里面的获取的
* 非活动类implements ActivityCompat.OnRequestPermissionsResultCallback
* 也不能在onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults)里面获取权限申请的结果
*/
public class PermissionTransparentActivity extends Activity {
private int request_permissions_code = 1111;
private String[] permissions;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
View view = new View(this);
view.setBackgroundResource(R.color.tm);//透明背景
setContentView(view);
Intent intent = getIntent();
if (intent != null) {
permissions = intent.getStringArrayExtra("permissions");
if (null == permissions || 0 == permissions.length) {
finish();
}
} else {
finish();
}
if (!PermissionTestUtils.checkSelPermission(this, permissions)) {//没有获取到权限
ActivityCompat.requestPermissions(this, permissions, request_permissions_code);
} else {//获取到权限了,那么直接关闭,若是不关闭就什么都点不了(尽量在上层获取到权限了都不用进来)
finish();
}
}
/**
* 请求权限结果
*
* @param requestCode 请求的编码
* @param permissions 请求的权限String[]
* @param grantResults 请求权限String[]一一对应的结果int[](0代表授权成功,-1代表授权失败)
*/
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
if (requestCode == request_permissions_code) {//跟ActivityCompat.requestPermissions请求的requestCode要一致
PermissionTestListener listener = PermissionTestHelp.getInstance().getListener();//这样子获得回调
if (PermissionTestUtils.checkGrantResults(grantResults)) {//全部授权了
listener.onGranted(permissions);//回调回去
} else {//申请的权限没有全部被授权
// List grantedList = new ArrayList<>();//同意
List deniedList = new ArrayList<>();//拒绝
List askAgainList = new ArrayList<>();//拒绝且不再询问
for (String permission : permissions) {
if (!PermissionTestUtils.checkSelPermission(this, permission)) {//没有授权
if (PermissionTestUtils.checkShouldShowRequestPermissionRationale(this, permission)) {//拒绝
deniedList.add(permission);
} else {//拒绝且不再询问
askAgainList.add(permission);
}
}else {
// grantedList.add(permission);
}
}
// if (grantedList != null && grantedList.size() > 0) {
// listener.onGranted(grantedList);//转成string[],这里只是同意部分权限,
// }
if (deniedList != null && deniedList.size() > 0) {
listener.onDenied(deniedList);
}
if (askAgainList != null && askAgainList.size() > 0) {
listener.onAskAgain(askAgainList);
}
}
}
finish();
}
}
color补充:
#01000000
AndroidManifest.xml补充
String[] permissionStr = new String[]{Manifest.permission.CAMERA,
Manifest.permission.READ_PHONE_STATE};
PermissionTestUtils.requestPermissions(this, new PermissionTestListener() {
@Override
public void onGranted(String[] grPermission) {
Toast.makeText(PermissionTestActivity.this, "权限申请成功" + grPermission.length, Toast.LENGTH_SHORT).show();
}
@Override
public void onDenied(List dePermissions) {
Toast.makeText(PermissionTestActivity.this, "权限被拒绝" + dePermissions.size(), Toast.LENGTH_SHORT).show();
}
@Override
public void onAskAgain(List asPermissions) {
Toast.makeText(PermissionTestActivity.this, "权限被拒绝且不再询问,需要去设置开启" + asPermissions.size(), Toast.LENGTH_SHORT).show();
}
}, permissionStr);
权限 | 权限名 | 权限干嘛用的 |
Manifest.permission.CAMERA | 相机 | 自拍需要相机权限 |