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

跨不同签名App使用FileProvider写入文件时遭遇java.lang.SecurityException权限拒绝问题求助

解决跨签名App间FileProvider写入的SecurityException问题

看起来你遇到的核心问题是跨App的临时权限没有正确传递,导致App1无法访问App2提供的FileProvider Uri。下面我一步步帮你排查和解决:

首先明确错误原因

错误提示Permission Denial: opening provider ... that is not exported from UID 10155,这是正常的——FileProvider本身就不能设置android:exported="true",它依赖临时Uri权限来实现跨App访问。问题出在App2没有把写入权限正确授予App1,或者配置有遗漏。

分步解决方案

1. 确保App2启动App1时,Intent携带完整的权限标记

你提到已经配置了读写权限,但要确认是在启动Intent时主动添加权限flag,而不是只依赖系统默认。代码应该像这样:

// App2中启动App1的代码
Intent intent = new Intent(this, App1TargetActivity.class);
Uri app2SharedUri = FileProvider.getUriForFile(this, "com.your.app2.fileprovider", targetFile);
intent.putExtra(Intent.EXTRA_STREAM, app2SharedUri);
// 关键:同时添加读写临时权限
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
startActivityForResult(intent, YOUR_REQUEST_CODE);

注意用addFlags而不是setFlags,避免覆盖Intent原有的flag。

2. 检查App2的FileProvider配置

打开App2的AndroidManifest.xml,确认FileProvider的配置满足以下要求:

<provider
    android:name="androidx.core.content.FileProvider"
    android:authorities="com.your.app2.fileprovider" <!-- 要和生成Uri时的authority一致 -->
    android:grantUriPermissions="true" <!-- 必须开启,否则无法授予临时权限 -->
    android:exported="false"> <!-- 必须为false,FileProvider不允许exported -->
    <meta-data
        android:name="android.support.FILE_PROVIDER_PATHS"
        android:resource="@xml/file_paths" />
</provider>

重点是android:grantUriPermissions="true",没有这个属性,App2无法将Uri的访问权限授予其他App。

3. 优化App1的文件复制代码

你的代码里有两个可以优化的点,能避免额外的权限问题:

  • 源文件读取无需ContentResolver:因为scanResult.pdfFile是App1自己的文件,直接用FileInputStream读取即可,不需要通过Uri(避免触发不必要的权限检查)。
  • 用缓冲区提高复制效率:逐字节读写效率极低,换成字节缓冲区。

修改后的copyPDFs方法:

private void copyPDFs(File sourceFile, Uri targetUri){
    FileOutputStream out = null;
    FileInputStream in = null;
    ContentResolver cr = getContentResolver();
    try {
        // 直接打开目标Uri的输出流
        out = (FileOutputStream) cr.openOutputStream(targetUri);
        // 读取本地源文件
        in = new FileInputStream(sourceFile);
        
        // 用4KB缓冲区复制,效率更高
        byte[] buffer = new byte[4096];
        int bytesRead;
        while ((bytesRead = in.read(buffer)) != -1) {
            out.write(buffer, 0, bytesRead);
        }
    } catch (SecurityException e){
        Log.e("CopyPDF", "权限异常", e);
    } catch (IOException e) {
        Log.e("CopyPDF", "IO异常", e);
    } finally {
        // 关闭流(也可以用try-with-resources自动关闭)
        try {
            if (out != null) out.close();
            if (in != null) in.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

调用时直接传入源文件:

private void writeToSharedFile(){
    Intent startingIntent = getIntent();
    Uri sharedFileUri = startingIntent.getParcelableExtra(Intent.EXTRA_STREAM);
    copyPDFs(scanResult.pdfFile, sharedFileUri);
}

4. 确认App2生成的Uri是合法的FileProvider Uri

App2不能用Uri.fromFile(targetFile)生成Uri,必须用FileProvider的getUriForFile方法,比如:

// App2中生成共享Uri的代码
File sharedDir = new File(getFilesDir(), "shared_files");
if (!sharedDir.exists()) sharedDir.mkdirs();
File targetFile = new File(sharedDir, "received.pdf");
Uri app2SharedUri = FileProvider.getUriForFile(this, "com.your.app2.fileprovider", targetFile);

最后排查点

  • 如果App1在后台被系统回收,临时权限会失效,尽量让App1在前台完成写入操作。
  • 确认两个App的targetSdkVersion都在24以上(FileProvider要求),且都使用androidx的FileProvider。

按照这些步骤调整后,应该就能解决权限拒绝的问题了。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.29 23:43:13