Android应用读写服务器PDF合规方案咨询(适配Scoped Storage)
针对Scoped Storage的PDF存储与打开最佳实践
你的核心问题是在Android 10+版本中,直接申请WRITE_EXTERNAL_STORAGE权限并操作非应用专属的外部存储区域,违反了Scoped Storage规范,导致应用被拒审。以下是适配Scoped Storage的完整解决方案:
1. 清理冗余权限
- 针对Android 10(API 29)及以上版本,完全移除
WRITE_EXTERNAL_STORAGE权限声明。 - 若需兼容Android 9及以下,可保留权限但添加版本限制,避免影响高版本规则:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="28" />
2. 选择合规的存储位置
根据你的使用场景,分两种方案:
场景A:PDF仅用于本应用临时打开或内部访问
直接保存到应用专属存储目录,无需任何权限,卸载应用时文件会被自动清理,完全符合Scoped Storage要求:
// 获取应用外部专属文档目录 File appDocDir = getExternalFilesDir(Environment.DIRECTORY_DOCUMENTS); if (appDocDir == null) { // 处理目录获取失败的异常 return; } File pdfFile = new File(appDocDir, "target_file.pdf"); // 写入文件(复用你原有的写入逻辑) try (FileOutputStream fos = new FileOutputStream(pdfFile)) { fos.write(base64ContentOfMyFile); fos.flush(); } catch (IOException e) { e.printStackTrace(); }
场景B:需要PDF被用户在文件管理器/其他应用中永久访问
如果要保存到公共Downloads目录,使用MediaStore API(无需WRITE权限):
ContentValues values = new ContentValues(); values.put(MediaStore.Downloads.DISPLAY_NAME, "target_file.pdf"); values.put(MediaStore.Downloads.MIME_TYPE, "application/pdf"); values.put(MediaStore.Downloads.RELATIVE_PATH, Environment.DIRECTORY_DOWNLOADS); ContentResolver resolver = getContentResolver(); Uri mediaUri = resolver.insert(MediaStore.Downloads.EXTERNAL_CONTENT_URI, values); if (mediaUri == null) { // 处理元数据插入失败的情况 return; } // 写入文件 try (OutputStream outputStream = resolver.openOutputStream(mediaUri)) { outputStream.write(base64ContentOfMyFile); outputStream.flush(); } catch (IOException e) { e.printStackTrace(); // 写入失败,清理已插入的元数据 resolver.delete(mediaUri, null, null); }
3. 优化Intent打开逻辑
你原有的Intent代码存在重复设置setDataAndType、冗余权限flag的问题,优化后版本:
Uri targetUri; // 场景A:用FileProvider生成共享Uri targetUri = FileProvider.getUriForFile(getApplicationContext(), BuildConfig.APPLICATION_ID + ".provider", pdfFile); // 场景B:直接使用MediaStore返回的uri // targetUri = mediaUri; Intent intentView = new Intent(Intent.ACTION_VIEW); intentView.setDataAndType(targetUri, "application/pdf"); intentView.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); // 仅授予读权限即可(打开查看不需要写权限) intentView.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); Intent intentChooser = Intent.createChooser(intentView, "Open with..."); startActivity(intentChooser);
4. 配置FileProvider(仅场景A需要)
在AndroidManifest.xml中添加FileProvider声明:
<provider android:name="androidx.core.content.FileProvider" android:authorities="${applicationId}.provider" 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-files-path name="external_documents" path="Documents" /> </paths>
内容的提问来源于stack exchange,提问作者Oza
相关产品推荐
相关产品推荐

