maui-hybridwebview
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseHybridWebView in .NET MAUI
.NET MAUI中的HybridWebView
Overview
概述
HybridWebViewHybridWebViewProject layout
项目布局
Place web assets under Resources/Raw/wwwroot (the default root). Set a
different root with the property if needed.
HybridRootComponentResources/Raw/wwwroot/
index.html ← entry point (default)
scripts/app.js
styles/app.css将Web资源放置在 Resources/Raw/wwwroot 目录下(默认根目录)。如需修改根目录,可设置属性。
HybridRootComponentResources/Raw/wwwroot/
index.html ← 入口文件(默认)
scripts/app.js
styles/app.cssXAML setup
XAML配置
xml
<HybridWebView
x:Name="myHybridWebView"
DefaultFile="index.html"
RawMessageReceived="OnRawMessageReceived"
HorizontalOptions="Fill"
VerticalOptions="Fill" />DefaultFileindex.htmlxml
<HybridWebView
x:Name="myHybridWebView"
DefaultFile="index.html"
RawMessageReceived="OnRawMessageReceived"
HorizontalOptions="Fill"
VerticalOptions="Fill" />DefaultFileindex.htmlindex.html structure
index.html结构
The page must include the bridge script before any app scripts:
html
<!DOCTYPE html>
<html lang="en">
<head><meta charset="utf-8" /></head>
<body>
<!-- app markup -->
<script src="_hwv/HybridWebView.js"></script>
<script src="scripts/app.js"></script>
</body>
</html>页面必须在所有应用脚本之前引入桥接脚本:
html
<!DOCTYPE html>
<html lang="en">
<head><meta charset="utf-8" /></head>
<body>
<!-- 应用标记 -->
<script src="_hwv/HybridWebView.js"></script>
<script src="scripts/app.js"></script>
</body>
</html>C# → JavaScript (InvokeJavaScriptAsync)
C# → JavaScript(InvokeJavaScriptAsync)
Call a JS function from C# and receive a typed result:
csharp
// JS: function addNumbers(a, b) { return a + b; }
var result = await myHybridWebView.InvokeJavaScriptAsync<int>(
"addNumbers",
MyJsonContext.Default.Int32, // return type info
[2, 3], // parameters
[MyJsonContext.Default.Int32, // param 1 type info
MyJsonContext.Default.Int32]); // param 2 type infoFor complex types:
csharp
var person = await myHybridWebView.InvokeJavaScriptAsync<Person>(
"getPerson",
MyJsonContext.Default.Person,
[id],
[MyJsonContext.Default.Int32]);Every parameter type and the return type must have a
registered in a .
JsonTypeInfoJsonSerializerContext从C#调用JS函数并接收强类型结果:
csharp
// JS: function addNumbers(a, b) { return a + b; }
var result = await myHybridWebView.InvokeJavaScriptAsync<int>(
"addNumbers",
MyJsonContext.Default.Int32, // 返回类型信息
[2, 3], // 参数
[MyJsonContext.Default.Int32, // 参数1类型信息
MyJsonContext.Default.Int32]); // 参数2类型信息处理复杂类型:
csharp
var person = await myHybridWebView.InvokeJavaScriptAsync<Person>(
"getPerson",
MyJsonContext.Default.Person,
[id],
[MyJsonContext.Default.Int32]);所有参数类型和返回类型必须在中注册对应的。
JsonSerializerContextJsonTypeInfoJavaScript → C# (InvokeDotNet)
JavaScript → C#(InvokeDotNet)
From JS, call a C# method exposed on the invoke target:
javascript
const result = await window.HybridWebView.InvokeDotNet('MethodName', [param1, param2]);
window.HybridWebView.InvokeDotNet('LogEvent', ['click', 'button1']); // fire-and-forget在JS中调用Invoke目标暴露的C#方法:
javascript
const result = await window.HybridWebView.InvokeDotNet('MethodName', [param1, param2]);
window.HybridWebView.InvokeDotNet('LogEvent', ['click', 'button1']); // 无需返回结果的调用Setting the invoke target
设置Invoke目标
Register the object whose public methods JS can call:
csharp
myHybridWebView.SetInvokeJavaScriptTarget(new MyJsBridge());
public class MyJsBridge
{
public string Greet(string name) => $"Hello, {name}!";
public Person GetPerson(int id) => new Person { Id = id, Name = "Ada" };
}Method parameters and return values are serialized as JSON.
注册供JS调用其公共方法的对象:
csharp
myHybridWebView.SetInvokeJavaScriptTarget(new MyJsBridge());
public class MyJsBridge
{
public string Greet(string name) => $"Hello, {name}!";
public Person GetPerson(int id) => new Person { Id = id, Name = "Ada" };
}方法参数和返回值将序列化为JSON格式。
Raw messages
原始消息传递
For unstructured string communication use raw messages instead of typed interop.
C# → JS:
csharp
myHybridWebView.SendRawMessage("payload string");JS → C#:
javascript
window.HybridWebView.SendRawMessage('payload string');Receiving in C#:
csharp
void OnRawMessageReceived(object sender, HybridWebViewRawMessageReceivedEventArgs e)
{
var message = e.Message;
}Receiving in JS:
javascript
window.addEventListener('HybridWebViewMessageReceived', e => {
const message = e.detail.message;
});对于非结构化字符串通信,建议使用原始消息传递而非强类型互操作。
C# → JS:
csharp
myHybridWebView.SendRawMessage("payload string");JS → C#:
javascript
window.HybridWebView.SendRawMessage('payload string');在C#中接收:
csharp
void OnRawMessageReceived(object sender, HybridWebViewRawMessageReceivedEventArgs e)
{
var message = e.Message;
}在JS中接收:
javascript
window.addEventListener('HybridWebViewMessageReceived', e => {
const message = e.detail.message;
});JSON serialization setup
JSON序列化配置
Use source-generated JSON serialization. Define a partial context covering
every type exchanged between JS and C#:
csharp
[JsonSourceGenerationOptions(
WriteIndented = false,
PropertyNamingPolicy = JsonKnownNamingPolicy.CamelCase)]
[JsonSerializable(typeof(int))]
[JsonSerializable(typeof(string))]
[JsonSerializable(typeof(Person))]
internal partial class MyJsonContext : JsonSerializerContext { }
public class Person
{
public int Id { get; set; }
public string Name { get; set; } = string.Empty;
}Rule: If you add a new type to the interop surface, you must add aattribute to the context.[JsonSerializable(typeof(T))]
使用源代码生成的JSON序列化方式。定义一个部分类上下文,涵盖JS与C#之间交互的所有类型:
csharp
[JsonSourceGenerationOptions(
WriteIndented = false,
PropertyNamingPolicy = JsonKnownNamingPolicy.CamelCase)]
[JsonSerializable(typeof(int))]
[JsonSerializable(typeof(string))]
[JsonSerializable(typeof(Person))]
internal partial class MyJsonContext : JsonSerializerContext { }
public class Person
{
public int Id { get; set; }
public string Name { get; set; } = string.Empty;
}规则:如果在互操作接口中添加新类型,必须在上下文类中添加特性。[JsonSerializable(typeof(T))]
JS exception forwarding (.NET 9+)
JS异常转发(.NET 9+)
JavaScript exceptions thrown during are automatically
forwarded to .NET as managed exceptions. Wrap calls in try/catch:
InvokeJavaScriptAsynccsharp
try
{
var result = await myHybridWebView.InvokeJavaScriptAsync<string>(
"riskyFunction", MyJsonContext.Default.String);
}
catch (Exception ex)
{
Debug.WriteLine($"JS error: {ex.Message}");
}在调用期间抛出的JavaScript异常会自动转发到.NET端,作为托管异常处理。请将调用代码包裹在try/catch块中:
InvokeJavaScriptAsynccsharp
try
{
var result = await myHybridWebView.InvokeJavaScriptAsync<string>(
"riskyFunction", MyJsonContext.Default.String);
}
catch (Exception ex)
{
Debug.WriteLine($"JS error: {ex.Message}");
}Trimming and NativeAOT
裁剪与NativeAOT
Trimming and NativeAOT are disabled by default in MAUI projects. If you
enable them, ensure JSON source generators are used:
xml
<PropertyGroup>
<PublishTrimmed>true</PublishTrimmed>
<JsonSerializerIsReflectionEnabledByDefault>false</JsonSerializerIsReflectionEnabledByDefault>
</PropertyGroup>Using (source generation) as shown above is the
recommended pattern regardless of trimming settings.
JsonSerializerContextMAUI项目默认禁用裁剪和NativeAOT功能。如果启用这些功能,请确保使用JSON源代码生成器:
xml
<PropertyGroup>
<PublishTrimmed>true</PublishTrimmed>
<JsonSerializerIsReflectionEnabledByDefault>false</JsonSerializerIsReflectionEnabledByDefault>
</PropertyGroup>无论是否启用裁剪,推荐使用上述(源代码生成)的实现方式。
JsonSerializerContextQuick checklist
快速检查清单
- Web content is under .
Resources/Raw/wwwroot - includes
index.html.<script src="_hwv/HybridWebView.js"></script> - is set (or defaults to
DefaultFile).index.html - Every interop type has a entry in a
[JsonSerializable].JsonSerializerContext - is called before JS invokes C# methods.
SetInvokeJavaScriptTarget - Wrap in try/catch to handle JS exceptions (.NET 9+).
InvokeJavaScriptAsync
- Web内容放置在目录下。
Resources/Raw/wwwroot - 中引入
index.html。<script src="_hwv/HybridWebView.js"></script> - 已设置(或使用默认的
DefaultFile)。index.html - 所有互操作类型在中都有对应的
JsonSerializerContext配置。[JsonSerializable] - 在JS调用C#方法前已调用。
SetInvokeJavaScriptTarget - 将调用包裹在try/catch块中以处理JS异常(.NET 9+)。
InvokeJavaScriptAsync