基类继承方式处理Android平台动态权限申请问题

android从MM开始,添加了动态权限机制。

针对一些特别的敏感权限,要求程序主动向用户申请,用户同意之后才可以使用相关权限。

个人觉得处理添加动态权限最方便的是写一个基类(类似于PermissionBaseActivity,PermissionBaseFragment),然后让需要申请权限的界面(某个Activity或者Fragment)继承于对应的基类。

因为在基类中已经写好了申请权限的基本方法,所以继承自基类的子类,可以方便的处理权限相关的逻辑。

以Activity为例,新建基类PermissonBaseActivity继承于AppCompatActivity

public abstract class PermissionBaseActivity extends AppCompatActivity {

private Set mPermsAll = new HashSet();
private Set mPermsNeedful = new HashSet();
protected String TAG;
protected Context mContext;
protected static final int PERMISSION_REQUEST_CODE = 110;
protected FragmentManager mFragmentManager;

private int mTransactionIndex = 1;
private int getTransactionId() {
    return mTransactionIndex++;
}
private void resetTransactionId(@IntRange(from = 0) int v) {
    mTransactionIndex = v;
}

public interface IPermissionCallback {
    void onPermissionResult(@NonNull String perm, int result);
}

private static final String KEY_PERMISSION = "permission";
private final SparseArray> mPermissionMapHandler = new SparseArray<>();
private IPermissionCallback pushPermissionsHolderData(int key, String[] perms, @NonNull IPermissionCallback permissionCallback) {
    HashMap permKey = mPermissionMapHandler.get(key);
    if (permKey == null) {
        permKey = new HashMap<>();
    }
    permKey.clear();
    for (String perm: perms) {
        permKey.put(perm, permissionCallback);
    }
    mPermissionMapHandler.put(key, permKey);
    return permissionCallback;
}

private void addPermissionsHolderGuardKey(int key, @NonNull IPermissionCallback permissionCallback) {
    HashMap permKey = mPermissionMapHandler.get(key);
    if (permKey == null) {
        permKey = new HashMap<>();
    }
    permKey.put(KEY_PERMISSION, permissionCallback);
    mPermissionMapHandler.put(key, permKey);
}

private IPermissionCallback removePermissionHolder(int key, @NonNull String perm) {
    HashMap permCallback = mPermissionMapHandler.get(key);
    if (permCallback != null) {
        return permCallback.get(perm);
    }
    return null;
}

private IPermissionCallback getPermissionCallback(int key) {
    HashMap permissionMap = mPermissionMapHandler.get(key);
    for (IPermissionCallback callback: permissionMap.values()) {
        if (callback != null) {
            return callback;
        }
    }
    return null;
}

private void iteratePermissionHolder(int key) {
    HashMap permsMap = mPermissionMapHandler.get(key);
    if (permsMap == null) {
        return;
    }
    Iterator> it = permsMap.entrySet().iterator();
    Map.Entry entry;
    while (it.hasNext()) {
        entry = it.next();
        if (!entry.getKey().equals(KEY_PERMISSION)) {
            entry.getValue().onPermissionResult(entry.getKey(), PackageManager.PERMISSION_GRANTED);
        }
    }
    mPermissionMapHandler.remove(key);
}

@CallSuper
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    mContext = getApplicationContext();
    TAG = this.getClass().getSimpleName();
    mFragmentManager = getFragmentManager();
}

protected void pushPermsData(String... perms) {
    //略
}

protected void updatePermInfo() {
   //略
}

protected boolean checkPermission(String perm) {
    if (Build.VERSION.SDK_INT >= M) {
        return ActivityCompat.checkSelfPermission(mContext, perm) == PackageManager.PERMISSION_GRANTED;
    }
    return true;
}

protected boolean checkPermState() {
    updatePermInfo();
    //略
}

