Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 15 additions & 1 deletion docs/deployment/includes/feature-switches.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
ms.topic: include
ms.date: 11/14/2024
ms.date: 07/08/2026
---

.NET MAUI has trimmer directives, known as feature switches, that make it possible to preserve the code for features that aren't trim safe. These trimmer directives can be used when the `$(TrimMode)` build property is set to `full`, as well as for Native AOT:
Expand All @@ -13,8 +13,17 @@ ms.date: 11/14/2024
| `MauiImplicitCastOperatorsUsageViaReflectionSupport` | When set to `false`, .NET MAUI won't look for implicit conversion operators when converting values from one type to another. This can affect bindings between properties with different types, and setting a property value of a bindable object with a value of a different type. Instead, you should define a <xref:System.ComponentModel.TypeConverter> for your type and attach it to the type using the <xref:System.ComponentModel.TypeConverterAttribute> attribute. By default, this build property is set to `false` when full trimming or Native AOT is enabled. |
| `_MauiBindingInterceptorsSupport` | When set to `false`, .NET MAUI won't intercept any calls to the `SetBinding` methods and won't try to compile them. By default, this build property is set to `true`. |
| `MauiEnableXamlCBindingWithSourceCompilation` | When set to `true`, .NET MAUI will compile all bindings, including those where the `Source` property is used. If you enable this feature ensure that all bindings have the correct `x:DataType` so that they compile, or clear the data type with `x:Data={x:Null}}` if the binding shouldn't be compiled. By default, this build property is set to `true` when full trimming or Native AOT is enabled. |

::: moniker range="<=net-maui-10.0"

.NET 10 and earlier also include the following feature switch:

| MSBuild property | Description |
| ---------------- | ----------- |
| `MauiHybridWebViewSupported` | When set to `false`, the <xref:Microsoft.Maui.Controls.HybridWebView> control won't be available. By default, this build property is set to `false` when full trimming or Native AOT is enabled. |

::: moniker-end

These MSBuild properties also have equivalent <xref:System.AppContext> switches:

- The `MauiEnableVisualAssemblyScanning` MSBuild property has an equivalent <xref:System.AppContext> switch named `Microsoft.Maui.RuntimeFeature.IsIVisualAssemblyScanningEnabled`.
Expand All @@ -23,6 +32,11 @@ These MSBuild properties also have equivalent <xref:System.AppContext> switches:
- The `MauiImplicitCastOperatorsUsageViaReflectionSupport` MSBuild property has an equivalent <xref:System.AppContext> switch named `Microsoft.Maui.RuntimeFeature.IsImplicitCastOperatorsUsageViaReflectionSupported`.
- The `_MauiBindingInterceptorsSupport` MSBuild property has an equivalent <xref:System.AppContext> switch named `Microsoft.Maui.RuntimeFeature.AreBindingInterceptorsSupported`.
- The `MauiEnableXamlCBindingWithSourceCompilation` MSBuild property has an equivalent <xref:System.AppContext> switch named `Microsoft.Maui.RuntimeFeature.MauiEnableXamlCBindingWithSourceCompilationEnabled`.

::: moniker range="<=net-maui-10.0"

- The `MauiHybridWebViewSupported` MSBuild property has an equivalent <xref:System.AppContext> switch named `Microsoft.Maui.RuntimeFeature.IsHybridWebViewSupported`.

::: moniker-end

The easiest way to consume a feature switch is by putting the corresponding MSBuild property into your app's project file (*.csproj), which causes the related code to be trimmed from the .NET MAUI assemblies.
8 changes: 7 additions & 1 deletion docs/deployment/includes/trimming-incompatibilities.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
ms.topic: include
ms.date: 12/03/2024
ms.date: 07/08/2026
monikerRange: ">=net-maui-9.0"
---

