fix: Workaround Android/iOS HR issues
This commit is contained in:
Родитель
3bcdbcd368
Коммит
b992b48512
|
@ -21,8 +21,15 @@ internal class HotReloadWorkspace
|
|||
{
|
||||
public record UpdateResult(ImmutableArray<Diagnostic> Diagnostics, ImmutableArray<WatchHotReloadService.Update> MetadataUpdates);
|
||||
|
||||
const string NetCoreCapsRaw = "Baseline AddMethodToExistingType AddStaticFieldToExistingType AddInstanceFieldToExistingType NewTypeDefinition ChangeCustomAttributes UpdateParameters";
|
||||
const string MonoCapsRaw = "Baseline AddMethodToExistingType AddStaticFieldToExistingType NewTypeDefinition ChangeCustomAttributes";
|
||||
#if NET8_0
|
||||
const string NetCoreCapsRaw = "Baseline AddMethodToExistingType AddStaticFieldToExistingType NewTypeDefinition ChangeCustomAttributes AddInstanceFieldToExistingType GenericAddMethodToExistingType GenericUpdateMethod UpdateParameters GenericAddFieldToExistingType";
|
||||
const string MonoCapsRaw = "Baseline AddMethodToExistingType AddStaticFieldToExistingType NewTypeDefinition ChangeCustomAttributes AddInstanceFieldToExistingType GenericAddMethodToExistingType GenericUpdateMethod UpdateParameters GenericAddFieldToExistingType";
|
||||
#elif NET9_0
|
||||
const string NetCoreCapsRaw = "Baseline AddMethodToExistingType AddStaticFieldToExistingType NewTypeDefinition ChangeCustomAttributes AddInstanceFieldToExistingType GenericAddMethodToExistingType GenericUpdateMethod UpdateParameters GenericAddFieldToExistingType";
|
||||
const string MonoCapsRaw = "Baseline AddMethodToExistingType AddStaticFieldToExistingType NewTypeDefinition ChangeCustomAttributes AddInstanceFieldToExistingType GenericAddMethodToExistingType GenericUpdateMethod UpdateParameters GenericAddFieldToExistingType";
|
||||
#else
|
||||
#error Capabilities should be defined for the updated target framework.
|
||||
#endif
|
||||
|
||||
private readonly string _baseWorkFolder;
|
||||
private readonly bool _isDebugCompilation;
|
||||
|
@ -371,7 +378,7 @@ internal class HotReloadWorkspace
|
|||
#endif
|
||||
|
||||
var availableTargets = new[] {
|
||||
Path.Combine("Uno.UI.Skia", configuration, "8.0"),
|
||||
Path.Combine("Uno.UI.Skia", configuration, "net8.0"),
|
||||
Path.Combine("Uno.UI.Reference", configuration, "net8.0"),
|
||||
Path.Combine("Uno.UI.Tests", configuration, "net8.0"),
|
||||
};
|
||||
|
|
|
@ -143,6 +143,8 @@ namespace Uno.UI.SourceGenerators.XamlGenerator
|
|||
|
||||
internal ImmutableArray<ITypeProvider> TypeProviders { get; }
|
||||
|
||||
internal bool IsSkia { get; }
|
||||
|
||||
public XamlCodeGeneration(GeneratorExecutionContext context)
|
||||
{
|
||||
// To easily debug XAML code generation:
|
||||
|
@ -260,6 +262,7 @@ namespace Uno.UI.SourceGenerators.XamlGenerator
|
|||
_defaultNamespace = context.GetMSBuildPropertyValue("RootNamespace");
|
||||
|
||||
_isWasm = context.GetMSBuildPropertyValue("DefineConstantsProperty")?.Contains("__WASM__") ?? false;
|
||||
IsSkia = context.GetMSBuildPropertyValue("DefineConstantsProperty")?.Contains("__SKIA__") ?? false;
|
||||
_isDesignTimeBuild = Helpers.DesignTimeHelper.IsDesignTime(context);
|
||||
|
||||
StringSymbol = GetSpecialTypeSymbolAsLazy(SpecialType.System_String);
|
||||
|
@ -686,9 +689,10 @@ namespace Uno.UI.SourceGenerators.XamlGenerator
|
|||
writer.AppendLineIndented("/// Contains all the static resources defined for the application");
|
||||
writer.AppendLineIndented("/// </summary>");
|
||||
|
||||
if (_isDebug)
|
||||
if (_isDebug && !IsSkia)
|
||||
{
|
||||
//writer.AppendLineIndented("[global::System.Runtime.CompilerServices.CreateNewOnMetadataUpdate]");
|
||||
// On Skia, we don't use CreateNewOnMetadataUpdate at all.
|
||||
writer.AppendLineIndented("[global::System.Runtime.CompilerServices.CreateNewOnMetadataUpdate]");
|
||||
}
|
||||
|
||||
AnalyzerSuppressionsGenerator.Generate(writer, _analyzerSuppressions);
|
||||
|
|
|
@ -178,19 +178,19 @@ namespace Uno.UI.SourceGenerators.XamlGenerator
|
|||
return IsType(xamlType, Generation.FrameworkElementSymbol.Value);
|
||||
}
|
||||
|
||||
private bool IsAndroidView(XamlType xamlType)
|
||||
private bool IsAndroidView(INamedTypeSymbol? type)
|
||||
{
|
||||
return IsType(xamlType, Generation.AndroidViewSymbol.Value);
|
||||
return IsType(type, Generation.AndroidViewSymbol.Value);
|
||||
}
|
||||
|
||||
private bool IsIOSUIView(XamlType xamlType)
|
||||
private bool IsIOSUIView(INamedTypeSymbol? type)
|
||||
{
|
||||
return IsType(xamlType, Generation.IOSViewSymbol.Value);
|
||||
return IsType(type, Generation.IOSViewSymbol.Value);
|
||||
}
|
||||
|
||||
private bool IsMacOSNSView(XamlType xamlType)
|
||||
private bool IsMacOSNSView(INamedTypeSymbol? type)
|
||||
{
|
||||
return IsType(xamlType, Generation.AppKitViewSymbol.Value);
|
||||
return IsType(type, Generation.AppKitViewSymbol.Value);
|
||||
}
|
||||
|
||||
private bool IsDependencyObject(XamlObjectDefinition component)
|
||||
|
@ -205,7 +205,9 @@ namespace Uno.UI.SourceGenerators.XamlGenerator
|
|||
/// <summary>
|
||||
/// Is the type derived from the native view type on a Xamarin platform?
|
||||
/// </summary>
|
||||
private bool IsNativeView(XamlType xamlType) => IsAndroidView(xamlType) || IsIOSUIView(xamlType) || IsMacOSNSView(xamlType);
|
||||
private bool IsNativeView(XamlType xamlType) => IsNativeView(FindType(xamlType));
|
||||
|
||||
private bool IsNativeView(INamedTypeSymbol? type) => IsAndroidView(type) || IsIOSUIView(type) || IsMacOSNSView(type);
|
||||
|
||||
/// <summary>
|
||||
/// Is the type one of the base view types in WinUI? (UIElement is most commonly used to mean 'any WinUI view type,' but
|
||||
|
|
|
@ -372,7 +372,7 @@ namespace Uno.UI.SourceGenerators.XamlGenerator
|
|||
|
||||
var controlBaseType = GetType(topLevelControl.Type);
|
||||
|
||||
WriteMetadataNewTypeAttribute(writer);
|
||||
WriteMetadataNewTypeAttributeOnMarkerIfNativeView(writer, controlBaseType);
|
||||
|
||||
using (writer.BlockInvariant("partial class {0} : {1}", _xClassName.ClassName, controlBaseType.GetFullyQualifiedTypeIncludingGlobal()))
|
||||
{
|
||||
|
@ -1396,9 +1396,35 @@ namespace Uno.UI.SourceGenerators.XamlGenerator
|
|||
|
||||
private void WriteMetadataNewTypeAttribute(IIndentedStringBuilder writer)
|
||||
{
|
||||
if (_isHotReloadEnabled)
|
||||
if (_isHotReloadEnabled && !Generation.IsSkia)
|
||||
{
|
||||
//writer.AppendLineIndented("[global::System.Runtime.CompilerServices.CreateNewOnMetadataUpdate]");
|
||||
// On Skia, we don't use CreateNewOnMetadataUpdate at all.
|
||||
writer.AppendLineIndented("[global::System.Runtime.CompilerServices.CreateNewOnMetadataUpdate]");
|
||||
}
|
||||
}
|
||||
|
||||
private void WriteMetadataNewTypeAttributeOnMarkerIfNativeView(IIndentedStringBuilder writer, INamedTypeSymbol originalType)
|
||||
{
|
||||
if (!_isHotReloadEnabled || Generation.IsSkia)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (IsNativeView(originalType))
|
||||
{
|
||||
var originalTypeFullyQualified = originalType.GetFullyQualifiedTypeIncludingGlobal();
|
||||
// On non-Skia, we add the attribute to the marker class when the type is a native view
|
||||
writer.AppendLineIndented("[global::System.Runtime.CompilerServices.CreateNewOnMetadataUpdate]");
|
||||
writer.AppendLineIndented($"[global::Uno.Foundation.UnoOriginalType(typeof({originalTypeFullyQualified}))]");
|
||||
using (writer.BlockInvariant($"internal sealed class __Uno_HotReload_Marker_{originalType.Name}_{_fileDefinition.UniqueID}_{HashBuilder.Build(originalTypeFullyQualified)}"))
|
||||
{
|
||||
writer.AppendLineIndented($"private const string HashCode = \"{_fileDefinition.Checksum}\";");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// On non-Skia, we add the attribute directly if the type is not a native view
|
||||
writer.AppendLineIndented("[global::System.Runtime.CompilerServices.CreateNewOnMetadataUpdate]");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3824,12 +3850,13 @@ namespace Uno.UI.SourceGenerators.XamlGenerator
|
|||
writer.AppendLineInvariantIndented("// UI automation id: {0}", uiAutomationId);
|
||||
|
||||
// ContentDescription and AccessibilityIdentifier are used by Xamarin.UITest (Test Cloud) to identify visual elements
|
||||
if (IsAndroidView(parent.Type))
|
||||
var parentType = FindType(parent.Type);
|
||||
if (IsAndroidView(parentType))
|
||||
{
|
||||
writer.AppendLineInvariantIndented("{0}.ContentDescription = \"{1}\";", closureName, uiAutomationId);
|
||||
};
|
||||
|
||||
if (IsIOSUIView(parent.Type))
|
||||
if (IsIOSUIView(parentType))
|
||||
{
|
||||
writer.AppendLineInvariantIndented("{0}.AccessibilityIdentifier = \"{1}\";", closureName, uiAutomationId);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
using System.ComponentModel;
|
||||
|
||||
namespace Uno.Foundation;
|
||||
|
||||
/// <summary>
|
||||
/// This attribute is used by XAML generator for HotReload purposes.
|
||||
/// External users should not use this attribute.
|
||||
/// </summary>
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
public sealed class UnoOriginalTypeAttribute : Attribute
|
||||
{
|
||||
public UnoOriginalTypeAttribute(Type type)
|
||||
{
|
||||
OriginalType = type;
|
||||
}
|
||||
|
||||
public Type OriginalType { get; }
|
||||
}
|
|
@ -2,16 +2,17 @@
|
|||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.Loader;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Uno.Extensions;
|
||||
using Uno.Foundation;
|
||||
using Uno.Foundation.Logging;
|
||||
using Uno.UI.RemoteControl.HotReload.Messages;
|
||||
using System.Runtime.Loader;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace Uno.UI.RemoteControl.HotReload
|
||||
{
|
||||
|
@ -189,7 +190,7 @@ namespace Uno.UI.RemoteControl.HotReload
|
|||
from type in asm.GetTypes()
|
||||
let originalType = type.GetCustomAttribute<MetadataUpdateOriginalTypeAttribute>()
|
||||
where originalType is not null
|
||||
group type by originalType.OriginalType into g
|
||||
group type by GetOriginalType(type, originalType.OriginalType) into g
|
||||
select new
|
||||
{
|
||||
Key = g.Key.FullName,
|
||||
|
@ -199,5 +200,14 @@ namespace Uno.UI.RemoteControl.HotReload
|
|||
|
||||
return mappedTypes.ToDictionary(p => p.Key, p => p.LastMapped);
|
||||
}
|
||||
|
||||
private static Type GetOriginalType(Type type, Type originalType)
|
||||
// Normally, HotReload should work by reading the original type from MetadataUpdateOriginalTypeAttribute.
|
||||
// It's currently a problem on Android and iOS that a new type can't be emitted as it ends up with two managed types pointing to the same native type.
|
||||
// For this reason, we create a fake marker class with CreateNewOnMetadataUpdate attribute.
|
||||
// The marker class has UnoOriginalTypeAttribute which points to the real original type.
|
||||
// So, when we update the marker class, we should use the OriginalType specified by it.
|
||||
// Otherwise, use the original type from MetadataUpdateOriginalTypeAttribute
|
||||
=> type.GetCustomAttribute<UnoOriginalTypeAttribute>()?.OriginalType ?? originalType;
|
||||
}
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче