返回 Skill 列表
extension
分类: 开发与工程无需 API Key

maui-hybridwebview

关于在.NET MAUI应用程序中使用HybridWebView嵌入网页内容的指南,包括JavaScript-C#互操作、双向通信、原始消息传递以及裁剪/NativeAOT考虑事项。适用于:“HybridWebView”,“JavaScript互操作”,“嵌入网页内容”,“JS到C#互操作”,“C#到JavaScript”,“web视图互操作”,“原始消息”,“InvokeJavaScriptAsync”,“web内容MAUI”。不适用于:从外部URL进行深度链接(请使用maui-deep-linking),REST API调用(请使用maui-rest-api)或Blazor Hybrid应用(与HybridWebView不同)。

person作者: jakexiaohubgithub

HybridWebView in .NET MAUI

HybridWebView hosts HTML/JS/CSS content inside a .NET MAUI app with bidirectional C#↔JS communication. It is not a general browser control — it is designed for local web content shipped with the app.

Common gotchas

| Issue | Fix | |---|---| | Blank white screen | Web assets missing from Resources/Raw/wwwroot or DefaultFile not set | | JS interop silently fails | Missing <script src="_hwv/HybridWebView.js"></script> in HTML | | InvokeJavaScriptAsync returns null | Return type missing [JsonSerializable] attribute in JsonSerializerContext | | JS → C# calls do nothing | SetInvokeJavaScriptTarget not called before JS invokes C# methods | | Serialization crash with trimming | Not using source-generated JsonSerializerContext |

⚠️ Bridge script is mandatory

The HTML page must include the bridge script before any app scripts:

<!-- ✅ Correct order -->
<script src="_hwv/HybridWebView.js"></script>
<script src="scripts/app.js"></script>

<!-- ❌ Wrong — app.js loads before bridge, interop calls fail silently -->
<script src="scripts/app.js"></script>
<script src="_hwv/HybridWebView.js"></script>

JSON serialization — every type must be registered

Every parameter type and return type used in InvokeJavaScriptAsync must have a [JsonSerializable] entry:

// ✅ Correct — all interop types registered
[JsonSerializable(typeof(int))]
[JsonSerializable(typeof(string))]
[JsonSerializable(typeof(Person))]
internal partial class MyJsonContext : JsonSerializerContext { }

// ❌ Wrong — adding a new type to interop without registering it
// This causes silent null returns or runtime exceptions

Rule: When you add a new type to the interop surface, you must add a [JsonSerializable(typeof(T))] attribute to the context. Forgetting this is the #1 cause of mysterious interop failures.

SetInvokeJavaScriptTarget — timing matters

// ✅ Set target BEFORE the web page loads and JS calls C#
myHybridWebView.SetInvokeJavaScriptTarget(new MyJsBridge());

// ❌ Setting it after JS already tried to call — calls are lost

⚠️ Call SetInvokeJavaScriptTarget during page construction or OnAppearing, not lazily.

Exception handling (.NET 9+)

JS exceptions thrown during InvokeJavaScriptAsync are forwarded to .NET. Always wrap interop calls:

// ✅ Catches JS errors
try
{
    var result = await myHybridWebView.InvokeJavaScriptAsync<string>(
        "riskyFunction", MyJsonContext.Default.String);
}
catch (Exception ex)
{
    Debug.WriteLine($"JS error: {ex.Message}");
}

// ❌ Unhandled JS exception crashes the interop pipeline
var result = await myHybridWebView.InvokeJavaScriptAsync<string>(
    "riskyFunction", MyJsonContext.Default.String);

Trimming / NativeAOT pitfalls

Trimming is disabled by default in MAUI projects. If you enable it:

  • ⚠️ You must use source-generated JsonSerializerContext (not reflection-based serialization)
  • ⚠️ Set JsonSerializerIsReflectionEnabledByDefault to false
  • Using JsonSerializerContext as shown above is recommended regardless of trimming settings
<PropertyGroup>
  <PublishTrimmed>true</PublishTrimmed>
  <JsonSerializerIsReflectionEnabledByDefault>false</JsonSerializerIsReflectionEnabledByDefault>
</PropertyGroup>

Decision framework — typed interop vs raw messages

| Need | Use | |---|---| | Structured data exchange with type safety | InvokeJavaScriptAsync / InvokeDotNet with JsonSerializerContext | | Simple string payloads, fire-and-forget | SendRawMessage / RawMessageReceived | | Calling C# from JS with return values | InvokeDotNet (target must be set first) | | Multiple JS functions to call | Typed interop — one InvokeJavaScriptAsync per function |

Quick checklist

  • [ ] Web content is under Resources/Raw/wwwroot
  • [ ] index.html includes <script src="_hwv/HybridWebView.js"></script> before app scripts
  • [ ] DefaultFile is set (or defaults to index.html)
  • [ ] Every interop type has a [JsonSerializable] entry in a JsonSerializerContext
  • [ ] SetInvokeJavaScriptTarget is called before JS invokes C# methods
  • [ ] InvokeJavaScriptAsync calls are wrapped in try/catch (.NET 9+)
  • [ ] If trimming enabled: source-generated JSON serialization configured