Android6.0权限分配终极解决方案
来源:互联网 发布:sftp指定端口 编辑:程序博客网 时间:2024/06/02 05:10
1、问题描述
如下一段代码,在Android 5.0设备运行时,可以得到正确结果,但在Android 6.0以上设备运行时,提示没有读写权限。但AndroidManifest文件中已经设置过权限了。
错误提示信息是这样的:
Caused by: java.lang.SecurityException: Permission Denial: reading com.android.providers.media.MediaProvider uri content://media/external/audio/media from pid=3508, uid=10078 requires android.permission.READ_EXTERNAL_STORAGE, or grantUriPermission()
Activity代码
public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Cursor cursor = getContentResolver().query(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, null, null, null, null); cursor.moveToFirst(); do { String title = cursor.getString(cursor.getColumnIndex("title")); Log.e("TITLE",title); }while (cursor.moveToNext()); }}
AndroidManifest代码
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.lenovo.permissiontest"> <application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/AppTheme"> <activity android:name=".MainActivity"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/></manifest>
2、问题诊断
众所周知,我们在做Android开发时,经常会用到一些系统的权限,比如读写外部存储、读写联系人信息、调用电话短信、访问网络等。在Android 6.0之前,对于这些权限调用的声明,只需要在AndroidManifest文件中声明即可,就像下面这样:
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/><uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
用户在安装应用时,会提示该程序总共用到哪些权限,但用户没有选择权,只有知情权,那么安全问题就随之而来。所以在android 6.0 棉花糖版本之后,系统不会在软件安装的时候就赋予该app所有其申请的权限,对于一些危险级别的权限,app需要在运行时一个一个询问用户授予权限。这就是所谓的“权限动态授权”。
那么哪些权限是危险权限呢?下表所示即为危险权限,这些权限都必须在应用内部经用户动态授权才能使用。
3、问题解决
动态权限分配,通过代码如何实现呢?请看下面代码。
Activity代码
public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); //检查当前权限(若没有该权限,值为-1;若有该权限,值为0) int hasReadExternalStoragePermission = ContextCompat.checkSelfPermission(getApplication(),Manifest.permission.READ_EXTERNAL_STORAGE); Log.e("PERMISION_CODE",hasReadExternalStoragePermission+"***"); if(hasReadExternalStoragePermission== PackageManager.PERMISSION_GRANTED){ obtainMediaInfo(); }else{ //若没有授权,会弹出一个对话框(这个对话框是系统的,开发者不能自己定制),用户选择是否授权应用使用系统权限 ActivityCompat.requestPermissions(this,new String[]{Manifest.permission.READ_EXTERNAL_STORAGE},1); } } //用户选择是否同意授权后,会回调这个方法 @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { if(requestCode==1){ if(permissions[0].equals(Manifest.permission.READ_EXTERNAL_STORAGE)&&grantResults[0]==PackageManager.PERMISSION_GRANTED){ //用户同意授权,执行读取文件的代码 obtainMediaInfo(); }else{ //若用户不同意授权,直接暴力退出应用。 // 当然,这里也可以有比较温柔的操作。 finish(); } } } //将之前获取音乐信息的代码单独封装到了一个方法里面 private void obtainMediaInfo() { Cursor cursor = getContentResolver().query(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, null, null, null, null); cursor.moveToFirst(); do { String title = cursor.getString(cursor.getColumnIndex("title")); Log.e("TITLE",title); }while (cursor.moveToNext()); }}
总结
这里主要用到两个方法
- ActivityCompat.requestPermissions()
- onRequestPermissionsResult()
ActivityCompat.requestPermissions()方法有3个参数:
第1个参数,当前上下文环境;
第2个参数,需要授权的字符串数组;
第3个参数,请求码requestCode,在回调方法中会用到。
onRequestPermissionsResult()是个回调方法,也就是说在用户点击“允许”或“拒绝”按钮后,才会调用。这个方法也有3个参数:
第1个参数,请求码,对应上述方法的第3个参数;
第2个参数,请求权限数组;
第3个参数,请求权限的结果数组。
详细使用方法请看上方代码,注释较为详细。
至此,我们已经完成了单个权限授权的代码。但是,距离完美还差那么一点点,比如:
- 如果我们想要一次性进行多次授权呢?
- 如果用户选择了不再弹出之后呢?
请继续往下看
4、更优雅的解决方案
Android6.0提出了如此周到、复杂的权限处理方式,对用户而言是好事,对程序员而言是极大的繁琐。
幸运的是我们有github,早已有人开发了第三方插件。
印度人写的第三方插件(点击查看)
https://github.com/pankaj89/PermissionHelper
build.gradle中编译
compile ‘com.master.android:permissionhelper:1.3’
github链接里已经写了详细的使用步骤,我也写了个例子,亲测非常好用。代码附上。
public class HelloActivity extends AppCompatActivity { private String TAG = "HelloActivity"; private PermissionHelper permissionHelper; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_hello); permissionHelper = new PermissionHelper(this, new String[]{Manifest.permission.CAMERA, Manifest.permission.WRITE_EXTERNAL_STORAGE}, 100); permissionHelper.request(new PermissionHelper.PermissionCallback() { @Override public void onPermissionGranted() { //全都授权 Log.e(TAG,"onPermissionGranted..."); } @Override public void onIndividualPermissionGranted(String[] grantedPermission) { //某个授权 Log.e(TAG,"onIndividualPermissionGranted() called with: grantedPermission = [" + TextUtils.join(",",grantedPermission) + "]"); } @Override public void onPermissionDenied() { //某个拒绝 Log.e(TAG,"onPermissionDenied..."); } @Override public void onPermissionDeniedBySystem() { //用户选择了"不再询问"后,点击"拒绝按钮",执行此方法 Log.e(TAG,"onPermissionDeniedBySystem..."); } }); } @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); if (permissionHelper != null) { permissionHelper.onRequestPermissionsResult(requestCode, permissions, grantResults); } }}
- Android6.0权限分配终极解决方案
- Android6.0权限申请解决方案
- 一个Android6.0权限解决方案
- Android6.0运行时权限解决方案
- Android6.0运行时权限解决方案
- 轻量级Android6.0动态权限解决方案
- 轻量级Android6.0动态权限解决方案
- Android6.0运行时权限的便捷解决方案
- 关于Android6.0系统动态权限管理的解决方案
- Android6.0 权限申请无法开启悬浮窗权限,无权限开启悬浮窗解决方案
- Android6.0权限开发
- Android6.0权限管理
- Android6.0动态权限
- Android6.0权限申请
- android6.0 权限管理
- Android6.0系统权限
- android6.0权限管理
- Android6.0权限管理
- JMS(四)--Spring和ActiveMQ整合的完整实例
- SPOJ3890 莫比乌斯
- Eclipse调试时出现source not found的问题
- 动态规划:从新手到专家
- HashMap的工作原理
- Android6.0权限分配终极解决方案
- 2017上海ACM ECL-final 总结
- Windows7操作系统的安装
- MATLAB图像旋转源代码
- 栈(先进后出)
- 关于centOS6.5安装问题
- jquery性能优化
- Codeforces Round #452 (Div. 2) B. Months and Years
- HDOJ 1004 Let the Balloon Rise 让气球升起来