添加MemoryPack AOT支持

This commit is contained in:
LanZhan-Harmony
2026-03-11 14:41:39 +08:00
parent 7d3a99bb99
commit 04d3c79998
8 changed files with 221 additions and 150 deletions

View File

@@ -5,6 +5,7 @@ using Microsoft.Extensions.Logging;
using Microsoft.UI.Xaml;
using UntamedMusicPlayer.Activation;
using UntamedMusicPlayer.Contracts.Services;
using UntamedMusicPlayer.Helpers;
using UntamedMusicPlayer.Models;
using UntamedMusicPlayer.Services;
using UntamedMusicPlayer.ViewModels;
@@ -47,6 +48,9 @@ public sealed partial class App : Application
// 初始化日志服务(必须在任何日志记录之前)
LoggingService.Initialize();
// 初始化 MemoryPack 格式化器(用于 AOT 支持)
MemoryPackAotHelper.RegisterFormatters();
Host = Microsoft
.Extensions.Hosting.Host.CreateDefaultBuilder()
.UseContentRoot(AppContext.BaseDirectory)

View File

@@ -0,0 +1,66 @@
using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices;
using MemoryPack;
using MemoryPack.Formatters;
using UntamedMusicPlayer.Contracts.Models;
using UntamedMusicPlayer.Models;
using UntamedMusicPlayer.OnlineAPIs.CloudMusicAPI;
using UntamedMusicPlayer.Playback;
namespace UntamedMusicPlayer.Helpers;
public class MemoryPackAotHelper
{
public static void RegisterFormatters()
{
// 为 [MemoryPackable] 类型显式注册 MemoryPackableFormatter 以支持 NativeAOT
// 这样可以避开 MemoryPack 内部探测时使用的反射(容易因 NativeAOT 裁剪而失败)
Register<BriefLocalSongInfo>();
Register<BriefUnknownSongInfo>();
Register<BriefCloudOnlineSongInfo>();
Register<LocalAlbumInfo>();
Register<LocalArtistInfo>();
Register<PlaylistInfo>();
Register<IndexedPlaylistSong>();
Register<IndexedPlayQueueSong>();
// 接口类型特殊处理
RuntimeHelpers.RunClassConstructor(typeof(IBriefSongInfoBase).TypeHandle);
// 显式注册集合类型格式化器,以解决 NativeAOT 中的反射和修剪问题
MemoryPackFormatterProvider.Register(new ConcurrentBagFormatter<BriefLocalSongInfo>());
MemoryPackFormatterProvider.Register(
new ConcurrentDictionaryFormatter<string, LocalAlbumInfo>()
);
MemoryPackFormatterProvider.Register(
new ConcurrentDictionaryFormatter<string, LocalArtistInfo>()
);
MemoryPackFormatterProvider.Register(new ConcurrentDictionaryFormatter<string, byte>());
MemoryPackFormatterProvider.Register(
new ObservableCollectionFormatter<IndexedPlayQueueSong>()
);
MemoryPackFormatterProvider.Register(
new ObservableCollectionFormatter<IndexedPlaylistSong>()
);
MemoryPackFormatterProvider.Register(new ListFormatter<PlaylistInfo>());
MemoryPackFormatterProvider.Register(new ListFormatter<string>());
MemoryPackFormatterProvider.Register(new DictionaryFormatter<string, string>());
MemoryPackFormatterProvider.Register(new HashSetFormatter<string>());
}
[UnconditionalSuppressMessage(
"Trimming",
"IL2059",
Justification = "T is annotated with DynamicallyAccessedMembers(All) which preserves the static constructor."
)]
private static void Register<
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] T
>()
where T : class, IMemoryPackable<T>
{
// 运行静态构造函数以激活内部注册逻辑
RuntimeHelpers.RunClassConstructor(typeof(T).TypeHandle);
// 同时提供显式格式化器以防万一
MemoryPackFormatterProvider.Register(new MemoryPackableFormatter<T>());
}
}

View File

