Android 在Manifest中设置权限无效的原因(6.0 新特性就是动态权限)

本文介绍了解决Android 6.0及以上版本设备上应用程序无法正常读取SD卡内图片的问题。文章提供了两种解决方法:一是通过调整targetSdkVersion到6.0以下以避免动态权限请求;二是实现运行时动态请求读写权限。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.问题描述

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

我知道要显示手机SD卡里面的图片需要,读取权限,在Manifest里面添加了以上权限后,仍然无法显示图片。具体代码如下:

        String picturePath=sdPath+"/a.png";
        File file = new File(picturePath);
        log("picturePath:"+picturePath);
        if (file.exists()){
            Bitmap bm = BitmapFactory.decodeFile(picturePath);
            log("bm:"+bm);
            imageView.setImageBitmap(bm);
            log("文件存在");
        }else {
            log("文件不存在");
        }

经过打印log发现程序是能判断文件时存在的,但bm始终未null。

2.解决方法

经过多番努力,终于在这篇文章中找到了解决方案

https://blog.youkuaiyun.com/ldhj1993/article/details/72668734

我总结一下就是

6.0 有个新特性就是动态权限,也就是说 write 和 read 的权限是要在代码中获取的。

解决方法:

第一种:如果图省事,把targetSdkVersion改到6.0(23)以下就行了。

    compileSdkVersion 25
    buildToolsVersion "28.0.1"

    defaultConfig {
        applicationId "com.innovpower.readimagedemo"
        minSdkVersion 14
        targetSdkVersion 22
        versionCode 1
        versionName "1.0"
    }

第二种:动态获取权限

具体操作还有点复杂,不是一两句代码能搞定的。可以参考这篇博客https://blog.youkuaiyun.com/lin_dianwei/article/details/79025324,亲测有效。

 

