对于app的现状,应用的权限申请必不可少,不同的功能都可能用的上,所以把权限模块抽出来最好不过,另外附上提交maven仓库的脚本,如果公司本身有maven的仓库的话,可以用过脚本提交到maven仓库,到时候用的时候依赖就可以了。去查看github的时候,其实已经有蛮多的优秀权限申请的库了,本着公司少用开源库的原则,只好自己写一套了。
权限分组
一般系统分三种权限,一种是正常权限(不需要申请),另外一种是危险权限(需要申请),特殊权限(需要申请),具体介绍如下链接:
https://developer.android.google.cn/guide/topics/security/permissions#normal-dangerous
然后危险权限和对应的权限组如下:
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
在同一个权限组中,只要请求其中一个就可以了。
根据官方的例子:
// Here, thisActivity is the current activity
if (ContextCompat.checkSelfPermission(thisActivity,
Manifest.permission.READ_CONTACTS)
!= PackageManager.PERMISSION_GRANTED) {
// Should we show an explanation?
if (ActivityCompat.shouldShowRequestPermissionRationale(thisActivity,
Manifest.permission.READ_CONTACTS)) {
// Show an expanation to the user *asynchronously* -- don't block
// this thread waiting for the user's response! After the user
// sees the explanation, try again to request the permission.
} else {
// No explanation needed, we can request the permission.
ActivityCompat.requestPermissions(thisActivity,
new String[]{Manifest.permission.READ_CONTACTS},
MY_PERMISSIONS_REQUEST_READ_CONTACTS);
// MY_PERMISSIONS_REQUEST_READ_CONTACTS is an
// app-defined int constant. The callback method gets the
// result of the request.
}
}
上面是官方的例子,权限申请有几个状态,首先判断权限是否授权,即
if (ContextCompat.checkSelfPermission(thisActivity,
Manifest.permission.READ_CONTACTS)
!= PackageManager.PERMISSION_GRANTED) {
当未授权时执行代码,然后在未授权的情况下有三种状态:
1、第一次申请的情况
2、用户已经拒绝过权限申请(rationnal)
3、用户拒绝并且选择了不再提示按钮
所以我们抽出来的功能要把这个三种情况覆盖,当第一次申请的时候,我直接提示授权框继续申请权限,当用户拒绝后,我们应该提示一个合理性提示框,向用户解释需要申请权限即rationnal dialog。如果用户拒绝并且选择不再提示的时候,权限的申请只能跳转到设置页面,然后用户手动允许权限功能了。
抽出权限申请的功能类,要最大化的方便使用,所以我定义一个方法的调用类PermissionManager,该类只提供三个方法
public static void requestPermission(android.app.Fragment holder, RationalInterface rationalInterface, int requestCode,
String... permissions)
public static void requestPermission(Fragment holder, RationalInterface rationalInterface, int requestCode, String... permissions)
public static void requestPermission(Activity holder, RationalInterface rationalInterface, int requestCode, String... permissions)
对于rational的情况对外提供接口,因为对于一些项目是需要展示不一样的ui的。
然后调用结束之后,会在宿主activity/fragmeng中回调相应的方法,成功、失败、不再提示
@PermissionSuccess
public void success(int requestCoe, String[] permissions) {
Log.i(TAG, "PermissionSuccess");
}
@PermissionFail
public void fail(int requestCoe, String[] permissions) {
Log.i(TAG, "PermissionFail");
}
@PermissionAlwayDenied
public void gotoSetting(int requestCoe, String[] permissions) {
然后继续分解,在执行requestPermission过程中
/**
* activity权限请求
* 1先检查有哪些权限没授权,如有未授权,再检查这个未授权是不是rational,
* 2再核查是不是用户拒绝并且点击不再提示,只能通过onRequestPermissionsResult去核实
* 3如果没有未授权的 success
*
* @param holder
* @param requestCode
* @param permissions
*/
public static void requestPermission(Activity holder, RationalInterface rationalInterface, int requestCode, String... permissions) {
RequestPermission requestPermission = new RequestPermission.Builder(holder, requestCode, permissions)
.setRationalInterface(rationalInterface).builder();
if (!hasPermission(holder, permissions)) {
List rationalList = getNationalPermission(requestPermission);
//触发rationnal回调
if (rationalList.size() > 0) {
requestPermission.getRationalInterface().callback(requestPermission);
} else {
//走正常requestPermssion,这里包含了2
requestPermission.getPermissionHelper().requesetPermissions(requestCode, permissions);
}
return;
}
//权限通过
resolverAnnotateSuccess(holder, requestCode, permissions);
}
先是判断是否有权限,如果权限全部通过,则会走@PermissionSuccess的方法,如果有权限需要申请,先判断该权限是否已经被拒绝过,如果已经被拒绝过则走rationnal的回调过程,如果未拒绝或拒绝选择了不再提示,则走 requestPermission.getPermissionHelper().requesetPermissions(requestCode, permissions);
下一步是正确的权限申请方法,因为宿主可能是activity或者fragment,他们的处理情况不一样,所以要分情况进行处理,由此建立了基类:
public abstract class AbstractPermissionHelper<T> {
/**
* 是否rationnal
* @param perm
* @return
*/
public abstract boolean shouldShowRequestPermissionRationale(String perm);
/**
* 权限请求
* @param requestCode
* @param perm
*/
public abstract void requesetPermissions(int requestCode, String[] perm);
/**
* 是否选择不再提示
* @param perms
* @return
*/
public abstract boolean somePermissionAlwayDenied( List<String> perms);
public abstract T getHolder();
public abstract Context getContext();
}
activity、fragment、v4.fragment分别具体实现方法
下一步,因为选择了不再提示的时候,需要通过宿主activit或者fragmeng的
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
回调方法才能判断,又因为不想在调用的时候麻烦,所以就单独建立了一个activity并且设置透明效果,单独从事权限申请的结果回调工作。代码如下:
public class PermissionActivity extends AppCompatActivity {
private static final String KEY_PERMISSION = "KEY_PERMISSION";
private static AbstractPermissionHelper permissionHelper;
public static void activityRequestPermission(AbstractPermissionHelper permissionHelper, String[] permissions) {
PermissionActivity.permissionHelper = permissionHelper;
Intent intent = new Intent(permissionHelper.getContext(), PermissionActivity.class);
intent.putExtra(KEY_PERMISSION, permissions);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
permissionHelper.getContext().startActivity(intent);
}
@RequiresApi(api = Build.VERSION_CODES.M)
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
String[] permissions = getIntent().getStringArrayExtra(KEY_PERMISSION);
requestPermissions(permissions, 1);
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
PermissionManager.onRequestPermissionsResult(requestCode, permissions, grantResults, permissionHelper);
finish();
}
到最后面,当用户选择了不再提示按钮时,我们需要跳转到设置页面进行手动授权,至此,框架封装结束了,在调用页调用一下方法即可:
PermissionManager.requestPermission(MainActivity.this, new RationalDialog(), 1, Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.READ_CONTACTS);
附上项目github,欢迎star和鼓励
https://github.com/liangzs/permissionDemo
网友评论