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

Android 11代码实现文件夹间文件移动的权限获取问题

Android 11 (API 32) 文件移动权限问题解决方案

核心问题分析

Android 11 开始强制启用分区存储,原有的 WRITE_EXTERNAL_STORAGE 权限在 API 29+ 完全失效;MANAGE_EXTERNAL_STORAGE 作为特殊权限,无法通过普通权限弹窗请求,必须引导用户到系统设置手动授予。同时你的权限校验逻辑未适配 Android 11+ 的权限规则,导致即便用户授予旧权限,仍会出现权限拒绝错误。


步骤1:修正权限配置与请求逻辑

1.1 更新 AndroidManifest.xml

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools">

    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
        android:maxSdkVersion="28" />
    <!-- 适配 Android 11+ 的全存储访问权限,添加tools:ignore避免IDE警告 -->
    <uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE"
        tools:ignore="ScopedStorage" />

    <application
        <!-- Android 11+ 下 requestLegacyExternalStorage 无效,直接移除 -->
        ...>
    </application>
</manifest>

1.2 适配权限校验方法

private static final int REQUEST_EXTERNAL_STORAGE = 1001;
private static final int REQUEST_MANAGE_STORAGE = 1002;

public static void verifyStoragePermissions(Activity activity) {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
        // Android 11+ 检查全存储访问权限
        if (!Environment.isExternalStorageManager()) {
            Intent intent = new Intent(Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION);
            Uri uri = Uri.fromParts("package", activity.getPackageName(), null);
            intent.setData(uri);
            activity.startActivityForResult(intent, REQUEST_MANAGE_STORAGE);
        }
    } else {
        // Android 10及以下检查传统存储权限
        int permission = ActivityCompat.checkSelfPermission(activity, Manifest.permission.WRITE_EXTERNAL_STORAGE);
        if (permission != PackageManager.PERMISSION_GRANTED) {
            ActivityCompat.requestPermissions(
                    activity,
                    new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
                    REQUEST_EXTERNAL_STORAGE
            );
        }
    }
}

步骤2:优化文件移动代码

优先使用 File.renameTo() 方法(同一存储设备内移动效率远高于流复制),失败时再降级到流复制方案:

// 用File对象封装路径,避免字符串拼接错误
File inputFile = new File(inputPath, "file.txt");
File outputDir = new File(outputPath);

// 创建目标目录
if (!outputDir.exists()) {
    boolean isDirCreated = outputDir.mkdirs();
    Log.i("mkdirs result", String.valueOf(isDirCreated));
}

File outputFile = new File(outputDir, "file.txt");

// 尝试快速移动
boolean isMoved = inputFile.renameTo(outputFile);
if (!isMoved) {
    // 移动失败时用流复制
    try (FileInputStream in = new FileInputStream(inputFile);
         FileOutputStream out = new FileOutputStream(outputFile)) {
        byte[] buffer = new byte[1024];
        int readLen;
        while ((readLen = in.read(buffer)) != -1) {
            out.write(buffer, 0, readLen);
        }
        // 复制完成后删除原文件
        inputFile.delete();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

关键注意事项

  1. MANAGE_EXTERNAL_STORAGE 是敏感权限,Google Play 仅允许文件管理器、备份类等特定类型应用使用该权限,非此类应用建议改用分区存储合规方案(如将文件放在应用专属目录)。
  2. Android 11+ 下 requestLegacyExternalStorage="true" 完全失效,无需保留。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.17 16:35:28