Android M 或以上的设备,在使用涉及隐私的安全权限时,需要动态申请,虽然不难,但写下来代码工作量也不少,而且几乎每个应用都需要用到。所以一直在探索一个要足够简单简洁优雅的处理方式,强迫症的精神指导我要拒绝一切繁琐。至于完不完美那就仁者见仁了。
一、思路:
如果在每个用到权限的地方去申请,有点繁琐,所以做法是直接在每个Activity界面显示前就把该界面所需的权限全部申请允许了,再进入正常的流程。如果有权限未被允许,开发者可以在接口中自己处理,可以直接提示并退出,或者提示权限的作用后重新发起权限申请。
二、危险权限列表:Dangerous Permissions
在Android M 或以上,以下权限需要动态申请的意思。
group:android.permission-group.CONTACTS permission:android.permission.WRITE_CONTACTS permission:android.permission.GET_ACCOUNTS permission:android.permission.READ_CONTACTS group: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_VOICEMAIL group:android.permission-group.CALENDAR permission:android.permission.READ_CALENDAR permission:android.permission.WRITE_CALENDAR group:android.permission-group.CAMERA permission:android.permission.CAMERA group:android.permission-group.SENSORS permission:android.permission.BODY_SENSORS group:android.permission-group.LOCATION permission:android.permission.ACCESS_FINE_LOCATION permission:android.permission.ACCESS_COARSE_LOCATION group:android.permission-group.STORAGE permission:android.permission.READ_EXTERNAL_STORAGE permission:android.permission.WRITE_EXTERNAL_STORAGE group:android.permission-group.MICROPHONE permission:android.permission.RECORD_AUDIO group: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
三、使用方式: 先从Activity的使用开始。
public class MainActivity extends AppCompatActivity implements PermissionInterface { private PermissionHelper mPermissionHelper; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); //初始化并发起权限申请 mPermissionHelper = new PermissionHelper(this, this); mPermissionHelper.requestPermissions(); } @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { if(mPermissionHelper.requestPermissionsResult(requestCode, permissions, grantResults)){ //权限请求结果,并已经处理了该回调 return; } super.onRequestPermissionsResult(requestCode, permissions, grantResults); } @Override public int getPermissionsRequestCode() { //设置权限请求requestCode,只有不跟onRequestPermissionsResult方法中的其他请求码冲突即可。 return 10000; } @Override public String[] getPermissions() { //设置该界面所需的全部权限 return new String[]{ Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_PHONE_STATE }; } @Override public void requestPermissionsSuccess() { //权限请求用户已经全部允许 initViews(); } @Override public void requestPermissionsFail() { //权限请求不被用户允许。可以提示并退出或者提示权限的用途并重新发起权限申请。 finish(); } private void initViews(){ //已经拥有所需权限,可以放心操作任何东西了 } }
四、其中使用到的两个类和一个接口实现: 1、Activity需要实现的接口PermissionInterface.java
/** * 权限请求接口 * Created by dway on 2018/1/10. */ public interface PermissionInterface { /** * 可设置请求权限请求码 */ int getPermissionsRequestCode(); /** * 设置需要请求的权限 */ String[] getPermissions(); /** * 请求权限成功回调 */ void requestPermissionsSuccess(); /** * 请求权限失败回调 */ void requestPermissionsFail(); } 2、工具类PermissionUtil.java /** * 动态权限工具类 * Created by dway on 2017/1/13. */ public class PermissionUtil { /** * 判断是否有某个权限 * @param context * @param permission * @return */ public static boolean hasPermission(Context context, String permission){ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { if(context.checkSelfPermission(permission) != PackageManager.PERMISSION_GRANTED){ return false; } } return true; } /** * 弹出对话框请求权限 * @param activity * @param permissions * @param requestCode */ public static void requestPermissions(Activity activity, String[] permissions, int requestCode){ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { activity.requestPermissions(permissions, requestCode); } } /** * 返回缺失的权限 * @param context * @param permissions * @return 返回缺少的权限,null 意味着没有缺少权限 */ public static String[] getDeniedPermissions(Context context, String[] permissions){ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { ArrayList<String> deniedPermissionList = new ArrayList<>(); for(String permission : permissions){ if(context.checkSelfPermission(permission) != PackageManager.PERMISSION_GRANTED){ deniedPermissionList.add(permission); } } int size = deniedPermissionList.size(); if(size > 0){ return deniedPermissionList.toArray(new String[deniedPermissionList.size()]); } } return null; } } 3、权限操作帮助类PermissionHelper.java package com.dway.permission; import android.app.Activity; import android.content.pm.PackageManager; import android.support.annotation.NonNull; /** * 动态权限帮助类 * Created by dway on 2018/1/10. */ public class PermissionHelper { private Activity mActivity; private PermissionInterface mPermissionInterface; public PermissionHelper(@NonNull Activity activity, @NonNull PermissionInterface permissionInterface) { mActivity = activity; mPermissionInterface = permissionInterface; } /** * 开始请求权限。 * 方法内部已经对Android M 或以上版本进行了判断,外部使用不再需要重复判断。 * 如果设备还不是M或以上版本,则也会回调到requestPermissionsSuccess方法。 */ public void requestPermissions(){ String[] deniedPermissions = PermissionUtil.getDeniedPermissions(mActivity, mPermissionInterface.getPermissions()); if(deniedPermissions != null && deniedPermissions.length > 0){ PermissionUtil.requestPermissions(mActivity, deniedPermissions, mPermissionInterface.getPermissionsRequestCode()); }else{ mPermissionInterface.requestPermissionsSuccess(); } } /** * 在Activity中的onRequestPermissionsResult中调用 * @param requestCode * @param permissions * @param grantResults * @return true 代表对该requestCode感兴趣,并已经处理掉了。false 对该requestCode不感兴趣,不处理。 */ public boolean requestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults){ if(requestCode == mPermissionInterface.getPermissionsRequestCode()){ boolean isAllGranted = true;//是否全部权限已授权 for(int result : grantResults){ if(result == PackageManager.PERMISSION_DENIED){ isAllGranted = false; break; } } if(isAllGranted){ //已全部授权 mPermissionInterface.requestPermissionsSuccess(); }else{ //权限有缺失 mPermissionInterface.requestPermissionsFail(); } return true; } return false; } }
OK,完成。哪个Activity需要权限就实现接口,其他用帮助类就全部搞定。