Google-EasyPermissions
来源:互联网 发布:楚留香1979源码 编辑:程序博客网 时间:2024/06/05 09:24
Github: easypermissions 分析版本: 962b99d
EasyPermissions 是一个在 Android M 或者更高版本的上使用去简化系统权限逻辑的开源库。
使用
添加依赖到 Gradle
:
dependencies { compile 'pub.devrel:easypermissions:0.1.5'}
准备
在使用 EasyPermissions 之前,需要在 Activity
或者 Fragment
中实现EasyPermissions.PermissionCallbacks
接口,并且覆盖以下方法:
public class MainActivity extends AppCompatActivity implements EasyPermissions.PermissionCallbacks { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } @Override public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); // 将结果转发给EasyPermissions EasyPermissions.onRequestPermissionsResult(requestCode, permissions, grantResults, this); } @Override public void onPermissionsGranted(int requestCode, List<String> list) { // 权限被授予 // ... } @Override public void onPermissionsDenied(int requestCode, List<String> list) { // 权限被拒绝 // ... }}
请求权限
使用
EasyPermissions#hasPermissions(...)
去判断 app 是否已经有权限了。该方法的最后个参数是可变数组形式的,所以可以一次性查询多个权限。使用
EasyPermissions#requestPermissions
去请求权限。该方法在请求权限的同时有必要的话会显示使用权限理由。requestCode
对于该方法来说必须是唯一的,同时最后个参数也是可变数组形式的,所以可以一次性请求多个权限。使用
AfterPermissioonGranted
注解。这是可选的,但是提供出来是为了方便。如果所有的请求的权限都被授予了,被注解的方法将会被执行,这样做是为了简化通常的请求权限成功之后再调用方法的流程。同时也可以在onPermissionsGranted
的回调中添加逻辑操作:@AfterPermissionGranted(RC_CAMERA_AND_WIFI)private void methodRequiresTwoPermission() { String[] perms = {Manifest.permission.CAMERA, Manifest.permission.CHANGE_WIFI_STATE}; if (EasyPermissions.hasPermissions(this, perms)) { // Already have permission, do the thing // ... } else { // Do not have permissions, request them now EasyPermissions.requestPermissions(this, getString(R.string.camera_and_wifi_rationale), RC_CAMERA_AND_WIFI, perms); }}
源码
hasPermissions
public class EasyPermissions { /** * Check if the calling context has a set of permissions. * * @param context the calling context. * @param perms one ore more permissions, such as {@code android.Manifest.permission.CAMERA}. * @return true if all permissions are already granted, false if at least one permission * is not yet granted. */ public static boolean hasPermissions(Context context, String... perms) { for (String perm : perms) { //通过ContextCompat#checkSelfPermission判断 boolean hasPerm = (ContextCompat.checkSelfPermission(context, perm) == PackageManager.PERMISSION_GRANTED); if (!hasPerm) { return false; } } return true; }}
该方法的作用是判断是否授予了权限,通过 v4 的ContextCompat#checkSelfPermission
来判断,在返回结果的时候,如果所有的请求的权限都是被授予了的话,就返回 true
,否则返回 false
。
requestPermissions
public class EasyPermissions { public static void requestPermissions(final Object object, String rationale, final int requestCode, final String... perms) { requestPermissions(object, rationale, android.R.string.ok, android.R.string.cancel, requestCode, perms); } /** * Request a set of permissions, showing rationale if the system requests it. * * @param object Activity or Fragment requesting permissions. Should implement * {@link android.support.v4.app.ActivityCompat.OnRequestPermissionsResultCallback} * or * {@link android.support.v13.app.FragmentCompat.OnRequestPermissionsResultCallback} * @param rationale a message explaining why the application needs this set of permissions, will * be displayed if the user rejects the request the first time. * @param positiveButton custom text for positive button * @param negativeButton custom text for negative button * @param requestCode request code to track this request, must be < 256. * @param perms a set of permissions to be requested. */ public static void requestPermissions(final Object object, String rationale, @StringRes int positiveButton, @StringRes int negativeButton, final int requestCode, final String... perms) { //判断传入参数是否合适 checkCallingObjectSuitability(object); //拿到PermissionCallbacks对象 final PermissionCallbacks callbacks = (PermissionCallbacks) object; boolean shouldShowRationale = false; for (String perm : perms) { //是否需要显示理由 shouldShowRationale = shouldShowRationale || shouldShowRequestPermissionRationale(object, perm); } //如果需要的话,显示dialog进行显示 if (shouldShowRationale) { AlertDialog dialog = new AlertDialog.Builder(getActivity(object)) .setMessage(rationale) .setPositiveButton(positiveButton, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { //用户同意了,进行系统权限申请操作 executePermissionsRequest(object, perms, requestCode); } }) .setNegativeButton(negativeButton, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { // act as if the permissions were denied //没有同意的话,回调出去 callbacks.onPermissionsDenied(requestCode, Arrays.asList(perms)); } }).create(); dialog.show(); } else { //不需要显示理由,直接进行权限请求操作 executePermissionsRequest(object, perms, requestCode); } } /** * 判断传入的对象合适合法,判断规则是传入的object是不是 Fragment 或者 Activity 类,同时是否实现了 PermissionCallbacks * * @param object */ private static void checkCallingObjectSuitability(Object object) { // Make sure Object is an Activity or Fragment if (!((object instanceof Fragment) || (object instanceof Activity))) { throw new IllegalArgumentException("Caller must be an Activity or a Fragment."); } // Make sure Object implements callbacks if (!(object instanceof PermissionCallbacks)) { throw new IllegalArgumentException("Caller must implement PermissionCallbacks."); } } /** * 是否需要显示请求权限理由 * * @param object * @param perm * @return 需要的话返回true,不需要的话返回false */ private static boolean shouldShowRequestPermissionRationale(Object object, String perm) { if (object instanceof Activity) { return ActivityCompat.shouldShowRequestPermissionRationale((Activity) object, perm); } else if (object instanceof Fragment) { return ((Fragment) object).shouldShowRequestPermissionRationale(perm); } else { return false; } } /** * 执行权限请求操作 * * @param object * @param perms * @param requestCode */ private static void executePermissionsRequest(Object object, String[] perms, int requestCode) { //判断传入参数是否合适 checkCallingObjectSuitability(object); if (object instanceof Activity) { ActivityCompat.requestPermissions((Activity) object, perms, requestCode); } else if (object instanceof Fragment) { ((Fragment) object).requestPermissions(perms, requestCode); } } /** * 拿到Activity对象 * * @param object * @return */ private static Activity getActivity(Object object) { if (object instanceof Activity) { return ((Activity) object); } else if (object instanceof Fragment) { return ((Fragment) object).getActivity(); } else { return null; } }}
requestPermission()
有两个不同参数的实现,区别在于弹出的对话框中的 positive 和 negative 文字是否自定义。传入的 Object
对象得是 Activity
或者Fragment
并且实现了android.support.v4.app.ActivityCompat.OnRequestPermissionsResultCallback
或者android.support.v13.app.FragmentCompat.OnRequestPermissionsResultCallback
。然后通过 shouldShowRequestPermissionRationale
方法去判断是否需要显示请求权限的理由,当申请的权限中有一个需要显示请求权限的话,那么就会弹出 dialog 。如果需要弹出 dialog ,用户取消的话那么直接回调出去,没有取消的话就让系统进行权限的申请。
走到这里 requestPermission()
的任务完成了,那么当用户同意或者不同意授予请求的权限,会进入到android.support.v4.app.ActivityCompat.OnRequestPermissionsResultCallback
或者android.support.v13.app.FragmentCompat.OnRequestPermissionsResultCallback
。再回过头看看 使用#准备
中的内容,发现在OnRequestPermissionsResultCallback
方法中调用了EasyPermissions.onRequestPermissionsResult(requestCode, permissions, grantResults, this);
。
onRequestPermissionsResult
public class EasyPermissions { /** * Handle the result of a permission request, should be called from the calling Activity's * {@link android.support.v4.app.ActivityCompat.OnRequestPermissionsResultCallback#onRequestPermissionsResult(int, String[], int[])} * method. * <p/> * If any permissions were granted or denied, the Activity will receive the appropriate * callbacks through {@link PermissionCallbacks} and methods annotated with * {@link AfterPermissionGranted} will be run if appropriate. * * @param requestCode requestCode argument to permission result callback. * @param permissions permissions argument to permission result callback. * @param grantResults grantResults argument to permission result callback. * @param object the calling Activity or Fragment. * @throws IllegalArgumentException if the calling Activity does not implement * {@link PermissionCallbacks}. */ public static void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults, Object object) { //判断传入参数是否合适 checkCallingObjectSuitability(object); //合适的话直接强转,不合适抛异常 PermissionCallbacks callbacks = (PermissionCallbacks) object; // Make a collection of granted and denied permissions from the request. ArrayList<String> granted = new ArrayList<>(); ArrayList<String> denied = new ArrayList<>(); //判断返回的权限数据,如果权限被授予,添加到granted的List中,没有被授予则添加到denied的List中 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); } } // Report granted permissions, if any. //进行回调 if (!granted.isEmpty()) { // Notify callbacks callbacks.onPermissionsGranted(requestCode, granted); } // Report denied permissions, if any. //进行回调 if (!denied.isEmpty()) { callbacks.onPermissionsDenied(requestCode, denied); } // If 100% successful, call annotated methods //如果所有请求的权限都被授予,则调用被注解的方法 if (!granted.isEmpty() && denied.isEmpty()) { runAnnotatedMethods(object, requestCode); } }}
onRequestPermissionsResult()
方法处理系统请求权限之后返回的数据,将授予和没有授予的权限通过 PermissionCallbacks
分别回调出去。最后如果请求的权限都被授予的话,则自动去调用被注解了的方法。
runAnnotatedMethods
public class EasyPermissions { /** * 通过反射的方式调用被注解了的方法 * * @param object * @param requestCode */ private static void runAnnotatedMethods(Object object, int requestCode) { Class clazz = object.getClass(); for (Method method : clazz.getDeclaredMethods()) { //是否被AfterPermissionGranted注解了的方法 if (method.isAnnotationPresent(AfterPermissionGranted.class)) { // Check for annotated methods with matching request code. AfterPermissionGranted ann = method.getAnnotation(AfterPermissionGranted.class); //requestCode和AfterPermissionGranted注解传入的requestCode相同的话 if (ann.value() == requestCode) { // Method must be void so that we can invoke it //必须是没有参数的方法 if (method.getParameterTypes().length > 0) { throw new RuntimeException("Cannot execute non-void method " + method.getName()); } try { // Make method accessible if private //如果是private的话,设置Accessible if (!method.isAccessible()) { method.setAccessible(true); } //调用 method.invoke(object); } catch (IllegalAccessException e) { Log.e(TAG, "runDefaultMethod:IllegalAccessException", e); } catch (InvocationTargetException e) { Log.e(TAG, "runDefaultMethod:InvocationTargetException", e); } } } } }}
runAnnotatedMethods()
方法通过反射方法去调用被注解了的方法,同时这个方法得满足 requestCode
相同且方法没有参数。
AfterPermissionGranted
@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.METHOD)public @interface AfterPermissionGranted { int value();}
这是一个 RUNTIME
的注解,常用使用方式就是通过反射的形式。
总结
EasyPermissions
通过注解的方式巧妙的减少了在成功请求权限之后的操作,减少的步奏是完成获取权限成功之后自动调用被注解的方法。简单的例子就如 demo 中的一样:
@AfterPermissionGranted(RC_CAMERA_PERM)public void cameraTask() { if (EasyPermissions.hasPermissions(this, Manifest.permission.CAMERA)) { // Have permission, do the thing! Toast.makeText(this, "TODO: Camera things", Toast.LENGTH_LONG).show(); } else { // Ask for one permission EasyPermissions.requestPermissions(this, getString(R.string.rationale_camera), RC_CAMERA_PERM, Manifest.permission.CAMERA); }}
没有权限的情况下请求权限,请求完之后如果成功则又自动进入这个方法,进行 Toast 操作。
运行时权限
group:android.permission-group.CONTACTS permission:android.permission.WRITE_CONTACTS permission:android.permission.GET_ACCOUNTS permission:android.permission.READ_CONTACTSgroup: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_VOICEMAILgroup:android.permission-group.CALENDAR permission:android.permission.READ_CALENDAR permission:android.permission.WRITE_CALENDARgroup:android.permission-group.CAMERA permission:android.permission.CAMERAgroup:android.permission-group.SENSORS permission:android.permission.BODY_SENSORSgroup:android.permission-group.LOCATION permission:android.permission.ACCESS_FINE_LOCATION permission:android.permission.ACCESS_COARSE_LOCATIONgroup:android.permission-group.STORAGE permission:android.permission.READ_EXTERNAL_STORAGE permission:android.permission.WRITE_EXTERNAL_STORAGEgroup:android.permission-group.MICROPHONE permission:android.permission.RECORD_AUDIOgroup: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
同时也可以通过 adb shell pm list permissions -d -g
进行查看。
运行权限也分为了一组一组的,同时申请权限的时候也是按组来申请的,也就是说app 对 READ_CONTACTS
已经授权了,当你的 app 申请 WRITE_CONTACTS
时,系统会直接授权通过 。
注意
EasyPermissions
提供的 Fragment
是 v4 包的,如果要使用android.app.Fragment
的话就需要自己添加了。
- Google-EasyPermissions
- Google-EasyPermissions源码解析
- easypermissions
- Android 6.0多个权限申请,教你使用Google easypermissions框架,100%申请成功
- easypermissions使用
- Easypermissions使用
- googlesamples之easypermissions使用
- EasyPermissions的使用方法
- googlesamples/easypermissions使用学习
- Android 权限检查EasyPermissions
- easypermissions的基本使用
- Android开源项目-Easypermissions
- Android开源项目-Easypermissions
- Android开源项目-Easypermissions
- Android开源项目-Easypermissions
- Android开源项目-Easypermissions
- Android6.0------权限申请~easypermissions
- Android开源项目-Easypermissions
- C++第2次实验报告项目4:多分数段函数求值
- N皇后问题
- php文件上传
- 设计模式的分类
- 4种方法让SpringMVC接收多个对象
- Google-EasyPermissions
- prefreesurferpipeline学习
- MySQL—函数—GROUP_CONCAT
- poj3069 Saruman's Army
- 深入浅出DNS系列(十一)- 压力测试工具与根服务器提示文件
- 数字证书及CA的扫盲介绍
- 概率分布之共轭分布
- 2.1.2队列——正式版(经过封装)
- 软件工程期中复习