Android API21以下调用相机Intent拍摄照片崩溃问题求助
从你提供的LogCat可以看到核心错误:
java.lang.SecurityException: Permission Denial: opening provider android.support.v4.content.FileProvider from ProcessRecord{a538ebb8 3090:com.android.camera/u0a32} (pid=3090, uid=10032) that is not exported from uid 10057
这个问题的根源是Android 4.4(API19)及以下版本的权限机制限制:即使你在Manifest里给FileProvider设置了android:grantUriPermissions="true",通过startActivityForResult启动第三方相机应用时,系统不会自动把URI的读写权限授予给相机进程,导致相机应用无法访问你通过FileProvider提供的文件路径。
具体修复步骤
1. 显式为相机应用授予URI权限
修改你的dispatchTakePictureIntent方法,在启动相机Intent之前,针对目标相机应用的包名手动授予权限:
private void dispatchTakePictureIntent() { Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); PackageManager packageManager = getPackageManager(); // 确认有相机应用可以处理Intent if (takePictureIntent.resolveActivity(packageManager) != null) { File photoFile = null; try { photoFile = createImageFile(); } catch (IOException ex) { // 处理文件创建失败的情况 ex.printStackTrace(); } if (photoFile != null) { Uri photoURI = FileProvider.getUriForFile(this, "com.example.android.fileprovider", photoFile); // 关键:获取相机应用的组件信息,显式授予权限 ComponentName cameraComponent = takePictureIntent.resolveActivity(packageManager); if (cameraComponent != null) { grantUriPermission( cameraComponent.getPackageName(), photoURI, Intent.FLAG_GRANT_WRITE_URI_PERMISSION | Intent.FLAG_GRANT_READ_URI_PERMISSION ); } takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI); startActivityForResult(takePictureIntent, REQUEST_TAKE_PHOTO); } } }
2. 校验FileProvider配置的一致性
- 确保Manifest中
FileProvider的android:authorities值和代码里FileProvider.getUriForFile的第二个参数完全一致(比如你代码里的com.example.android.fileprovider,建议改成和应用包名绑定的格式,比如com.your.real.package.fileprovider,避免冲突) - 检查
res/xml/file_paths.xml里的路径配置:把占位符com.example.package.name替换成你的应用实际包名,因为getExternalFilesDir(Environment.DIRECTORY_PICTURES)返回的路径是Android/data/你的包名/files/Pictures,路径必须完全匹配才能让FileProvider正确映射。
3. 安全提醒
绝对不要把FileProvider的android:exported设置为true,这会让其他应用随意访问你的私有文件,带来严重的安全风险,保持false即可。
为什么API21以上正常?
从Android 5.0(API21)开始,系统优化了URI权限的传递机制:当你通过startActivityForResult启动其他应用时,系统会自动将Intent中携带的URI权限授予给目标应用,所以你的代码在高版本设备上可以正常运行。
内容的提问来源于stack exchange,提问作者Aleksey Kabanov