protected ArrayList updatePermissions(String[] perms, ArrayList granted) {
    if (perms == null) {
        return null;
    }

    ArrayList resultPerms = new ArrayList<>();
    for (String perm : perms) {
        if (ActivityCompat.checkSelfPermission(mContext, perm) == PackageManager.PERMISSION_GRANTED) {
            granted.add(perm);
        } else {
            resultPerms.add(perm);
        }
    }
    return resultPerms;
}

private void requestPermissionManage(@NonNull String[] perms, @NonNull IPermissionCallback permissionCallback) {
    int key = getTransactionId();
    if (key != -1 && (key & 0xffff0000) != 0) {
        key = 1;
        resetTransactionId(1);
    }

    if (perms.length == 1) {
        //如果只申请一个权限,调用这里
        requestSingleCompatPermission(key, perms[0], permissionCallback);
    } else {
        //申请多个权限,调用这里
        requestMultiCompatPermissions(key, perms, permissionCallback);
    }
}

private void requestMultiCompatPermissions(@IntRange(from = 0) int key, @NonNull String[] perms, @NonNull IPermissionCallback permissionCallback) {
    ArrayList granted = new ArrayList<>();
    //申请多个权限的时候,需要过滤权限,筛选出已经获得过的权限
    ArrayList needRequest = updatePermissions(perms, granted);
    if (granted.size() > 0) {
        if (needRequest.size() > 0) {
            String[] grantedArray = new String[granted.size()];
            granted.toArray(grantedArray);
            //这个稍后补充说明
            pushPermissionsHolderData(key, grantedArray, permissionCallback);
        } else {
            //如果想申请的所有权限都已经被授予过了,那么直接回调返回
            for (String perm: granted) {
                permissionCallback.onPermissionResult(perm, PackageManager.PERMISSION_GRANTED);
            }
            return;
        }
    }
    //TODO check ActivityCompat.shouldShowRequestPermissionRationale for every permission
    if (needRequest.size() > 0) {
        String[] permsArray = new String[needRequest.size()];
        needRequest.toArray(permsArray);
        addPermissionsHolderGuardKey(key, permissionCallback);
        //开始申请那些还未获得的权限
        ActivityCompat.requestPermissions(this, permsArray, key);
    }
}

private void requestSingleCompatPermission(@IntRange(from = 0) int key, @NonNull String perm, @NonNull IPermissionCallback permissionCallback) {
    if (ActivityCompat.checkSelfPermission(mContext, perm) == PackageManager.PERMISSION_GRANTED) {
        //如果要申请的权限已经被授予,直接回调返回
        permissionCallback.onPermissionResult(perm, PackageManager.PERMISSION_GRANTED);
    } else {
       //以前申请权限时,用户是否勾选过不再提示的复选框
        boolean should = ActivityCompat.shouldShowRequestPermissionRationale(this, perm);
        if (!should) {//如果勾选过,那么直接跳到APP详细信息页面
            jumpToAppDetailsDialog();
        } else {//开始申请权限
            addPermissionsHolderGuardKey(key, permissionCallback);
            ActivityCompat.requestPermissions(this, new String[]{perm}, key);
        }
    }
}
//申请权限从这里开始,String... perms就是需要申请的权限,permissionCallback是申请成功或者失败后的回调
protected void requestPermissions(IPermissionCallback permissionCallback, String... perms) {
    if (perms == null) {
        return;
    }

    if (permissionCallback == null) {
        return;
    }

    if (Build.VERSION.SDK_INT >= M) {
        //如果是MM平台以上,跳转去处理申请权限
        requestPermissionManage(perms, permissionCallback);
    } else {
        //如果MM平台之前的,直接处理回调
        for (String perm: perms) {
            permissionCallback.onPermissionResult(perm, PackageManager.PERMISSION_GRANTED);
        }
    }
}

protected void requestPermissions(IPermissionCallback permissionCallback) {
    //略
}

protected void requestPermissions() {
    //略
}

@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    updatePermInfo();
    permissionResultHandler(requestCode, permissions, grantResults);
}

