You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android 11及以上版本从相册选图片提示权限被拒问题求助

Android 11+ 相册选图权限拒绝问题解决指南

问题核心

已在Manifest配置对应权限,但Android 11及以上版本从相册选图时仍提示"access denied",目标是完成选图、裁剪并转换为Bitmap。

权限配置确认(当前配置没问题,无需修改)

<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"
    android:maxSdkVersion="32" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
    android:maxSdkVersion="29" />

代码问题分析与修复

1. 替换Uri.fromFile()为FileProvider(Android 7+跨应用Uri访问限制)

Android 7.0开始禁止跨应用传递file://格式Uri,会触发权限拒绝或异常,必须用FileProvider生成content://格式Uri。

步骤1:配置FileProvider

在AndroidManifest.xml的<application>标签内添加:

<provider
    android:name="androidx.core.content.FileProvider"
    android:authorities="${applicationId}.fileprovider"
    android:exported="false"
    android:grantUriPermissions="true">
    <meta-data
        android:name="android.support.FILE_PROVIDER_PATHS"
        android:resource="@xml/file_paths" />
</provider>

在res/xml目录下创建file_paths.xml:

<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
    <external-cache-path name="external_cache" path="." />
</paths>

步骤2:修改选图代码(移除多余的EXTRA_OUTPUT)

ACTION_PICK无需设置输出Uri,选图结果直接从data.getData()返回:

public void selectImageFromGallery(ImageView view) {
    setResourceImg(view);
    checkListener();

    Intent intent = new Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
    intent.setType("image/*");
    if (fragment == null) {
        mContext.startActivityForResult(intent, REQUEST_PICTURE_FROM_GALLERY);
    } else {
        fragment.startActivityForResult(intent, REQUEST_PICTURE_FROM_GALLERY);
    }
}

步骤3:修改裁剪代码(使用FileProvider并授予临时权限)

给裁剪应用授予读写Uri的临时权限,避免权限拒绝:

public void requestCropImage(Uri uri, int outputX, int outputY, int aspectX, int aspectY) {
    checkListener();

    if (tempFileFromCrop == null) {
        try {
            tempFileFromCrop = File.createTempFile("crop", "png", mContext.getExternalCacheDir());
        } catch (IOException e) {
            e.printStackTrace();
            return;
        }
    }
    // 用FileProvider生成content://格式Uri
    tempUriFromCrop = FileProvider.getUriForFile(mContext, mContext.getPackageName() + ".fileprovider", tempFileFromCrop);

    final Intent intent = new Intent("com.android.camera.action.CROP");
    intent.setDataAndType(uri, "image/*");
    // 授予裁剪应用读写权限
    intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
    intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
    intent.putExtra("output", tempUriFromCrop);
    intent.putExtra("outputX", outputX);
    intent.putExtra("outputY", outputY);
    intent.putExtra("aspectX", aspectX);
    intent.putExtra("aspectY", aspectY);
    intent.putExtra("scale", true);
    intent.putExtra("noFaceDetection", true);
    
    // 确保有应用能处理裁剪Intent
    if (intent.resolveActivity(mContext.getPackageManager()) != null) {
        if (fragment == null) {
            mContext.startActivityForResult(intent, REQUEST_CROP_PICTURE);
        } else {
            fragment.startActivityForResult(intent, REQUEST_CROP_PICTURE);
        }
    }
}

2. 修正Bitmap获取方式(Android 11+路径访问限制)

Android 11+无法通过MediaStore.Images.Media.DATA字段获取的路径直接访问文件,需通过ContentResolver打开输入流:

@Override
public void onImageCropped(Uri uri, File imageFile) {
    try {
        InputStream inputStream = getContext().getContentResolver().openInputStream(uri);
        Bitmap bitmap = BitmapFactory.decodeStream(inputStream);
        // 此处处理bitmap
        
        if (inputStream != null) {
            inputStream.close();
        }
    } catch (Exception e) {
        e.printStackTrace();
    }
}

3. 补充动态权限申请

Android 13+需动态申请READ_MEDIA_IMAGES,Android 10-12需动态申请READ_EXTERNAL_STORAGE,确保选图前已获取权限:

// 示例:用ActivityResultLauncher申请权限
private ActivityResultLauncher<String> permissionLauncher = registerForActivityResult(
    new ActivityResultContracts.RequestPermission(),
    isGranted -> {
        if (isGranted) {
            // 权限已获取,执行选图逻辑
        } else {
            // 权限被拒绝,提示用户开启
        }
    }
);

private void checkAndRequestPermissions() {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
        if (ContextCompat.checkSelfPermission(mContext, Manifest.permission.READ_MEDIA_IMAGES) != PackageManager.PERMISSION_GRANTED) {
            permissionLauncher.launch(Manifest.permission.READ_MEDIA_IMAGES);
        }
    } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
        if (ContextCompat.checkSelfPermission(mContext, Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
            permissionLauncher.launch(Manifest.permission.READ_EXTERNAL_STORAGE);
        }
    } else {
        if (ContextCompat.checkSelfPermission(mContext, Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
            permissionLauncher.launch(Manifest.permission.READ_EXTERNAL_STORAGE);
        }
    }
}

内容的提问来源于stack exchange,提问作者Mohammad

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.01 15:55:18