Maui 的學習之路(二)--設定

Maui 的學習之路(二)--設定

不只是 MAUI,本篇非常實用

最後更新 2022/6/23 下午11:29
轩研 Maui开发者
預計閱讀 8 分鐘
分類
MAUI
標籤
.NET MAUI

上一篇我們做了 Maui 的基本介紹,理論上這一篇應該會建立第一個 Maui 的應用,以便對此進行詳細的評估,並逐步深入。

如果你需要進行 Maui 首個應用的建立,那麼歡迎造訪.NET MAUI 建立行動應用—Get Start,以及MAUI 與 Blazor 共享一套 UI,媲美 Flutter,實現 Windows、macOS、Android、iOS、Web 通用 UI,本文的重點不是建立 Maui 的應用而是如何更好的配置 Maui 的專案。

解決煩人的「obj」

長久以來都有一個問題深深得困擾著我們,每當 C# 程式編譯後,總會在專案資料夾下產生「obj」目錄,非常刺眼,一旦提交 Git 我們需要進行逐個排除(如果專案很多會生不如死)這讓人非常惱火。那麼我們能不能把他移走?

在完成以下設定之前,請跟我做如下的事情:

  1. 建立一個 C++ 專案(我們並非是要進行 C++ 程式開發而是他會對我們後續的學習產生非常積極的作用)

這裡我建立了一個C++ Console 專案

建立一個 XML 檔案,把他重新命名為 Directory.build.props(這個名稱隨意,只是喜歡這麼叫)

雙擊 Directory.build.props 檔案開啟並編輯,刪除 XML 中所有內容,在該檔案中加入如下設定

<Project>
 <PropertyGroup>
  <BaseIntermediateOutputPath>$(MSBuildThisFileDirectory).vs\$(SolutionName)\Intermediate\$(MSBuildProjectName)\</BaseIntermediateOutputPath>
 </PropertyGroup>
</Project>

這裡我不會介紹 BaseIntermediateOutputPath 這個設定欄位的用意,如果你需要知道請造訪:常用的 MSBuild 專案屬性 - MSBuild | Microsoft Docs(如果你是用的是 vs2022 for mac,那麼很抱歉的告訴你他不支援這個屬性,我在官方的 issue 翻閱過這個 bug 早在 vs2019 for mac 就存在,只不過微軟視而不見),所以為了避免尷尬的事情發生,我們需要加上一個條件判定,這個條件就是當作業系統是 Windows 時這個設定項才生效

 <!--這個屬性可以讓你跟obj say goodbye-->
 <PropertyGroup Condition="$([MSBuild]::IsOSPlatform('windows'))">
  <BaseIntermediateOutputPath>$(MSBuildThisFileDirectory).vs\$(SolutionName)\Intermediate\$(MSBuildProjectName)\</BaseIntermediateOutputPath>
 </PropertyGroup>

在這裡我不得不說微軟 VS 團隊是真的強大,你只需要安裝 VS 就能在不同的平台打開同一份程式碼,而不需要做其他的編譯設定

我們是一家人

當一個解決方案(Solution)存在多個專案時(csproj),我們一定希望所有專案產生的 dll 或者 exe 以及設定檔都統統編譯產生到一個固定的地方,通常我們都會手動設定編譯產生路徑,這個方式極不推薦因為你做的選擇總是一個不可靠的路徑(如果這是一個團隊合作的專案),我們只需要做如下一點點改變(該設定仍然是在 Directory.build.props 中進行加入)

<PropertyGroup>
  <!--這個屬性可以讓你規劃統一產生路徑-->
  <OutputPath>$(MSBuildThisFileDirectory)Binary\</OutputPath>
 </PropertyGroup>

讓他成為全部

我們常常有這樣的思考,能不能在一個地方設定,所有專案都能有改變,比如 Nullable 的啟用,比如 C# 的語言版本等等,那麼只需要對 Directory.build.props 增加如下設定

<PropertyGroup>
  <!--這個屬性可以讓你規劃統一產生路徑-->
  <OutputPath>$(MSBuildThisFileDirectory)Binary\</OutputPath>
  <LangVersion>latest</LangVersion>
  <Nullable>enable</Nullable>
  <ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>

不能沒有你

你是否有這樣的困惑,當我的解決方案(Solution)下的所有專案(csproj)都需要用到同一個 package 時,我能否只要做一次套件的參考行為?接下來請跟我一起操作:

  1. 建立一個 XML(這已經很熟悉了),將他改名為 Directory.build.targets(我喜歡這個名字)

  1. Directory.build.targets 中的內容修改為:
<Project>
 <!--這樣的設計可以讓你當前解決方案下的所有專案都能獲取到package-->
 <ItemGroup>
  <PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
 </ItemGroup>
</Project>

讓他變得主動

完成上述設定你已經成為一個解決方案管理高手了,但是這還不夠,我們都知道 .NET 6 或者是 C# 10 引入了檔案層級的命名空間(File-scoped)你只需要寫一個 namespace xxx,更少的大括弧讓你的程式碼看起來更加簡潔,很可惜如果你不做任何改變,那麼他永遠不會那麼主動,你建立的預設 class 他一定長這樣:

