しばやん雑記

Azure Serverless とメイドさんが大好きなフリーランスのプログラマーのブログ

Windows App SDK 1.1 がリリースされたので UWP アプリを移行してビルド自動化まで対応した

Build 2022 合わせで Windows App SDK 1.1 の正式版がリリースされていたようです。あまりリリース自体が話題になっていない気がしますが、UWP アプリケーションからの移行先なので 1.1 対応を行いました。

リリースノートを見る限り、割と地味なアップデートという感があります。ぶっちゃけ 1.1 の機能の大半は 1.0 の時にやっておいて欲しかったものです。

公式ブログと窓の杜で紹介されているので共有しておきます。やはり 1.1 が実質 1.0 という感じです。

残念ながら 1.1 になっても、おまじないのような WinRT Interop 向けコードを書く必要が多く、Window の設定は XAML で書くことが出来ず AppWindow を HWND から引っ張り出してくる必要があり、これが公式の UI Framework なのかという感想を持たざるを得ないです。

Windows App SDK 2.0 や 3.0 で大化けすることを期待したいですが、途中で捨てられそうな予感があります。

Windows App SDK 拡張のインストール

気を取り直して実際に Windows App SDK 1.1 への移行を行った件について進めます。Visual Studio 2022 のアップデートと同時に最新の SDK が入っていなかったので、以下のページから C# 2022 用の拡張をダウンロードしてきてインストールしました。

普通は Windows App SDK 1.1 と同時にインストールされるっぽいですが、Single Project MSIX Packaging Tools も最新版が公開されているので、バージョンを確認しておいた方が良いです。

これで Windows App SDK 1.1 のテンプレートとパッケージングの拡張が入りました。

UWP から Windows App SDK への移行

Windows App SDK は .NET 6 ベースになっているので、新しくプロジェクトを作成してファイル一式をコピーする方法が比較的楽でした。いくつかプロジェクトがありますが UWP は元から単一プロジェクトなので、Windows App SDK でも単一プロジェクトを選んだほうが良いです。

実際にプロジェクトを作成してファイル一式をコピーするだけでは当然ながら大量にエラーが出ますが、名前空間周りは機械的に対応できるので ReSharper に大体任せて対応しました。

残りのエラーは地道に対応していくしかありませんでしたが、UWP から Windows App SDK へのマイグレーション方法は公式ドキュメントにまとめられているので、大体ここを読めば解決しました。

大体はまるケースとしては GetForCurrentView が存在しないか、正常に動作しないようになっていることかと思います。マイグレーション方法はクラス毎に用意されていたので、ドキュメント通りに WinRT Interop を使って対応することも多かったです。

WebView2 対応も別途必要になったのが割と面倒でしたが、この辺りは気合で何とかするしかないです。

Desktop Acrylic / Mica 対応

Windows App SDK 1.1 を使う最大のメリットは Desktop Acrylic と Mica のサポートなので、必ずアプリケーションに組み込んでおきたい部分です。対応方法は以前に書いたので、以下のエントリを参照してください。

1.1 の正式版になっても WinRT Interop 周りの謎コードを書く必要はあるみたいです。使いたい機能なので Window のプロパティで気軽に設定させてほしかったです。

ちなみに Windows 11 22H2 では DWM レベルで Desktop Acrylic と Mica サポートが公式に入るようです。

サンプルコードを見る限りでは Windows App SDK 1.1 で有効化するより簡単な気がしました。本当にこういうところだぞという感想しか持てないです。

Store 用パッケージを GitHub Actions でビルド

何とか Windows App SDK 1.1 への移行を終わらせた後は、GitHub Actions を使って MSIX のビルド自動化を行っておきます。コマンドベースでの MSIX 作成方法は以下のドキュメントで紹介されています。

要するに GenerateAppxPackageOnBuildtrue に設定してビルドすれば生成されます。

MSBuild を使う必要がありますが x64 向けに署名無しの MSIX を作成する場合は、以下のようなコマンドを実行すると生成されます。Store で公開する場合は署名無しで問題ありません。

UWP の時は AppxBundlePlatforms に複数アーキテクチャを指定できましたが、Windows App SDK では未対応なので単一アーキテクチャを指定してビルドする必要がありました。

msbuild .\QuickCapture.sln -p:Configuration=Release -p:Version=1.0.0.0 -p:Platform=x64 \
        -p:UapAppxPackageBuildMode=StoreUpload -p:AppxBundlePlatforms=x64 \
        -p:AppxPackageDir=..\packed\ -p:AppxBundle=Never -p:AppxPackageSigningEnabled=false \
        -p:GenerateAppxPackageOnBuild=true -p:PackageCertificateThumbprint="" \
        -verbosity:minimal

必要に応じて ReadyToRun を行っておくと良いです。.NET 6 から ReadyToRun に必要なパッケージは、明示的に PublishReadyToRun を設定して復元しないとインストールされなくなったので注意が必要です。

詳しくは以前書いた以下のエントリを参照してください。MSBuild だと復元が分かり難かったです。

MSBuild を使ってビルドを行うと UWP の時のように自動的に msixbundle や msixupload を作ってはくれず、単一のアーキテクチャ向け msix が生成されるだけなので、Store で公開する前には msixbundle を自前で作っておく必要があります。具体的には MakeAppx を使います。

GitHub Actions では MakeAppx へのパスを通すのが若干面倒なので、専用の Action を使った方が楽です。

MakeAppx は msix が入っているディレクトリを指定する必要があるので、以下のように GitHub Actions では先に msix だけコピーしてきてから、Action を使って msixbundle を作成しました。

- name: Collect msix files
  run: |
    mkdir msix
    cp ./packed/QuickCapture_${{ steps.setup_version.outputs.VERSION }}_arm64_Test/*.msix ./msix
    cp ./packed/QuickCapture_${{ steps.setup_version.outputs.VERSION }}_x64_Test/*.msix ./msix

- name: Make msixbundle
  uses: LanceMcCarthy/Action-MsixBundler@v1.0.1
  with:
    msix-folder: msix
    msixbundle-filepath: QuickCapture_${{ steps.setup_version.outputs.VERSION }}.msixbundle
    msixbundle-version: ${{ steps.setup_version.outputs.VERSION }}

- name: Upload msixbundle
  uses: actions/upload-artifact@v2
  with:
    name: msixbundle
    path: QuickCapture*.msixbundle

msixbundle にもバージョンがあるので、Action のパラメータで渡しておきます。フォーマットが x.x.x.x のように 4 つの数字で構成されるバージョンじゃないとエラーになるので注意しましょう。

以下は実際に GitHub Actions を使って msixbundle まで自動で生成している例です。半分ぐらいは Windows App SDK が msixbundle の作成と複数アーキテクチャ向けビルドに対応すれば必要なくなるものです。

既に Windows App SDK 1.1 に移行したアプリは Microsoft Store で公開されていますが、手元で再現できない謎のクラッシュが発生しているので別途対応しているところです。

UWP よりは Stack Trace はマシですが AppCenter が何故か正しく動いていないので調査しています。