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

如何为.NET MAUI WebView添加Handler加载内存HTML与数据库媒体资源

在.NET MAUI中实现WebView从内存加载媒体资源

我想编写如下代码,用内存中的HTML字符串通过WebView展示,同时图片、音频、视频也要从内存加载:

WebView webView = new WebView
{
    Source = new HtmlWebViewSource
    {
        Html = @"<!DOCTYPE html><HTML>
<BODY>
<H1>.NET MAUI</H1>
<P>Welcome to WebView.</P>
<img src=""myimg.jpg"" alt=""My Image"" width=""500"" height=""600"">
</BODY>
</HTML>",
    },
};

请问该如何给webView或webView.Source添加Handler,让它在加载媒体资源时被调用,返回可解析为图片、音频或视频的byte[]数据?

我搜到过类似webView.Source.Load(new MauiWKWebView());的思路,但我没有ASP.NET项目,而且我知道如果把图片作为静态资源能正常运行,但我的媒体数据存在数据库里。


解决方案:通过自定义WebView Handler拦截资源请求

1. 定义自定义WebView(可选,也可直接用原生WebView)

创建自定义WebView类,用于绑定资源获取逻辑:

public class CustomWebView : WebView
{
    // 委托:根据资源名称从内存/数据库获取byte[]数据
    public Func<string, byte[]> GetResourceData { get; set; }
}

2. 注册平台特定Handler

在各平台项目中注册自定义Handler,拦截WebView的资源请求。

Android平台实现

在Android项目的MainActivity.cs的OnCreate方法中添加:

Microsoft.Maui.Handlers.WebViewHandler.Mapper.AppendToMapping("CustomResourceHandler", (handler, view) =>
{
    if (view is CustomWebView customWebView)
    {
        handler.PlatformView.SetWebViewClient(new CustomWebViewClient(customWebView.GetResourceData));
    }
});

// 自定义WebViewClient拦截请求并返回内存资源
public class CustomWebViewClient : Android.Webkit.WebViewClient
{
    private readonly Func<string, byte[]> _getResourceData;

    public CustomWebViewClient(Func<string, byte[]> getResourceData)
    {
        _getResourceData = getResourceData;
    }

    public override WebResourceResponse ShouldInterceptRequest(Android.Webkit.WebView view, IWebResourceRequest request)
    {
        string fileName = System.IO.Path.GetFileName(request.Url.ToString());
        byte[] resourceData = _getResourceData?.Invoke(fileName);
        
        if (resourceData != null)
        {
            string mimeType = GetMimeType(fileName);
            return new WebResourceResponse(
                mimeType,
                "UTF-8",
                new System.IO.MemoryStream(resourceData)
            );
        }

        return base.ShouldInterceptRequest(view, request);
    }

    // 根据文件后缀返回对应MIME类型
    private string GetMimeType(string fileName)
    {
        string extension = System.IO.Path.GetExtension(fileName).ToLowerInvariant();
        return extension switch
        {
            ".jpg" or ".jpeg" => "image/jpeg",
            ".png" => "image/png",
            ".mp3" => "audio/mpeg",
            ".mp4" => "video/mp4",
            _ => "application/octet-stream"
        };
    }
}

iOS平台实现

在iOS项目的AppDelegate.cs的FinishedLaunching方法中添加:

Microsoft.Maui.Handlers.WebViewHandler.Mapper.AppendToMapping("CustomResourceHandler", (handler, view) =>
{
    if (view is CustomWebView customWebView)
    {
        var wkWebView = handler.PlatformView as WKWebView;
        wkWebView.Configuration.SetURLSchemeHandler(new CustomUrlSchemeHandler(customWebView.GetResourceData), "localres");
    }
});

// 自定义Scheme处理器拦截自定义协议请求
public class CustomUrlSchemeHandler : NSObject, IWKURLSchemeHandler
{
    private readonly Func<string, byte[]> _getResourceData;

    public CustomUrlSchemeHandler(Func<string, byte[]> getResourceData)
    {
        _getResourceData = getResourceData;
    }

    public void StartURLSchemeTask(WKWebView webView, IWKURLSchemeTask task)
    {
        string fileName = task.Request.Url.AbsoluteString.Replace("localres://", "");
        byte[] resourceData = _getResourceData?.Invoke(fileName);
        
        if (resourceData != null)
        {
            string mimeType = GetMimeType(fileName);
            NSData data = NSData.FromArray(resourceData);
            NSUrlResponse response = new NSUrlResponse(task.Request.Url, mimeType, data.Length, null);
            
            task.DidReceiveResponse(response);
            task.DidReceiveData(data);
            task.DidFinish();
        }
        else
        {
            task.DidFailWithError(new NSError(new NSString("ResourceNotFound"), 404));
        }
    }

    public void StopURLSchemeTask(WKWebView webView, IWKURLSchemeTask task)
    {
        // 可选:处理任务终止逻辑
    }

    private string GetMimeType(string fileName)
    {
        string extension = System.IO.Path.GetExtension(fileName).ToLowerInvariant();
        return extension switch
        {
            ".jpg" or ".jpeg" => "image/jpeg",
            ".png" => "image/png",
            ".mp3" => "audio/mpeg",
            ".mp4" => "video/mp4",
            _ => "application/octet-stream"
        };
    }
}

3. 使用自定义WebView并绑定资源获取逻辑

在页面中实例化CustomWebView,并从数据库获取媒体数据:

var customWebView = new CustomWebView
{
    Source = new HtmlWebViewSource
    {
        // iOS使用自定义协议localres://,Android也可兼容该协议
        Html = @"<!DOCTYPE html><HTML>
<BODY>
<H1>.NET MAUI</H1>
<P>Welcome to WebView.</P>
<img src=""localres://myimg.jpg"" alt=""My Image"" width=""500"" height=""600"">
</BODY>
</HTML>",
    },
    GetResourceData = (fileName) =>
    {
        // 从数据库查询对应文件名的byte[]数据
        using var db = new YourDbContext();
        var media = db.MediaFiles.FirstOrDefault(m => m.FileName == fileName);
        return media?.Data;
    }
};

关键说明

  • Android通过WebViewClient的ShouldInterceptRequest拦截请求,直接返回内存资源流。
  • iOS推荐使用自定义协议(如localres://)配合WKURLSchemeHandler拦截,兼容性更稳定。
  • 必须设置正确的MIME类型,否则WebView无法解析资源。
  • HTML中的资源路径需与拦截逻辑匹配,统一使用自定义协议可跨平台兼容。

内容的提问来源于stack exchange,提问作者Matthias F.

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.10 14:45:47