本文是 WinUI 3 踩坑记 的一部分,该系列发布于 GitHub@Scighost/WinUI3Keng,若内容出现冲突以 GitHub 上的为准。
创建项目
现在 WinUI 3 的入门体验比刚发布那会儿好太多了,至少不会再出现模板项目无法生成的情况 [1]。打开 Visual Studio 创建 WinUI 3 项目,有如下的三个模板可以选择:
第一个模板的 WinUI 3 项目和打包项目是同一个项目,第三个模板的则是两个不同的项目。如果在发布时需要让多个可执行文件存在于不同文件夹,就选择第三个模板。
打包与非打包
WinUI 3 默认创建打包项目,打包发布需要使用被用户设备信任的证书给包签名,如果要发布非打包的项目,在项目文件(*.csproj)中加入以下内容即可 [2]。
<!-- *.csproj -->
<PropertyGroup>
......
<!-- 不打包 -->
<WindowsPackageType>None</WindowsPackageType>
<!-- 自包含 Windows App SDK Runtime,否则需要单独安装 -->
<WindowsAppSDKSelfContained>true</WindowsAppSDKSelfContained>
</PropertyGroup>
优缺点
优点 | 缺点 | |
---|---|---|
打包 | 操作系统保证包内文件不会被篡改 | 需要代码签名 |
非打包 | 部署灵活 | 无法使用与应用包有关的 API |
发布
创建项目后,会在文件夹 ./Properties/PublishProfiles/
内创建三个不同 CPU 架构的发布配置文件,下面以 x64 平台的为例。
<!-- win10-x64.pubxml -->
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<PublishProtocol>FileSystem</PublishProtocol>
<Platform>x64</Platform>
<RuntimeIdentifier>win10-x64</RuntimeIdentifier>
<PublishDir>bin\$(Configuration)\$(TargetFramework)\$(RuntimeIdentifier)\publish\</PublishDir>
<!-- 自包含 .NET 运行时 -->
<SelfContained>true</SelfContained>
<!-- 不要发布为单个文件 -->
<PublishSingleFile>False</PublishSingleFile>
<!-- Release 配置时使用 ReadyToRun 编译 -->
<PublishReadyToRun Condition="'$(Configuration)' == 'Debug'">False</PublishReadyToRun>
<PublishReadyToRun Condition="'$(Configuration)' != 'Debug'">True</PublishReadyToRun>
<!-- 暂时不能使用剪裁 -->
<!--
See https://github.com/microsoft/CsWinRT/issues/373
<PublishTrimmed>True</PublishTrimmed>
-->
</PropertyGroup>
</Project>
自包含和 ReadyToRun 编译让 WinUI 3 安装包的体积不逊于 Electron,尽管现在硬盘空间很宽裕,但是在打包后还是要注意一下安装包的大小,因为第三方库可能会引入 WinForm 和 WPF 的框架文件。
这里以云之幻的网络回环管理器为例,项目中引用的第三方库仅有四个,但是安装包大小却有 90.3 MB。
<!-- LoopbackManager.App.csproj -->
<PackageReference Include="PInvoke.User32" Version="0.7.124" />
<PackageReference Include="ReactiveUI" Version="18.3.1" />
<PackageReference Include="ReactiveUI.Fody" Version="18.3.1" />
<PackageReference Include="ReactiveUI.WinUI" Version="18.3.1" />
打开安装后应用的文件夹,以文件大小排序,发现几个眼熟的东西,这不就是 WinForm 和 WPF 的吗。(图中仅截取了前几个,后面还有更多)
究其原因,在项目中有这样一条引用链:网络回环管理器 -> ReactiveUI -> DynamicData ->System.Reactive
,而在 System.Reactive
的项目文件中有这样一段,导致在 WinUI 3 项目中会引入 WinForm 和 WPF 的框架文件。
<!-- System.Reactive.csproj -->
<PropertyGroup Condition="'$(TargetFramework)' == 'netcoreapp3.1' or $(TargetFramework.StartsWith('net5.0-windows'))">
<UseWPF>true</UseWPF>
<UseWindowsForms>true</UseWindowsForms>
<IncludeBuildOutput Condition="'$(TargetFramework)' == 'netcoreapp3.1'">false</IncludeBuildOutput>
</PropertyGroup>
可惜的是,除了不引用这些第三方库以外,我暂时还没有找到在打包项目中解决这个问题的办法。
不同条件下的应用大小
因为有可能会引入额外的框架文件,我测试了 WinUI 3 模板项目在不同发布条件下的大小,帮各位读者排排雷。
这里的 2W 是指 WinForm 和 WPF,在我的测试中,如果仅使用 UseWindowsForms
或 UseWPF
,额外引入的框架文件是一样的,所以不对二者进行区分。
WindowsAppSDK
是指项目文件中 WindowsAppSDKSelfContained = true
的情况,用户在安装打包项目的安装包时(msix 或 msixbundle 文件),系统会自动下载并安装 Windows App SDK Runtime。但是非打包项目没有这个福利,所以这一项仅供非打包项目参考。
安装包 | 安装后 | |
---|---|---|
WinUI | 40.4 MB | 101 MB |
WinUI + ReadyToRun | 51.1 MB | 138 MB |
WinUI + WindowsAppSDK | 59.6 MB | 155 MB |
WinUI + WindowsAppSDK + ReadyToRun | 70.3 MB | 193 MB |
WinUI + 2W | 75.5 MB | 188 MB |
WinUI + 2W + ReadyToRun | 86.2 MB | 225 MB |
WinUI + 2W + WindowsAppSDK | 94.7 MB | 242 MB |
WinUI + 2W + WindowsAppSDK + ReadyToRun | 105.0 MB | 279 MB |
额外引入的内容
下表列出了额外引入 WinForm 和 WPF 框架时多出的文件或文件夹。
点击展开
文件或文件夹名称 |
---|
cs/ |
de/ |
es/ |
fr/ |
it/ |
ja/ |
ko/ |
pl/ |
pt-BR/ |
ru/ |
tr/ |
zh-Hans/ |
zh-Hant/ |
Accessibility.dll |
D3DCompiler_47_cor3.dll |
DirectWriteForwarder.dll |
Microsoft.VisualBasic.Forms.dll |
Microsoft.Win32.Registry.AccessControl.dll |
Microsoft.Win32.SystemEvents.dll |
PenImc_cor3.dll |
PresentationCore.dll |
PresentationFramework.Aero.dll |
PresentationFramework.Aero2.dll |
PresentationFramework.AeroLite.dll |
PresentationFramework.Classic.dll |
PresentationFramework.dll |
PresentationFramework.Luna.dll |
PresentationFramework.Royale.dll |
PresentationFramework-SystemCore.dll |
PresentationFramework-SystemData.dll |
PresentationFramework-SystemDrawing.dll |
PresentationFramework-SystemXml.dll |
PresentationFramework-SystemXmlLinq.dll |
PresentationNative_cor3.dll |
PresentationUI.dll |
ReachFramework.dll |
System.CodeDom.dll |
System.Configuration.ConfigurationManager.dll |
System.Design.dll |
System.Diagnostics.EventLog.dll |
System.Diagnostics.EventLog.Messages.dll |
System.Diagnostics.PerformanceCounter.dll |
System.DirectoryServices.dll |
System.Drawing.Common.dll |
System.Drawing.Design.dll |
System.IO.Packaging.dll |
System.Printing.dll |
System.Resources.Extensions.dll |
System.Security.Cryptography.Pkcs.dll |
System.Security.Cryptography.ProtectedData.dll |
System.Security.Cryptography.Xml.dll |
System.Security.Permissions.dll |
System.Threading.AccessControl.dll |
System.Windows.Controls.Ribbon.dll |
System.Windows.Extensions.dll |
System.Windows.Forms.Design.dll |
System.Windows.Forms.Design.Editors.dll |
System.Windows.Forms.dll |
System.Windows.Forms.Primitives.dll |
System.Windows.Input.Manipulations.dll |
System.Windows.Presentation.dll |
System.Xaml.dll |
UIAutomationClient.dll |
UIAutomationClientSideProviders.dll |
UIAutomationProvider.dll |
UIAutomationTypes.dll |
vcruntime140_cor3.dll |
WindowsFormsIntegration.dll |
wpfgfx_cor3.dll |