跨不同签名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
相关产品推荐
相关产品推荐

