diff --git a/docs/deployment/includes/feature-switches.md b/docs/deployment/includes/feature-switches.md index ea01953549..58a4c5eaa2 100644 --- a/docs/deployment/includes/feature-switches.md +++ b/docs/deployment/includes/feature-switches.md @@ -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: @@ -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 for your type and attach it to the type using the 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 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 switches: - The `MauiEnableVisualAssemblyScanning` MSBuild property has an equivalent switch named `Microsoft.Maui.RuntimeFeature.IsIVisualAssemblyScanningEnabled`. @@ -23,6 +32,11 @@ These MSBuild properties also have equivalent switches: - The `MauiImplicitCastOperatorsUsageViaReflectionSupport` MSBuild property has an equivalent switch named `Microsoft.Maui.RuntimeFeature.IsImplicitCastOperatorsUsageViaReflectionSupported`. - The `_MauiBindingInterceptorsSupport` MSBuild property has an equivalent switch named `Microsoft.Maui.RuntimeFeature.AreBindingInterceptorsSupported`. - The `MauiEnableXamlCBindingWithSourceCompilation` MSBuild property has an equivalent switch named `Microsoft.Maui.RuntimeFeature.MauiEnableXamlCBindingWithSourceCompilationEnabled`. + +::: moniker range="<=net-maui-10.0" + - The `MauiHybridWebViewSupported` MSBuild property has an equivalent 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. diff --git a/docs/deployment/includes/trimming-incompatibilities.md b/docs/deployment/includes/trimming-incompatibilities.md index bf826f1c1e..979e508f9c 100644 --- a/docs/deployment/includes/trimming-incompatibilities.md +++ b/docs/deployment/includes/trimming-incompatibilities.md @@ -1,6 +1,6 @@ --- ms.topic: include -ms.date: 12/03/2024 +ms.date: 07/08/2026 monikerRange: ">=net-maui-9.0" --- @@ -11,6 +11,12 @@ The following .NET MAUI features are incompatible with full trimming and will be - Loading XAML at runtime with the 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 . Instead, you should implement the 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 to define the appearance of 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 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 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 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). diff --git a/docs/user-interface/controls/hybridwebview.md b/docs/user-interface/controls/hybridwebview.md index 5701156fb5..9913d5d9f6 100644 --- a/docs/user-interface/controls/hybridwebview.md +++ b/docs/user-interface/controls/hybridwebview.md @@ -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. @@ -31,9 +31,20 @@ To create a .NET MAUI app with 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 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 control can be used with full trimming and Native AOT when JavaScript-to-.NET invocation is registered with source-generated JSON metadata. Use the overload that accepts a . 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)] @@ -713,10 +724,8 @@ Your app's JavaScript code within the method to set the object that will be the target of JavaScript calls from the : ```csharp @@ -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 with 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 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 target)` overload remains available for non-trim/AOT scenarios, but it uses reflection-based dispatch and is annotated with and , so it can produce trimming and Native AOT warnings. + +::: moniker-end + The public methods on the object set via the method can then be invoked from JavaScript with the `window.HybridWebView.InvokeDotNet` function: ```js @@ -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 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 that contains 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: @@ -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" + + 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 + 1. Call the method from JavaScript, passing a JavaScript object that matches the C# class structure: ```js @@ -1091,5 +1174,3 @@ Common patterns include: | iOS | ❌ | ✅ | ❌ | | Mac Catalyst | ❌ | ✅ | ❌ | | Windows | ✅ | ✅ | ✅ | - -::: moniker-end