Skip to content

chore: Introductory support for NativeAOT builds#1233

Draft
jonpryor wants to merge 1 commit intomasterfrom
dev/jonpryor/jonp-naot-support
Draft

chore: Introductory support for NativeAOT builds#1233
jonpryor wants to merge 1 commit intomasterfrom
dev/jonpryor/jonp-naot-support

Conversation

@jonpryor
Copy link
Contributor

@jonpryor jonpryor commented Jan 28, 2026

Context: unoplatform/uno@559b1f7
Context: unoplatform/uno.toolkit.ui@3ef6d6c
Context: unoplatform/ShowMeTheXAML#30

What do we want? To build and run with Native AOT!
Which in turn requires Uno.Sdk 6.6.0 or later:

sed -i '' 's/"Uno.Sdk": ".*"/"Uno.Sdk": "6.6.0-dev.15"/g' global.json

dotnet publish -c Release -r osx-x64 -f net10.0-desktop -p:TargetFrameworkOverride=net10.0-desktop \
  -bl Uno.Gallery/Uno.Gallery.csproj -p:UseSkiaRendering=true -p:SelfContained=true \
  -p:PublishAot=true

…which promptly fails to build:

…Microsoft.NET.Sdk.FrameworkReferenceResolution.targets(120,5): error NETSDK1207:
  Ahead-of-time compilation is not supported for the target framework.

~~ Build Support for Native AOT ~~

This specifically happens because Uno.Gallery.csproj has a
@(ProjectReference) to Uno.Gallery.SourceGenerators.csproj, which
is a .NET Standard 2.0 project, which doesn't support Native AOT.

To fix this, we need an "indirection": a property which we can set on
the command-line which causes $(PublishAot) to be set.

The "conventional" indirection used in unoplatform/uno SamplesApp and
in unoplatform/uno.chefs is $(SkiaPublishAot). This allows:

dotnet publish -c Release -r osx-x64 -f net10.0-desktop -p:TargetFrameworkOverride=net10.0-desktop \
  -bl Uno.Gallery/Uno.Gallery.csproj -p:UseSkiaRendering=true -p:SelfContained=true \
  -p:SkiaPublishAot=true \
  -p:EmitCompilerGeneratedFiles=true -p:CompilerGeneratedFilesOutputPath=`pwd`/_gen

