WinUI 3 (以下简称 WinUI)框架发布后的二进制文件过大的问题存在了很长时间,我在这篇文章中有过详细的讨论,好在 Windows App SDK v1.2 就已经支持剪裁发布,但是我却一直没有成功实现,直到最近才发现了问题所在。

坑在哪

在 WinUI 上使用云母或亚克力材质的时候,一般会照抄微软文档中提供的方法。问题就出在这,这一页最后更新于 2022-09-24,那时 WinUI 还不支持剪裁,文档中的方法自然不会有问题。

// 仅包含关键代码
class WindowsSystemDispatcherQueueHelper
{
// ... object m_dispatcherQueueController = null; [DllImport("CoreMessaging.dll")]
private static extern int CreateDispatcherQueueController([In] DispatcherQueueOptions options, [In, Out, MarshalAs(UnmanagedType.IUnknown)] ref object dispatcherQueueController); // 此方法在设置云母或亚克力前调用
public void EnsureWindowsSystemDispatcherQueueController()
{
// ... if (m_dispatcherQueueController == null)
{
DispatcherQueueOptions options;
// ...
CreateDispatcherQueueController(options, ref m_dispatcherQueueController);
}
}
}

在这里通过 P/Invoke 调用了一个外部 COM 函数,而开启剪裁后,编译器会警告:Trim analysis warning IL2050: P/invoke method 'WindowsSystemDispatcherQueueHelper.CreateDispatcherQueueController' declares a parameter with COM marshalling. Correctness of COM interop cannot be guaranteed after trimming. Interfaces and interface members might be removed. 剪裁后无法保证 COM 互操作的正确性,可能会删除接口和接口成员。事实证明剪裁后确实出错了。

查看函数 CreateDispatcherQueueController 的定义,第二个参数返回的是一个指针,同时我们也不关心 COM 对象内容的细节,那解决方法就很简单,使用 IntPtr 替换 object 即可。

HRESULT CreateDispatcherQueueController(
[in] DispatcherQueueOptions options,
[out] PDISPATCHERQUEUECONTROLLER *dispatcherQueueController
);

修改后的代码如下:

class WindowsSystemDispatcherQueueHelper
{
// 改为 nint
nint m_dispatcherQueueController; [DllImport("CoreMessaging.dll")]
// 删除互操作相关的特性
private static extern int CreateDispatcherQueueController(in DispatcherQueueOptions options, out nint dispatcherQueueController); public void EnsureWindowsSystemDispatcherQueueController()
{
if (m_dispatcherQueueController == 0)
{
DispatcherQueueOptions options; _ = CreateDispatcherQueueController(options, out m_dispatcherQueueController);
}
}
}

在最新的 Windows App SDK v1.3 实验版 1 中引入了新的 API,大大简化了设置背景材质的流程,并且这个新 API 不存在上述问题。

发布设置

WinUI 支持了剪裁,这为我们发布小体积应用创造了条件,不过这里的坑也很多。

需要注意的是,.NET 7 修改了剪裁粒度的默认值,默认剪裁全部程序集,所以发布时一定要把 TrimMode 设置为 partial。这是一个比较粗糙的解决办法,可能有更优的方案,但是我没有深入研究。

WinUI 运行依赖 Windows App Runtime,这个组件没有内置在系统中,并且更新还很频繁。当发布为 Msix 包时,无论是否上架微软商店,安装应用的过程中商店服务都会自动下载并安装 Runtime(可能会因为网络问题安装失败)。但是不上架商店的 Msix 包安装起来就很麻烦,发布为非打包的二进制程序更为合适。

发布为非打包的二进制程序时,可以选择是否包含 Windows App Runtime,如果不包含并且按照以下设置发布:

<!--  不打包  -->
<WindowsPackageType>None</WindowsPackageType>
<!-- 启用剪裁 -->
<PublishTrimmed>true</PublishTrimmed>
<TrimMode>partial</TrimMode>
<!-- 自包含 .NET 运行时 -->
<SelfContained>true</SelfContained>
<!-- 单文件 -->
<PublishSingleFile>true</PublishSingleFile>
<!-- 关闭 ReadyToRun -->
<PublishReadyToRun>false</PublishReadyToRun>
<!-- 不包含 Windows App Runtime -->
<WindowsAppSDKSelfContained>false</WindowsAppSDKSelfContained>
<!-- 压缩发布的文件 -->
<EnableCompressionInSingleFile>true</EnableCompressionInSingleFile>
<!-- 单文件包含原生库 -->
<IncludeNativeLibrariesForSelfExtract>true</IncludeNativeLibrariesForSelfExtract>

空模板项目最终生成三个文件,“小而美”,但是运行后会弹窗提醒下载安装 Windows App Runtime,在这个网页中没有引导真的很难找到正确的下载链接。

如果选择发布时包含 Windows App Runtime,就不能在发布的单文件中包含原生库,否则会出现无法打开的情况,相关讨论参考 issue。结果就是发布后的文件很繁杂,整个 Runtime 都在发布文件夹中,并且还存在着非常多的语言相关文件夹。经过我的测试只需要保留 en-usMicrosoft.UI.Xaml 这两个文件夹,删除其他文件夹不影响使用。这样一个空模板项目的大小最终是 58 MB。

总结

没有总结。

