WinUI 剪裁发布中的一个小坑
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-us 和 Microsoft.UI.Xaml 这两个文件夹,删除其他文件夹不影响使用。这样一个空模板项目的大小最终是 58 MB。

总结
没有总结。
WinUI 剪裁发布中的一个小坑的更多相关文章
- 今天碰到的angular 中的一个小坑
最近在自个儿研究angular,在写一个demo的时候总是有问题,最后发现居然是大小写的问题,卧槽 特tm的坑爹了,代码如下: <!DOCTYPE html> <html lang= ...
- mysql url 连接配置的一个小坑。 工作中不会遇到。 学习的时候会
<property name="driverClassName"> <value>com.mysql.jdbc.Driver</value> & ...
- go的变量redeclare的问题,golang的一个小坑
go的变量声明有几种方式: 1 通过关键字 var 进行声明 例如:var i int 然后进行赋值操作 i = 5 2 最简单的,通过符号 := 进行声明和赋值 例如: i:=5 golang会 ...
- 一次 react-router 中遇到的小坑
react-router Link 标签不生效的问题 废话不多说, 直接上问题, 排解过程和答案 现象: 发现 使用 Link 标签没有 元素的样式和效果, 也不能进行跳转 代码如下: render( ...
- [LeetCode]29 两数相除和一个小坑点
给定两个整数,被除数 dividend 和除数 divisor.将两数相除,要求不使用乘法.除法和 mod 运算符. 返回被除数 dividend 除以除数 divisor 得到的商. 示例 1: 输 ...
- 注意Android里TextView控件的一个小坑,用android:theme来设置样式时动态载入的layout会丢失该样式
注意Android里TextView控件的一个小坑,用android:theme来设置样式时动态载入的layout会丢失该样式 这个坑,必须要注意呀, 比如在用ListView的时候,如果在List_ ...
- 关于sniff函数的一个小坑
最近在用scapy模块写一个关于WiFi的脚本时用到sniff函数,其中遇到了一个小坑,记录如下: sniff函数是在指定网卡上每次嗅探到一个数据包后然后将它传给prn指定的函数.
- Github作为图床的一个小坑
Github作为图床的一个小坑 前言 听了少铭同学建议把github作为图床,结果遇到了一个小坑,总是显示不出来图片. 问题描述与解决 形如下的链接是显示不出来的: https://github.co ...
- Go的List操作上的一个小“坑”
转自http://sharecore.net/blog/2014/01/09/the-trap-in-golang-list/ 一直想不清楚一个问题,简单设计的东西到底是“坑多”还是“坑少”呢? 复杂 ...
- python中全局变量和局部变量的一个小坑
python 中全局变量和局部变量在使用过程中的一个容易出错的地方 什么是全局变量 python中,在函数外部声明的变量可以叫做全局变量. x = 10 def fn1(): pass fn1() 什 ...
随机推荐
- i春秋SQLi
打开题目网页是个很简单的登录网页 先查看源码,抓包 都没找到可用的信息 依我所见这里应该就是一个注入 但是怎么输入都会回显username错误 直到输入admin 尝试admin# Admin'# ...
- lauyi渲染
下拉框 <div class="layui-form-item x-city" id="start"> <label class=" ...
- oracle第二步创建表空间、用户、授权
Windows+r→键入sqlplus,输入已安装好的oracle数据库超级管理员账号密码登录.显示: 成功. 创建表空间: 创建用户并默认表空间: 授权该创建用户对数据库的操作: 代码: SQL&g ...
- 第二十六节:urllib、requests、selenium请求库代理设置
1.urllib代理设置 1 from urllib.error import URLError 2 from urllib.request import ProxyHandler 3 from ur ...
- vulnhub靶场之CONTAINME: 1
准备: 攻击机:虚拟机kali.本机win10. 靶机:CONTAINME: 1,下载地址:https://download.vulnhub.com/containme/THM-ContainMe-v ...
- 【Java】【数据库】B树
B-树的形式 (B-树就是B树, 而且'-'是一个连接符号,不是减号.) B树的结构如下 不同于B+树(关于B+树,我的这篇博客里有写:B+树)的一些特点: 数据 \(K_i\) 左边的树不会将 \( ...
- 发送http2请求
有时服务器会检测http协议版本,有http/1.1和h2,requests发送的是http1.1的请求 # pip install httpx client = httpx.Client(http2 ...
- 用 while 生成猜数字
import java.util.Random; import java.util.Scanner; public class zy2 { public static void main(String ...
- [随笔所想] UBC学习生活经验分享
当时受到了很多人的帮助,在网上也查到了很多经验帖子,比如如何办理签证,如何填写表格,要准备哪些材料以及生活上要带哪些物品,等等.当时就想到等我办理好这些,也一定和大家分享,为更多的人提供一些参考. 1 ...
- [深度学习]DEEP LEARNING(深度学习)学习笔记整理
转载于博客http://blog.csdn.net/zouxy09 一.概述 Artificial Intelligence,也就是人工智能,就像长生不老和星际漫游一样,是人类最美好的梦想之中的一个. ...