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

Android 10+及以下设备无需MANAGE_EXTERNAL_STORAGE的存储权限方案

无需MANAGE_EXTERNAL_STORAGE的视频播放器存储权限适配方案

一、权限配置调整

先把MANAGE_EXTERNAL_STORAGE权限从清单中移除,再根据不同Android版本配置必要权限:

<!-- 全版本通用的媒体读取权限 -->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />

<!-- Android 10及以下需要的写入权限 -->
<uses-permission
    android:name="android.permission.WRITE_EXTERNAL_STORAGE"
    android:maxSdkVersion="29" />

<!-- 仅针对Android 10(API 29)启用旧存储兼容模式,API 30+无需设置 -->
android:requestLegacyExternalStorage="true"

二、权限检查与申请逻辑重构

删掉原代码中MANAGE_EXTERNAL_STORAGE相关的逻辑,针对不同版本做适配:

1. 权限检查方法

private boolean checkPermission() {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
        // Android 11+:访问公共媒体目录无需额外权限,直接通过MediaStore操作
        return true;
    } else if (Build.VERSION.SDK_INT == Build.VERSION_CODES.Q) {
        // Android 10:仅需读取权限,写入通过MediaStore完成
        return ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED;
    } else {
        // Android 9及以下:需要同时拥有读写权限
        int readResult = ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE);
        int writeResult = ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE);
        return readResult == PackageManager.PERMISSION_GRANTED && writeResult == PackageManager.PERMISSION_GRANTED;
    }
}

2. 权限申请方法

private static final int PERMISSION_REQUEST_CODE = 100;

private void requestPermission() {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
        // Android 11+:无需申请权限,直接执行存储操作
        performStorageOperations();
    } else if (Build.VERSION.SDK_INT == Build.VERSION_CODES.Q) {
        // Android 10:仅申请读取权限
        ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, PERMISSION_REQUEST_CODE);
    } else {
        // Android 9及以下:申请读写权限
        ActivityCompat.requestPermissions(this, 
            new String[]{Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE}, 
            PERMISSION_REQUEST_CODE);
    }
}

3. 权限回调处理

@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    if (requestCode == PERMISSION_REQUEST_CODE) {
        boolean allGranted = true;
        for (int result : grantResults) {
            if (result != PackageManager.PERMISSION_GRANTED) {
                allGranted = false;
                break;
            }
        }
        if (allGranted) {
            performStorageOperations();
        } else {
            Toast.makeText(this, "请授予存储权限以访问视频文件", Toast.LENGTH_SHORT).show();
        }
    }
}

// 权限通过后执行存储操作的入口方法
private void performStorageOperations() {
    // 读取视频列表、修改名称、删除、下载等逻辑写在这里
}

三、核心功能实现(基于MediaStore)

Android10+不能直接用File API操作公共目录,必须通过MediaStore完成需求:

1. 读取/storage/Media/Videos目录下的视频列表

private List<String> getVideoList() {
    List<String> videoPaths = new ArrayList<>();
    String[] projection = {MediaStore.Video.Media.DATA};
    Cursor cursor = getContentResolver().query(
        MediaStore.Video.Media.EXTERNAL_CONTENT_URI,
        projection,
        null,
        null,
        MediaStore.Video.Media.DATE_ADDED + " DESC"
    );
    if (cursor != null) {
        while (cursor.moveToNext()) {
            String path = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Video.Media.DATA));
            videoPaths.add(path);
        }
        cursor.close();
    }
    return videoPaths;
}

2. 修改视频名称

private void renameVideo(String oldPath, String newName) {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
        // Android 10+:通过MediaStore更新
        ContentValues values = new ContentValues();
        values.put(MediaStore.Video.Media.DISPLAY_NAME, newName);
        String selection = MediaStore.Video.Media.DATA + "=?";
        String[] selectionArgs = {oldPath};
        getContentResolver().update(
            MediaStore.Video.Media.EXTERNAL_CONTENT_URI,
            values,
            selection,
            selectionArgs
        );
    } else {
        // Android 9及以下:直接操作文件
        File oldFile = new File(oldPath);
        if (oldFile.exists()) {
            File newFile = new File(oldFile.getParent(), newName);
            oldFile.renameTo(newFile);
        }
    }
}

3. 删除视频

private void deleteVideo(String videoPath) {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
        // Android 10+:通过MediaStore删除
        String selection = MediaStore.Video.Media.DATA + "=?";
        String[] selectionArgs = {videoPath};
        getContentResolver().delete(
            MediaStore.Video.Media.EXTERNAL_CONTENT_URI,
            selection,
            selectionArgs
        );
    } else {
        // Android 9及以下:直接删除文件
        File videoFile = new File(videoPath);
        if (videoFile.exists()) {
            videoFile.delete();
        }
    }
}

4. 下载视频到/storage/Download目录

private void downloadVideoToDownloadDir(InputStream inputStream, String fileName) {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
        // Android 10+:通过MediaStore写入Download目录
        ContentValues values = new ContentValues();
        values.put(MediaStore.Downloads.DISPLAY_NAME, fileName);
        values.put(MediaStore.Downloads.MIME_TYPE, "video/mp4"); // 根据实际视频类型调整
        values.put(MediaStore.Downloads.RELATIVE_PATH, Environment.DIRECTORY_DOWNLOADS);

        Uri uri = getContentResolver().insert(MediaStore.Downloads.EXTERNAL_CONTENT_URI, values);
        if (uri != null) {
            try (OutputStream outputStream = getContentResolver().openOutputStream(uri)) {
                byte[] buffer = new byte[1024];
                int bytesRead;
                while ((bytesRead = inputStream.read(buffer)) != -1) {
                    outputStream.write(buffer, 0, bytesRead);
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    } else {
        // Android 9及以下:直接写入Download目录
        File downloadDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS);
        File videoFile = new File(downloadDir, fileName);
        try (OutputStream outputStream = new FileOutputStream(videoFile)) {
            byte[] buffer = new byte[1024];
            int bytesRead;
            while ((bytesRead = inputStream.read(buffer)) != -1) {
                outputStream.write(buffer, 0, bytesRead);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

四、关键注意事项

  • Android 11+:完全不需要申请存储权限,所有操作通过MediaStore完成,符合Google Play权限政策。
  • Android 10:启用requestLegacyExternalStorage="true"后,既可以兼容旧File API,也可以用MediaStore,建议优先迁移到MediaStore适配后续版本。
  • 绝对不要使用MANAGE_EXTERNAL_STORAGE,该权限仅开放给文件管理器等特殊应用,普通视频播放器不符合审核要求。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.10 11:45:29