需求
现在android版本出现到了7.0,今后高版本的android肯定会占据市场的主流,所以在我们的应用中进行运行时处理,也是势在必行的了。
引用郭霖对android运行时权限的总结,一共9组24个权限,只有在android6.0 及以上的android机上使用到这些权限的时候,才需要进行运行时权限处理.
使用场景
前提:应用运行到android 6.0 及以上的android机上(低版本的android机不用进行运行时权限处理);
1.项目的targetSdkVersion < 23 , 即应用没有兼容android6.0及以上
此时应用运行到android6.0 及以上的android机上是不需要进行运行时权限处理的。系统会按照默认的权限加载方式加载。
2.targetSdkVersion >=23,但是是从小于23的版本升级上来的
及应用以前不兼容android6.0及以上版本,但是现在升级后兼容了android6.0及以上版本。
实际场景:手机之前安装了低版本(不兼容android6.0)的应用,不卸载直接升级新版本(兼容了android6.0)的。这种情况
android会默认将应用申请的权限全部授权
但是,如果你是先卸载之前低版本的应用,再安装高版本的应用,那就需要进行运行时权限处理了。
3.targetSdkVersion >=23,应用兼容android6.0及以上
此时就需要进行运行时权限处理了,需要提一下,即使是在代码中处理的运行时权限,也是需要在manifest中注册的
郭霖CSDN运行时权限公开课地址:http://edu.csdn.net/course/detail/3539
郭霖运行时权限微信推荐文章:http://chuansong.me/n/1017834351332
下面我将郭霖公开课的代码截屏如下:
原生方式实现
基本用法,申请单个权限
- 高级用法,申请一组权限
封装框架
郭神提供了三种实现思路
1.新建一个PermissionActivity,设置成透明的,所有的权限操作都在这个activity中进行,授权后在finish掉,回到原来的activity。
2.参考第三方开源运行时权限处理框架RxPermission
github地址:注意它是要结合RxJava一起使用的,但是RxJava有RxJava1和RxJava2两个库
所以RxPermission也有对应的两个库
RxPermission1:https://github.com/tbruyelle/RxPermissions
RxPermission2https://github.com/sirencode/RxPermissions2
这种的处理方法是,新建一个RxPermissionFragment 去集成 Fragment,因为Fragment里面也有运行时权限处理的方法,就是上面讲到的原生实现中涉及到的方法,并且这个RxPermissionFragment 利用了Fragment的特性,它是没有界面没有大小的,只用来处理运行时权限。
3.利用BaseActivity自己封装运行时权限
android源码中用0和-1来表示授权是否成功,0表示获取授权成功,-1表示获取授权失败。
PackageManager.PERMISSION_GRANTED = 0 ;
PackageManager.PERMISSION_DENIED= -1 ;
封装实战
实现思路
代码很简单,重点是学习这种封装的思路
1.项目中所有的Activity都继承BaseActivity
为了项目的可扩展性,一般的项目都是这样的。如果你的项目不是这样写的,自己赶紧改过来吧。2.将运行时权限检测写到BaseActivity中
3.提供授权成功和授权失败的回调接口
4.为了能够在非Activity中使用,使用Activity管理器提供栈顶Activity
实现代码
说一句,郭神在视频中说,不提供源码,是因为编程是个需要动手的过程,只看和复制别人的代码是很难提高的
- 1.BaseActivity,运行时权限处理
public class BaseActivity extends AppCompatActivity {
private static final String TAG = "BaseActivity";
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ActivityCollector.addActivity(this);
}
@Override
protected void onDestroy() {
super.onDestroy();
ActivityCollector.removeActivity(this);
}
private static PermissionListener mListener;
/**
* 请求运行时权限
*
* @param permissions
* @param listener
*/
public static void requestRuntimePermission(String[] permissions, PermissionListener listener) {
try {
Activity topActivity = ActivityCollector.getTopActivity();
if (topActivity == null) {
return;
}
mListener = listener;
List<String> permissionList = new ArrayList<>();
for (String permission : permissions) {
if (ContextCompat.checkSelfPermission(topActivity, permission) != PackageManager.PERMISSION_GRANTED) {
permissionList.add(permission);
}
}
if (!permissionList.isEmpty()) {
ActivityCompat.requestPermissions(topActivity, permissionList.toArray(new String[permissionList.size()]), 1);
} else {
//授权成功
mListener.onGranted();
}
} catch (Exception e) {
e.printStackTrace();
Log.e(TAG, "requestRuntimePermission: "+e.getMessage());
}
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
switch (requestCode) {
case 1:
//有权限被拒绝
if (grantResults.length > 0) {
List<String> deniedPermissions = new ArrayList<>();
for (int i = 0; i < grantResults.length; i++) {
int grantResult = grantResults[i];
String permission = permissions[i];
if (grantResult != PackageManager.PERMISSION_GRANTED) {
deniedPermissions.add(permission);
}
}
//全部授权成功
if (deniedPermissions.isEmpty()) {
mListener.onGranted();
} else {
mListener.onDenied(deniedPermissions);
}
}
break;
default:
break;
}
}
}
- 2.授权回调接口
public interface PermissionListener {
//授权,同意
void onGranted();
//拒绝
void onDenied(List<String> deniedPermission);
}
- 3.Activity控制器
public class ActivityCollector {
private static List<Activity> activityList = new ArrayList<>();
public static void addActivity(Activity activity){
activityList.add(activity);
}
public static void removeActivity(Activity activity){
activityList.remove(activity);
}
//获取当前栈顶activity
public static Activity getTopActivity(){
if (activityList.isEmpty()){
return null;
}else {
return activityList.get(activityList.size()-1);
}
}
public static void finishAll(){
for (Activity activity : activityList) {
if (!activity.isFinishing()){
activity.finish();
}
}
}
}
- 注意
在非Activity中使用requestRuntimePermission()方法时需要在前面加上类名,如下:
BaseActivity.requestRuntimePermission(...);
requestRuntimePermission()方法里面的try–catch,加不加都可以。
课程中提到的一些小知识点
1.访问应用包名下的目录,可以不用申请权限
/data/data/包名
2.访问应用的缓存目录,getExternalCacheDir();
3.访问应用的重要文件存储目录,getExternalFilesDir(str);
str=”“,表files的根目录;
str=”adc”,表示files下的abc目录,没有就创建。
4.访问应用的包名目录,getDataDirectory();