namespace MauiLib1
{
   internal class Class2
   {
   }
}

請跟我完成以下操作,他會變得更聽話:

  1. 建立一個 editorconfig

  1. 雙擊 .editorconfig,開啟 File scped 設定(如果你開啟的不是設定介面而是直接開啟的文字,請不用擔心,在下一次重啟後再完成後續的設定即可)

至此你就完成了部分高效設定,關閉 VS,重新開啟解決方案,上述所有設定才會生效,別忘了刪除已經產生的編譯垃圾,如以下這些:

此時你建立的新 class,他變成了這樣:

namespace MauiLib1;
internal class Class3
{
}

重新編譯解決方案,你的所有 dll 和 exe 都已經產生到 binary 下面了,每一個 csproj 目錄下都相當乾淨了(注意以上設定對 C++ 專案無效,C++ 專案需要單獨設定,這裡不做介紹)。

別忘了他

完成上述設定,我們剛剛建立的 C++ 專案似乎都沒有起到任何作用,沒錯 C++ 專案只是給你看看的(我就是玩兒你),接下來我們需要探討的是,這些你是怎麼知道的(如圖)

其實這些是 VS 的一些內建巨集定義,我們在 C# 中無法得知為什麼有這些巨集,此時我們需要用 C++ 專案

在這裡你可以看到這些形形色色的設定欄位以及對應巨集所顯示的值了,這個巨集是屬於 VS 的,所以 C# 專案也有效

給得實在太多了

接下來我們會進行一些 Maui 的深層設定探討,在 Windows 上,總是預設給我編譯出 Android、iOS、maccatalyst,太多了我根本不需要,那麼可以修改 TargetFrameworks(比如像這樣)

注意:一旦修改了這項,也就意味著你再也不能夠選擇其他平台查看程式碼是否正確(程式碼可靠性將得不到保證)(去掉其他平台編譯設定最直觀的表象就是編譯變得異常的快)

讓她變得忠誠

當我產生 Window 的應用時,我們要參考一個 Window 平台相關的 package,比如我們很熟悉的 Pinvoke.User32,很明顯這個函式庫只適合 Windows 平台,其他平台參考過去雖然不會造成編譯錯誤,但是在封裝檔案內勢必會有這個一個不相關的 dll(也許沒有我沒測試過,我猜他有),這是我們不希望看到的,所以我們要這樣:

<!--這是一個專屬於Windows的設定,讓他成為Windows忠誠的伴侶-->
<ItemGroup Condition="$(TargetFramework.Contains('-windows'))">
  <!-- Required - WinUI does not yet have buildTransitive for everything -->
  <PackageReference Include="PInvoke.User32" Version="0.7.104" />
</ItemGroup>

他們需要隔離

在撰寫程式碼時,我們通常會遇到我的部分程式碼是適用於 Windows 的而不適用於其他平台,此時你可以使用編譯巨集命令 #if #elif #else #endif

public static MauiApp CreateMauiApp()
{
   var builder = MauiApp.CreateBuilder();
   builder
    .UseMauiApp<App>()
    .ConfigureFonts(fonts =>
    {
     fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular");
     fonts.AddFont("OpenSans-Semibold.ttf", "OpenSansSemibold");
    });

#if WINDOWS
    string? name = "Windows";
#elif MACCATALYST
    string? name = "Mac";
#else
   string? name = "Mobile";
#endif
   return builder.Build();
}

讓他做回自己

我們很期待使用 Maui 撰寫的 Windows 應用雙擊 exe 就能夠直接執行(這在以前是個奢望),現在你只需要修改兩項設定就可以做到(在主程式的專案檔案 csproj),增加如下兩個設定(使用該設定後就不再支援 anycpu 編譯,所以我們做一個條件編譯):

<!--這個方案可以讓你的Maui在Windows下產生的exe做回自己-->
<PropertyGroup Condition="'$(Platform)' != 'AnyCPU' And $(TargetFramework.Contains('-windows'))">
  <!-- Unpack : SelfContainedDeployment for winui3 -->
  <WindowsPackageType>None</WindowsPackageType>
  <WindowsAppSDKSelfContained>true</WindowsAppSDKSelfContained>
</PropertyGroup>

多編譯平台設定

在上一項改動中,因為需要實現 exe 直接執行,增加的設定在 anycpu 編譯環境下是完全不支援的,所以你需要設定多平台編譯方案(比如 x64 x86 ARM64 等),設定方法如下:

  1. 點開 Configuration Manager

  1. 新增 X64 等平台編譯

綜上,我們完成了解決方案(Solution)以及專案(csproj)中的絕大多數設定,做好這些設定會讓你一部分工作變得得心應手。

以上設定都已上傳 github

繼續探索

延伸閱讀

更多文章
同分類 / 同標籤 2023/1/12

Maui Blazor 使用攝影機實現

由於 Maui Blazor 中界面是由 WebView 渲染,所以在使用 Android 的攝影機時無法獲取,因為原生的攝影機需要綁定界面元件

繼續閱讀