android 6.0以后,新增加了动态申请权限这一要求,具体是怎么回事呢?
1.概述
- 关于运行时权限
在Android6.0开始,App可以直接安装,App在运行时一个一个询问用户授予权限,系统会弹出一个对话框让用户选择是否授权某个权限给App(这个Dialog不能由开发者定制),当App需要用户授予不恰当的权限的时候,用户可以拒绝,用户也可以在设置页面对每个App的权限进行管理。
特别注意:这个对话框不是开发者调用某个权限的功能时由系统自动弹出,而是需要开发者手动调用,如果你直接调用而没有去申请权限的话,将会导致App崩溃。 - 哪些权限需要动态申请
正常权限: 使用时直接在清单文件中声明即可。
危险权限: 使用时需要动态申请权限。
2.申请权限工具类
申请权限的流程:
1.判断是否是 Android 6.0以上
2.判断权限(危险权限)是否申请了
3.没有申请,去申请
1.定义权限申请回掉接口
public interface PermissionListener {
// 申请成功
public void onSucceed();
// 申请失败
public void onFiled();
}
2.申请权限的工具类
public class PermissionUtils {
//判断版本是否是6.0
public static boolean isVersionCodeM() {
return Build.VERSION.SDK_INT > Build.VERSION_CODES.M;
}
/**
*
* @param context
* @param permissions
* @return 获取未授权的集合
*/
public static List<String> getDeniedList(Context context,String... permissions){
//创建一个未授权的集合
List<String> deniedList =new ArrayList<>();
//如果传入为null,返回空的集合
if (permissions.length==0) {
return deniedList;
}
for (String permission : permissions) {
int permissionCode = ContextCompat.checkSelfPermission(context, permission);
if (permissionCode== PackageManager.PERMISSION_DENIED) {
//将没有授权的添加到集合
deniedList.add(permission);
}
}
return deniedList;
}
}
3.申请权限的帮助类 (无界面的fragment)
public class PermissionFragment extends Fragment {
private static final int REQUESTCODE = 66;
private static final int REQUEST_PERMISSION_SETTING = 55;
private PermissionListener mPermissionListener;
private Activity mActivity;
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Fragment具有属性retainInstance,默认值为false。当设备旋转时,fragment会随托管activity一起销毁并重建。调用setRetainInstance(true)方法可保留fragment,
setRetainInstance(true);
}
public void setPermissionListener(PermissionListener permissionListener) {
this.mPermissionListener = permissionListener;
}
@RequiresApi(api = Build.VERSION_CODES.M)
public void requestPermissions(Activity activity, String[] permission) {
this.mActivity = activity;
requestPermissions(permission, REQUESTCODE);
}
@RequiresApi(api = Build.VERSION_CODES.M)
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == REQUESTCODE) {
// 获取未申请的权限列表
List<String> deniedPermissions = PermissionUtils.getDeniedList(mActivity, permissions);
if (deniedPermissions.size() > 0) {
// 执行失败的方法
onFailed(permissions);
} else {
// 执行成功的方法
onSucceed();
}
}
}
/**
* 成功时回调方法
*/
private void onSucceed() {
if (mPermissionListener != null) {
mPermissionListener.onSucceed();
}
}
@RequiresApi(api = Build.VERSION_CODES.M)
private void onFailed(String[] permissions) {
for (int i = 0; i < permissions.length; i++) {
// 用户拒绝是true 用户选择不再提示是:false
if (!shouldShowRequestPermissionRationale(permissions[i])) {
new AlertDialog.Builder(mActivity)
.setTitle("权限被拒绝")
.setMessage("权限管理-->打开拒绝的权限")
.setPositiveButton("去打开", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
openSetting();
}
})
.setNegativeButton("取消", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
mPermissionListener.onFiled();
}
})
.show();
return;
}
}
mPermissionListener.onFiled();
}
/**
* 打开应用设置页面
*/
private void openSetting() {
Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
Uri uri = Uri.fromParts("package", mActivity.getPackageName(), null);
intent.setData(uri);
startActivityForResult(intent, REQUEST_PERMISSION_SETTING);
}
@Override
public void onDestroy() {
// 销毁对象,防止内存泄漏
mActivity = null;
mPermissionListener = null;
super.onDestroy();
}
}
4.申请权限的帮助类
/**
* Created by LiMing on 2018/4/25.
* QQ:1002464056
* Email: 1002464056@qq.com
* Version:1.0
*/
public class XPermission {
private Activity mActivity;
private PermissionFragment mPermissionFragment;
private static final String TAG = "XPermission";
private String[] mPermissions;
public XPermission(Activity activity) {
this.mActivity = activity;
mPermissionFragment = getPermissionFragment(activity);
}
private PermissionFragment getPermissionFragment(Activity activity) {
//获取权限的fragment
PermissionFragment permissionFragment = findPermissionFragment(activity);
boolean isNewInstance = (permissionFragment == null);
if (isNewInstance) {
permissionFragment = new PermissionFragment();
FragmentManager fragmentManager = activity.getFragmentManager();
fragmentManager.beginTransaction()
.add(permissionFragment, TAG)
.commitAllowingStateLoss();
fragmentManager.executePendingTransactions();
}
return permissionFragment;
}
/**
* 获取权限fragment
*
* @param activity
* @return
*/
private PermissionFragment findPermissionFragment(Activity activity) {
return (PermissionFragment) activity.getFragmentManager().findFragmentByTag(TAG);
}
/**
* 要申请的权限组
*
* @param permissions
* @return
*/
public XPermission permissions(String... permissions) {
mPermissions = permissions;
return this;
}
/**
* 申请权限
*
* @param permissionListener
*/
@RequiresApi(api = Build.VERSION_CODES.M)
public void request(PermissionListener permissionListener) {
mPermissionFragment.setPermissionListener(permissionListener);
// 1.判断版本
if (!PermissionUtils.isVersionCodeM()) {
// 版本6.0一下,直接回调成功方法
permissionListener.onSucceed();
return;
}
// 版本6.0及以上
// 2.获取未授权的列表
List<String> deniedList = PermissionUtils.getDeniedList(mActivity, mPermissions);
if (deniedList.size() > 0) {
// 3.去申请权限
mPermissionFragment.requestPermissions(mActivity, deniedList.toArray(new String[deniedList.size()]));
} else {
permissionListener.onSucceed();
}
}
}
5.在MainActivity中调用
public class MainActivity extends AppCompatActivity {
@RequiresApi(api = Build.VERSION_CODES.M)
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
//点击事件
@RequiresApi(api = Build.VERSION_CODES.M)
public void click(View view) {
new XPermission(this)
.permissions(Manifest.permission.CAMERA)
.request(new PermissionListener() {
@Override
public void onSucceed() {
// TODO
Toast.makeText(MainActivity.this,"授权成功",Toast.LENGTH_SHORT).show();
}
@Override
public void onFiled() {
Toast.makeText(MainActivity.this,"授权失败",Toast.LENGTH_SHORT).show();
}
});
}
}
简单的封装基本可以满足使用,代码易懂,有特殊需求完全可以去二次封装,附上链接地址https://github.com/CatEatFishs/XPermission/tree/v1.0
感谢@刘付文 的博客