Android API28后台服务无交互写入系统Download文件夹权限问题
问题核心
目标API为28(Android 9),后台Service无交互写入系统Download文件夹时,持续报java.io.FileNotFoundException: /storage/emulated/0/Download/name.pdf (Permission denied),已在Manifest中添加读写存储权限、MANAGE_EXTERNAL_STORAGE权限,并开启requestLegacyExternalStorage,但问题未解决。
解决方案
1. 清理无效权限
API 28及以下版本不需要MANAGE_EXTERNAL_STORAGE权限,该权限是API 30+才引入的,且后台场景无法触发其所需的用户弹窗授权,直接移除Manifest中的该权限:
<!-- 移除这一行 --> <uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE"/>
2. 必须在前台提前申请动态权限
API 23+(包含API 28)要求危险权限必须动态申请,而Service无法弹出权限请求弹窗,因此需要在应用首次前台运行时(比如启动页Activity)完成读写存储权限的申请,后续后台Service可复用已授予的权限状态。
示例代码(在Activity中实现):
private static final int STORAGE_PERMISSION_REQUEST_CODE = 1001; // 在Activity onCreate或启动逻辑中调用 private void checkAndRequestStoragePermission() { if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { ActivityCompat.requestPermissions( this, new String[]{Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE}, STORAGE_PERMISSION_REQUEST_CODE ); } } // 处理权限申请结果 @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); if (requestCode == STORAGE_PERMISSION_REQUEST_CODE) { if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { // 权限已授予,后续后台Service可正常写入Download文件夹 } else { // 权限被拒绝,需提示用户开启权限,否则功能无法正常运行 } } }
3. 使用系统API获取Download文件夹路径
不要硬编码/storage/emulated/0/Download/,改用系统提供的API获取标准路径,避免因设备差异导致路径错误:
// 获取系统Download文件夹的正确路径 File downloadDirectory = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS); File targetFile = new File(downloadDirectory, "name.pdf");
4. 确认requestLegacyExternalStorage配置完整
确保该属性在<application>标签中正确配置,没有遗漏或拼写错误:
<application android:name=".YourApplication" android:requestLegacyExternalStorage="true" <!-- 其他属性 --> > <!-- 组件声明 --> </application>
关键说明
Android从API 26开始对后台应用有严格限制,后台Service无法主动触发权限申请弹窗。因此必须在应用前台运行时完成权限授权,之后后台Service才能正常使用已授予的存储权限完成文件写入操作。
内容的提问来源于stack exchange,提问作者arist0v