Expand All @@ -11,6 +11,12 @@ The following .NET MAUI features are incompatible with full trimming and will be
- Loading XAML at runtime with the <xref:Microsoft.Maui.Controls.Xaml.Extensions.LoadFromXaml%2A> extension method. This XAML can be made trim safe by annotating all types that could be loaded at runtime with the [`DynamicallyAccessedMembers`](xref:System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembersAttribute) attribute or the [`DynamicDependency`](xref:System.Diagnostics.CodeAnalysis.DynamicDependencyAttribute) attribute. However, this is very error prone and isn't recommended.
- Receiving navigation data using the <xref:Microsoft.Maui.Controls.QueryPropertyAttribute>. Instead, you should implement the <xref:Microsoft.Maui.Controls.IQueryAttributable> interface on types that need to accept query parameters. For more information, see [Process navigation data using a single method](~/fundamentals/shell/navigation.md#process-navigation-data-using-a-single-method).
- The `SearchHandler.DisplayMemberName` property. Instead, you should provide an <xref:Microsoft.Maui.Controls.ItemsView.ItemTemplate> to define the appearance of <xref:Microsoft.Maui.Controls.SearchHandler> results. For more information, see [Define search results item appearance](~/fundamentals/shell/search.md#define-search-results-item-appearance).

::: moniker range="<=net-maui-10.0"

- The <xref:Microsoft.Maui.Controls.HybridWebView> control, due to its use of dynamic `System.Text.Json` serialization features.

::: moniker-end

- UI customization with the [`OnPlatform`](xref:Microsoft.Maui.Controls.Xaml.OnPlatformExtension) XAML markup extension. Instead, you should use the <xref:Microsoft.Maui.Controls.OnPlatform`1> class. For more information, see [Customize UI appearance based on the platform](~/platform-integration/customize-ui-appearance.md#customize-ui-appearance-based-on-the-platform).
- UI customization with the [`OnIdiom`](xref:Microsoft.Maui.Controls.Xaml.OnIdiomExtension) XAML markup extension. Instead, you should use the <xref:Microsoft.Maui.Controls.OnIdiom`1> class. For more information, see [Customize UI appearance based on the device idiom](~/platform-integration/customize-ui-appearance.md#customize-ui-appearance-based-on-the-device-idiom).
103 changes: 92 additions & 11 deletions docs/user-interface/controls/hybridwebview.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
title: HybridWebView
description: Learn how to use a HybridWebView to host HTML/JS/CSS content in a WebView, and communicate between that content and .NET.
ms.topic: concept-article
ms.date: 12/08/2025
ms.date: 07/08/2026
monikerRange: ">=net-maui-9.0"

#customer intent: As a developer, I want to host HTML/JS/CSS content in a web view so that I can publish the web app as a mobile app.
Expand Down Expand Up @@ -31,9 +31,20 @@ To create a .NET MAUI app with <xref:Microsoft.Maui.Controls.HybridWebView> you

The entire app, including the web content, is packaged and runs locally on a device, and can be published to applicable app stores. The web content is hosted within a native web view control and runs within the context of the app. Any part of the app can access external web services, but isn't required to.

::: moniker range="<=net-maui-10.0"

> [!IMPORTANT]
> By default, the <xref:Microsoft.Maui.Controls.HybridWebView> control won't be available when full trimming or Native AOT is enabled. To change this behavior, see [Trimming feature switches](~/deployment/trimming.md#trimming-feature-switches).

::: moniker-end

::: moniker range=">=net-maui-11.0"

> [!IMPORTANT]
> In .NET 11 and later, the <xref:Microsoft.Maui.Controls.HybridWebView> control can be used with full trimming and Native AOT when JavaScript-to-.NET invocation is registered with source-generated JSON metadata. Use the <xref:Microsoft.Maui.Controls.HybridWebView.SetInvokeJavaScriptTarget%2A> overload that accepts a <xref:System.Text.Json.Serialization.JsonSerializerContext>. For more information, see [Invoke C# from JavaScript](#invoke-c-from-javascript).

::: moniker-end

[!INCLUDE [WebView2 Program Files warning](includes/webview2-program-files-warning.md)]

[!INCLUDE [browser-engines](includes/browser-engines.md)]
Expand Down Expand Up @@ -713,10 +724,8 @@ Your app's JavaScript code within the <xref:Microsoft.Maui.Controls.HybridWebVie
The following example defines public synchronous and asynchronous methods for invoking from JavaScript:

```csharp
public partial class MainPage : ContentPage
public sealed class DotNetMethods
{
...

public void DoSyncWork()
{
Debug.WriteLine("DoSyncWork");
Expand Down Expand Up @@ -777,10 +786,12 @@ public partial class MainPage : ContentPage
{
public string? Message { get; set; }
public int Value { get; set; }
}
}
}
```

::: moniker range="<=net-maui-10.0"

You must then call the <xref:Microsoft.Maui.Controls.HybridWebView.SetInvokeJavaScriptTarget%2A> method to set the object that will be the target of JavaScript calls from the <xref:Microsoft.Maui.Controls.HybridWebView>:

```csharp
Expand All @@ -789,12 +800,49 @@ public partial class MainPage : ContentPage
public MainPage()
{
InitializeComponent();
hybridWebView.SetInvokeJavaScriptTarget(this);
hybridWebView.SetInvokeJavaScriptTarget(new DotNetMethods());
}
...
}
```

::: moniker-end

::: moniker range=">=net-maui-11.0"

For .NET 11 and later apps that use full trimming or Native AOT, define a <xref:System.Text.Json.Serialization.JsonSerializerContext> with <xref:System.Text.Json.Serialization.JsonSerializableAttribute> entries for each parameter and return type used by methods JavaScript can invoke:

```csharp
using System.Text.Json.Serialization;

[JsonSerializable(typeof(int))]
[JsonSerializable(typeof(string))]
[JsonSerializable(typeof(DotNetMethods.SyncReturn))]
internal partial class MyJsonContext : JsonSerializerContext
{
}
```

Then call the <xref:Microsoft.Maui.Controls.HybridWebView.SetInvokeJavaScriptTarget%2A> overload that accepts the target object and JSON context:

```csharp
public partial class MainPage : ContentPage
{
public MainPage()
{
InitializeComponent();
hybridWebView.SetInvokeJavaScriptTarget(
new DotNetMethods(),
MyJsonContext.Default);
}
...
}
```

The source generator intercepts this overload and creates a trim-safe and AOT-safe dispatcher for JavaScript-to-.NET calls. The `SetInvokeJavaScriptTarget<T>(T target)` overload remains available for non-trim/AOT scenarios, but it uses reflection-based dispatch and is annotated with <xref:System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute> and <xref:System.Diagnostics.CodeAnalysis.RequiresDynamicCodeAttribute>, so it can produce trimming and Native AOT warnings.

::: moniker-end

The public methods on the object set via the <xref:Microsoft.Maui.Controls.HybridWebView.SetInvokeJavaScriptTarget%2A> method can then be invoked from JavaScript with the `window.HybridWebView.InvokeDotNet` function:

```js
Expand All @@ -818,8 +866,18 @@ The `window.HybridWebView.InvokeDotNet` JavaScript function invokes a specified

### Pass complex types from JavaScript to C\#

::: moniker range="<=net-maui-10.0"

When invoking C# methods from JavaScript, you can pass complex types (objects, not just primitives) as parameters and receive complex types as return values. Unlike when [invoking JavaScript from C#](#invoke-javascript-from-c), you don't need to define a `JsonSerializerContext` for JavaScript-to-C# invocations. The <xref:Microsoft.Maui.Controls.HybridWebView> automatically deserializes parameters using reflection-based JSON deserialization.

::: moniker-end

::: moniker range=">=net-maui-11.0"

When invoking C# methods from JavaScript, you can pass complex types (objects, not just primitives) as parameters and receive complex types as return values. In apps that use full trimming or Native AOT, register the JavaScript-to-.NET target with a <xref:System.Text.Json.Serialization.JsonSerializerContext> that contains <xref:System.Text.Json.Serialization.JsonSerializableAttribute> entries for each parameter and return type used by methods JavaScript can invoke. In non-trim/AOT scenarios, the legacy overload can still use reflection-based JSON deserialization but can produce trimming and Native AOT warnings.

::: moniker-end

To pass complex types from JavaScript to C#:

1. Define your C# class that will be used as a parameter or return type:
Expand All @@ -839,15 +897,40 @@ To pass complex types from JavaScript to C#:
}
```

1. Define a C# method that accepts the complex type:
1. Define a C# target class with a method that accepts the complex type:

```csharp
public string ProcessPerson(Person person)
public class DotNetMethods
{
return $"{person.Name} is {person.Age} years old and lives in {person.Address?.City}";
public string ProcessPerson(Person person)
{
return $"{person.Name} is {person.Age} years old and lives in {person.Address?.City}";
}
}
```

::: moniker range=">=net-maui-11.0"

1. For .NET 11 and later apps that use full trimming or Native AOT, define JSON metadata for the method's parameter and return types and register the target object with that context:

```csharp
using System.Text.Json.Serialization;

[JsonSerializable(typeof(Person))]
[JsonSerializable(typeof(string))]
internal partial class MyJsonContext : JsonSerializerContext
{
}
```

```csharp
hybridWebView.SetInvokeJavaScriptTarget(
new DotNetMethods(),
MyJsonContext.Default);
```

::: moniker-end
Comment thread
Copilot marked this conversation as resolved.
Outdated

1. Call the method from JavaScript, passing a JavaScript object that matches the C# class structure:

```js
Expand Down Expand Up @@ -1091,5 +1174,3 @@ Common patterns include:
| iOS | ❌ | ✅ | ❌ |
| Mac Catalyst | ❌ | ✅ | ❌ |
| Windows | ✅ | ✅ | ✅ |

::: moniker-end
Loading