@@ -41,8 +41,7 @@ public static class FileManager
try
{
// 创建音乐库数据目录
var localFolder = ApplicationData.Current.LocalFolder;
var libraryFolder = await localFolder.CreateFolderAsync(
var libraryFolder = await ApplicationData.Current.LocalFolder.CreateFolderAsync(
"LibraryData",
CreationCollisionOption.OpenIfExists
);
@@ -98,8 +97,7 @@ public static class FileManager
{
try
{
var localFolder = ApplicationData.Current.LocalFolder;
var playQueueFolder = await localFolder.CreateFolderAsync(
var playQueueFolder = await ApplicationData.Current.LocalFolder.CreateFolderAsync(
"PlayQueueData",
CreationCollisionOption.OpenIfExists
);
@@ -128,8 +126,7 @@ public static class FileManager
{
try
{
var localFolder = ApplicationData.Current.LocalFolder;
var playlistFolder = await localFolder.CreateFolderAsync(
var playlistFolder = await ApplicationData.Current.LocalFolder.CreateFolderAsync(
"PlaylistData",
CreationCollisionOption.OpenIfExists
);
@@ -149,8 +146,7 @@ public static class FileManager
{
try
{
var localFolder = ApplicationData.Current.LocalFolder;
var playlistFolder = await localFolder.CreateFolderAsync(
var playlistFolder = await ApplicationData.Current.LocalFolder.CreateFolderAsync(
"PlaylistM3u8Data",
CreationCollisionOption.OpenIfExists
);
@@ -185,18 +181,16 @@ public static class FileManager
try
{
// 获取本地文件夹
var localFolder = ApplicationData.Current.LocalFolder;
// 尝试打开音乐库数据目录
StorageFolder libraryFolder;
try
{
libraryFolder = await localFolder.GetFolderAsync("LibraryData");
libraryFolder = await ApplicationData.Current.LocalFolder.GetFolderAsync(
"LibraryData"
);
}
catch
catch // 文件夹不存在,需要重新扫描
{
// 文件夹不存在,需要重新扫描
return (true, data);
}
@@ -295,11 +289,12 @@ public static class FileManager
{
try
{
var localFolder = ApplicationData.Current.LocalFolder;
StorageFolder playQueueFolder;
try
{
playQueueFolder = await localFolder.GetFolderAsync("PlayQueueData");
playQueueFolder = await ApplicationData.Current.LocalFolder.GetFolderAsync(
"PlayQueueData"
);
}
catch
{
@@ -335,11 +330,12 @@ public static class FileManager
{
try
{
var localFolder = ApplicationData.Current.LocalFolder;
StorageFolder playlistFolder;
try
{
playlistFolder = await localFolder.GetFolderAsync("PlaylistData");
playlistFolder = await ApplicationData.Current.LocalFolder.GetFolderAsync(
"PlaylistData"
);
}
catch
{
@@ -366,8 +362,18 @@ public static class FileManager
{
try
{
var localFolder = ApplicationData.Current.LocalFolder;
var playlistFolder = await localFolder.GetFolderAsync("PlaylistM3u8Data");
StorageFolder playlistFolder;
try
{
playlistFolder = await ApplicationData.Current.LocalFolder.GetFolderAsync(
"PlaylistM3u8Data"
);
}
catch
{
return [];
}
var files = await playlistFolder.GetFilesAsync();
var playlists = new List<PlaylistInfo>();
foreach (var file in files)

View File

@@ -11,8 +11,8 @@
<Identity
Name="C19A3696.28439CB846862"
Publisher="CN=D8BFD4E9-94E2-482B-A987-F96C72D65FDF"
Version="0.5.4.0" />
Publisher="CN=Admin"
Version="0.5.5.0" />
<mp:PhoneIdentity PhoneProductId="4b2c875e-db2d-4ef4-938e-760bd94fe9a8" PhonePublisherId="00000000-0000-0000-0000-000000000000"/>

View File

@@ -1,11 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<PublishProtocol>FileSystem</PublishProtocol>
<Platform>arm64</Platform>
<RuntimeIdentifier>win-arm64</RuntimeIdentifier>
<PublishDir>bin\$(Configuration)\$(TargetFramework)\$(RuntimeIdentifier)\publish\</PublishDir>
<SelfContained>True</SelfContained>
<PublishSingleFile>False</PublishSingleFile>
</PropertyGroup>
<PropertyGroup>
<PublishProtocol>FileSystem</PublishProtocol>
<Platform>arm64</Platform>
<RuntimeIdentifier>win-arm64</RuntimeIdentifier>
<PublishDir>bin\$(Configuration)\$(TargetFramework)\$(RuntimeIdentifier)\publish\</PublishDir>
<PublishSingleFile>False</PublishSingleFile>
</PropertyGroup>
<ItemGroup Condition="'$(Platform)' == 'arm64'">
<None Include="Libraries\arm64\**\*">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<Link>%(Filename)%(Extension)</Link>
</None>
</ItemGroup>
</Project>

View File

@@ -1,11 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<PublishProtocol>FileSystem</PublishProtocol>
<Platform>x64</Platform>
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
<PublishDir>bin\$(Configuration)\$(TargetFramework)\$(RuntimeIdentifier)\publish\</PublishDir>
<SelfContained>True</SelfContained>
<PublishSingleFile>False</PublishSingleFile>
</PropertyGroup>
<PropertyGroup>
<PublishProtocol>FileSystem</PublishProtocol>
<Platform>x64</Platform>
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
<PublishDir>bin\$(Configuration)\$(TargetFramework)\$(RuntimeIdentifier)\publish\</PublishDir>
<PublishSingleFile>False</PublishSingleFile>
</PropertyGroup>
<ItemGroup Condition="'$(Platform)' == 'x64'">
<None Include="Libraries\x64\**\*">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<Link>%(Filename)%(Extension)</Link>
</None>
</ItemGroup>
</Project>

View File

@@ -1,11 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<PublishProtocol>FileSystem</PublishProtocol>
<Platform>x86</Platform>
<RuntimeIdentifier>win-x86</RuntimeIdentifier>
<PublishDir>bin\$(Configuration)\$(TargetFramework)\$(RuntimeIdentifier)\publish\</PublishDir>
<SelfContained>True</SelfContained>
<PublishSingleFile>False</PublishSingleFile>
</PropertyGroup>
<PropertyGroup>
<PublishProtocol>FileSystem</PublishProtocol>
<Platform>x86</Platform>
<RuntimeIdentifier>win-x86</RuntimeIdentifier>
<PublishDir>bin\$(Configuration)\$(TargetFramework)\$(RuntimeIdentifier)\publish\</PublishDir>
<PublishSingleFile>False</PublishSingleFile>
</PropertyGroup>
<ItemGroup Condition="'$(Platform)' == 'x86'">
<None Include="Libraries\x86\**\*">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<Link>%(Filename)%(Extension)</Link>
</None>
</ItemGroup>
</Project>

View File

@@ -1,106 +1,86 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net10.0-windows10.0.26100.0</TargetFramework>
<TargetPlatformMinVersion>10.0.19041.0</TargetPlatformMinVersion>
<RootNamespace>UntamedMusicPlayer</RootNamespace>
<ApplicationIcon>Assets/AppIcon/Icon.ico</ApplicationIcon>
<ApplicationManifest>app.manifest</ApplicationManifest>
<Platforms>x86;x64;arm64</Platforms>
<RuntimeIdentifiers>win-x86;win-x64;win-arm64</RuntimeIdentifiers>
<PublishProfile>win-$(Platform).pubxml</PublishProfile>
<UseWinUI>True</UseWinUI>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<AllowUnsafeBlocks>True</AllowUnsafeBlocks>
<LangVersion>preview</LangVersion>
</PropertyGroup>
<ItemGroup>
<None Remove="Assets\**\*" />
<Content Update="Assets\Fonts\*">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<None Update="appsettings.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
<ItemGroup Condition="'$(Platform)' == 'x86'">
<None Include="Libraries\x86\**\*">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<Link>%(Filename)%(Extension)</Link>
</None>
</ItemGroup>
<ItemGroup Condition="'$(Platform)' == 'x64'">
<None Include="Libraries\x64\**\*">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<Link>%(Filename)%(Extension)</Link>
</None>
</ItemGroup>
<ItemGroup Condition="'$(Platform)' == 'arm64'">
<None Include="Libraries\arm64\**\*">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<Link>%(Filename)%(Extension)</Link>
</None>
</ItemGroup>
<ItemGroup>
<Manifest Include="$(ApplicationManifest)" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.4.0" />
<PackageReference Include="CommunityToolkit.WinUI.Controls.Segmented" Version="8.2.251219" />
<PackageReference Include="CommunityToolkit.WinUI.Controls.SettingsControls" Version="8.2.251219" />
<PackageReference Include="CommunityToolkit.WinUI.Converters" Version="8.2.251219" />
<PackageReference Include="CommunityToolkit.WinUI.Media" Version="8.2.251219" />
<PackageReference Include="hyjiacan.pinyin4net" Version="4.1.1" />
<PackageReference Include="ManagedBass" Version="4.0.2" />
<PackageReference Include="ManagedBass.Fx" Version="4.0.2" />
<PackageReference Include="ManagedBass.Wasapi" Version="4.0.2" />
<PackageReference Include="MemoryPack" Version="1.21.4" />
<PackageReference Include="Microsoft.Extensions.Hosting" Version="10.0.3" />
<PackageReference Include="Microsoft.Graphics.Win2D" Version="1.3.2" />
<PackageReference Include="Microsoft.WindowsAppSDK" Version="1.8.260209005" />
<PackageReference Include="Microsoft.Xaml.Behaviors.WinUI.Managed" Version="3.0.1" />
<PackageReference Include="TagLibSharp" Version="2.3.0" />
<PackageReference Include="WinUIEx" Version="2.9.0" />
<PackageReference Include="ZLinq" Version="1.5.5" />
<PackageReference Include="ZLogger" Version="2.5.10" />
</ItemGroup>
<ItemGroup>
<TrimmerRootAssembly Include="TagLibSharp" />
</ItemGroup>
<!-- 在此处定义“Msix” ProjectCapability 允许即使尚未还原 Windows App SDK Nuget 包,也可以为此项目激活单项目 MSIX 打包工具扩展。 -->
<ItemGroup Condition="'$(DisableMsixProjectCapabilityAddedByProject)'!='true' and '$(EnableMsixTooling)'=='true'">
<ProjectCapability Include="Msix" />
</ItemGroup>
<!-- 在此处定义“HasPackageAndPublishMenuAddedByProject”属性允许即使尚未还原 Windows App SDK Nuget 包,也可以为此项目启用解决方案资源管理器“打包和发布”上下文菜单项。 -->
<PropertyGroup Condition="'$(DisableHasPackageAndPublishMenuAddedByProject)'!='true' and '$(EnableMsixTooling)'=='true'">
<HasPackageAndPublishMenu>True</HasPackageAndPublishMenu>
</PropertyGroup>
<ItemGroup>
<PRIResource Update="Strings\zh-cn\Resources.resw">
<Generator>ResXFileCodeGenerator</Generator>
</PRIResource>
</ItemGroup>
<!-- 发布属性 -->
<PropertyGroup>
<DefaultLanguage>en-us</DefaultLanguage>
<AppxBundlePlatforms>x86|x64|arm64</AppxBundlePlatforms>
<PublishSelfContained>True</PublishSelfContained>
<WindowsAppSDKSelfContained>True</WindowsAppSDKSelfContained>
<PublishReadyToRun>True</PublishReadyToRun>
<IsAotCompatible>True</IsAotCompatible>
<!--<PublishAot>True</PublishAot>
<PublishTrimmed>True</PublishTrimmed>-->
<JsonSerializerIsReflectionEnabledByDefault>True</JsonSerializerIsReflectionEnabledByDefault>
<GenerateTestArtifacts>True</GenerateTestArtifacts>
<GenerateTemporaryStoreCertificate>True</GenerateTemporaryStoreCertificate>
<PackageCertificateKeyFile>UntamedMusicPlayer_TemporaryKey.pfx</PackageCertificateKeyFile>
<AppxPackageSigningEnabled>False</AppxPackageSigningEnabled>
<AppxPackageSigningTimestampDigestAlgorithm>SHA256</AppxPackageSigningTimestampDigestAlgorithm>
<AppxAutoIncrementPackageRevision>True</AppxAutoIncrementPackageRevision>
<AppxSymbolPackageEnabled>False</AppxSymbolPackageEnabled>
<EnableMsixTooling>True</EnableMsixTooling>
<GenerateAppInstallerFile>False</GenerateAppInstallerFile>
<AppxBundle>Never</AppxBundle>
</PropertyGroup>
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net10.0-windows10.0.26100.0</TargetFramework>
<TargetPlatformMinVersion>10.0.19041.0</TargetPlatformMinVersion>
<RootNamespace>UntamedMusicPlayer</RootNamespace>
<ApplicationIcon>Assets/AppIcon/Icon.ico</ApplicationIcon>
<ApplicationManifest>app.manifest</ApplicationManifest>
<Platforms>x86;x64;arm64</Platforms>
<RuntimeIdentifiers>win-x86;win-x64;win-arm64</RuntimeIdentifiers>
<PublishProfile>win-$(Platform).pubxml</PublishProfile>
<UseWinUI>True</UseWinUI>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<AllowUnsafeBlocks>True</AllowUnsafeBlocks>
<LangVersion>preview</LangVersion>
</PropertyGroup>
<ItemGroup>
<None Remove="Assets\**\*" />
<Content Update="Assets\Fonts\*">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<None Update="appsettings.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
<ItemGroup>
<Manifest Include="$(ApplicationManifest)" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.4.0" />
<PackageReference Include="CommunityToolkit.WinUI.Controls.Segmented" Version="8.2.251219" />
<PackageReference Include="CommunityToolkit.WinUI.Controls.SettingsControls" Version="8.2.251219" />
<PackageReference Include="CommunityToolkit.WinUI.Converters" Version="8.2.251219" />
<PackageReference Include="CommunityToolkit.WinUI.Media" Version="8.2.251219" />
<PackageReference Include="hyjiacan.pinyin4net" Version="4.1.1" />
<PackageReference Include="ManagedBass" Version="4.0.2" />
<PackageReference Include="ManagedBass.Fx" Version="4.0.2" />
<PackageReference Include="ManagedBass.Wasapi" Version="4.0.2" />
<PackageReference Include="MemoryPack" Version="1.21.4" />
<PackageReference Include="Microsoft.Extensions.Hosting" Version="10.0.4" />
<PackageReference Include="Microsoft.Graphics.Win2D" Version="1.3.2" />
<PackageReference Include="Microsoft.WindowsAppSDK" Version="1.8.260209005" />
<PackageReference Include="Microsoft.Xaml.Behaviors.WinUI.Managed" Version="3.0.1" />
<PackageReference Include="TagLibSharp" Version="2.3.0" />
<PackageReference Include="WinUIEx" Version="2.9.0" />
<PackageReference Include="ZLinq" Version="1.5.5" />
<PackageReference Include="ZLogger" Version="2.5.10" />
</ItemGroup>
<ItemGroup>
<TrimmerRootAssembly Include="TagLibSharp" />
</ItemGroup>
<!-- 在此处定义“Msix” ProjectCapability 允许即使尚未还原 Windows App SDK Nuget 包,也可以为此项目激活单项目 MSIX 打包工具扩展。 -->
<ItemGroup Condition="'$(DisableMsixProjectCapabilityAddedByProject)'!='true' and '$(EnableMsixTooling)'=='true'">
<ProjectCapability Include="Msix" />
</ItemGroup>
<!-- 在此处定义“HasPackageAndPublishMenuAddedByProject”属性允许即使尚未还原 Windows App SDK Nuget 包,也可以为此项目启用解决方案资源管理器“打包和发布”上下文菜单项。 -->
<PropertyGroup Condition="'$(DisableHasPackageAndPublishMenuAddedByProject)'!='true' and '$(EnableMsixTooling)'=='true'">
<HasPackageAndPublishMenu>True</HasPackageAndPublishMenu>
</PropertyGroup>
<ItemGroup>
<PRIResource Update="Strings\zh-cn\Resources.resw">
<Generator>ResXFileCodeGenerator</Generator>
</PRIResource>
</ItemGroup>
<!-- 发布属性 -->
<PropertyGroup>
<DefaultLanguage>en-us</DefaultLanguage>
<AppxBundlePlatforms>x86|x64|arm64</AppxBundlePlatforms>
<SelfContained>True</SelfContained>
<WindowsAppSDKSelfContained>True</WindowsAppSDKSelfContained>
<IsAotCompatible>True</IsAotCompatible>
<PublishAot>True</PublishAot>
<JsonSerializerIsReflectionEnabledByDefault>True</JsonSerializerIsReflectionEnabledByDefault>
<GenerateTestArtifacts>True</GenerateTestArtifacts>
<GenerateTemporaryStoreCertificate>True</GenerateTemporaryStoreCertificate>
<PackageCertificateKeyFile>UntamedMusicPlayer_TemporaryKey.pfx</PackageCertificateKeyFile>
<AppxPackageSigningEnabled>True</AppxPackageSigningEnabled>
<AppxPackageSigningTimestampDigestAlgorithm>SHA256</AppxPackageSigningTimestampDigestAlgorithm>
<AppxAutoIncrementPackageRevision>False</AppxAutoIncrementPackageRevision>
<AppxSymbolPackageEnabled>False</AppxSymbolPackageEnabled>
<EnableMsixTooling>True</EnableMsixTooling>
<GenerateAppInstallerFile>False</GenerateAppInstallerFile>
<AppxBundle>Never</AppxBundle>
</PropertyGroup>
</Project>