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

Android WebView中相机捕获图片无法传递至HTML完成上传的问题

解决Android WebView中相机拍照后无法传递图片到HTML的问题

这种WebView和相机交互的坑我踩过不少,Chrome浏览器本身对文件上传和相机交互做了完善适配,但WebView的默认配置很多时候没跟上,给你一步步拆解解决方法:

1. 确保Android应用拥有必要权限

WebView要调用相机并访问拍摄的图片,首先得让应用拿到对应的权限:

  • 在AndroidManifest.xml中声明静态权限:
<uses-permission android:name="android.permission.CAMERA" />
<!-- Android 13及以上用READ_MEDIA_IMAGES替代WRITE_EXTERNAL_STORAGE -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="32" />
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" android:minSdkVersion="33" />
<uses-feature android:name="android.hardware.camera" android:required="false" />
  • 还要在代码中动态申请权限(Android 6.0+要求),比如在启动WebView前请求相机和存储权限,用户同意后再加载网页。

2. 配置WebView的文件上传支持

WebView默认没有处理相机拍照后的文件回调,必须重写WebChromeClient的onShowFileChooser方法来接管文件选择逻辑:

webView.setWebChromeClient(new WebChromeClient() {
    private ValueCallback<Uri[]> mFilePathCallback;
    private String mCurrentPhotoPath;
    private static final int REQUEST_CAMERA = 1001;

    @Override
    public boolean onShowFileChooser(WebView webView, ValueCallback<Uri[]> filePathCallback, FileChooserParams fileChooserParams) {
        // 保存回调,用于拍照完成后返回结果
        mFilePathCallback = filePathCallback;
        
        // 构建相机拍照的Intent
        Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
        if (takePictureIntent.resolveActivity(getPackageManager()) != null) {
            // 创建临时文件存储拍照后的图片
            File photoFile = null;
            try {
                photoFile = createImageFile();
                mCurrentPhotoPath = photoFile.getAbsolutePath();
            } catch (IOException ex) {
                ex.printStackTrace();
            }
            if (photoFile != null) {
                Uri photoUri = FileProvider.getUriForFile(MainActivity.this,
                        "com.your.package.fileprovider", photoFile);
                takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoUri);
            }
        }
        
        // 启动相机Activity
        startActivityForResult(takePictureIntent, REQUEST_CAMERA);
        return true;
    }

    // 创建临时图片文件的辅助方法
    private File createImageFile() throws IOException {
        String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.getDefault()).format(new Date());
        String imageFileName = "JPEG_" + timeStamp + "_";
        File storageDir = getExternalFilesDir(Environment.DIRECTORY_PICTURES);
        return File.createTempFile(imageFileName, ".jpg", storageDir);
    }
});

注意:这里用到了FileProvider来避免Android 7.0+的文件Uri暴露问题,需要在AndroidManifest.xml中配置FileProvider:

<provider
    android:name="androidx.core.content.FileProvider"
    android:authorities="com.your.package.fileprovider"
    android:exported="false"
    android:grantUriPermissions="true">
    <meta-data
        android:name="android.support.FILE_PROVIDER_PATHS"
        android:resource="@xml/file_paths" />
</provider>

然后在res/xml下创建file_paths.xml:

<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
    <external-files-path name="my_images" path="Pictures" />
</paths>

3. 处理拍照后的结果返回

在onActivityResult(或AndroidX的ActivityResultContracts)中接收相机返回的结果,把Uri传递给WebView的回调:

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    if (requestCode == REQUEST_CAMERA) {
        if (mFilePathCallback != null) {
            Uri[] results = null;
            // 检查拍照是否成功
            if (resultCode == RESULT_OK && mCurrentPhotoPath != null) {
                results = new Uri[]{Uri.fromFile(new File(mCurrentPhotoPath))};
            }
            // 将结果传递回WebView
            mFilePathCallback.onReceiveValue(results);
            mFilePathCallback = null;
        }
    }
}

4. 检查HTML中的input标签配置

确保你的HTML文件上传标签正确配置,指定相机捕获:

<input type="file" accept="image/*" capture="camera" id="photoUpload">

capture="camera"会直接唤起相机,accept="image/*"限制只选择图片类型,这样WebView才能正确识别并触发相机逻辑。

最后补充

  • 如果是Android 10及以上,注意在Manifest的application标签里开启android:requestLegacyExternalStorage="true",避免Scoped Storage的限制;
  • 测试时尽量用真机,模拟器的相机有时候会有兼容性问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.19 09:14:34