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() 什 ...
随机推荐
- 手动安装Mysql数据库,适合重装系统和绿色安装。
依次输入命令: d:cd D:\MySQL Server 5.6\bin 根据自己的目录设置 mysqld --install mysql4001 --defaults-file="D:\m ...
- 【Java EE】Day04 MySQL多表、事务、事务隔离级别、DCL
一.多表查询 1.概述 笛卡尔积:两集合的所有组成情况 多表查询:消除笛卡尔积得到的无用数据 2.分类 内连接查询(满足指定条件无空值,只显示有关联的数据) 隐式内连接:使用where限制消除无用数据 ...
- 互联网最全cka真题解析-2022
1.CKA真题解析kubectl自动补全及帮助信息1.配置kubectl自动补全apt install bash-completion source <(kubectl completion b ...
- SpringBoot基础学习笔记
Springboot框架: springboot官网参考 Sringboot是整合spring技术栈的一站式框架,其简化配置,实现了自动化配置 Springboot基础结构: 1.pom.xml文件: ...
- [Computer Networks]一个http请求的完成的全过程
摘要 本文主要讲述了一个 http request 请求从发出到收到 response 的整个生命周期,希望可以通过对整个流程的一个描述来梳理清楚五层网络协议的定义以及各层之间是如何协作的. 对于后端 ...
- 建立一个简单干净的 gn+ninja 工具链
背景 事情的起因是,想找个跨 Windows 和 Mac 的构建方案.第一考虑自然是 CMake,毕竟基本上是事实标准了. 但是研究了一下 Modern CMake,也就是以 target 为核心的理 ...
- Java进阶篇——设计模式
设计模式 一.代理模式 使用代理类对真实对象进行代理,包括真实对象方法的调用.功能的扩展等.访问的时候也只能访问到代理对象,既保护了真实对象同时可以在原始对象上进行扩展.类似于中介在卖家和买家之间的角 ...
- 【力扣】787. K 站中转内最便宜的航班加权——有向图最短路径
前言 我感觉这题比较有代表性,所以记录一下,这题是加权有向图中求最短路径的问题. 题目 787. K 站中转内最便宜的航班 动态规划 假设有一条路径是[src, i, ..., j, dst],解法一 ...
- 使用小黄鸟(HttpCanary)+模拟器(VMOS Pro)对手机APP进行抓包
最近接触app开发,苦于app端不能像网页端可以F12看请求信息,对于后端来说当接口出现异常却不能拿到请求参数是很苦恼的, 因为之前了解过逍遥模拟器,先使用了模拟器对appj进行抓包,但发现这一款ap ...
- 图文并茂quasar2.6+vue3+ts+vite创建项目并引入mockjs,mockjs 拦截ajax请求的原理是什么,quasar为什么要使用boot?
每天都要开心(▽)哇: 首先呢,我们来创建项目 执行下面命令,开始创建项目啦 $ npm i -g @quasar/cli $ npm init quasar 下面是我的选项,仅供参考哇 √ What ...