DotNetBrowser 中的裁剪和 Native AOT 支持
本文介绍了相关变更、可用能力,以及在使用这些部署模式时如何正确配置应用程序。
裁剪
裁剪是 .NET 在发布阶段提供的一项功能,用于移除链接器判断为永远不会调用的 IL 代码。这样可以减小发布产物的体积,因为未引用的类型、方法和资源都会从输出中移除。
风险在于,某些仅在运行时通过反射或动态加载发现的代码可能会被裁掉,从而在运行时导致 MissingMethodException 或类似错误。
为了能够安全地供启用裁剪的应用程序使用,库必须声明 IsTrimmable=true,并为所有相关代码路径添加注解,让链接器知道哪些成员需要保留。
Native AOT
Native AOT 会在发布时将整个 .NET 应用程序编译为独立的原生二进制文件。
运行时没有 JIT 编译器,不支持基于反射的代码生成,也不支持 Assembly.Load。
这可以显著降低启动时间和内存开销,但也是 .NET 支持的最严格的部署模式。
DotNetBrowser 中的变更
兼容的软件包
目前,所有 DotNetBrowser 核心软件包在 .NET 8 目标框架下都声明了 IsTrimmable=true 和 IsAotCompatible=true:
| 包 | 说明 |
|---|---|
DotNetBrowser | 公共 API 接口 |
DotNetBrowser.Core | 核心实现 |
DotNetBrowser.Logging | 日志基础设施 |
DotNetBrowser.AvaloniaUi | Avalonia UI 集成 |
注意: DotNetBrowser 仅在控制台应用程序和 Avalonia UI 11.x 版本(从 11.2.0 开始)中支持裁剪和 AOT。
Native AOT 部署要求
由于 Native AOT 模式下无法加载程序集,因此不支持内置 Chromium 二进制文件的自动提取。在应用程序启动之前,必须先将 Chromium 二进制文件部署到已知目录中。
第 1 步:预先部署 Chromium 二进制文件
将 Chromium 二进制文件复制到目标机器上的某个目录。该目录中的结构依赖于平台和体系结构:
<chromium-dir>/
Windows 二进制文件 → WindowsX86/, WindowsX64/, WindowsArm64/
Linux 二进制文件 → LinuxX64/, LinuxArm64/
macOS 二进制文件 → MacX64/, MacArm64/
第 2 步:告诉 DotNetBrowser 二进制文件的位置
方式 A:环境变量(无需修改代码):
# Linux / macOS
export DOTNETBROWSER_CHROMIUM_DIR=/opt/myapp/chromium
# Windows
set DOTNETBROWSER_CHROMIUM_DIR=C:\myapp\chromium
方式 B:EngineOptions.ChromiumDirectory(在代码中配置):
var engine = EngineFactory.Create(new EngineOptions.Builder
{
ChromiumDirectory = "/opt/myapp/chromium"
}.Build());
Dim engine = EngineFactory.Create(
New EngineOptions.Builder() With {
.ChromiumDirectory = "/opt/myapp/chromium"
}.Build()
)
如果上述两种方式都没有配置,且二进制文件不存在,DotNetBrowser 会抛出 ChromiumBinariesMissingException。
使用 Native AOT 发布
下面是在 Linux 上使用 DotNetBrowser 和 Avalonia UI 的 Native AOT 应用程序的最小 .csproj 配置:
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<PublishAot>true</PublishAot>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="DotNetBrowser.AvaloniaUi" Version="..." />
</ItemGroup>
发布命令:
dotnet publish -c Release -r linux-x64
发布输出中不包含 Chromium 二进制文件。你需要单独部署这些文件,并按照上文所述配置其路径。
仅使用裁剪发布
如果你希望在不使用 Native AOT 的情况下减小输出体积,可以只启用裁剪:
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<PublishTrimmed>true</PublishTrimmed>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="DotNetBrowser.AvaloniaUi" Version="..." />
</ItemGroup>
在这种模式下,Chromium 二进制文件可以像普通应用程序一样,在首次启动时从 NuGet 包中自动提取。
唯一额外需要完成的部署步骤,是确保包含 DotNetBrowser.Chromium.X.dll 程序集,因为在发布期间由于没有直接引用,它不会被自动复制。
支持的 UI 框架
在此版本中,只有 Avalonia UI 集成支持裁剪和 Native AOT。
WPF、WinForms 和 WinUI3 不兼容裁剪和 Native AOT。
已知限制
在 AOT 模式下必须预先部署 Chromium 二进制文件。 Native AOT 应用程序不支持从 NuGet 嵌入资源中自动提取这些文件。
基于反射的 JS 便捷重载。 某些 IJsObject 互操作帮助程序在内部使用了反射。
这些代码路径已经添加了注解,因此调用时是安全的;但如果你大量使用 dynamic 类型的 JS 返回结果,建议在具体的 AOT 场景中验证其行为。
从 JavaScript 调用 .NET。 需要添加 [DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(MyObject))] 特性,以确保注入的对象在裁剪过程中被保留。
如果没有添加该特性,该对象可能会被裁剪器移除,从而在运行时不可用。
示例代码如下:
public class MyObject {
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(MyObject))]
public string SayHelloTo(string firstName) {
return "Hello " + firstName + "!";
}
}
Public Class MyObject
<DynamicDependency(DynamicallyAccessedMemberTypes.All, GetType(MyObject))>
Public Function SayHelloTo(ByVal firstName As String) As String
Return "Hello " & firstName & "!"
End Function
End Class
IJsObject window = frame.ExecuteJavaScript<IJsObject>("window").Result;
window.Properties["MyObject"] = new MyObject();
Dim window As IJsObject = frame.ExecuteJavaScript(Of IJsObject)("window").Result
window.Properties("MyObject") = New MyObject()
完成后,你就可以在 JavaScript 代码中引用该对象并调用其方法:
console.log(window.MyObject.SayHelloTo("John"));