https://github.com/smourier/webview2aot
WebView2 .NET AOT-compatible bindings independent from WinForms or WPF.
https://github.com/smourier/webview2aot
aot directn directnaot dotnet-core native-aot webview2
Last synced: 11 months ago
JSON representation
WebView2 .NET AOT-compatible bindings independent from WinForms or WPF.
- Host: GitHub
- URL: https://github.com/smourier/webview2aot
- Owner: smourier
- License: mit
- Created: 2025-04-14T18:35:23.000Z (about 1 year ago)
- Default Branch: main
- Last Pushed: 2025-07-11T22:14:59.000Z (12 months ago)
- Last Synced: 2025-07-12T00:22:18.129Z (12 months ago)
- Topics: aot, directn, directnaot, dotnet-core, native-aot, webview2
- Language: C#
- Homepage:
- Size: 351 KB
- Stars: 9
- Watchers: 1
- Forks: 1
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# WebView2Aot
[Microsoft WebView2](https://developer.microsoft.com/en-us/microsoft-edge/webview2?form=MA13LH) .NET 9+ AOT-compatible bindings 100% independent from WinForms or WPF.
* **HelloWebView2** is a sample hello world in 40 lignes of C# code (see screenshot below).
* **WebView2** is the .NET Core 9+ AOT-compatible bindings dll that can be used to use WebView2.
* **WebView2Aot.InteropBuilder.Cli** is the tool that generates code in the WebView2 dll. This is based on the linked [Win32InteropBuilder](https://github.com/smourier/Win32InteropBuilder) generic project. It also needs Microsoft.Web.WebView2.Win32.winmd which is the WebView2 metadata (check this for more information https://github.com/wravery/webview2-win32md).
WebView2 has a dependency to [DirectN AOT](https://github.com/smourier/DirectNAot) for some Windows definitions (BOOL, PWSTR, etc.) but has zero dependency on any UI framework.
Of course, all this requires the WebView2 to be installed!
## Deployment
WebView2 comes with a `WebView2Utilities.Initialize` method that will initialize the web view loader WebView2Loader.dll.
To make it work, you can reference the standard [Microsoft.Web.WebView2 ](https://www.nuget.org/packages/microsoft.web.webview2) nuget package as usual. However, it comes with all pre-built WPF & Winforms NET dll and xml, while we only need the native *WebView2Loader.dll* file.
So `WebView2Utilities.Initialize` also supports two other modes: you can extract the file corresponding to your processor architecture (x86, x64, arm4), or even all files from all architectures, as they rarely change, and either:
1) copy them locally in your app's folder, following the `regular runtimes\[arch]\native\WebView2Loader.dll` relative path
2) embed them as a .NET resource (from Visual Studio, set "Build Action" to "Embedded resource"), for example like this:

What's nice with embedding, especially in AOT deployment cases, is you just need to ship one file.
## HelloWebView2 sample

## ScriptHostObjectWebView2 sample
A sample that demonstrates how to add a host object to the WebView2 scripting context, always with AOT publishing:

This is the relevant html part:
```
Waiting 2000 ms for .NET function to return...
const dotnet = chrome.webview.hostObjects.dotnet;
dotnet.getInfoAsync(2000).then((value) => { document.getElementById('container').innerText = ".NET returned: " + value; });
// just show a clock while working...
function showClock() { clock.innerText = new Date().toLocaleTimeString(); dotnet.onClockTick(new Date()); }
showClock();
setInterval(showClock, 1000);
```
And the host object which is named 'dotnet' in the previous javascript code.
```
[GeneratedComClass]
public partial class HostObject : DispatchObject
{
public event EventHandler? ClockTick;
// non async method
public string GetInfo()
{
var info = new HostObjectInfo();
return JsonSerializer.Serialize(info, JsonSourceGenerationContext.Default.HostObjectInfo);
}
// async method
public Task GetInfoAsync(int delay) => Task.Run(async () =>
{
await Task.Delay(delay).ConfigureAwait(false); // simulate some async work
return GetInfo();
});
public void OnClockTick(string date) => ClockTick?.Invoke(this, date);
// note this is necessary to avoid trimming Task.Result for AOT publishing
// all Task results should be unwrapped here, so you can return any type you want (string being by far the most used one)
protected override object? GetTaskResult(Task task)
{
if (task is Task s)
return s.Result;
return null;
}
}
```