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

Xamarin Forms中WebView文件选择器无法添加相机拍摄/选取的图片

解决Xamarin Forms WebView选择图片后无法加载的问题

核心问题分析

你的代码缺少以下关键环节,导致选中的图片无法传递给WebView:

  • 未保存filePathCallback引用,无法在图片选择完成后回调WebView
  • 未实现OnActivityResult方法处理图片选择结果
  • Android 7.0+版本未使用FileProvider生成安全URI,可能引发权限问题
  • 相机拍照后的图片URI未正确传递回WebView

修正后的完整代码实现

首先,在AndroidManifest.xml中配置FileProvider:

<application ...>
    <provider
        android:name="androidx.core.content.FileProvider"
        android:authorities="${applicationId}.fileprovider"
        android:exported="false"
        android:grantUriPermissions="true">
        <meta-data
            android:name="android.support.FILE_PROVIDER_PATHS"
            android:resource="@xml/file_paths" />
    </provider>
</application>

在Resources/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" />
    <cache-path name="my_cache" path="." />
</paths>

修改WebViewClient的代码:

private Android.Webkit.IValueCallback mFilePathCallback;
private const int INPUT_FILE_REQUEST_CODE = 100;
private string mCameraPhotoPath;
private Context mContext;

public override bool OnShowFileChooser(Android.Webkit.WebView webView, Android.Webkit.IValueCallback filePathCallback, FileChooserParams fileChooserParams)
{
    // 保存回调引用
    mFilePathCallback = filePathCallback;

    Intent takePictureIntent = new Intent(MediaStore.ActionImageCapture);

    if (takePictureIntent.ResolveActivity(mContext.PackageManager) != null)
    {
        Java.IO.File photoFile = null;
        try
        {
            photoFile = createImageFile();
            if (photoFile != null)
            {
                mCameraPhotoPath = photoFile.AbsolutePath;
                // 使用FileProvider生成安全URI
                Uri photoUri = FileProvider.GetUriForFile(mContext, mContext.PackageName + ".fileprovider", photoFile);
                takePictureIntent.PutExtra(MediaStore.ExtraOutput, photoUri);
                takePictureIntent.AddFlags(ActivityFlags.GrantReadUriPermission);
            }
            else
            {
                takePictureIntent = null;
            }
        }
        catch (Exception e)
        {
            Console.WriteLine("拍照文件创建失败: " + e.Message);
            takePictureIntent = null;
        }
    }

    Intent contentSelectionIntent = new Intent(Intent.ActionGetContent);
    contentSelectionIntent.AddCategory(Intent.CategoryOpenable);
    contentSelectionIntent.SetType("image/*"); // 限制选择图片类型

    Intent[] intentArray = takePictureIntent != null ? new[] { takePictureIntent } : new Intent[0];

    Intent chooserIntent = new Intent(Intent.ActionChooser);
    chooserIntent.PutExtra(Intent.ExtraIntent, contentSelectionIntent);
    chooserIntent.PutExtra(Intent.ExtraTitle, "选择图片");
    chooserIntent.PutExtra(Intent.ExtraInitialIntents, intentArray);

    ((Activity)mContext).StartActivityForResult(chooserIntent, INPUT_FILE_REQUEST_CODE);
    return true;
}

// 处理图片选择结果
public override void OnActivityResult(int requestCode, Result resultCode, Intent data)
{
    base.OnActivityResult(requestCode, resultCode, data);

    if (requestCode != INPUT_FILE_REQUEST_CODE || mFilePathCallback == null)
        return;

    Uri[] results = null;

    // 处理相机拍照结果
    if (resultCode == Result.Ok && !string.IsNullOrEmpty(mCameraPhotoPath))
    {
        Java.IO.File file = new Java.IO.File(mCameraPhotoPath);
        Uri uri = FileProvider.GetUriForFile(mContext, mContext.PackageName + ".fileprovider", file);
        results = new[] { uri };
    }
    // 处理文件选择器结果
    else if (data != null && resultCode == Result.Ok)
    {
        string dataString = data.DataString;
        if (!string.IsNullOrEmpty(dataString))
        {
            results = new[] { Uri.Parse(dataString) };
        }
    }

    // 将结果回调给WebView
    mFilePathCallback.OnReceiveValue(results);
    mFilePathCallback = null;
    mCameraPhotoPath = null;
}

private Java.IO.File createImageFile()
{
    string timeStamp = DateTime.Now.ToString("yyyyMMdd_HHmmss");
    string imageFileName = "JPEG_" + timeStamp + "_";
    Java.IO.File storageDir = mContext.GetExternalFilesDir(Android.OS.Environment.DirectoryPictures);

    return Java.IO.File.CreateTempFile(imageFileName, ".jpg", storageDir);
}

关键修正点说明

  • 保存回调引用:将filePathCallback存储为成员变量,确保在结果返回时能回调WebView
  • 实现OnActivityResult:统一处理相机拍照和文件选择的结果,生成合法URI传递给WebView
  • FileProvider适配:解决Android 7.0+的文件权限限制,避免FileUriExposedException
  • 权限授予:为相机Intent添加临时URI读取权限,确保拍照后能正常访问图片文件

内容的提问来源于stack exchange,提问作者I'm Coder

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 19:24:28