安卓6.0之后谷歌将权限分为:普通权限,敏感权限。普通权限直接在配置文件中配置即可,敏感权限则需要开发者手动申请,如果大家进行过动态权限申请,可能会发现写法很麻烦,回调也不直观,本文针对动态权限申请做了简单的封装,简化其操作,同时介绍用户拒绝权限再次提示后,如何引导用户进入应用设置页面自行授权。
我们申请权限的思路一般是
1、确认是否拥有权限A(或者多个权限)
2、如果有权限--------执行相应功能
3、如果没有权限----------申请权限
1、申请通过后-----------执行相应功能
2、申请被拒绝后----------提示用户或者引导用户自行授权
按照这个思路,我们写代码的话会疯掉,每次申请都要写一遍,这就是为什么我们要封装或者使用现有工具
1、RxPermissions
RxPermissions是基于RxJava2的动态权限框架,对其原理感兴趣的同学可以自行研究,本文只介绍其简单用法
第一步:添加依赖
compile'com.tbruyelle.rxpermissions:rxpermissions:0.9.4@aar'
compile'io.reactivex:rxandroid:1.2.1'
第二步:初始化RxPermissions,申请权限,添加回调(别忘记在Mainfest中注册需要的权限)
private void requestPer() {//RxPermissions获取权限
RxPermissions permissions = new RxPermissions(this);
permissions.request(Manifest.permission.ACCESS_COARSE_LOCATION,
Manifest.permission.WRITE_EXTERNAL_STORAGE).subscribe(new Observer() {
@Override
public void onCompleted() {
}
@Override
public void onError(Throwable e) {
}
@Override
public void onNext(Boolean aBoolean) {
if (aBoolean) {
Toast.makeText(MainActivity.this, "获取", Toast.LENGTH_LONG).show();
} else {
Toast.makeText(MainActivity.this, "未获取", Toast.LENGTH_LONG).show();
}
}
});
}
大家可以直接复用上面的代码,简介的地方就在于我们不用去写一遍
onRequestPermissionsResult
直观的在一个地方申请、获取权限后执行功能、未获取时提示等。比较简洁,下面介绍自行封装的方式
2、简单的自行封装-适用于整个工程
封装的目的是不需要重复写onRequestPermissionsResult和每次申请都要写一遍申请方法,以及简单直观的回调监控
第一步:创建基类ActivityBase
package com.demo.mybaidumapdemo;
import android.app.Activity;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import java.util.ArrayList;
import java.util.List;
/**
* Created by zyy on 2019/9/20.
*/
public class ActivityBase extends Activity {
private applyPerCallBack callBack;
private static final int PERMISSION_REQUESTCODE = 100;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
public void requestRunPermisssion(String[] permissions, applyPerCallBack mcallBack){
callBack = mcallBack;
List permissionLists = new ArrayList<>();
for(String permission : permissions){
if(ContextCompat.checkSelfPermission(this, permission) != PackageManager.PERMISSION_GRANTED){
permissionLists.add(permission);
}
}
if(!permissionLists.isEmpty()){
ActivityCompat.requestPermissions(this, permissionLists.toArray(new String[permissionLists.size()]), PERMISSION_REQUESTCODE);
}else{
//表示全都授权了
callBack.onGranted();
}
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
switch (requestCode){
case PERMISSION_REQUESTCODE:
if(grantResults.length > 0){
//存放没授权的权限
List deniedPermissions = new ArrayList<>();
for(int i = 0; i < grantResults.length; i++){
int grantResult = grantResults[i];
String permission = permissions[i];
if(grantResult != PackageManager.PERMISSION_GRANTED){
deniedPermissions.add(permission);
}
}
if(deniedPermissions.isEmpty()){
//说明都授权了
callBack.onGranted();
}else{
callBack.onDenied(deniedPermissions);
}
}
break;
default:
break;
}
}
}
我们在基类中写好权限申请的方法和事件监控,同时创建回调类,在使用时实现此接口即可
第二步,使用如下
final int i = ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.ACCESS_COARSE_LOCATION);
if (i != PackageManager.PERMISSION_GRANTED) {//检测是否获取权限
// requestPer();//没获取权限则申请
requestRunPermisssion(new String[]{Manifest.permission.ACCESS_COARSE_LOCATION,
Manifest.permission.WRITE_EXTERNAL_STORAGE}, new applyPerCallBack() {
@Override
public void onGranted() {
Toast.makeText(MainActivity.this, "所有权限都授权", Toast.LENGTH_SHORT).show();
}
@Override
public void onDenied(List deniedPermission) {
for(String permission : deniedPermission){
Toast.makeText(MainActivity.this, "被拒绝的权限:" + permission, Toast.LENGTH_SHORT).show();
}
}
});
}
注意mainActivity继承ActivityBase
applyPerCallBack代码
import java.util.List;
/**
* Created by zyy on 2019/9/20.
*/
public interface applyPerCallBack {
void onGranted();//已授权
void onDenied(List deniedPermission);//未授权
}
总结:此方法封装需创建一个简单的基类,在使用时直接调用基类方法实现CallBack即可
3、用户拒绝再次提示
用户拒绝再次提示时,即使我们在代码中申请权限,弹框也不会出现,此时该如何引导用户自行开启权限,给用户更人性化的体验,不废话,看代码
import android.app.Activity;
import android.content.ComponentName;
import android.content.Intent;
import android.net.Uri;
import android.os.Build;
import android.provider.Settings;
import android.support.v7.appcompat.BuildConfig;
import static com.demo.mybaidumapdemo.PermissionsManager.PERMISSION_SETTING_FOR_RESULT;
/**
* Created by zyy on 2018/3/12.
* 直接跳转到权限后返回,可以监控权限授权情况,但是,跳转到应用详情页,无法监测权限情况
* 是否要加以区分,若是应用详情页,则跳转回来后,onRestart检测所求权限,如果授权,则收回提示,如果没授权,则继续提示
*/
public class permissionUtilSetting {
/**
* Build.MANUFACTURER判断各大手机厂商品牌
*/
private static final String MANUFACTURER_HUAWEI = "Huawei";//华为
private static final String MANUFACTURER_MEIZU = "Meizu";//魅族
private static final String MANUFACTURER_XIAOMI = "Xiaomi";//小米
private static final String MANUFACTURER_SONY = "Sony";//索尼
private static final String MANUFACTURER_OPPO = "OPPO";
private static final String MANUFACTURER_LG = "LG";
private static final String MANUFACTURER_VIVO = "vivo";
private static final String MANUFACTURER_SAMSUNG = "samsung";//三星
private static final String MANUFACTURER_LETV = "Letv";//乐视
private static final String MANUFACTURER_ZTE = "ZTE";//中兴
private static final String MANUFACTURER_YULONG = "YuLong";//酷派
private static final String MANUFACTURER_LENOVO = "LENOVO";//联想
public static boolean isAppSettingOpen=false;
/**
* 跳转到相应品牌手机系统权限设置页,如果跳转不成功,则跳转到应用详情页
* 这里需要改造成返回true或者false,应用详情页:true,应用权限页:false
* @param activity
*/
public static void GoToSetting(Activity activity){
switch (Build.MANUFACTURER){
case MANUFACTURER_HUAWEI://华为
Huawei(activity);
break;
case MANUFACTURER_MEIZU://魅族
Meizu(activity);
break;
case MANUFACTURER_XIAOMI://小米
Xiaomi(activity);
break;
case MANUFACTURER_SONY://索尼
Sony(activity);
break;
case MANUFACTURER_OPPO://oppo
OPPO(activity);
break;
case MANUFACTURER_LG://lg
LG(activity);
break;
case MANUFACTURER_LETV://乐视
Letv(activity);
break;
default://其他
try {//防止应用详情页也找不到,捕获异常后跳转到设置,这里跳转最好是两级,太多用户也会觉得麻烦,还不如不跳
openAppDetailSetting(activity);
// activity.startActivityForResult(getAppDetailSettingIntent(activity), PERMISSION_SETTING_FOR_RESULT);
}catch (Exception e){
SystemConfig(activity);
}
break;
}
}
/**
* 华为跳转权限设置页
* @param activity
*/
public static void Huawei(Activity activity) {
try {
Intent intent = new Intent();
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.putExtra("packageName", BuildConfig.APPLICATION_ID);
ComponentName comp = new ComponentName("com.huawei.systemmanager", "com.huawei.permissionmanager.ui.MainActivity");
intent.setComponent(comp);
activity.startActivityForResult(intent,PERMISSION_SETTING_FOR_RESULT);
isAppSettingOpen=false;
} catch (Exception e) {
openAppDetailSetting(activity);
// activity.startActivityForResult(getAppDetailSettingIntent(activity), PERMISSION_SETTING_FOR_RESULT);
}
}
/**
* 魅族跳转权限设置页,测试时,点击无反应,具体原因不明
* @param activity
*/
public static void Meizu(Activity activity) {
try {
Intent intent = new Intent("com.meizu.safe.security.SHOW_APPSEC");
intent.addCategory(Intent.CATEGORY_DEFAULT);
intent.putExtra("packageName", BuildConfig.APPLICATION_ID);
activity.startActivity(intent);
isAppSettingOpen=false;
}catch (Exception e){
openAppDetailSetting(activity);
// activity.startActivityForResult(getAppDetailSettingIntent(activity), PERMISSION_SETTING_FOR_RESULT);
}
}
/**
* 小米,功能正常
* @param activity
*/
public static void Xiaomi(Activity activity) {
try { // MIUI 8 9
Intent localIntent = new Intent("miui.intent.action.APP_PERM_EDITOR");
localIntent.setClassName("com.miui.securitycenter", "com.miui.permcenter.permissions.PermissionsEditorActivity");
localIntent.putExtra("extra_pkgname", activity.getPackageName());
activity.startActivityForResult(localIntent, PERMISSION_SETTING_FOR_RESULT);
isAppSettingOpen=false;
// activity.startActivity(localIntent);
} catch (Exception e) {
try { // MIUI 5/6/7
Intent localIntent = new Intent("miui.intent.action.APP_PERM_EDITOR");
localIntent.setClassName("com.miui.securitycenter", "com.miui.permcenter.permissions.AppPermissionsEditorActivity");
localIntent.putExtra("extra_pkgname", activity.getPackageName());
activity.startActivityForResult(localIntent, PERMISSION_SETTING_FOR_RESULT);
isAppSettingOpen=false;
// activity.startActivity(localIntent);
} catch (Exception e1) { // 否则跳转到应用详情
openAppDetailSetting(activity);
// activity.startActivityForResult(getAppDetailSettingIntent(activity), PERMISSION_SETTING_FOR_RESULT);
//这里有个问题,进入活动后需要再跳一级活动,就检测不到返回结果
// activity.startActivity(getAppDetailSettingIntent());
}
}
}
/**
* 索尼,6.0以上的手机非常少,基本没看见
* @param activity
*/
public static void Sony(Activity activity) {
try {
Intent intent = new Intent();
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.putExtra("packageName", BuildConfig.APPLICATION_ID);
ComponentName comp = new ComponentName("com.sonymobile.cta", "com.sonymobile.cta.SomcCTAMainActivity");
intent.setComponent(comp);
activity.startActivity(intent);
isAppSettingOpen=false;
}catch (Exception e){
openAppDetailSetting(activity);
// activity.startActivityForResult(getAppDetailSettingIntent(activity), PERMISSION_SETTING_FOR_RESULT);
}
}
/**
* OPPO
* @param activity
*/
public static void OPPO(Activity activity) {
try {
Intent intent = new Intent();
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.putExtra("packageName", BuildConfig.APPLICATION_ID);
ComponentName comp = new ComponentName("com.color.safecenter", "com.color.safecenter.permission.PermissionManagerActivity");
intent.setComponent(comp);
activity.startActivity(intent);
isAppSettingOpen=false;
}catch (Exception e){
openAppDetailSetting(activity);
// activity.startActivityForResult(getAppDetailSettingIntent(activity), PERMISSION_SETTING_FOR_RESULT);
}
}
/**
* LG经过测试,正常使用
* @param activity
*/
public static void LG(Activity activity) {
try {
Intent intent = new Intent("android.intent.action.MAIN");
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.putExtra("packageName", BuildConfig.APPLICATION_ID);
ComponentName comp = new ComponentName("com.android.settings", "com.android.settings.Settings$AccessLockSummaryActivity");
intent.setComponent(comp);
activity.startActivity(intent);
isAppSettingOpen=false;
}catch (Exception e){
openAppDetailSetting(activity);
// activity.startActivityForResult(getAppDetailSettingIntent(activity), PERMISSION_SETTING_FOR_RESULT);
}
}
/**
* 乐视6.0以上很少,基本都可以忽略了,现在乐视手机不多
* @param activity
*/
public static void Letv(Activity activity) {
try {
Intent intent = new Intent();
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.putExtra("packageName", BuildConfig.APPLICATION_ID);
ComponentName comp = new ComponentName("com.letv.android.letvsafe", "com.letv.android.letvsafe.PermissionAndApps");
intent.setComponent(comp);
activity.startActivity(intent);
isAppSettingOpen=false;
}catch (Exception e){
openAppDetailSetting(activity);
// activity.startActivityForResult(getAppDetailSettingIntent(activity), PERMISSION_SETTING_FOR_RESULT);
}
}
/**
* 只能打开到自带安全软件
* @param activity
*/
public static void _360(Activity activity) {
try {
Intent intent = new Intent("android.intent.action.MAIN");
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.putExtra("packageName", BuildConfig.APPLICATION_ID);
ComponentName comp = new ComponentName("com.qihoo360.mobilesafe", "com.qihoo360.mobilesafe.ui.index.AppEnterActivity");
intent.setComponent(comp);
activity.startActivity(intent);
}catch (Exception e){
openAppDetailSetting(activity);
// activity.startActivityForResult(getAppDetailSettingIntent(activity), PERMISSION_SETTING_FOR_RESULT);
}
}
/**
* 系统设置界面
* @param activity
*/
public static void SystemConfig(Activity activity) {
Intent intent = new Intent(Settings.ACTION_SETTINGS);
activity.startActivity(intent);
}
/**
* 获取应用详情页面
* @return
*/
private static Intent getAppDetailSettingIntent(Activity activity) {
Intent localIntent = new Intent();
localIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
if (Build.VERSION.SDK_INT >= 9) {
localIntent.setAction("android.settings.APPLICATION_DETAILS_SETTINGS");
localIntent.setData(Uri.fromParts("package", activity.getPackageName(), null));
} else if (Build.VERSION.SDK_INT <= 8) {
localIntent.setAction(Intent.ACTION_VIEW);
localIntent.setClassName("com.android.settings", "com.android.settings.InstalledAppDetails");
localIntent.putExtra("com.android.settings.ApplicationPkgName", activity.getPackageName());
}
return localIntent;
}
public static void openAppDetailSetting(Activity activity){
activity.startActivityForResult(getAppDetailSettingIntent(activity), PERMISSION_SETTING_FOR_RESULT);
isAppSettingOpen=true;
}
}
码字不易,转载请注明出处