which builds successfully. (It doesn't run successfully yet;
that's for later.)

~~ Build Support for Android + Native AOT ~~

Remove $(RunAOTCompilation) from the Android build, as it's
presence prevents use of Native AOT on Android:

/usr/local/share/dotnet/packs/Microsoft.Android.Sdk.Darwin/36.1.12/targets/Microsoft.Android.Sdk.Aot.targets(123,5): error
  Precompiling failed for …/Uno.Gallery/obj/Release/net10.0-android/android-x64/aot-in/System.Collections.dll with exit code 134.
  Runtime critical type System.RuntimeMethodHandle not found
# and 24 more similar errors

~~ Build Support for Mobile Side-by-Side Installation ~~

Additionally, to "reasonably easily" support side-by-side execution
of Uno Gallery builds on e.g. iOS or Android, introduce support for
the following MSBuild properties (also done in unoplatform/uno.chefs):

  • $(ApplicationIdVendorSuffix): Value to append to
    $(ApplicationId), so that separate builds have separate names.

  • $(ApplicationTitleVendorSuffix): Value to append to
    $(ApplicationTitle), so that the different builds are
    distinguishable on app launchers.

On iOS, this allows side-by-side installs, but the iOS build doesn't
use the $(ApplicationTitle) value. This is because
Uno.Gallery/Platforms/iOS/Info.plist already had a
CFBundleDisplayName entry, which overrides $(ApplicationTitle).
Remove the CFBundleDisplayName entry so that $(ApplicationTitle)
can be used to control CFBundleDisplayName.

~~ Desktop Startup Timing ~~

Introduce a trivial "hack" to support app starting time comparisons:
add a --exit command-line argument which causes the app to Exit()
at the end of App.OnLaunched(). This allows using time(1) to
capture "app startup time":

# CoreCLR:
% dotnet publish -c Release -r osx-x64 -f net10.0-desktop -p:TargetFrameworkOverride=net10.0-desktop \
  -bl Uno.Gallery/Uno.Gallery.csproj -p:UseSkiaRendering=true -p:SelfContained=true
% time Uno.Gallery/bin/Release/net10.0-desktop/osx-x64/publish/Uno.Gallery --exit
Uno.Gallery/bin/Release/net10.0-desktop/osx-x64/publish/Uno.Gallery --exit  1.08s user 0.32s system 70% cpu 1.982 total

# Native AOT:
% dotnet publish -c Release -r osx-x64 -f net10.0-desktop -p:TargetFrameworkOverride=net10.0-desktop \
  -bl Uno.Gallery/Uno.Gallery.csproj -p:UseSkiaRendering=true -p:SelfContained=true -p:SkiaPublishAot=true
% time Uno.Gallery/bin/Release/net10.0-desktop/osx-x64/publish/Uno.Gallery --exit
Uno.Gallery/bin/Release/net10.0-desktop/osx-x64/publish/Uno.Gallery --exit  0.27s user 0.15s system 51% cpu 0.811 total

Or on Windows:

Measure-Command { .\Uno.Gallery\bin\Release\net10.0-desktop\win-x64\publish\Uno.Gallery.exe --exit | Out-Default } | Select TotalMilliseconds

~~ iOS Startup Timing ~~

No changes are needed; to capture startup time on iOS:

  1. Install the .ipa onto your iOS device.

  2. Open Instruments (launch Xcode, then
    click Xcode > Open Developer Tool > Instruments)

  3. In Instruments, click File > New ⌘N.

  4. In the Choose a Template… window, select App Launch.

  5. In the Window which appears, in the central area is a Target
    section; from the Device dropdown, select your connected iOS
    device, and from the Target dropdowns, select Launch and
    the Uno Gallery app from the dropdown.

    Note: the Target dropdown shows CFBundleExecutable -- which is
    identical regardless of $(ApplicationIdVendorSuffix) or
    $(ApplicationTitleVendorSuffix) -- so this is easiest to do if
    there is only one Uno.Gallery app installed.

  6. Click File > Record Trace ⌘R to start recording, which will launch
    the app on the device.

  7. When the app has finished launching, force-quit the app.
    Instruments will now start processing the data.

  8. Type ⌘4 to switch to App Lifecycle. This shows a table of
    events with Start, Duration, and Narrative columns.
    Look for the Launching - Initial Frame Rendering Narrative entry.
    The Start value is the time taken to launch the app.

    Start Duration Narrative
    00:00.000.000 480.77 ms The system took 480.77 ms to create the process.
    00:01.306.446 4.41 ms Launching – Initial Frame Rendering

    In this run, app startup time was 1.306 seconds.

~~ Native AOT Runtime Fixes ~~

Begin fixing some of the runtime issues with Native AOT builds.
The following messages would appear on the Console during startup:

fail: Uno.Gallery.Sample[0]
      Failed to initialize data for `AutoSuggestBoxSamplePage`. dataType: Uno.Gallery.Views.Samples.AutoSuggestBoxSamplePageViewModel. Exception: System.MissingMethodException: No parameterless constructor defined for type 'Uno.Gallery.Views.Samples.AutoSuggestBoxSamplePageViewModel'.
         at System.ActivatorImplementation.CreateInstance(Type, Boolean) + 0x180
         at Uno.Gallery.Sample.CreateData(Type) + 0x3a
fail: Uno.Gallery.Sample[0]
      Failed to initialize data for `BarometerSamplePage`. dataType: BarometerSamplePageViewModel. Exception: System.MissingMethodException: No parameterless constructor defined for type 'BarometerSamplePageViewModel'.
         at System.ActivatorImplementation.CreateInstance(Type, Boolean) + 0x180
         at Uno.Gallery.Sample.CreateData(Type) + 0x3a

Plus 19 more similar messages.

These fail messages appear because of missing "reflection metadata"
(unoplatform/uno@559b1f78), and we can fix these by using the
[DynamicallyAccessedMembers] and [DynamicDependency] attributes.

In order to use [DynamicallyAccessedMembers], we need either a
generic type parameter or a typeof() expression. Searching around,
there are useful places typeof() is already used; from
Uno.Gallery.SourceGenerators generated output, in
$(CompilerGeneratedFilesOutputPath), we have:

// …/App.Samples.g.cs
public partial class App {
  public static Sample[] GetSamples()
  {
    return new[] {
      // …
      new global::Uno.Gallery.Sample(new global::Uno.Gallery.SamplePageAttribute(category: (global::Uno.Gallery.SampleCategory)(2), title: "AutoSuggestBox", source: (global::Uno.Gallery.SourceSdk)(0), glyph: "") { Description = @"Represents a text control that makes suggestions to users as they enter text.", DocumentationLink = "https://learn.microsoft.com/en-us/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.autosuggestbox?view=windows-app-sdk-1.3", DataType = typeof(global::Uno.Gallery.Views.Samples.AutoSuggestBoxSamplePageViewModel), SortOrder = 2147483647 }, typeof(Uno.Gallery.Views.Samples.AutoSuggestBoxSamplePage)),
      // …
    };
  }
}

Which has the handy benefit of containing both
AutoSuggestBoxSamplePage and AutoSuggestBoxSamplePageViewModel,
which were mentioned in the fail message.

This in turn makes the fix straightforward: update the Sample and
SamplePageAttribute types to use [DynamicallyAccessedMembers] on
their respective Type parameters and properties to preserve
constructors (from the original message) and properties, which almost
certainly will be needed anyway.
(Property preservation is reflexive at this point.)

If you select UI components > AutoSuggestBox in the left-side
tree view, then click the <> "Show XAML" button, nothing is shown
and the following messages are written to the Console:

fail: Uno.UI.DataBinding.BindingPropertyHelper[0]
      The [ShowMeTheXAML:XamlDisplayExtensions.Header] property getter does not exist on type [ShowMeTheXAML.XamlDisplay]
fail: Uno.UI.DataBinding.BindingPropertyHelper[0]
      The [ShowMeTheXAML:XamlDisplayExtensions.Description] property getter does not exist on type [ShowMeTheXAML.XamlDisplay]
fail: Uno.UI.DataBinding.BindingPropertyHelper[0]
      The [ShowMeTheXAML:XamlDisplayExtensions.Options] property getter does not exist on type [ShowMeTheXAML.XamlDisplay]
fail: Uno.UI.DataBinding.BindingPropertyHelper[0]
      The [ShowMeTheXAML:XamlDisplayExtensions.PrettyXaml] property getter does not exist on type [ShowMeTheXAML.XamlDisplay]
fail: Uno.UI.DataBinding.BindingPropertyHelper[0]
      The [ShowMeTheXAML:XamlDisplayExtensions.ShowXaml] property getter does not exist on type [ShowMeTheXAML.XamlDisplay]

This is because WPF Attached Properties require use of
[DynamicDependency] to ensure that the required methods are
accessible via Reflection; see also unoplatform/uno.toolkit.ui@3ef6d6ce.
Update all use of DependencyProperty.RegisterAttached() so that
required methods are retained.

Unfortunately, while this fixes the above fail messages, clicking
the <> "Show XAML" button still does nothing.

Fixing the <> "Show XAML" button requires
unoplatform/ShowMeTheXAML#30 and replacing the existing
XamlDisplay.Init() invocation with XamlDictionary.Init().
Bump to Uno.ShowMeTheXAML 2.0.0-dev0026 to get this fix, and bump
Uno.Sdk within global.json to 6.4.58 so that things still build.

If you select UI components > BreadcrumbBar in the left-side
tree view, then the BreadcrumbBar with Custom DataTemplate
section on the right-hand page doesn't show anything, and Console
output contains:

fail: Uno.UI.DataBinding.BindingPropertyHelper[0]
      The [Name] property getter does not exist on type [Uno.Gallery.Entities.Data.Folder]
fail: Uno.UI.DataBinding.BindingPropertyHelper[0]
      The [ItemCount] property getter does not exist on type [Uno.Gallery.Entities.Data.Folder]
fail: Uno.UI.DataBinding.BindingPropertyHelper[0]
      The [Description] property getter does not exist on type [Uno.Gallery.Entities.Data.Folder]

Fix this by adding [Microsoft.UI.Xaml.Data.Bindable] to
Uno.Gallery.Entities.Data.Folder. The use of [Bindable] causes
the Uno.UI.SourceGenerators.BindableTypeProvider source generator
to emit BindableType(…, typeof(Folder)) to BindableMetadata.g.cs,
which cause all public properties to be added to reflection metadata.

Add [Bindable] to all other types containing properties within
Uno.Gallery.Entities.Data. This fixes a number of other samples
and messages such as:

fail: Uno.UI.DataBinding.BindingPropertyHelper[0]
      The [Color] property getter does not exist on type [Uno.Gallery.Entities.Data.Record]

If you select UI features > Binding in the left-side
tree view, the right-hand panel would be subtly different between
CoreCLR and Native AOT:

  • CoreCLR: The length is: [empty]
  • Native AOT: The length is:

Worse, if you enter text into "myTextBox", the bound fields properly
update under CoreCLR. For example, enter "123" into "myTextBox",
and CoreCLR would show:

The text of myTextBox is: 123
The length is: 3

Under Native AOT, nothing updates.

Console output contains:

fail: Uno.UI.DataBinding.BindingPropertyHelper[0]
      The [Text] property getter does not exist on type [Uno.Gallery.Views.Samples.BindingSamplePageViewModel]
fail: Uno.UI.DataBinding.BindingPropertyHelper[0]
      The [TextLength] property getter does not exist on type [Uno.Gallery.Views.Samples.BindingSamplePageViewModel]

Fix this by adding [Bindable] to BindingSamplePageViewModel.
(Which means "just add [Bindable]!" is quickly becoming my favorite
answer to everything. Unless the type has required or init-only
properties; see also unoplatform/uno.chefs@06f4f804.)

Continue this pattern: update all types which implement
INotifyPropertyChanged or inherit from a type which implements
INotifyPropertyChanged to have [Bindable]. This fixes the
following fail messages, among others:

The [AccelerationX] property getter does not exist on type [Uno.Gallery.Views.Samples.AccelerometerSamplePageViewModel]
The [AccelerationY] property getter does not exist on type [Uno.Gallery.Views.Samples.AccelerometerSamplePageViewModel]
The [AccelerationZ] property getter does not exist on type [Uno.Gallery.Views.Samples.AccelerometerSamplePageViewModel]
The [AccelerometerAvailable] property getter does not exist on type [Uno.Gallery.Views.Samples.AccelerometerSamplePageViewModel]
The [ButtonContent] property getter does not exist on type [Uno.Gallery.Views.Samples.AccelerometerSamplePageViewModel]
The [ButtonContent] property getter does not exist on type [Uno.Gallery.Views.Samples.GeolocatorSamplePageViewModel]
The [GeolocatedAccuracy] property getter does not exist on type [Uno.Gallery.Views.Samples.GeolocatorSamplePageViewModel]
The [GeolocatedAltitude] property getter does not exist on type [Uno.Gallery.Views.Samples.GeolocatorSamplePageViewModel]
The [GeolocatedLatitude] property getter does not exist on type [Uno.Gallery.Views.Samples.GeolocatorSamplePageViewModel]
The [GeolocatedLongitude] property getter does not exist on type [Uno.Gallery.Views.Samples.GeolocatorSamplePageViewModel]
The [GeolocatedTimestamp] property getter does not exist on type [Uno.Gallery.Views.Samples.GeolocatorSamplePageViewModel]
The [LastReadTimestamp] property getter does not exist on type [Uno.Gallery.Views.Samples.AccelerometerSamplePageViewModel]
The [LastShakeTimestamp] property getter does not exist on type [Uno.Gallery.Views.Samples.AccelerometerSamplePageViewModel]
The [ListenButtonContent] property getter does not exist on type [Uno.Gallery.Views.Samples.ClipboardSamplePageViewModel]
The [Message] property getter does not exist on type [Uno.Gallery.Views.Samples.ClipboardSamplePageViewModel]
The [ReportInterval] property getter does not exist on type [Uno.Gallery.Views.Samples.AccelerometerSamplePageViewModel]
The [ShakeCount] property getter does not exist on type [Uno.Gallery.Views.Samples.AccelerometerSamplePageViewModel]
The [ToggleButtonContent] property getter does not exist on type [Uno.Gallery.Views.Samples.GeolocatorSamplePageViewModel]

@jonpryor jonpryor force-pushed the dev/jonpryor/jonp-naot-support branch from e4c85b8 to 4a9173e Compare January 28, 2026 22:29
jonpryor added a commit to unoplatform/ShowMeTheXAML that referenced this pull request Jan 29, 2026
Context: unoplatform/Uno.Gallery#1233
Context: unoplatform/uno-private#1696 (comment)

What do we want? To build and run Uno.Gallery with NativeAOT!
(See also: unoplatform/Uno.Gallery#1233)

We also want Uno.Gallery to run *properly*.

The problem: The "`<>` Show XAML" button doesn't work properly.

Use unoplatform/Uno.Gallery#1233 to build and run Uno.Gallery with
NativeAOT:

	dotnet publish -c Release -r osx-x64 -f net10.0-desktop -p:TargetFrameworkOverride=net10.0-desktop \
	  -bl Uno.Gallery/Uno.Gallery.csproj -p:UseSkiaRendering=true -p:SelfContained=true \
	  -p:SkiaPublishAot=true
	./Uno.Gallery/bin/Release/net10.0-desktop/osx-x64/publish/Uno.Gallery

Once the app has launched, select **UI components > AutoSuggestBox**
in the left-hand tree.  Then, in the right-hand panel, click the
"`<>` Show XAML" button.

Expected results: *Something is shown*.

Actual results: An empty box is shown.

As with most NativeAOT-related issues, this is due to Reflection:
`XamlDisplay.Init()` tries to lookup the `ShowMeTheXAML.XamlDictionary`
type from an `Assembly`.  By default, nothing is statically referencing
`XamlDictionary`, so it isn't accessible via Reflection, so this
attempted lookup (silently) fails.

This aspect can be worked around in Uno.Gallery via
[`[DynamicDependency]`][0], e.g.

	diff --git a/Uno.Gallery/App.xaml.cs b/Uno.Gallery/App.xaml.cs
	index 51ae161a..45b16dfd 100644
	--- a/Uno.Gallery/App.xaml.cs
	+++ b/Uno.Gallery/App.xaml.cs
	@@ -78,6 +78,7 @@ namespace Uno.Gallery
	                        }
	                }

	+               [System.Diagnostics.CodeAnalysis.DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(ShowMeTheXAML.XamlDictionary))]
	                private void OnLaunchedOrActivated()
	                {
	                        MainWindow = new Window();

The problem is that once `XamlDisplay.Init()` finds `XamlDictionary`,
it then attempts to invoke its static constructor:

	//Invoke the static constructor
	global::System.Runtime.CompilerServices.RuntimeHelpers.RunClassConstructor(xamlDictionary.TypeHandle);

*This* fails, hard:

	System.NotSupportedException: 'ShowMeTheXAML.XamlDictionary' is missing native code or metadata. This can happen for code that is not compatible with trimming or AOT. Inspect and fix trimming and AOT related warnings that were generated when the app was published. For more information see https://aka.ms/nativeaot-compatibility
	   at System.Reflection.Runtime.TypeInfos.RuntimeTypeInfo.get_TypeHandle() + 0x95
	   at ShowMeTheXAML.XamlDisplay.<Init>g__LoadFromAssembly|7_0(Assembly) + 0x4d
	   at ShowMeTheXAML.XamlDisplay.Init(Assembly[]) + 0x47
	   at Uno.Gallery.App..ctor() + 0x99
	   at Uno.Gallery.Program.<>c.<Main>b__0_0() + 0x18
	   at Uno.UI.Runtime.Skia.MacOS.MacSkiaHost.<StartApp>g__CreateApp|18_0(ApplicationInitializationCallbackParams _) + 0x21
	   at Microsoft.UI.Xaml.Application.StartPartial(ApplicationInitializationCallback) + 0x70
	   at Uno.UI.Runtime.Skia.MacOS.MacSkiaHost.StartApp() + 0xbc

Address this by removing the *need* for Reflection: update the
`XamlDictionary` templates to contain a static `Init()` method:

	partial class XamlDictionary
	{
	    public static void Init()
	    {
	    }
	}

This allows Uno.Gallery to *explicitly* call `XamlDictionary.Init()`,
which *implicitly* invokes the `XamlDictionary` static constructor,
avoiding the need for Reflection *entirely*.

This in turn allows the "`<>` Show XAML" button to work properly.

Additionally, make the `XamlDictionary` declaration `partial`, so
that if future "workarounds" such as `Init()` are needed, a new
`Uno.ShowMeTheXAML.MSBuild` NuGet package isn't required.

[0]: https://learn.microsoft.com/en-us/dotnet/api/system.diagnostics.codeanalysis.dynamicdependencyattribute?view=net-9.0
jonpryor added a commit to unoplatform/ShowMeTheXAML that referenced this pull request Jan 30, 2026
Context: unoplatform/Uno.Gallery#1233
Context: unoplatform/uno-private#1696 (comment)

What do we want? To build and run Uno.Gallery with NativeAOT!
(See also: unoplatform/Uno.Gallery#1233)

We also want Uno.Gallery to run *properly*.

The problem: The "`<>` Show XAML" button doesn't work properly.

Use unoplatform/Uno.Gallery#1233 to build and run Uno.Gallery with
NativeAOT:

	dotnet publish -c Release -r osx-x64 -f net10.0-desktop -p:TargetFrameworkOverride=net10.0-desktop \
	  -bl Uno.Gallery/Uno.Gallery.csproj -p:UseSkiaRendering=true -p:SelfContained=true \
	  -p:SkiaPublishAot=true
	./Uno.Gallery/bin/Release/net10.0-desktop/osx-x64/publish/Uno.Gallery

Once the app has launched, select **UI components > AutoSuggestBox**
in the left-hand tree.  Then, in the right-hand panel, click the
"`<>` Show XAML" button.

Expected results: *Something is shown*.

Actual results: An empty box is shown.

As with most NativeAOT-related issues, this is due to Reflection:
`XamlDisplay.Init()` tries to lookup the `ShowMeTheXAML.XamlDictionary`
type from an `Assembly`.  By default, nothing is statically referencing
`XamlDictionary`, so it isn't accessible via Reflection, so this
attempted lookup (silently) fails.

This aspect can be worked around in Uno.Gallery via
[`[DynamicDependency]`][0], e.g.

	diff --git a/Uno.Gallery/App.xaml.cs b/Uno.Gallery/App.xaml.cs
	index 51ae161a..45b16dfd 100644
	--- a/Uno.Gallery/App.xaml.cs
	+++ b/Uno.Gallery/App.xaml.cs
	@@ -78,6 +78,7 @@ namespace Uno.Gallery
	                        }
	                }

	+               [System.Diagnostics.CodeAnalysis.DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(ShowMeTheXAML.XamlDictionary))]
	                private void OnLaunchedOrActivated()
	                {
	                        MainWindow = new Window();

The problem is that once `XamlDisplay.Init()` finds `XamlDictionary`,
it then attempts to invoke its static constructor:

	//Invoke the static constructor
	global::System.Runtime.CompilerServices.RuntimeHelpers.RunClassConstructor(xamlDictionary.TypeHandle);

*This* fails, hard:

	System.NotSupportedException: 'ShowMeTheXAML.XamlDictionary' is missing native code or metadata. This can happen for code that is not compatible with trimming or AOT. Inspect and fix trimming and AOT related warnings that were generated when the app was published. For more information see https://aka.ms/nativeaot-compatibility
	   at System.Reflection.Runtime.TypeInfos.RuntimeTypeInfo.get_TypeHandle() + 0x95
	   at ShowMeTheXAML.XamlDisplay.<Init>g__LoadFromAssembly|7_0(Assembly) + 0x4d
	   at ShowMeTheXAML.XamlDisplay.Init(Assembly[]) + 0x47
	   at Uno.Gallery.App..ctor() + 0x99
	   at Uno.Gallery.Program.<>c.<Main>b__0_0() + 0x18
	   at Uno.UI.Runtime.Skia.MacOS.MacSkiaHost.<StartApp>g__CreateApp|18_0(ApplicationInitializationCallbackParams _) + 0x21
	   at Microsoft.UI.Xaml.Application.StartPartial(ApplicationInitializationCallback) + 0x70
	   at Uno.UI.Runtime.Skia.MacOS.MacSkiaHost.StartApp() + 0xbc

Address this by removing the *need* for Reflection: update the
`XamlDictionary` templates to contain a static `Init()` method:

	partial class XamlDictionary
	{
	    public static void Init()
	    {
	    }
	}

This allows Uno.Gallery to *explicitly* call `XamlDictionary.Init()`,
which *implicitly* invokes the `XamlDictionary` static constructor,
avoiding the need for Reflection *entirely*.

This in turn allows the "`<>` Show XAML" button to work properly.

Additionally, make the `XamlDictionary` declaration `partial`, so
that if future "workarounds" such as `Init()` are needed, a new
`Uno.ShowMeTheXAML.MSBuild` NuGet package isn't required.

[0]: https://learn.microsoft.com/en-us/dotnet/api/system.diagnostics.codeanalysis.dynamicdependencyattribute?view=net-9.0
jonpryor added a commit to unoplatform/ShowMeTheXAML that referenced this pull request Jan 30, 2026
Context: unoplatform/Uno.Gallery#1233
Context: unoplatform/uno-private#1696 (comment)

What do we want? To build and run Uno.Gallery with NativeAOT!
(See also: unoplatform/Uno.Gallery#1233)

We also want Uno.Gallery to run *properly*.

The problem: The "`<>` Show XAML" button doesn't work properly.

Use unoplatform/Uno.Gallery#1233 to build and run Uno.Gallery with
NativeAOT:

	dotnet publish -c Release -r osx-x64 -f net10.0-desktop -p:TargetFrameworkOverride=net10.0-desktop \
	  -bl Uno.Gallery/Uno.Gallery.csproj -p:UseSkiaRendering=true -p:SelfContained=true \
	  -p:SkiaPublishAot=true
	./Uno.Gallery/bin/Release/net10.0-desktop/osx-x64/publish/Uno.Gallery

Once the app has launched, select **UI components > AutoSuggestBox**
in the left-hand tree.  Then, in the right-hand panel, click the
"`<>` Show XAML" button.

Expected results: *Something is shown*.

Actual results: An empty box is shown.

As with most NativeAOT-related issues, this is due to Reflection:
`XamlDisplay.Init()` tries to lookup the `ShowMeTheXAML.XamlDictionary`
type from an `Assembly`.  By default, nothing is statically referencing
`XamlDictionary`, so it isn't accessible via Reflection, so this
attempted lookup (silently) fails.

This aspect can be worked around in Uno.Gallery via
[`[DynamicDependency]`][0], e.g.

	diff --git a/Uno.Gallery/App.xaml.cs b/Uno.Gallery/App.xaml.cs
	index 51ae161a..45b16dfd 100644
	--- a/Uno.Gallery/App.xaml.cs
	+++ b/Uno.Gallery/App.xaml.cs
	@@ -78,6 +78,7 @@ namespace Uno.Gallery
	                        }
	                }

	+               [System.Diagnostics.CodeAnalysis.DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(ShowMeTheXAML.XamlDictionary))]
	                private void OnLaunchedOrActivated()
	                {
	                        MainWindow = new Window();

The problem is that once `XamlDisplay.Init()` finds `XamlDictionary`,
it then attempts to invoke its static constructor:

	//Invoke the static constructor
	global::System.Runtime.CompilerServices.RuntimeHelpers.RunClassConstructor(xamlDictionary.TypeHandle);

*This* fails, hard:

	System.NotSupportedException: 'ShowMeTheXAML.XamlDictionary' is missing native code or metadata. This can happen for code that is not compatible with trimming or AOT. Inspect and fix trimming and AOT related warnings that were generated when the app was published. For more information see https://aka.ms/nativeaot-compatibility
	   at System.Reflection.Runtime.TypeInfos.RuntimeTypeInfo.get_TypeHandle() + 0x95
	   at ShowMeTheXAML.XamlDisplay.<Init>g__LoadFromAssembly|7_0(Assembly) + 0x4d
	   at ShowMeTheXAML.XamlDisplay.Init(Assembly[]) + 0x47
	   at Uno.Gallery.App..ctor() + 0x99
	   at Uno.Gallery.Program.<>c.<Main>b__0_0() + 0x18
	   at Uno.UI.Runtime.Skia.MacOS.MacSkiaHost.<StartApp>g__CreateApp|18_0(ApplicationInitializationCallbackParams _) + 0x21
	   at Microsoft.UI.Xaml.Application.StartPartial(ApplicationInitializationCallback) + 0x70
	   at Uno.UI.Runtime.Skia.MacOS.MacSkiaHost.StartApp() + 0xbc

Address this by removing the *need* for Reflection: update the
`XamlDictionary` templates to contain a static `Init()` method:

	partial class XamlDictionary
	{
	    public static void Init()
	    {
	    }
	}

This allows Uno.Gallery to *explicitly* call `XamlDictionary.Init()`,
which *implicitly* invokes the `XamlDictionary` static constructor,
avoiding the need for Reflection *entirely*.

This in turn allows the "`<>` Show XAML" button to work properly.

Additionally, make the `XamlDictionary` declaration `partial`, so
that if future "workarounds" such as `Init()` are needed, a new
`Uno.ShowMeTheXAML.MSBuild` NuGet package isn't required.

[0]: https://learn.microsoft.com/en-us/dotnet/api/system.diagnostics.codeanalysis.dynamicdependencyattribute?view=net-9.0
jonpryor added a commit to unoplatform/ShowMeTheXAML that referenced this pull request Jan 30, 2026
Context: unoplatform/Uno.Gallery#1233
Context: unoplatform/uno-private#1696 (comment)

What do we want? To build and run Uno.Gallery with NativeAOT!
(See also: unoplatform/Uno.Gallery#1233)

We also want Uno.Gallery to run *properly*.

The problem: The "`<>` Show XAML" button doesn't work properly.

Use unoplatform/Uno.Gallery#1233 to build and run Uno.Gallery with
NativeAOT:

	dotnet publish -c Release -r osx-x64 -f net10.0-desktop -p:TargetFrameworkOverride=net10.0-desktop \
	  -bl Uno.Gallery/Uno.Gallery.csproj -p:UseSkiaRendering=true -p:SelfContained=true \
	  -p:SkiaPublishAot=true
	./Uno.Gallery/bin/Release/net10.0-desktop/osx-x64/publish/Uno.Gallery

Once the app has launched, select **UI components > AutoSuggestBox**
in the left-hand tree.  Then, in the right-hand panel, click the
"`<>` Show XAML" button.

Expected results: *Something is shown*.

Actual results: An empty box is shown.

As with most NativeAOT-related issues, this is due to Reflection:
`XamlDisplay.Init()` tries to lookup the `ShowMeTheXAML.XamlDictionary`
type from an `Assembly`.  By default, nothing is statically referencing
`XamlDictionary`, so it isn't accessible via Reflection, so this
attempted lookup (silently) fails.

This aspect can be worked around in Uno.Gallery via
[`[DynamicDependency]`][0], e.g.

	diff --git a/Uno.Gallery/App.xaml.cs b/Uno.Gallery/App.xaml.cs
	index 51ae161a..45b16dfd 100644
	--- a/Uno.Gallery/App.xaml.cs
	+++ b/Uno.Gallery/App.xaml.cs
	@@ -78,6 +78,7 @@ namespace Uno.Gallery
	                        }
	                }

	+               [System.Diagnostics.CodeAnalysis.DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(ShowMeTheXAML.XamlDictionary))]
	                private void OnLaunchedOrActivated()
	                {
	                        MainWindow = new Window();

The problem is that once `XamlDisplay.Init()` finds `XamlDictionary`,
it then attempts to invoke its static constructor:

	//Invoke the static constructor
	global::System.Runtime.CompilerServices.RuntimeHelpers.RunClassConstructor(xamlDictionary.TypeHandle);

*This* fails, hard:

	System.NotSupportedException: 'ShowMeTheXAML.XamlDictionary' is missing native code or metadata. This can happen for code that is not compatible with trimming or AOT. Inspect and fix trimming and AOT related warnings that were generated when the app was published. For more information see https://aka.ms/nativeaot-compatibility
	   at System.Reflection.Runtime.TypeInfos.RuntimeTypeInfo.get_TypeHandle() + 0x95
	   at ShowMeTheXAML.XamlDisplay.<Init>g__LoadFromAssembly|7_0(Assembly) + 0x4d
	   at ShowMeTheXAML.XamlDisplay.Init(Assembly[]) + 0x47
	   at Uno.Gallery.App..ctor() + 0x99
	   at Uno.Gallery.Program.<>c.<Main>b__0_0() + 0x18
	   at Uno.UI.Runtime.Skia.MacOS.MacSkiaHost.<StartApp>g__CreateApp|18_0(ApplicationInitializationCallbackParams _) + 0x21
	   at Microsoft.UI.Xaml.Application.StartPartial(ApplicationInitializationCallback) + 0x70
	   at Uno.UI.Runtime.Skia.MacOS.MacSkiaHost.StartApp() + 0xbc

Address this by removing the *need* for Reflection: update the
`XamlDictionary` templates to contain a static `Init()` method:

	partial class XamlDictionary
	{
	    public static void Init()
	    {
	    }
	}

This allows Uno.Gallery to *explicitly* call `XamlDictionary.Init()`,
which *implicitly* invokes the `XamlDictionary` static constructor,
avoiding the need for Reflection *entirely*.

This in turn allows the "`<>` Show XAML" button to work properly.

Additionally, make the `XamlDictionary` declaration `partial`, so
that if future "workarounds" such as `Init()` are needed, a new
`Uno.ShowMeTheXAML.MSBuild` NuGet package isn't required.

[0]: https://learn.microsoft.com/en-us/dotnet/api/system.diagnostics.codeanalysis.dynamicdependencyattribute?view=net-9.0
@jonpryor jonpryor force-pushed the dev/jonpryor/jonp-naot-support branch from 4a9173e to a7f8427 Compare January 30, 2026 20:15
@unodevops
Copy link

⚠️⚠️ The build 193979 has failed on Uno.Gallery - CI.

@jonpryor jonpryor force-pushed the dev/jonpryor/jonp-naot-support branch 2 times, most recently from bff0328 to c0c7d82 Compare February 2, 2026 19:50
@unodevops
Copy link

⚠️⚠️ The build 194240 has failed on Uno.Gallery - CI.

@jonpryor jonpryor force-pushed the dev/jonpryor/jonp-naot-support branch 2 times, most recently from bce852a to 9061849 Compare February 4, 2026 12:42
@unodevops
Copy link

⚠️⚠️ The build 194636 has failed on Uno.Gallery - CI.

jonpryor added a commit to unoplatform/uno that referenced this pull request Feb 4, 2026
Context: unoplatform/Uno.Gallery#1233

While trying to get Uno Gallery working with Android+Native AOT:

	dotnet publish -m:1 -c Release -r android-x64 -f net10.0-android -p:TargetFrameworkOverride=net10.0-android \
	  -bl Uno.Gallery/Uno.Gallery.csproj -p:UseSkiaRendering=true -p:SkiaPublishAot=true
	adb install Uno.Gallery/bin/Release/net10.0-android/android-x64/publish/com.nventive.uno.ui.demo-Signed.apk
	adb shell am start com.nventive.uno.ui.demo/crc64a57a145253f0f267.MainActivity

The app would crash at startup:

	E DOTNET  : Unhandled exception.
	E DOTNET  : System.Reflection.TargetInvocationException: Arg_TargetInvocationException
	E DOTNET  :  ---> System.Exception: Failed to load icuuc.
	E DOTNET  :    at Microsoft.UI.Xaml.Documents.UnicodeText.ICU.Init() + 0x338
	E DOTNET  :    at libUno.Gallery!<BaseAddress>+0x570efa9
	E DOTNET  :    at System.Reflection.DynamicInvokeInfo.InvokeWithFewArguments(IntPtr, Byte&, Byte&, Object[], BinderBundle, Boolean) + 0x91
	E DOTNET  :    Exception_EndOfInnerExceptionStack
	E DOTNET  :    at System.Reflection.DynamicInvokeInfo.InvokeWithFewArguments(IntPtr, Byte&, Byte&, Object[], BinderBundle, Boolean) + 0x11f
	E DOTNET  :    at System.Reflection.DynamicInvokeInfo.Invoke(Object, IntPtr, Object[], BinderBundle, Boolean) + 0xba
	E DOTNET  :    at Internal.Reflection.Execution.MethodInvokers.StaticMethodInvoker.Invoke(Object, Object[], BinderBundle, Boolean) + 0x20
	E DOTNET  :    at Internal.Reflection.Core.Execution.MethodBaseInvoker.Invoke(Object, Object[], Binder, BindingFlags, CultureInfo) + 0x48
	E DOTNET  :    at System.Reflection.Runtime.MethodInfos.RuntimeMethodInfo.Invoke(Object, BindingFlags, Binder, Object[], CultureInfo) + 0x70
	E DOTNET  :    at __IcuDa

The cause of the crash is *not* that `icuuc` could not be loaded,
unlike what the exception messages says.

Instead, the problem is that the `u_getVersion_N` symbol could not be
found, where `N` is a value in range [67-100].

The Android emulator that @jonpryor was using was for API-28, which
is version *60*:

	% adb pull /system/lib/libicuuc.so
	% nm -D libicuuc.so| grep u_getV
	00077580 T u_getVersion_60

Expand the range of versions probed to [50-100], which covers Android
API-21+.  (API-21 has `u_getVersion_53`.). This allows ICU to be
initialized correctly on Android API-21+.
@jonpryor jonpryor force-pushed the dev/jonpryor/jonp-naot-support branch from 9061849 to 95acf1e Compare February 6, 2026 12:46
@unodevops
Copy link

⚠️⚠️ The build 195092 has failed on Uno.Gallery - CI.

@jonpryor jonpryor force-pushed the dev/jonpryor/jonp-naot-support branch from 95acf1e to f93a246 Compare February 6, 2026 19:55
Context: unoplatform/uno@559b1f7
Context: unoplatform/uno.toolkit.ui@3ef6d6c
Context: unoplatform/ShowMeTheXAML#30

What do we want? To build and run with Native AOT!
Which in turn requires Uno.Sdk 6.6.0 or later:

	sed -i '' 's/"Uno.Sdk": ".*"/"Uno.Sdk": "6.6.0-dev.15"/g' global.json

	dotnet publish -c Release -r osx-x64 -f net10.0-desktop -p:TargetFrameworkOverride=net10.0-desktop \
	  -bl Uno.Gallery/Uno.Gallery.csproj -p:UseSkiaRendering=true -p:SelfContained=true \
	  -p:PublishAot=true

…which promptly fails to build:

	…Microsoft.NET.Sdk.FrameworkReferenceResolution.targets(120,5): error NETSDK1207:
	  Ahead-of-time compilation is not supported for the target framework.

~~ Build Support for Native AOT ~~

This specifically happens because `Uno.Gallery.csproj` has a
`@(ProjectReference)` to `Uno.Gallery.SourceGenerators.csproj`, which
is a .NET Standard 2.0 project, which doesn't support Native AOT.

To fix this, we need an "indirection": a property which we can set on
the command-line which causes `$(PublishAot)` to be set.

The "conventional" indirection used in unoplatform/uno SamplesApp and
in unoplatform/uno.chefs is `$(SkiaPublishAot)`.  This allows:

	dotnet publish -c Release -r osx-x64 -f net10.0-desktop -p:TargetFrameworkOverride=net10.0-desktop \
	  -bl Uno.Gallery/Uno.Gallery.csproj -p:UseSkiaRendering=true -p:SelfContained=true \
	  -p:SkiaPublishAot=true \
	  -p:EmitCompilerGeneratedFiles=true -p:CompilerGeneratedFilesOutputPath=`pwd`/_gen

which *builds* successfully.  (It doesn't *run* successfully yet;
that's for later.)

~~ Build Support for Android + Native AOT ~~

Remove `$(RunAOTCompilation)` from the Android build, as it's
presence prevents use of Native AOT on Android:

	/usr/local/share/dotnet/packs/Microsoft.Android.Sdk.Darwin/36.1.12/targets/Microsoft.Android.Sdk.Aot.targets(123,5): error
	  Precompiling failed for …/Uno.Gallery/obj/Release/net10.0-android/android-x64/aot-in/System.Collections.dll with exit code 134.
	  Runtime critical type System.RuntimeMethodHandle not found
	# and 24 more similar errors

~~ Build Support for Mobile Side-by-Side Installation ~~

Additionally, to "reasonably easily" support side-by-side execution
of Uno Gallery builds on e.g. iOS or Android, introduce support for
the following MSBuild properties (also done in unoplatform/uno.chefs):

  * `$(ApplicationIdVendorSuffix)`: Value to append to
    `$(ApplicationId)`, so that separate builds have separate names.

  * `$(ApplicationTitleVendorSuffix)`: Value to append to
    `$(ApplicationTitle)`, so that the different builds are
    distinguishable on app launchers.

On iOS, this allows side-by-side installs, but the iOS build doesn't
use the `$(ApplicationTitle)` value.  This is because
`Uno.Gallery/Platforms/iOS/Info.plist` already had a
`CFBundleDisplayName` entry, which overrides `$(ApplicationTitle)`.
Remove the `CFBundleDisplayName` entry so that `$(ApplicationTitle)`
can be used to control `CFBundleDisplayName`.

~~ Desktop Startup Timing ~~

Introduce a trivial "hack" to support app starting time comparisons:
add a `--exit` command-line argument which causes the app to `Exit()`
at the end of `App.OnLaunched()`.  This allows using **time**(1) to
capture "app startup time":

	# CoreCLR:
	% dotnet publish -c Release -r osx-x64 -f net10.0-desktop -p:TargetFrameworkOverride=net10.0-desktop \
	  -bl Uno.Gallery/Uno.Gallery.csproj -p:UseSkiaRendering=true -p:SelfContained=true
	% time Uno.Gallery/bin/Release/net10.0-desktop/osx-x64/publish/Uno.Gallery --exit
	Uno.Gallery/bin/Release/net10.0-desktop/osx-x64/publish/Uno.Gallery --exit  1.08s user 0.32s system 70% cpu 1.982 total

	# Native AOT:
	% dotnet publish -c Release -r osx-x64 -f net10.0-desktop -p:TargetFrameworkOverride=net10.0-desktop \
	  -bl Uno.Gallery/Uno.Gallery.csproj -p:UseSkiaRendering=true -p:SelfContained=true -p:SkiaPublishAot=true
	% time Uno.Gallery/bin/Release/net10.0-desktop/osx-x64/publish/Uno.Gallery --exit
	Uno.Gallery/bin/Release/net10.0-desktop/osx-x64/publish/Uno.Gallery --exit  0.27s user 0.15s system 51% cpu 0.811 total

Or on Windows:

	Measure-Command { .\Uno.Gallery\bin\Release\net10.0-desktop\win-x64\publish\Uno.Gallery.exe --exit | Out-Default } | Select TotalMilliseconds

~~ iOS Startup Timing ~~

No changes are needed; to capture startup time on iOS:

 1. Install the `.ipa` onto your iOS device.

 2. Open **Instruments** (launch Xcode, then
    click Xcode > Open Developer Tool > Instruments)

 3. In Instruments, click File > New ⌘N.

 4. In the **Choose a Template…** window, select **App Launch**.

 5. In the Window which appears, in the central area is a **Target**
    section; from the **Device** dropdown, select your connected iOS
	device, and from the **Target** dropdowns, select **Launch** and
	the Uno Gallery app from the dropdown.

    Note: the Target dropdown shows `CFBundleExecutable` -- which is
	identical regardless of `$(ApplicationIdVendorSuffix)` or
	`$(ApplicationTitleVendorSuffix)` -- so this is	easiest to do if
	there is only *one* Uno.Gallery app installed.

 6. Click File > Record Trace ⌘R to start recording, which will launch
	the app on the device.

 7. When the app has finished launching, force-quit the app.
    Instruments will now start processing the data.

 8. Type ⌘4 to switch to **App Lifecycle**.  This shows a table of
    events with Start, Duration, and Narrative columns.
    Look for the *Launching - Initial Frame Rendering* Narrative entry.
    The Start value is the time taken to launch the app.

    |         Start |  Duration | Narrative                                         |
    | ------------: | --------: | :------------------------------------------------ |
    | 00:00.000.000 | 480.77 ms | The system took 480.77 ms to create the process.  |
    |             … |         … | …                                                 |
    | 00:01.306.446 |   4.41 ms | Launching – Initial Frame Rendering               |

    In this run, app startup time was 1.306 seconds.

~~ Native AOT Runtime Fixes ~~

Begin fixing some of the runtime issues with Native AOT builds.
The following messages would appear on the Console during startup:

	fail: Uno.Gallery.Sample[0]
	      Failed to initialize data for `AutoSuggestBoxSamplePage`. dataType: Uno.Gallery.Views.Samples.AutoSuggestBoxSamplePageViewModel. Exception: System.MissingMethodException: No parameterless constructor defined for type 'Uno.Gallery.Views.Samples.AutoSuggestBoxSamplePageViewModel'.
	         at System.ActivatorImplementation.CreateInstance(Type, Boolean) + 0x180
	         at Uno.Gallery.Sample.CreateData(Type) + 0x3a
	fail: Uno.Gallery.Sample[0]
	      Failed to initialize data for `BarometerSamplePage`. dataType: BarometerSamplePageViewModel. Exception: System.MissingMethodException: No parameterless constructor defined for type 'BarometerSamplePageViewModel'.
	         at System.ActivatorImplementation.CreateInstance(Type, Boolean) + 0x180
	         at Uno.Gallery.Sample.CreateData(Type) + 0x3a

Plus 19 more similar messages.

These `fail` messages appear because of missing "reflection metadata"
(unoplatform/uno@559b1f78), and we can fix these by using the
`[DynamicallyAccessedMembers]` and `[DynamicDependency]` attributes.

In order to use `[DynamicallyAccessedMembers]`, we need either a
generic type parameter or a `typeof()` expression.  Searching around,
there are useful places `typeof()` is already used; from
`Uno.Gallery.SourceGenerators` generated output, in
`$(CompilerGeneratedFilesOutputPath)`, we have:

	// …/App.Samples.g.cs
	public partial class App {
	  public static Sample[] GetSamples()
	  {
	    return new[] {
	      // …
	      new global::Uno.Gallery.Sample(new global::Uno.Gallery.SamplePageAttribute(category: (global::Uno.Gallery.SampleCategory)(2), title: "AutoSuggestBox", source: (global::Uno.Gallery.SourceSdk)(0), glyph: "") { Description = @"Represents a text control that makes suggestions to users as they enter text.", DocumentationLink = "https://learn.microsoft.com/en-us/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.autosuggestbox?view=windows-app-sdk-1.3", DataType = typeof(global::Uno.Gallery.Views.Samples.AutoSuggestBoxSamplePageViewModel), SortOrder = 2147483647 }, typeof(Uno.Gallery.Views.Samples.AutoSuggestBoxSamplePage)),
	      // …
	    };
	  }
	}

Which has the handy benefit of containing *both*
`AutoSuggestBoxSamplePage` and `AutoSuggestBoxSamplePageViewModel`,
which were mentioned in the `fail` message.

This in turn makes the fix straightforward: update the `Sample` and
`SamplePageAttribute` types to use `[DynamicallyAccessedMembers]` on
their respective `Type` parameters and properties to preserve
constructors (from the original message) and properties, which almost
certainly will be needed anyway.
(Property preservation is reflexive at this point.)

If you select **UI components > AutoSuggestBox** in the left-side
tree view, then click the `<>` "Show XAML" button, nothing is shown
*and* the following messages are written to the Console:

	fail: Uno.UI.DataBinding.BindingPropertyHelper[0]
	      The [ShowMeTheXAML:XamlDisplayExtensions.Header] property getter does not exist on type [ShowMeTheXAML.XamlDisplay]
	fail: Uno.UI.DataBinding.BindingPropertyHelper[0]
	      The [ShowMeTheXAML:XamlDisplayExtensions.Description] property getter does not exist on type [ShowMeTheXAML.XamlDisplay]
	fail: Uno.UI.DataBinding.BindingPropertyHelper[0]
	      The [ShowMeTheXAML:XamlDisplayExtensions.Options] property getter does not exist on type [ShowMeTheXAML.XamlDisplay]
	fail: Uno.UI.DataBinding.BindingPropertyHelper[0]
	      The [ShowMeTheXAML:XamlDisplayExtensions.PrettyXaml] property getter does not exist on type [ShowMeTheXAML.XamlDisplay]
	fail: Uno.UI.DataBinding.BindingPropertyHelper[0]
	      The [ShowMeTheXAML:XamlDisplayExtensions.ShowXaml] property getter does not exist on type [ShowMeTheXAML.XamlDisplay]

This is because WPF Attached Properties require use of
`[DynamicDependency]` to ensure that the required methods are
accessible via Reflection; see also unoplatform/uno.toolkit.ui@3ef6d6ce.
Update all use of `DependencyProperty.RegisterAttached()` so that
required methods are retained.

Unfortunately, while this fixes the above `fail` messages, clicking
the `<>` "Show XAML" button still does nothing.

Fixing the `<>` "Show XAML" button requires
unoplatform/ShowMeTheXAML#30 and replacing the existing
`XamlDisplay.Init()` invocation with `XamlDictionary.Init()`.
Bump to Uno.ShowMeTheXAML 2.0.0-dev0026 to get this fix.
Unfortunately, this breaks the build:

	D:\a\1\s\Uno.Gallery\Uno.Gallery.csproj : error NU1605: Warning As Error: Detected package downgrade: Microsoft.Windows.SDK.BuildTools from 10.0.28000.1-RTM to 10.0.26100.7463. Reference the package directly from the project to select a different version.
	D:\a\1\s\Uno.Gallery\Uno.Gallery.csproj : error NU1605:  Uno.Gallery -> Uno.ShowMeTheXAML 2.0.0-dev0026 -> Microsoft.Windows.SDK.BuildTools (>= 10.0.28000.1-RTM)
	D:\a\1\s\Uno.Gallery\Uno.Gallery.csproj : error NU1605:  Uno.Gallery -> Microsoft.Windows.SDK.BuildTools (>= 10.0.26100.7463)
	D:\a\1\s\Uno.Gallery\Uno.Gallery.csproj : error NU1605: Warning As Error: Detected package downgrade: Microsoft.WindowsAppSDK from 1.8.260101001 to 1.7.250909003. Reference the package directly from the project to select a different version.
	D:\a\1\s\Uno.Gallery\Uno.Gallery.csproj : error NU1605:  Uno.Gallery -> Uno.ShowMeTheXAML 2.0.0-dev0026 -> Microsoft.WindowsAppSDK (>= 1.8.260101001)
	D:\a\1\s\Uno.Gallery\Uno.Gallery.csproj : error NU1605:  Uno.Gallery -> Microsoft.WindowsAppSDK (>= 1.7.250909003)

Fix this error by explicitly adding `Microsoft.WindowsAppSDK` and
`Microsoft.Windows.SDK.BuildTools` NuGet package references which
match the versions used by `Uno.ShowMeTheXAML`.

If you select **UI components > BreadcrumbBar** in the left-side
tree view, then the **BreadcrumbBar with Custom DataTemplate**
section on the right-hand page doesn't show anything, and Console
output contains:

	fail: Uno.UI.DataBinding.BindingPropertyHelper[0]
	      The [Name] property getter does not exist on type [Uno.Gallery.Entities.Data.Folder]
	fail: Uno.UI.DataBinding.BindingPropertyHelper[0]
	      The [ItemCount] property getter does not exist on type [Uno.Gallery.Entities.Data.Folder]
	fail: Uno.UI.DataBinding.BindingPropertyHelper[0]
	      The [Description] property getter does not exist on type [Uno.Gallery.Entities.Data.Folder]

Fix this by adding `[Microsoft.UI.Xaml.Data.Bindable]` to
`Uno.Gallery.Entities.Data.Folder`.  The use of `[Bindable]` causes
the `Uno.UI.SourceGenerators.BindableTypeProvider` source generator
to emit `BindableType(…, typeof(Folder))` to `BindableMetadata.g.cs`,
which cause all public properties to be added to reflection metadata.

Add `[Bindable]` to all other types containing properties within
`Uno.Gallery.Entities.Data`.  This fixes a number of other samples
and messages such as:

	fail: Uno.UI.DataBinding.BindingPropertyHelper[0]
	      The [Color] property getter does not exist on type [Uno.Gallery.Entities.Data.Record]

If you select **UI features > Binding** in the left-side
tree view, the right-hand panel would be subtly different between
CoreCLR and Native AOT:

  * CoreCLR: `The length is: [empty]`
  * Native AOT: `The length is:`

Worse, if you enter text into "myTextBox", the bound fields properly
update under CoreCLR.  For example, enter "123" into "myTextBox",
and CoreCLR would show:

> The text of myTextBox is: 123
> The length is: 3

Under Native AOT, *nothing* updates.

Console output contains:

	fail: Uno.UI.DataBinding.BindingPropertyHelper[0]
	      The [Text] property getter does not exist on type [Uno.Gallery.Views.Samples.BindingSamplePageViewModel]
	fail: Uno.UI.DataBinding.BindingPropertyHelper[0]
	      The [TextLength] property getter does not exist on type [Uno.Gallery.Views.Samples.BindingSamplePageViewModel]

Fix this by adding `[Bindable]` to `BindingSamplePageViewModel`.
(Which means "just add `[Bindable]`!" is quickly becoming my favorite
answer to everything.  Unless the type has `required` or `init`-only
properties; see also unoplatform/uno.chefs@06f4f804.)

Continue this pattern: update all types which implement
`INotifyPropertyChanged` or inherit from a type which implements
`INotifyPropertyChanged` to have `[Bindable]`.  This fixes the
following `fail` messages, among others:

	The [AccelerationX] property getter does not exist on type [Uno.Gallery.Views.Samples.AccelerometerSamplePageViewModel]
	The [AccelerationY] property getter does not exist on type [Uno.Gallery.Views.Samples.AccelerometerSamplePageViewModel]
	The [AccelerationZ] property getter does not exist on type [Uno.Gallery.Views.Samples.AccelerometerSamplePageViewModel]
	The [AccelerometerAvailable] property getter does not exist on type [Uno.Gallery.Views.Samples.AccelerometerSamplePageViewModel]
	The [ButtonContent] property getter does not exist on type [Uno.Gallery.Views.Samples.AccelerometerSamplePageViewModel]
	The [ButtonContent] property getter does not exist on type [Uno.Gallery.Views.Samples.GeolocatorSamplePageViewModel]
	The [GeolocatedAccuracy] property getter does not exist on type [Uno.Gallery.Views.Samples.GeolocatorSamplePageViewModel]
	The [GeolocatedAltitude] property getter does not exist on type [Uno.Gallery.Views.Samples.GeolocatorSamplePageViewModel]
	The [GeolocatedLatitude] property getter does not exist on type [Uno.Gallery.Views.Samples.GeolocatorSamplePageViewModel]
	The [GeolocatedLongitude] property getter does not exist on type [Uno.Gallery.Views.Samples.GeolocatorSamplePageViewModel]
	The [GeolocatedTimestamp] property getter does not exist on type [Uno.Gallery.Views.Samples.GeolocatorSamplePageViewModel]
	The [LastReadTimestamp] property getter does not exist on type [Uno.Gallery.Views.Samples.AccelerometerSamplePageViewModel]
	The [LastShakeTimestamp] property getter does not exist on type [Uno.Gallery.Views.Samples.AccelerometerSamplePageViewModel]
	The [ListenButtonContent] property getter does not exist on type [Uno.Gallery.Views.Samples.ClipboardSamplePageViewModel]
	The [Message] property getter does not exist on type [Uno.Gallery.Views.Samples.ClipboardSamplePageViewModel]
	The [ReportInterval] property getter does not exist on type [Uno.Gallery.Views.Samples.AccelerometerSamplePageViewModel]
	The [ShakeCount] property getter does not exist on type [Uno.Gallery.Views.Samples.AccelerometerSamplePageViewModel]
	The [ToggleButtonContent] property getter does not exist on type [Uno.Gallery.Views.Samples.GeolocatorSamplePageViewModel]
@jonpryor jonpryor force-pushed the dev/jonpryor/jonp-naot-support branch from f93a246 to 0ab8c3e Compare February 6, 2026 20:13
@unodevops
Copy link

⚠️⚠️ The build 195192 has failed on Uno.Gallery - CI.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants