Sworld

Sworld

The only way to do great work is to love what you do.

Avalonia採用AOT編譯後無法運行解決辦法

發現問題#

近日在製作 Avalonia 程序過程中,發現調試時很正常,發佈後卻無法運行,感覺很奇怪,我的發佈配置有以下兩條:

    <PublishTrimmed>True</PublishTrimmed>
    <PublishAot Condition="'$(Configuration)' != 'Debug'">true</PublishAot>

第一條啟用了裁剪,第二條啟用了 AOT 編譯(但是在開發時沒開啟,因為預覽窗口不支持 AOT)

經過一番排查,發現這兩個都有問題:

  1. 反射對 AOT 不友好,我的ViewLocator.cs使用了反射來創建對象
  2. 有的庫對剪裁支持不好,因此要對其關閉剪裁

解決方案#

問題 1: 消除反射#

原代碼使用反射創建對象:

public Control? Build(object? param)
{
    if (param != null && param is ViewModelBase)
    {
        var viewModelType = param.GetType();
        if (_viewModelViewMappings.TryGetValue(viewModelType, out var viewType))
        {
            return (Control)Activator.CreateInstance(viewType)!; // 這裡使用了反射
        }
        return new TextBlock { Text = "Not Found: " + viewModelType.FullName };
    }
    return null;
}

修改後使用工廠方法:

public Control? Build(object? param)
{
    if (param != null && param is ViewModelBase)
    {
        var viewModelType = param.GetType();
        if (_viewModelViewMappings.TryGetValue(viewModelType, out var viewFactory))
        {
            return viewFactory(); // 使用了工廠方法
        }
        return new TextBlock { Text = "Not Found: " + viewModelType.FullName };
    }
    return null;
}

這樣就可以消除反射了

問題 2: 關閉特定庫的剪裁#

發佈時我注意到很多這樣的剪裁警告

2>Assembly 'Serilog' produced trim warnings. For more information see https://aka.ms/dotnet-illink/libraries
2>Assembly 'ReactiveUI' produced trim warnings. For more information see https://aka.ms/dotnet-illink/libraries
2>Assembly 'SukiUI' produced trim warnings. For more information see https://aka.ms/dotnet-illink/libraries
2>Assembly 'Avalonia.Controls.DataGrid' produced trim warnings. For more information see https://aka.ms/dotnet-illink/libraries
2>Assembly 'Avalonia.Controls.DataGrid' produced AOT analysis warnings.

因此我修改項目的 sln 文件,增加以下片段,通過外部的 xml 文件來限制剪裁

  <ItemGroup>
    <TrimmerRootDescriptor Include="TrimmerRoots.xml" />
  </ItemGroup>

下面是TrimmerRoots.xml的內容

<?xml version="1.0" encoding="utf-8" ?>
<linker>
  <assembly fullname="Serilog" />
  <assembly fullname="Serilog.Sinks.Console" />
  <assembly fullname="Serilog.Sinks.File" />
  <assembly fullname="ReactiveUI" />
  <assembly fullname="SukiUI" />
  <assembly fullname="Serilog.Sinks.File" />
</linker>

我將所有報警告的項目都加入了進去,雖然後面的編譯依舊有新的警告,但是程序可以正常運行了。至此,所有問題解決。

載入中......
此文章數據所有權由區塊鏈加密技術和智能合約保障僅歸創作者所有。