private void permissionResultHandler(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    if (mPermissionMapHandler.size() > 0) {
        //这里主要是回调而已
        IPermissionCallback callback = getPermissionCallback(requestCode);
        iteratePermissionHolder(requestCode);
        for (int i = 0; i < permissions.length; i++) {
            if (callback != null) {
                callback.onPermissionResult(permissions[i], grantResults[i]);
            }
        }
    }
}

protected void jumpToAppSettings() {
    Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
    intent.setData(Uri.parse("package:" + getPackageName()));
    startActivity(intent);
}

private void jumpToAppDetailsDialog() {
    AlertDialog.Builder builder = new AlertDialog.Builder(this)
            .setTitle("Title")
            .setMessage("Message")
            .setPositiveButton("Okay", new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialog, int which) {
                    jumpToAppSettings();
                }
            })
            .setNegativeButton("Exit", new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialog, int which) {

                }
            });
    builder.create();
    builder.show();
}
}

解释下pushPermissionsHolderData(key, grantedArray, permissionCallback)
在开头的时候,定义了一个SparseArray:
private final SparseArray> mPermissionMapHandler = new SparseArray<>();

 IPermissionCallback pushPermissionsHolderData(int key, String[] perms,IPermissionCallback permissionCallback) {
   HashMap permKey = mPermissionMapHandler.get(key);
   if (permKey == null) {
       permKey = new HashMap<>();
   }
   permKey.clear();
   for (String perm: perms) {//以权限和回调接口建立键值对
       permKey.put(perm, permissionCallback);
   }
   mPermissionMapHandler.put(key, permKey);
   return permissionCallback;
 }

每次申请权限,都为这一次权限申请事件赋予一个独立的事务id : mTransactionIndex ,.

private int mTransactionIndex = 1;
private int getTransactionId() {
    return mTransactionIndex++;
}

当申请权限时,以这个自定义的mTransactionIndex 做为申请权限传入的requestCode:

int key = getTransactionId();
ActivityCompat.requestPermissions(this, permsArray, key);

这样在onRequestPermissionsResult方法中,就可以通过

HashMap permissionMap = mPermissionMapHandler.get(key);

获取到正确的权限事件映射。

在方法onRequestPermissionsResult中,获取到requestCode对应的HashMap键值对之后,就可以遍历想申请的权限,然后回调申请的结果:

private void permissionResultHandler(int requestCode, String[] permissions, @NonNull int[] grantResults) {
   if (mPermissionMapHandler.size() > 0) {
       IPermissionCallback callback = getPermissionCallback(requestCode);
       iteratePermissionHolder(requestCode);
       for (int i = 0; i < permissions.length; i++) {
           if (callback != null) {
               callback.onPermissionResult(permissions[i], grantResults[i]);
           }
      }
   }
}

大体流程就是这样,具体的使用方法如下:

   requestPermissions(new IPermissionCallback() {
               @Override
               public void onPermissionResult(@NonNull String perm, int result) {
                   Log.e(TAG, "onPermissionResult2 " + perm + " " + result);
               }
  }, Manifest.permission.RECORD_AUDIO, Manifest.permission.READ_CONTACTS, Manifest.permission.CAMERA );

不管用户最后是同意还是拒绝权限,最后都回调到 onPermissionResult(@NonNull String perm, int result) 方法。perm表示权限的名字,result是这个perm权限申请的结果,是同意(0)还是拒绝(-1)。

我使用动态权限的想法是,比如在需要录音权限的地方,这样使用

   requestPermissions(new IPermissionCallback() {
               @Override
               public void onPermissionResult(@NonNull String perm, int result) {
                   if (result == PackageManager.PERMISSION_GRANTED) {
                       //开始录音
                   } else {
                       //无法录音,添加用户提示
                   }
               }
   }, Manifest.permission.RECORD_AUDIO);

这是个人偏好的用法,分享出来。

你可能感兴趣的:(基类继承方式处理Android平台动态权限申请问题)