WinUI 剪裁发布中的一个小坑的更多相关文章

  1. 今天碰到的angular 中的一个小坑

    最近在自个儿研究angular,在写一个demo的时候总是有问题,最后发现居然是大小写的问题,卧槽 特tm的坑爹了,代码如下: <!DOCTYPE html> <html lang= ...

  2. mysql url 连接配置的一个小坑。 工作中不会遇到。 学习的时候会

    <property name="driverClassName"> <value>com.mysql.jdbc.Driver</value> & ...

  3. go的变量redeclare的问题,golang的一个小坑

    go的变量声明有几种方式: 1 通过关键字 var 进行声明 例如:var i int   然后进行赋值操作 i = 5 2 最简单的,通过符号 := 进行声明和赋值 例如: i:=5 golang会 ...

  4. 一次 react-router 中遇到的小坑

    react-router Link 标签不生效的问题 废话不多说, 直接上问题, 排解过程和答案 现象: 发现 使用 Link 标签没有 元素的样式和效果, 也不能进行跳转 代码如下: render( ...

  5. [LeetCode]29 两数相除和一个小坑点

    给定两个整数,被除数 dividend 和除数 divisor.将两数相除,要求不使用乘法.除法和 mod 运算符. 返回被除数 dividend 除以除数 divisor 得到的商. 示例 1: 输 ...

  6. 注意Android里TextView控件的一个小坑,用android:theme来设置样式时动态载入的layout会丢失该样式

    注意Android里TextView控件的一个小坑,用android:theme来设置样式时动态载入的layout会丢失该样式 这个坑,必须要注意呀, 比如在用ListView的时候,如果在List_ ...

  7. 关于sniff函数的一个小坑

    最近在用scapy模块写一个关于WiFi的脚本时用到sniff函数,其中遇到了一个小坑,记录如下: sniff函数是在指定网卡上每次嗅探到一个数据包后然后将它传给prn指定的函数.

  8. Github作为图床的一个小坑

    Github作为图床的一个小坑 前言 听了少铭同学建议把github作为图床,结果遇到了一个小坑,总是显示不出来图片. 问题描述与解决 形如下的链接是显示不出来的: https://github.co ...

  9. Go的List操作上的一个小“坑”

    转自http://sharecore.net/blog/2014/01/09/the-trap-in-golang-list/ 一直想不清楚一个问题,简单设计的东西到底是“坑多”还是“坑少”呢? 复杂 ...

  10. python中全局变量和局部变量的一个小坑

    python 中全局变量和局部变量在使用过程中的一个容易出错的地方 什么是全局变量 python中,在函数外部声明的变量可以叫做全局变量. x = 10 def fn1(): pass fn1() 什 ...

随机推荐

  1. 2.6:Python数据存取-文件、文件夹及目录、数据库

    一.Python文件读写 1.文件的打开模式 <class '_io.TextIOWrapper'>和<class '_io.BufferedReader'>.python使用 ...

  2. 【ASP.NET Core】MVC控制器的各种自定义:IActionHttpMethodProvider 接口

    IActionHttpMethodProvider 接口的结构很简单,实现该接口只要实现一个属性即可--HttpMethods.该属性是一个字符串序列. 这啥意思呢?这个字符串序列代表的就是受支持的 ...

  3. 《HTTP权威指南》– 7.缓存

    Web缓存的概念 Web缓存是可以自动保存常见文档副本的HTTP设备. 使用缓存的优点: 减少了数据的数据传输,节省了网络费用: 缓解了网络瓶颈的问题,不需要更多的带宽就能更快地加载页面: 降低了原始 ...

  4. ABP AutoMapper与自定义Mapping

    对象映射 在工作中,需要将相似的对象映射到另一个对象,这样我们来看一个最繁琐的映射方式 例: public class UserAppService : ApplicationService { pr ...

  5. jsvmp_wencai

    网站 aHR0cDovL3d3dy5pd2VuY2FpLmNvbS91bmlmaWVkd2FwL2hvbWUvaW5kZXg= 直接搜索关键词 下面是要抓取的数据 逆向位置(一个即可) hook到he ...

  6. 【转载】SQL SERVER 存储过程中执行动态Sql语句

    MSSQL为我们提供了两种动态执行SQL语句的命令,分别是EXEC和sp_executesql;通常,sp_executesql则更具有优势,它提供了输入输出接口,而EXEC没有.还有一个最大的好处就 ...

  7. 主题 1 The Shell

    主题 1 The Shell 课程概览与 shell · the missing semester of your cs education (missing-semester-cn.github.i ...

  8. python之路47 django路由层配置 虚拟环境

    可视化界面之数据增删改查 针对数据对象主键字段的获取可以使用更加方便的obj.pk获取 在模型类中定义双下str方法可以在数据对象被执行打印操作的时候方便的查看 ''' form表单中能够触发提交动作 ...

  9. [数据结构]深度优先搜索算法(Depth-First-Search,DFS)

    深度优先搜索算法的概念 与广度优先搜索算法不同,深度优先搜索算法类似与树的先序遍历.这种搜索算法所遵循的搜索策略是尽可能"深"地搜索一个图.它的基本思想如下:首先访问图中某一个起始 ...

  10. [cocos2d-x]TextureCache和spriteFramecache

    SpriteFrameCache 主要服务于多张碎图合并出来的纹理图片.这种纹理在一张大图中包含了多张小图,直接通过TextureCache引用会有诸多不便,因而衍生出来精灵框帧的处理方式,即把截取好 ...