
本文详解 android webview 中调用系统相机拍照后无法回传图片的问题,核心在于使用 `fileprovider` 替代已弃用的 `uri.fromfile()` 生成安全、可访问的图片 uri,确保 `onshowfilechooser` 回调能正确接收拍摄结果。
在 Android 7.0(API 24)及以上版本中,直接使用 Uri.fromFile() 会触发 FileUriExposedException 异常,且即使未崩溃,WebView 的文件选择回调(如 onShowFileChooser)也无法正确解析该 URI —— 这正是你遇到“相机拍照无响应、response.getData().getDataString() 为空”的根本原因。系统相机应用在保存照片后,会尝试通过 Intent 返回一个 Uri,但若该 URI 是非 content:// 协议(如 file:///sdcard/...),目标 Activity(即你的 WebView)将因权限限制无法读取,导致 getData() 返回 null 或空字符串。
✅ 正确解法:统一使用 FileProvider 生成 content:// URI
你需要将 createImageFile() 创建的临时照片文件,通过 FileProvider 转换为具有授权访问权限的 content:// URI,并在启动相机 Intent 时传入该 URI:
✅ 修改步骤(关键代码)
-
确保 provider_paths.xml 已正确定义(位于 res/xml/provider_paths.xml):
-
在 onShowFileChooser 中替换 Uri.fromFile(...) 为 FileProvider.getUriForFile(...):
找到你代码中这一行:takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(photoFile));
✅ 替换为:
Uri photoUri = FileProvider.getUriForFile( MainActivity.this, BuildConfig.APPLICATION_ID + ".fileprovider", // 注意:此处需与 manifest 中 provider 的 authorities 一致 photoFile ); takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoUri);
⚠️ 注意:BuildConfig.APPLICATION_ID + ".fileprovider" 必须与 AndroidManifest.xml 中
如果你的 provider 定义为:
那么此处应写为 BuildConfig.APPLICATION_ID(即 "com.webview.android"),而非 "com.webview.android.fileprovider"。
-
授予相机应用临时读写权限(重要!):
在启动相机 Intent 前,显式授予 photoUri 对应的 URI 权限:// 在 launch takePictureIntent 前添加 if (photoUri != null) { takePictureIntent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION); // 若 targetSdk >= 30,还需 grant read permission for compatibility if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { takePictureIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); } } -
在 onActivityResult 中正确处理 content:// URI:
你当前逻辑中仅依赖 response.getData().getDataString(),但相机拍摄后 Intent.getData() 通常为 null(因为结果通过 EXTRA_OUTPUT 写入指定路径)。此时应优先使用 mCM 缓存的 URI(即你生成的 photoUri):if (response.getData() == null && mCM != null) { results = new Uri[]{Uri.parse(mCM)}; // ✅ 此处 mCM 已是 content:// URI } else if (response.getData() != null) { String dataString = response.getData().getDataString(); if (dataString != null) { results = new Uri[]{Uri.parse(dataString)}; } }
? 补充注意事项
- 动态权限适配:Android 10+(API 29+)需申请 READ_MEDIA_IMAGES(你已在 manifest 中声明),但运行时仍需动态请求(尤其 targetSdk >= 33)。
- 存储适配:Environment.getExternalStoragePublicDirectory() 已弃用(API 29+),建议改用 getExternalFilesDir(Environment.DIRECTORY_PICTURES) 避免权限问题。
-
WebView 设置验证:确保 WebSettings 启用必要能力:
settings.setAllowContentAccess(true); settings.setAllowFileAccess(true); settings.setDomStorageEnabled(true);
✅ 总结
| 问题现象 | 根本原因 | 解决方案 |
|---|---|---|
| 相机拍照后无回调、getDataString() 为空 | 使用 Uri.fromFile() 生成不安全 file:// URI,被系统拦截或 WebView 拒绝解析 | 改用 FileProvider.getUriForFile() 生成带授权的 content:// URI,并正确配置 provider_paths.xml 和 AndroidManifest.xml |
完成上述修改后,WebView 将能无缝接收相机拍摄的照片,并自动填充至 HTML 字段,实现与文件选择器一致的用户体验。