<think>我们正在讨论Android动态申请运行时权限,解决文件操作时的EACCESPermissiondenied问题。参考引用内容,我们可以总结以下步骤:1.AndroidManifest.xml中声明权限(WRITE_EXTERNAL_STORAGE和READ_EXTERNAL_STORAGE)。2.对于Android10及以上版本,在<application>标签中添加android:requestLegacyExternalStorage="true"以启用旧版存储模式。3.在代码中动态申请权限(针对Android6.0及以上版本)。4.对于Android11(API30)及更高版本,如果需要访问所有文件(管理外部存储),则必须请求MANAGE_EXTERNAL_STORAGE权限,并引导用户到设置页面开启。下面详细说明动态申请运行时权限的步骤:###步骤1:在AndroidManifest.xml中声明权限```xml<uses-permissionandroid:name="android.permission.READ_EXTERNAL_STORAGE"/><uses-permissionandroid:name="android.permission.WRITE_EXTERNAL_STORAGE"/><!--针对Android11及以上,如果需要管理所有文件,还需要声明以下权限--><uses-permissionandroid:name="android.permission.MANAGE_EXTERNAL_STORAGE"android:minSdkVersion="30"/>```###步骤2:为Android10及以上应用启用旧版存储模式在`<application>`标签中添加:```xml<application...android:requestLegacyExternalStorage="true"...>...</application>```###步骤3:动态申请权限(针对Android6.0+)在需要访问存储的地方,检查权限并申请。```java//定义权限请求码privatestaticfinalintREQUEST_STORAGE_PERMISSION=1;//需要申请的权限数组privateString[]permissions={Manifest.permission.READ_EXTERNAL_STORAGE,Manifest.permission.WRITE_EXTERNAL_STORAGE};//检查并申请权限privatevoidcheckStoragePermissions(){//检查是否已经授予权限if(ContextCompat.checkSelfPermission(this,Manifest.permission.WRITE_EXTERNAL_STORAGE)!=PackageManager.PERMISSION_GRANTED){//没有权限,申请权限ActivityCompat.requestPermissions(this,permissions,REQUEST_STORAGE_PERMISSION);}else{//已经有权限,执行文件操作doFileOperation();}}//处理权限申请结果@OverridepublicvoidonRequestPermissionsResult(intrequestCode,@NonNullString[]permissions,@NonNullint[]grantResults){super.onRequestPermissionsResult(requestCode,permissions,grantResults);if(requestCode==REQUEST_STORAGE_PERMISSION){//检查是否所有权限都被授予if(grantResults.length>0&&grantResults[0]==PackageManager.PERMISSION_GRANTED&&grantResults[1]==PackageManager.PERMISSION_GRANTED){doFileOperation();}else{//权限被拒绝,提示用户Toast.makeText(this,"权限被拒绝,无法访问文件",Toast.LENGTH_SHORT).show();}}}```###步骤4:处理Android11(API30)及以上版本的管理所有文件权限Android11开始,普通存储权限(READ/WRITE_EXTERNAL_STORAGE)不能访问所有文件,如果需要管理所有文件,则必须使用MANAGE_EXTERNAL_STORAGE权限。```java//检查是否为Android11及以上if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.R){if(!Environment.isExternalStorageManager()){//引导用户到设置页面开启所有文件管理权限Intentintent=newIntent(Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION);intent.setData(Uri.parse("package:"+getPackageName()));startActivityForResult(intent,REQUEST_MANAGE_EXTERNAL_STORAGE);}else{//已经获得管理所有文件的权限doFileOperation();}}else{//Android11以下版本,使用之前的动态权限申请checkStoragePermissions();}```然后在`onActivityResult`中处理结果:```java@OverrideprotectedvoidonActivityResult(intrequestCode,intresultCode,@NullableIntentdata){super.onActivityResult(requestCode,resultCode,data);if(requestCode==REQUEST_MANAGE_EXTERNAL_STORAGE){if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.R){if(Environment.isExternalStorageManager()){doFileOperation();}else{Toast.makeText(this,"授予所有文件访问权限,功能受限",Toast.LENGTH_SHORT).show();}}}}```###注意事项1.动态申请权限时,需要处理用户拒绝权限的情况,可以提示用户该权限的必要性,并再次申请。2.Android11及以上,使用MANAGE_EXTERNAL_STORAGE权限时,需要在GooglePlay中声明该权限的使用目的,否则可能被拒绝上架。3.对于Android10的旧版存储模式,它只是一个过渡方案,在Android11及以上,如果targetSdkVersion为30或更高,则旧版存储模式无效,需要迁移到分区存储(ScopedStorage)模式。通过以上步骤,我们可以根据不同的Android版本动态申请权限,解决文件操作时的权限问题[^1][^2][^5]。§§相关问题§§1.Android权限机制有哪几种?例如普通权限和危险权限等2.如何迁移应用到Android11的分区存储模式?3.如何自定义权限申请对话框以提高用户授权率?</think> ### Android动态申请运行时权限解决文件操作权限异常 在Android中解决`EACCES (Permission denied)`文件操作失败问题,需按系统版本动态处理权限。以下是完整流程: --- #### **1. 基本权限声明** 在`AndroidManifest.xml`中声明权限(所有版本必需): ```xml <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> ``` --- #### **2. Android 5.0~9.0 (API 21~28) 动态权限申请** 使用运行时请求,需处理用户授权结果: ```java // 检查权限状态 if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { // 弹出权限请求对话框 ActivityCompat.requestPermissions( this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, REQUEST_CODE_STORAGE // 自定义请求码(如100) ); } // 处理授权结果 @Override public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { if (requestCode == REQUEST_CODE_STORAGE) { if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { // 权限已授予,执行文件操作 writeToFile(); } else { // 权限被拒绝,提示用户 Toast.makeText(this, "存储权限被拒绝,无法保存文件", Toast.LENGTH_SHORT).show(); } } } ``` --- #### **3. Android 10+ (API 29+) 特殊处理** 添加`requestLegacyExternalStorage`属性绕过分区存储限制: ```xml <application android:requestLegacyExternalStorage="true" ... > </application> ``` > **注意**:Android 11及更高版本中此属性作用受限,需额外处理[^1][^2]。 --- #### **4. Android 11+ (API 30+) 管理所有文件权限** 对完整存储访问需引导用户至系统设置页: ```java if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { if (!Environment.isExternalStorageManager()) { // 跳转系统设置页 Intent intent = new Intent(Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION); intent.setData(Uri.parse("package:" + getPackageName())); startActivityForResult(intent, REQUEST_CODE_MANAGE_STORAGE); } else { // 已有权限 } } ``` --- #### **5. 最佳实践建议** 1. **兼容性检查**: ```java if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { // 动态请求逻辑 } ``` 2. **解释必要性**(可选): 在请求权限前调用`shouldShowRequestPermissionRationale()`解释为何需要权限。 3. **降级处理**: 捕获文件操作异常并提示友好错误: ```java try { FileOutputStream fos = new FileOutputStream(filePath); } catch (FileNotFoundException e) { Log.e("FileError", "文件访问失败: " + e.getMessage()); // 检查权限状态并重试请求 } ``` --- **关键点总结**: 1. 声明基础读写权限 2. 动态请求运行时权限(API 23+) 3. Android 10+启用`requestLegacyExternalStorage` 4. Android 11+引导用户开启「所有文件访问」[^5] 5. 按需处理降级场景 通过分版本阶梯式处理,可彻底解决`EACCES (Permission denied)`文件访问问题[^1][^2][^5]。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值