Android之EasyPermissions源码解析
转载请标明出处:【顾林海的博客】
个人开发的微信小程序,目前功能是书籍推荐,后续会完善一些新功能,希望大家多多支持!
前言
我们知道在Android中想要申请权限就需要在AndroidManifest配置文件中通过uses-permission标签设置申请的权限,通过这种方式申请权限固然方便,但在安全性方面却不高,比如开发者申请获取用户隐私的权限,这样用户在不知情的情况下获取到了用户的隐私,如何避免这种不安全的权限获取?从Android 6.0开始,Google将权限分为两类,分别是默认权限(Normal Permission)和危险权限(Dangerous Permission),默认权限在程序安装时授权,但危险权限需要用户在运行APP时手动授权,这里使用EasyPermissions库来简化运行时权限的操作。
EasyPermissions使用
/** * 权限管理类 * * @author glh */public abstract class BasePermissionsActivity extends AppCompatActivity implements EasyPermissions.PermissionCallbacks { @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); requestPermissions(this); } public void requestPermissions(Context context) { String[] perms = {Manifest.permission.CAMERA, Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_PHONE_STATE}; if (!EasyPermissions.hasPermissions(context, perms)) { EasyPermissions.requestPermissions((Activity) context, context.getResources().getString(R.string.camera_rationale), 124, perms); } } @Override public void onPermissionsGranted(int requestCode, List perms) { ToastUtils.showToast(this, "用户授权成功"); } @Override public void onPermissionsDenied(int requestCode, List perms) { /* * 若是在权限弹窗中,用户勾选了'NEVER ASK AGAIN.'或者'不在提示',且拒绝权限。 * 这时候,需要跳转到设置界面去,让用户手动开启。 */ if (EasyPermissions.somePermissionPermanentlyDenied(this, perms)) { new AppSettingsDialog .Builder(this) .setTitle("\"某APP\"权限提示") .setRationale("\"某APP\"需要使用相关权限,是否打开设置") .setPositiveButton("是") .setNegativeButton("否") .build() .show(); } } @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); EasyPermissions.onRequestPermissionsResult(requestCode, permissions, grantResults, this); } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); switch (requestCode) { //当从软件设置界面,返回当前程序时候 case AppSettingsDialog.DEFAULT_SETTINGS_REQ_CODE: requestPermissions(this); break; } } @AfterPermissionGranted(value = 0x99) public void checkPermissions() { String[] perms = {Manifest.permission.CAMERA, Manifest.permission.CHANGE_WIFI_STATE}; if (EasyPermissions.hasPermissions(this, perms)) { //已经授权后的操作 } else { //没有授权后的操作 EasyPermissions.requestPermissions(this, getString(R.string.camera_rationale), 0x99, perms); } }}
使用EasyPermissions时,需要实现它的PermissionCallbacks接口,这个接口提供了三个方法,其中onPermissionsGranted方法是授权成功后的回调,onPermissionsDenied方法是授权失败的回调,onRequestPermissionsResult方法是android.support.v4.app的ActivityCompat中的公共接口,当我们进行权限的请求时onRequestPermissionsResult方法会返回相应的请求结果,通过这个权限回调,可以对相应的操作做出响应。
EasyPermissions提供了hasPermissions方法,第二个参数传入的是一个权限数组,该方法会判断APP是否对这些权限进行过授权,如果其中有一个权限并没有被授权,最终结果会返回false,这时可以通过EasyPermissions的requestPermissions方法进行权限授权,其中requestCode是请求码,可以根据对应的请求码在授权回调中进行相应的处理,第三个可变参数就是我们需要授权的相关权限。具体的权限回调处理上面只是给出一个模板,具体的操作还是根据相关业务场景来调整。
EasyPermissions还提供了注解形式来处理授权后对应的requestCode处理,具体使用如下:
@AfterPermissionGranted(value = 0x99) public void checkPermissions() { String[] perms = {Manifest.permission.CAMERA, Manifest.permission.CHANGE_WIFI_STATE}; if (EasyPermissions.hasPermissions(this, perms)) { //已经授权后的操作 } else { //没有授权后的操作 EasyPermissions.requestPermissions(this, getString(R.string.camera_rationale), 0x99, perms); } }
源码解析
public static boolean hasPermissions(Context context, @NonNull String... perms) { //Android版本判断 if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) { Log.w(TAG, "hasPermissions: API version < M, returning true by default"); return true; } if (context == null) { throw new IllegalArgumentException("Can't check permissions for null context"); } //对权限列表进行检查 for (String perm : perms) { if (ContextCompat.checkSelfPermission(context, perm) != PackageManager.PERMISSION_GRANTED) { return false; } } return true; }
hasPermissions方法比较简单,先是对Android版本进行判断,小于Android 6.0的版本直接检查通过,只有大于Android 6.0时才会对权限列表进行检查,这里使用了ContextCompat的checkSelfPermissions方法进行权限检查,检查的结果不为0说明未授权。
在Android源码中,权限的检查最终会调用到 ContextImp中的checkPermission方法,源码如下:
@Override public int checkPermission(String permission, int pid, int uid) { if (permission == null) { throw new IllegalArgumentException("permission is null"); } try { return ActivityManagerNative.getDefault().checkPermission( permission, pid, uid); } catch (RemoteException e) { return PackageManager.PERMISSION_DENIED; } }
在ContextImp中的checkPermission方法中,调用了ActivityManagerNative的getDefault()方法来获取ActivityManagerService的对象。ActivityManagerService 的职责是管理着应用程序中创建的所有组件(Activity、Service等),实现组件的管理,每个组件的状态变化都需要通知AMS,组件间的跨进程通信(IPC)是由ActivityManagerService 来操作的。
ActivityManagerNative中的getDefault方法如下:
static public IActivityManager getDefault() { return gDefault.get(); } private static final Singleton gDefault = new Singleton() { protected IActivityManager create() { IBinder b = ServiceManager.getService("activity"); if (false) { Log.v("ActivityManager", "default service binder = " + b); } IActivityManager am = asInterface(b); if (false) { Log.v("ActivityManager", "default service = " + am); } return am; }}; static public IActivityManager asInterface(IBinder obj) { if (obj == null) { return null; } IActivityManager in = (IActivityManager) obj.queryLocalInterface(descriptor); if (in != null) { return in; } return new ActivityManagerProxy(obj); }
在上面的create方法中通过ServiceManager.getService(“activity”)获取到ActivityManagerService对象,ActivityManagerService继承了 ActivityManagerNative,而 ActivityManagerNative继承了Binder并实现了IActivityManager接口,因此ActivityManagerService也是一个Binder对象,在asInterface方法中创建远程代理ActvityManagerProxy对象,经过一系列调用,最终调用ActivityManagerService的checkPermission方法。
int checkComponentPermission(String permission, int pid, int uid, int owningUid, boolean exported) { // We might be performing an operation on behalf of an indirect binder // invocation, e.g. via {@link #openContentUri}. Check and adjust the // client identity accordingly before proceeding. Identity tlsIdentity = sCallerIdentity.get(); if (tlsIdentity != null) { Slog.d(TAG, "checkComponentPermission() adjusting {pid,uid} to {" + tlsIdentity.pid + "," + tlsIdentity.uid + "}"); uid = tlsIdentity.uid; pid = tlsIdentity.pid; } if (pid == MY_PID) { return PackageManager.PERMISSION_GRANTED; } return ActivityManager.checkComponentPermission(permission, uid, owningUid, exported); // 调用ActivityManager的checkComponentPermission来检查权限 } @Override public int checkPermission(String permission, int pid, int uid) { if (permission == null) { return PackageManager.PERMISSION_DENIED; } // 调用checkComponentPermission函数来检查权限 return checkComponentPermission(permission, pid, UserHandle.getAppId(uid), -1, true); }
调用ActivityManager的checkComponentPermission方法:
./base/core/java/android/app/ActivityManager.java public static int checkComponentPermission(String permission, int uid, int owningUid, boolean exported) { ........ try { // 调用AppGlobals的getPackageManager()函数返回IPackageManager对象 return AppGlobals.getPackageManager() .checkUidPermission(permission, uid); } catch (RemoteException e) { // Should never happen, but if it does... deny! Slog.e(TAG, "PackageManager is dead?!?", e); } return PackageManager.PERMISSION_DENIED; }
./base/core/java/android/app/AppGlobals.java public static IPackageManager getPackageManager() { return ActivityThread.getPackageManager(); // 调用ActivityThread的getPackageManager()函数 }
./base/core/java/android/app/ActivityThread.java public static IPackageManager getPackageManager() { if (sPackageManager != null) { //Slog.v("PackageManager", "returning cur default = " + sPackageManager); return sPackageManager; } IBinder b = ServiceManager.getService("package"); //Slog.v("PackageManager", "default service binder = " + b); sPackageManager = IPackageManager.Stub.asInterface(b); //Slog.v("PackageManager", "default service = " + sPackageManager); return sPackageManager; }
AppGlobals的getPackageManager方法中,通过ActivityThread的getPackageManager方法获取PackageManageService对象。
接着通过PackageManageService的checkUidPermission方法来检查权限。
./base/services/core/java/com/android/server/pm/PackageManagerService.java @Override public int checkUidPermission(String permName, int uid) { synchronized (mPackages) { Object obj = mSettings.getUserIdLPr(UserHandle.getAppId(uid)); if (obj != null) { GrantedPermissions gp = (GrantedPermissions) obj; if (gp.grantedPermissions.contains(permName)) { return PackageManager.PERMISSION_GRANTED; } } else { HashSet perms = mSystemPermissions.get(uid); if ( perms != null &;&; perms.contains(permName)){ return PackageManager.PERMISSION_GRANTED; } } } return PackageManager.PERMISSION_DENIED; }
PackageManageService的checkUidPermission方法中,通过Settings的getUserIdLPr方法根据UID获取权限列表获,如果存在授权的权限返回PackageManager.PERMISSION_GRANTED,表示授权成功。
hasPermissions方法算是分析完毕了,这里在分析该方法的同时也梳理了权限检查的流程。
在分析EasyPermissions的requestPermissions方法前,先介绍一下几个重要的辅助类。
PermissionHelper是一个抽象类(模板方法),内部定义了几个抽象方法:
@RestrictTo(RestrictTo.Scope.LIBRARY)public abstract class PermissionHelper { ..... public abstract void directRequestPermissions(int requestCode, @NonNull String... perms); public abstract boolean shouldShowRequestPermissionRationale(@NonNull String perm); public abstract void showRequestPermissionRationale(@NonNull String rationale, @StringRes int positiveButton, @StringRes int negativeButton, int requestCode, @NonNull String... perms); public abstract Context getContext();}
shouldShowRequestPermissionRationale方法:如果应用之前请求过此权限但用户拒绝了请求,并在权限请求系统对话框中没有选择了 Don’t ask again 选项,此方法将返回 true。如果用户在过去拒绝了权限请求,并在权限请求系统对话框中选择了 Don’t ask again 选项,此方法将返回 false。如果设备规范禁止应用具有该权限,此方法也会返回 false。
directRequestPermissions方法:进行权限请求。
showRequestPermissionRationale方法:显示权限弹框,具体逻辑有子类实现。
getContext方法:获取对应的上下文。
很显然PermissionHelper是权限操作的抽象类,具体实现由子类来实现,请求权限时,可以在Activity、android.support.v4.app.Fragment或是android.app.Fragment中执行请求,PermissionHelper提供了创建这几种情况下的实现类。
@NonNullpublic static PermissionHelper newInstance(Activity host) { if (Build.VERSION.SDK_INT < 23) { return new LowApiPermissionsHelper(host); } return new ActivityPermissionHelper(host);}@NonNullpublic static PermissionHelper newInstance(Fragment host) { if (Build.VERSION.SDK_INT < 23) { return new LowApiPermissionsHelper(host); } return new SupportFragmentPermissionHelper(host);}@NonNullpublic static PermissionHelper newInstance(android.app.Fragment host) { if (Build.VERSION.SDK_INT < 23) { return new LowApiPermissionsHelper(host); } return new FrameworkFragmentPermissionHelper(host);}
如果权限授权在小于Android 6.0的版本时,会创建LowApiPermissionsHelper对象,LowApiPermissionsHelper实现了PermissionHelper的几个抽象方法。
class LowApiPermissionsHelper extends PermissionHelper
LowApiPermissionsHelper的几个方法都是空的,这是因为在API小于23时,不需要对运行时权限做处理。
ActivityPermissionHelper和FrameworkFragmentPermissionHelper针对的是在android.app包的Actvity和Fragment。
ActivityPermissionHelper:
class ActivityPermissionHelper extends BaseFrameworkPermissionsHelper { public ActivityPermissionHelper(Activity host) { super(host); } @Override @SuppressLint("NewApi") public FragmentManager getFragmentManager() { return getHost().getFragmentManager(); } @Override public void directRequestPermissions(int requestCode, @NonNull String... perms) { ActivityCompat.requestPermissions(getHost(), perms, requestCode); } @Override public boolean shouldShowRequestPermissionRationale(@NonNull String perm) { return ActivityCompat.shouldShowRequestPermissionRationale(getHost(), perm); } @Override public Context getContext() { return getHost(); }}
FrameworkFragmentPermissionHelper:
class FrameworkFragmentPermissionHelper extends BaseFrameworkPermissionsHelper { public FrameworkFragmentPermissionHelper(@NonNull Fragment host) { super(host); } @Override @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR1) public FragmentManager getFragmentManager() { return getHost().getChildFragmentManager(); } @Override @SuppressLint("NewApi") public void directRequestPermissions(int requestCode, @NonNull String... perms) { getHost().requestPermissions(perms, requestCode); } @Override @SuppressLint("NewApi") public boolean shouldShowRequestPermissionRationale(@NonNull String perm) { return getHost().shouldShowRequestPermissionRationale(perm); } @Override @SuppressLint("NewApi") public Context getContext() { return getHost().getActivity(); }}
ActivityPermissionHelper和FrameworkFragmentPermissionHelper实现逻辑都差不多,在Activity中请求权限会通过ActivityCompat的requestPermissions方法进行请求,在Fragment中会通过Fragment的requestPermissions方法进行权限请求。并且这两个Helper类都继承了BaseFrameworkPermissionsHelper类。
public abstract class BaseFrameworkPermissionsHelper extends PermissionHelper { public BaseFrameworkPermissionsHelper(@NonNull T host) { super(host); } public abstract FragmentManager getFragmentManager(); @Override @RequiresApi(api = Build.VERSION_CODES.HONEYCOMB) public void showRequestPermissionRationale(@NonNull String rationale, int positiveButton, int negativeButton, int requestCode, @NonNull String... perms) { RationaleDialogFragment .newInstance(positiveButton, negativeButton, rationale, requestCode, perms) .show(getFragmentManager(), RationaleDialogFragment.TAG); } }
BaseFrameworkPermissionsHelper类非常简单,就两个方法,其中一个抽象方法getFragmentManager获取FragmentManager对象,还有一个实现了PermissionHelper类中的抽象方法showRequestPermissionRationale,showRequestPermissionRationale方法会显示一个权限弹框。
具体的子类实现在PermissionHelper中已经介绍过,继续看support.v4.app包的下Fragment的权限操作(SupportFragmentPermissionHelper)。
class SupportFragmentPermissionHelper extends BaseSupportPermissionsHelper { public SupportFragmentPermissionHelper(@NonNull Fragment host) { super(host); } @Override public FragmentManager getSupportFragmentManager() { return getHost().getChildFragmentManager(); } @Override public void directRequestPermissions(int requestCode, @NonNull String... perms) { getHost().requestPermissions(perms, requestCode); } @Override public boolean shouldShowRequestPermissionRationale(@NonNull String perm) { return getHost().shouldShowRequestPermissionRationale(perm); } @Override public Context getContext() { return getHost().getActivity(); } }
SupportFragmentPermissionHelper的逻辑与之前两个Helper类一样,不需要再介绍了。
继续分析requestPermissions方法,EasyPermissions提供了多个requestPermissions方法:
public static void requestPermissions( @NonNull Activity host, @NonNull String rationale, int requestCode, @NonNull String... perms) { requestPermissions(host, rationale, android.R.string.ok, android.R.string.cancel, requestCode, perms); } public static void requestPermissions( @NonNull Fragment host, @NonNull String rationale, int requestCode, @NonNull String... perms) { requestPermissions(host, rationale, android.R.string.ok, android.R.string.cancel, requestCode, perms); } public static void requestPermissions( @NonNull android.app.Fragment host, @NonNull String rationale, int requestCode, @NonNull String... perms) { requestPermissions(host, rationale, android.R.string.ok, android.R.string.cancel, requestCode, perms); }
这个三个requestPermissions方法应该很熟悉了,权限弹框按钮的文案是默认的,要想设置权限弹框的文案,可以调用以下三种requestPermissions方法。
public static void requestPermissions( @NonNull Activity host, @NonNull String rationale, @StringRes int positiveButton, @StringRes int negativeButton, int requestCode, @NonNull String... perms) { requestPermissions(PermissionHelper.newInstance(host), rationale, positiveButton, negativeButton, requestCode, perms); } public static void requestPermissions( @NonNull Fragment host, @NonNull String rationale, @StringRes int positiveButton, @StringRes int negativeButton, int requestCode, @NonNull String... perms) { requestPermissions(PermissionHelper.newInstance(host), rationale, positiveButton, negativeButton, requestCode, perms); } public static void requestPermissions( @NonNull android.app.Fragment host, @NonNull String rationale, @StringRes int positiveButton, @StringRes int negativeButton, int requestCode, @NonNull String... perms) { requestPermissions(PermissionHelper.newInstance(host), rationale, positiveButton, negativeButton, requestCode, perms); }
通过一系列调用,最后都是都用以下方法:
private static void requestPermissions( @NonNull PermissionHelper helper, @NonNull String rationale, @StringRes int positiveButton, @StringRes int negativeButton, int requestCode, @NonNull String... perms) { //进行权限检查 if (hasPermissions(helper.getContext(), perms)) { notifyAlreadyHasPermissions(helper.getHost(), requestCode, perms); return; } //请求权限 helper.requestPermissions(rationale, positiveButton, negativeButton, requestCode, perms); }
方法第一个参数PermissionHelper就是前三个requestPermissions方法针对app包和suppor包下的Activity和Fragment权限操作类,也就是前面提到的那几个Helper类。在请求权限之前会检查之前权限有没有授权过,如果授权过调用notifyAlreadyHasPermissions方法。
private static void notifyAlreadyHasPermissions(@NonNull Object object, int requestCode, @NonNull String[] perms) { int[] grantResults = new int[perms.length]; for (int i = 0; i < perms.length; i++) { grantResults[i] = PackageManager.PERMISSION_GRANTED; } onRequestPermissionsResult(requestCode, perms, grantResults, object); }
notifyAlreadyHasPermissions方法非常简单,授权成功后将 grantResults 数组全部赋值未PackageManager.PERMISSION_GRANTED,再通过onRequestPermissionsResult方法将结果回调给客户端。继续看requestPermissions方法中的helper.requestPermissions方法,该方法就是调用app和support下Activity和Fragment的
shouldShowRequestPermissionRationale方法,该方法就是Android进行权限授权的方法,当进行授权操作后会回调onRequestPermissionsResult方法。如下:
@Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); EasyPermissions.onRequestPermissionsResult(requestCode, permissions, grantResults, this); }
拿到授权结果后通过EasyPermissions的onRequestPermissionsResult方法进行结果回调,onRequestPermissionsResult方法如下。
public static void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults, @NonNull Object... receivers) { //授权成功 List granted = new ArrayList<>(); //授权失败或没授权 List denied = new ArrayList<>(); for (int i = 0; i < permissions.length; i++) { String perm = permissions[i]; } if (grantResults[i] == PackageManager.PERMISSION_GRANTED) { granted.add(perm); } else { denied.add(perm); } for (Object object : receivers) { // 授权成功 if (!granted.isEmpty()) { if (object instanceof EasyPermissions.PermissionCallbacks) { ((EasyPermissions.PermissionCallbacks) object).onPermissionsGranted(requestCode, granted); } } //未授权 if (!denied.isEmpty()) { if (object instanceof EasyPermissions.PermissionCallbacks) { ((EasyPermissions.PermissionCallbacks) object).onPermissionsDenied(requestCode, denied); } } //全部授权通过 if (!granted.isEmpty() && denied.isEmpty()) { runAnnotatedMethods(object, requestCode); } } }
方法中granted集合用于保存授权成功的权限,denied集合保存的是未授权或授权失败的权限,接着通过循环遍历权限请求类,对授权成功和未成功集合做判断,如果granted集合不为空说明授权成功,会回调onPermissionsGranted方法,如果denied集合不为空,说明有权限未授权成功,会回调onPermissionsDenied方法,当然如果granted集合不为空并且denied集合为空,说明百分百之一百授权成功,这时调用runAnnotatedMethods方法。
private static void runAnnotatedMethods(@NonNull Object object, int requestCode) { Class clazz = object.getClass(); if (isUsingAndroidAnnotations(object)) { clazz = clazz.getSuperclass(); } while (clazz != null) { //遍历请求权限类中的方法 for (Method method : clazz.getDeclaredMethods()) { //判断是否使用了AfterPermissionGranted注解 if (method.isAnnotationPresent(AfterPermissionGranted.class)) { AfterPermissionGranted ann = method.getAnnotation(AfterPermissionGranted.class); if (ann.value() == requestCode) { //无参方法 if (method.getParameterTypes().length > 0) { throw new RuntimeException( "Cannot execute method " + method.getName() + " because it is non-void method and/or has input parameters."); } try { // Make method accessible if private if (!method.isAccessible()) { method.setAccessible(true); } //反射调用AfterPermissionGranted注解的方法 method.invoke(object); } catch (IllegalAccessException e) { Log.e(TAG, "runDefaultMethod:IllegalAccessException", e); } catch (InvocationTargetException e) { Log.e(TAG, "runDefaultMethod:InvocationTargetException", e); } } } } //获取父类的Class clazz = clazz.getSuperclass(); } }
该方法主要对AfterPermissionGranted注解的方法进行处理,通过遍历请求权限类的方法,如果是通过AfterPermissionGranted注解的方法并且是无参的,通过请求的requestCode与该注解方法的value一样,就通过反射执行该方法,告之请求类权限请求成功。这里稍微提下,一开始会执行isUsingAndroidAnnotations方法进行判断是否获取直接继承父类的class,isUsingAndroidAnnotations方法如下:
private static boolean isUsingAndroidAnnotations(@NonNull Object object) { if (!object.getClass().getSimpleName().endsWith("_")) { return false; } try { Class clazz = Class.forName("org.androidannotations.api.view.HasViews"); return clazz.isInstance(object); } catch (ClassNotFoundException e) { return false; } }
其实这个方法也就是判断是否使用了 AndroidAnnotations这个注解框架,关于这个框架大家可以自行网上搜索。
之前看了onRequestPermissionsResult方法,也就是授权后的结果回调,现在看下权限请求的逻辑。
//请求权限 helper.requestPermissions(rationale, positiveButton, negativeButton, requestCode, perms);
调用了PermissionHelper的requestPermissions方法。
public boolean shouldShowRationale(@NonNull String... perms){ for (String perm:perms){ // 上次弹出权限点击了禁止(但没有勾选“下次不在询问”) if(shouldShowRequestPermissionRationale(perm)){ return true; } } //第一次打开App时或者上次选择禁止并勾选“下次不在询问” return false; } public void requestPermissions(@NonNull String rationale, @StringRes int positiveButton, @StringRes int negativeButton, int requestCode, @NonNull String... perms){ if(shouldShowRationale(perms)){ // 上次弹出权限点击了禁止(但没有勾选“下次不在询问”) showRequestPermissionRationale(rationale, positiveButton, negativeButton, requestCode, perms); }else{ //第一次打开App时或者上次选择禁止并勾选“下次不在询问” //进行权限请求 directRequestPermissions(requestCode,perms); } }
requestPermissions方法中,当上次弹出权限点击了禁止(但没有勾选“下次不在询问”),这时需要弹出权限弹框,当第一次打开App时或者上次选择禁止并勾选“下次不在询问”,这时进行权限请求。shouldShowRequestPermissionRationale、showRequestPermissionRationale和directRequestPermissions都是抽象方法,具体实现由子类实现,关于这三个方法在上面已经介绍过了。
结合上面的一系列分析,权限请求后,通过回调onPermissionsGranted和onPermissionsDenied方法告之请求类请求结果,比如当我们选择禁止并勾选“下次不在询问”时,这时请求授权失败,回调onPermissionsDenied方法:
@Override public void onPermissionsDenied(int requestCode, List perms) { /** * 若是在权限弹窗中,用户勾选了'NEVER ASK AGAIN.'或者'不在提示',且拒绝权限。 * 这时候,需要跳转到设置界面去,让用户手动开启。 */ if(requestCode==124) { if (EasyPermissions.somePermissionPermanentlyDenied(this, perms)) { new AppSettingsDialog .Builder(this) .setTitle("\"火链财经\"权限提示") .setRationale("\"火链财经\"需要使用相关权限,是否打开设置") .setPositiveButton("是") .setNegativeButton("否") .build() .show(); } else { requestPermissions(this); } } }
可以针对具体业务进行操作,就像上面若是在权限弹窗中,用户勾选了’NEVER ASK AGAIN.‘或者’不在提示’,且拒绝权限。 这时候,需要跳转到设置界面去,让用户手动开启。否则再次请求授权。
到这里EasyPermissions分析分析完毕。
更多相关文章
- Android(安卓)系统权限
- Objective-C与JavaScript交互的那些事
- android中关于使用scrollview嵌套LinearLayout,页面滚动条不到底
- android外部存储读写权限问题
- 第一篇技术贴(Android(安卓)WebView)
- Android学习路线总结
- Android:剖析源码,随心所欲控制Toast显示
- 从AIDL开始谈Android进程间Binder通信机制
- Android之异步任务加载网络数据