本文是 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 |