对 Avalonia 进行 AOT 发布时,会发现存在几个库文件无法被打进入到 exe 可执行文件里面,于是进行分发的时候又需要进行压缩。现在很多用户已经不懂如何解压缩了,我就在想着如何只发布单个文件
本文提供的方法在 11.3.2 的 Avalonia 版本实验成功,支持 Windows x86 应用程序 AOT 发布为完全单文件。预期对 windows x64 也能成功 AOT 发布完全单文件
实现方式如下
先正常对应用项目进行 AOT 发布,发布之后,预期会多出以下几个 DLL 文件:
- av_libglesv2.dll
- libHarfBuzzSharp.dll
- libSkiaSharp.dll
将这几个 DLL 文件拷贝出来,随便找个文件夹放。如我这里就放在 C:\lindexi\Library\Avalonia_win-x86\
文件夹里
回到项目里面,修改 csproj 项目文件,添加对存放的 DLL 文件的引用,设置为嵌入程序集资源,大概代码如下
<ItemGroup>
<EmbeddedResource Include="C:\lindexi\Library\Avalonia_win-x86\*.dll" LinkBase="Assets\win-x86" />
</ItemGroup>
如果不知道这部分代码怎么写,可以在本文末尾获取本文所有代码的下载方法,拉取我的代码了解具体的代码
接着修改 Program.cs 的 Main 函数,将原本写在 Main 函数里面的 Avalonia 调用抽一个独立的方法。如我这里放在 RunAvalonia 方法里面。独立方法的作用是防止在进入 Main 时立刻碰到 Avalonia 类型,导致类型快速初始化,类型快速初始化时可能会碰到某些基础库引用,此时基础库还没被释放出来,就可能导致异常
再编写一个名为 LoadNativeLib 的方法,方法代码如下
private static void LoadNativeLib()
{
var assembly = typeof(Program).Assembly;
var manifestResourceNames = assembly.GetManifestResourceNames();
var platform = "win_x86";
var platformResource = $"CibairfejeballChecekayral.Desktop.Assets.{platform}.";
var folder = Directory.CreateDirectory(Path.Join(AppContext.BaseDirectory, platform));
foreach (var manifestResourceName in manifestResourceNames)
{
if (manifestResourceName.StartsWith(platformResource))
{
using var manifestResourceStream = assembly.GetManifestResourceStream(manifestResourceName)!;
var fileName = manifestResourceName[platformResource.Length..];
var file = Path.Join(folder.FullName, fileName);
if (!File.Exists(file))
{
using var fileStream = File.OpenWrite(file);
manifestResourceStream.CopyTo(fileStream);
}
NativeLibrary.Load(file);
}
}
}
通过以上代码可以看到核心实现就是将嵌入程序集里面的几个 DLL 释放出来,我这里只处理了 x86 的情况,其他情况还请大家自行判断处理。从程序集里面取出 DLL 写入到文件之后,调用 NativeLibrary.Load 方法即可执行加载
完成之后,再次进行 AOT 发布,此时只取发布出来的 exe 一个文件放在另一个空白文件夹里面双击运行,可见此时可以成功正常运行
通过如此方式即可实现在 Avalonia 里面进行独立 AOT 成单个文件,非常方便小工具的分发
本文代码放在 github 和 gitee 上,可以使用如下命令行拉取代码。我整个代码仓库比较庞大,使用以下命令行可以进行部分拉取,拉取速度比较快
先创建一个空文件夹,接着使用命令行 cd 命令进入此空文件夹,在命令行里面输入以下代码,即可获取到本文的代码
git init
git remote add origin https://gitee.com/lindexi/lindexi_gd.git
git pull origin 21d0bbfbb70ff2274d74357b90c80ea32656c727
以上使用的是国内的 gitee 的源,如果 gitee 不能访问,请替换为 github 的源。请在命令行继续输入以下代码,将 gitee 源换成 github 源进行拉取代码。如果依然拉取不到代码,可以发邮件向我要代码
git remote remove origin
git remote add origin https://github.com/lindexi/lindexi_gd.git
git pull origin 21d0bbfbb70ff2274d74357b90c80ea32656c727
获取代码之后,进入 AvaloniaIDemo/CibairfejeballChecekayral 文件夹,即可获取到源代码
更多技术博客,请参阅 博客导航
本文会经常更新,请阅读原文: https://blog.lindexi.com/post/Avalonia-%E5%88%B6%E4%BD%9C-AOT-%E5%8D%95%E6%96%87%E4%BB%B6.html ,以避免陈旧错误知识的误导,同时有更好的阅读体验。
如果你想持续阅读我的最新博客,请点击 RSS 订阅,推荐使用RSS Stalker订阅博客,或者收藏我的博客导航
本作品采用
知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议
进行许可。欢迎转载、使用、重新发布,但务必保留文章署名林德熙(包含链接:
https://blog.lindexi.com
),不得用于商业目的,基于本文修改后的作品务必以相同的许可发布。如有任何疑问,请
与我联系
。
无盈利,不卖课,做纯粹的技术博客
以下是广告时间
推荐关注 Edi.Wang 的公众号
欢迎进入 Eleven 老师组建的 .NET 社区
以上广告全是友情推广,无盈利