程序出错报告

在模拟器上调试程序,出错代码如下:

Cursor cur = context.getContentResolver().query(            MediaStore.Audio.Media.INTERNAL_CONTENT_URI,    new String[] { MediaStore.Audio.Media.TITLE, MediaStore.Audio.Media.DURATION, MediaStore.Audio.Media.ARTIST,                        MediaStore.Audio.Media._ID, MediaStore.Audio.Media.DATA }, null, null, null);

AndroidManifest.xml已经添加了如下权限.

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>

但是有如下错误:

java.lang.RuntimeException: Unable to start activity ComponentInfo{io.github.oncealong.yplayer/io.github.oncealong.yplayer.MainActivity}: java.lang.SecurityException: Permission Denial: reading com.android.providers.media.MediaProvider uri content://media/external/audio/media from pid=8520, uid=10058 requires android.permission.READ_EXTERNAL_STORAGE, or grantUriPermission()Caused by: java.lang.SecurityException: Permission Denial: reading com.android.providers.media.MediaProvider uri content://media/external/audio/media from pid=8520, uid=10058 requires android.permission.READ_EXTERNAL_STORAGE, or grantUriPermission()

程序出错原因

最后查明是因为API过高权限访问有修改, 在API级别>=23时, 权限访问被分为三个级别, 分别为”PROTECTION_NORMAL, PROTECTION_DANGEROUS, 和PROTECTION_SIGNATURE(还有两个标志可以和SIGNATURE联合使用才有意义)”. PROTECTION_NORMAL是普通权限, 通过manifest文件在安装时被授予. PROTECTION_SIGNATURE是签名权限, 通过”检查manifest和app签名是否匹配app中声明的权限”在安装时授予. 对于 PROTECTION_DANGEROUS, 不仅需要在manifest中声明, 还需要在运行时通过requestPermissions获得, 也就是弹出来一个个对话框, 让用户确认是否授予app这些权限.
这些是常见PROTECTION_DANGEROUS权限, 如果你在程序中使用了, 那么在API>=23, 很可能会不正常工作.
ACCESS_COARSE_LOCATION
ACCESS_FINE_LOCATION
ADD_VOICEMAIL
BODY_SENSORS
CALL_PHONE
CAMERA
GET_ACCOUNTS
PROCESS_OUTGOING_CALLS
READ_CALENDAR
READ_CALL_LOG
READ_CELL_BROADCASTS
READ_CONTACTS
READ_EXTERNAL_STORAGE
READ_PHONE_STATE
READ_SMS
RECEIVE_MMS
RECEIVE_SMS
RECEIVE_WAP_PUSH
RECORD_AUDIO
SEND_SMS
USE_SIP
WRITE_CALENDAR
WRITE_CALL_LOG WRITE_CONTACTS
WRITE_EXTERNAL_STORAGE

一篇讲解Android M最新的运行时权限的文章.
[http://jijiaxin89.com/2015/08/30/Android-s-Runtime-Permission/]

错误解决办法

最后解决办法: 使用PermissionsDispatcher库,这里封装了常用操作.github地址: https://github.com/hotchemi/PermissionsDispatcher.

简易使用方法:
1. 在build.gradle(Project)中的buildscript.dependecies添加:

 dependencies {        classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'    }

2. 在build.gradle(Module)中紧挨着

apply plugin: 'com.android.application'

添加

apply plugin: 'android-apt'

然后在 dependencies中添加如下内容,其中2.1.2代表版本.

compile "com.github.hotchemi:permissionsdispatcher:2.1.2"apt "com.github.hotchemi:permissionsdispatcher-processor:2.1.2"

整体看起来就像这样,带有**的表示需要添加的:

apply plugin: 'com.android.application'**apply plugin: 'android-apt'**android {    compileSdkVersion 23    buildToolsVersion "23.0.3"    defaultConfig {        applicationId "io.github.oncealong.yplayer"        minSdkVersion 14        targetSdkVersion 23        versionCode 1        versionName "1.0"    }    buildTypes {        release {            minifyEnabled false            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'        }    }}dependencies {    compile fileTree(dir: 'libs', include: ['*.jar'])    testCompile 'junit:junit:4.12'    compile 'com.android.support:appcompat-v7:+'    **compile "com.github.hotchemi:permissionsdispatcher:2.1.2"**     **apt "com.github.hotchemi:permissionsdispatcher-processor:2.1.2"**}

3. 在需要权限的类上加上@RuntimePermissions注解, 在需要权限的方法上加上@NeedsPermission, 需要权限的方法不能是private, PermissionsDispatcher不是使用的反射, 而是使用的委托的方式. 这两个注解是必须要有的,如下:

@RuntimePermissionspublic class MainActivity extends AppCompatActivity {    ...    @NeedsPermission(Manifest.permission.CAMERA)    void showCamera() {        getSupportFragmentManager().beginTransaction()                .replace(R.id.sample_content_fragment, CameraPreviewFragment.newInstance())                .addToBackStack("camera")                .commitAllowingStateLoss();    }    ...}

4. build一下, 会自动生成一个叫MainActivityPermissionsDispatcher的类, 所有需要权限的操作都会委托给这个类. 然后在activity的onRequestPermissionsResult方法中将操作委托给MainActivityPermissionsDispatcher.onRequestPermissionsResult方法.

@Overridepublic void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {    super.onRequestPermissionsResult(requestCode, permissions, grantResults);    // NOTE: delegate the permission handling to generated method    MainActivityPermissionsDispatcher.onRequestPermissionsResult(this, requestCode, grantResults);}

搞定收工, 如果你感觉这种简单还在接受范围内. 可以去github主页看下.

更多相关文章

  1. android获取bitmap的方法
  2. android 文件 修改权限
  3. Android数据库中查找一条数据 query方法详解
  4. android 彻底退出程序方法
  5. Android实现滑动加载数据的方法
  6. 绑定方式开始服务&调用服务的方法
  7. Android 4.0允许用户禁用所有系统自带程序
  8. Android 工具类的两种写法---单例模式与静态方法

随机推荐

  1. 【多媒体编解码】Openmax IL (二)Android多
  2. android下关联源码的最简单的方法
  3. android 绯荤粺閲嶅惎涓庡叧鏈猴細java
  4. 【android】Activity、Task、应用和进程
  5. Android(安卓)4.1的新特性介绍
  6. 【iOS-cocos2d-X 游戏开发之七】整合Coco
  7. [置顶] Android(安卓)长按Listview 每个i
  8. Android娓告垙婧愮爜鍚堥泦锛堜富瑕佹槸A
  9. 安卓下载安装更新包,各个版本注意事项
  10. VPlayer – Android(安卓)下的万能视频播