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

小米Android设备下载PDF时随机触发SecurityException问题求助

解决小米Android 6/7/8设备DownloadManager抛出SecurityException的问题

根据你遇到的情况——在小米Android 6、7、8设备上,明明已经授予存储运行时权限,却还是随机抛出SecurityException,错误指向Unsupported path /storage/emulated/999/Download/Somefile.pdf——我来帮你拆解问题并给出针对性解决方案:

问题根源分析

首先注意到路径里的999,这是小米设备工作资料/多用户模式的存储分区标识。在这些版本的MIUI系统中,问题主要来自三点:

  1. 当用户开启工作资料时,公共Download目录会切换到/storage/emulated/999/Download,但你的应用没有获取到访问该分区的特殊权限;
  2. 当前FileProvider的路径配置未覆盖公共Download目录,导致DownloadManager尝试写入该路径时无法获得合法的Uri授权;
  3. MIUI对存储权限的管控比原生Android更严格,即使申请了WRITE_EXTERNAL_STORAGE,也可能限制跨用户分区的访问。

具体解决方案

1. 适配多用户存储路径,避免硬编码

不要直接指定下载路径,而是通过系统API获取当前用户的合法公共Download目录,自动适配普通用户和工作资料模式:

File downloadDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS);
File targetFile = new File(downloadDir, "Somefile.pdf");

2. 更新FileProvider的路径配置

在file_paths.xml中添加公共Download目录的映射,让FileProvider能正确授权访问该路径:

<?xml version="1.0" encoding="utf-8"?>
<paths>
    <files-path name="images" path="images/" />
    <external-files-path name="share" path="share/" />
    <external-files-path name="reminder_images" path="reminder_images/" />
    <!-- 添加公共Download目录的映射 -->
    <external-path name="public_download" path="Download/" />
</paths>

注:如果应用目标SDK是29+,可以使用<external-public-path>替代<external-path>,更贴合公共存储的访问规则。

3. 给DownloadManager正确授予Uri权限

在调用DownloadManager.enqueue()前,确保给目标Uri授予临时写入权限,避免系统权限拦截:

File targetFile = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS), "Somefile.pdf");
Uri targetUri = FileProvider.getUriForFile(context, context.getPackageName() + ".provider", targetFile);

// 授予DownloadManager临时写入权限
context.grantUriPermission(
    "com.android.providers.downloads",
    targetUri,
    Intent.FLAG_GRANT_WRITE_URI_PERMISSION
);

DownloadManager.Request request = new DownloadManager.Request(Uri.parse(yourServerPdfUrl));
request.setDestinationUri(targetUri);

DownloadManager downloadManager = (DownloadManager) context.getSystemService(Context.DOWNLOAD_SERVICE);
downloadManager.enqueue(request);

4. 备选方案:使用应用私有外部存储

如果上述方案仍有问题,可以考虑将文件下载到应用私有外部存储目录,这里不需要额外的运行时权限(Android 4.4+),且不受多用户模式影响:

// 获取应用私有Download目录
File privateDownloadDir = new File(context.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS), "");
if (!privateDownloadDir.exists()) {
    privateDownloadDir.mkdirs();
}
File targetFile = new File(privateDownloadDir, "Somefile.pdf");

// 后续使用该文件路径创建Uri并发起下载

附用户提供的原始配置与堆栈信息

file_path.xml

<?xml version="1.0" encoding="utf-8"?>
<paths>
    <files-path name="images" path="images/" />
    <external-files-path name="share" path="share/" />
    <external-files-path name="reminder_images" path="reminder_images/" />
</paths>

AndroidManifest

<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>

堆栈信息

Caused by java.lang.SecurityException: Unsupported path /storage/emulated/999/Download/Somefile.pdf
at android.os.Parcel.readException(Parcel.java:2013)
at android.database.DatabaseUtils.readExceptionFromParcel(DatabaseUtils.java:183)
at android.database.DatabaseUtils.readExceptionFromParcel(DatabaseUtils.java:135)
at android.content.ContentProviderProxy.insert(ContentProviderProxy.java:476)
at android.content.ContentResolver.insert(ContentResolver.java:1555)
at android.app.DownloadManager.enqueue(DownloadManager.java:1163)
at com.esafirm.rxdownloader.RxDownloader.download(RxDownloader.java:83)
at com.esafirm.rxdownloader.RxDownloader.download(RxDownloader.java:60)
at in.okcredit.app.ui.account.AccountActivity.onReportGenerated(AccountActivity.java:320)
at in.okcredit.app.ui.account.AccountPresenter$1.onSuccess(AccountPresenter.java:118)
at in.okcredit.app.ui.account.AccountPresenter$1.onSuccess(AccountPresenter.java:111)
at io.reactivex.internal.operators.single.SingleObserveOn$ObserveOnSingleObserver.run(SingleObserveOn.java:81)
at io.reactivex.android.schedulers.HandlerScheduler$ScheduledRunnable.run(HandlerScheduler.java:119)
at android.os.Handler.handleCallback(Handler.java:794)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:176)
at android.app.ActivityThread.main(ActivityThread.java:6651)
at java.lang.reflect.Method.invoke(Method.java)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:547)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:824)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.12 05:38:17