はつねの日記

Kinect, Windows 10 UWP, Windows Azure, IoT, 電子工作

Xamarin.FormsからMAUIへアプリ内画像を移植する

前回:
hatsune.hatenablog.jp

MAUIアプリは、1つのプロジェクトの中で画像などもプラットフォーム共通部分とプラットフォーム固有部分を分けて定義できます。

プラットフォーム共通部分は、プロジェクト直下にある「Resource\Images」フォルダに配置し、プラットフォーム固有部分については(例えばAndroidの場合)「Platfoems\Android\Resources\Drawable」フォルダに配置します。

画像ファイル移動

Xamarin.FormsからMAUIに移植する作業であれば、「Platfoems\Android\Resources\Drawable」フォルダから「Resource\Images」フォルダに画像ファイルを移動することになります。

この画像ファイルの移動については、Visual Studioのソリューションエクスプローラで行いのではなく、ファイルエクスプローラを使ってファイルを移動させてください。理由は後程。

画像ファイル移動の注意点

画像ファイル名の変更

画像ファイル名は「英大文字」がつかえず「英小文字と_」のみになります。
よって、「ImageFolder.png」のようなファイル名は「image_folder.png」にする必要があります。

ビルドアクションの変更

「Platfoems\Android\Resources\Drawable」フォルダの画像ファイルのビルドアクションは「AndroidResouce」です。
一方、プラットフォーム共通の「Resource\Images」フォルダに配置する画像ファイルは「MauiImage」です。
「AndroidResouce」のままだとビルド時にエラーになります。
このビルドアクションの変更ですが、ファイルエクスプローラーでファイルを移動した場合、Visual Studioが自動的に「MauiImage」のビルドアクションを設定してれます。ソリューションエクスプローラでやるとビルドアクションが維持されちゃうので注意してください。

画像ファイルの指定方法の変更点

このように移動した前後でも画面定義体XAMLや、コード中での画像ファイルの参照は変更不要です。

もちろんファイル名をすべて小文字に変更する作業が発生したときは、ファイル名の小文字かだけは実施してください。

今回は以上になります。
せっかくMAUIにするのであれば、プラットフォーム固有は本当に必要な最小限にして共通部分に移植していきたいですね。

MAUIテンプレートを活用してXamarin.Formsアプリを移植してみよう

前回:
hatsune.hatenablog.jp

前回は、.NET Upgrade Assistantを使って、Xamarin.Formsのアプリを.NET MAUI化してみました。
ソリューション構造は、Xamarin.Formsのままで.NET MAUI化ができましたが、できれば、.NET MAUIのソリューション構造にしておきたいですよね。
理由としては、まったくの私見であり経験則というほどのものでもないのですが、これだけソリューション構造が異なるとすると、将来的なことを考えると.NET MAUIのソリューション構造の形にしておいた方が良いのではないかと思うからです。

.NET MAUIアプリを初期生成する

Visual Studioで「.NET MAUIアプリ」テンプレートを使って、新規アプリケーション作成を「MAUIApp」という名前で実施します。

フレームワークとしては「.NET 7.0」を選択します。

フレームワークを限定する

「.NET MAUIアプリ」テンプレートには、AndroidiOSMacOS、Tizen、WindowsOSの5つのプラットフォームが定義されています。

MAUI.appのTargetFrameworkを限定する

今回は、AndroidiOSのみが必要なので、MAUI.appのTargetFrameworkをAndroidiOSのみにします。
]

Platform定義の削除

ソリューションの「Platforms」フォルダの下からも不要なプラットフォームのフォルダを削除します。

試しにビルド

ビルドを開始しました...
1>------ ビルド開始: プロジェクト: MAUIApp, 構成: Debug Any CPU ------
1>MAUIApp -> C:\Sample\MAUIApp\MAUIApp\bin\Debug\net7.0-ios\iossimulator-x64\MAUIApp.dll
1>MAUIApp -> C:\Sample\MAUIApp\MAUIApp\bin\Debug\net7.0-android\MAUIApp.dll
========== ビルド: 成功 1、失敗 0、最新の状態 0、スキップ 0 ==========
========== ビルド は 10:28 AM に開始され、02:32.818 分 かかりました ==========

無事にiOSAndroidの2つがビルドできました。

移植を始めよう

ここまでが移植するもの関係なく必要な共通作業となります。
それでは、「Xamarin.Formsアプリ」テンプレートで作成したソリューションから移植をしていきましょう。

共通プロジェクト部分


Xamarin.Formsアプリの共通プロジェクト部分である「XamarinApp」部分については、.NET MAUIアプリではプロジェクトが1つになっていることもあって、下記の場所に配置されています。

App.xaml関連

Xamarinでは、App.xaml.csの中でメインページを指定していました。

.NET MAUIでは、AppShellを介してメインページを指定しています。

試しにApp.xaml.csで直接MainPageを指定しても正常に動作します。

AppShellの役目

AppShellには「TabBar」を定義してい複数の画面を切り替えるようなUIを作ることができます。
「FlyoutItem」を定義すればハンバーガーメニューとそこからの画面切り替えUIを作ることができます。
このあたりの画面遷移UIを採用しているのならば、AppShellは残しておいて、将来的にはXamarin.Formsでの実装方法からAppShellでの実装に変えていくと良いかもしれません。
今回は、そこまでは手を入れずにAppShellは残しておいてMainPageの指定にだけ使用しましょう。

画面の移植

Xamarin.Formsでも画面関連は、iOSAndroidで基本同じ定義になるので共通プロジェクト側に入っています。
これをそのまま.NET MAUI側にコピーしていくのが基本ですがいくつか変更が必要です。

XAMLファイル関連

Xamarin.Formsの画面定義である拡張子がxamlXAMLファイル関連の変更点としては名前空間の変更があります。
具体的には、Xamarin.Formsの名前空間「xmlns="http://xamarin.com/schemas/2014/forms"」→MAUIの名前空間「xmlns="http://schemas.microsoft.com/dotnet/2021/maui"」の置換が必要です。

XAML.csファイル関連

usingのところで参照している「Xamarin」「Xamarin.Forms」を「Microsoft.Maui」「Microsoft.Maui.Controls」に変更します。
usingではなくコード本文中で「Xamarin.Forms.~」のように記載している部分があれば、そこも変更が必要です。

Androidのリソースを移植する


.NET MAUIのプラットフォーム共通リソースについて

.NET MAUIはプロジェクトフォルダの直下に「Resources」フォルダがあって、ここにプラットフォーム共通の「アイコン」「起動時スプラッシュ」「文字フォント」「画像」などを格納できます。
Xamarin.Formsのときに共通プロジェクト側においてあるリソースがあれば、ここへの配置を考えてみると良いでしょう。
また、iOSAndroidで分けてリソース管理していたものも、移植を機会に共通化して定義の二度手間が省けるものは省いていくようにリファクタリングすることも計画すると良いかもしれません。

.NET MAUIのAndroid固有リソースについて

.NET MAUIでのAndroid固有リソースは、[Platforms]-[Android]-[Rrsoureces]フォルダにあります。
Xamarin.FormsでのAndroidプロジェクトの[Resouces]フォルダの中身を丸ごとコピーしてしまえば移植は完了です。

Androidの固有定義を移植する

AndroidManifest.xmlを移植する

Xamarin.FormsのAndroidプロジェクトの[Properties]フォルダにある「AndroidManifest.xml」ファイルを、.NET MAUIの[Platforms]-[Android]フォルダの下に上書きコピーします。

MainActivity.csを移植する

Xamarin.FormsのAndroidプロジェクトの「MainActivity.cs」ファイルは、を基底クラスとしているので、それを.NET MAUIの[Platforms]-[Android]フォルダの下に上書きコピーしてしまっては問題が発生します。

内容を抜粋して移植します。
このとき、Xamarin.FormsやEssentialsの初期化コード、LoadApplicationメソッドなどは削除します。

条件付きコンパイルシンボルの調整

MAUI.appにある[ビルド]-[全般]でビルド時のコンパイルシンボルを設定できます。
iOSについては「__IOS__」というシンボルが定義されているのですが、Androidについては「__DROID__」というシンボルが定義されていないので、追加します。

実機実行

Xamarin.Formsアプリをアップグレードしたときと異なり、開発者モードにした実機をUSB接続すればターゲットとして実機がでてきて、すぐにデバッグ実行できます。
なぜかSplashScreenに指定した画像が表示されませんが、それも、Visual Studioを繋げずに実機側でアプリを起動すればきちんと表示されます。

今回は非常にシンプルな(ほとんど何もしない)アプリでしたが、次回はMVVMで作成したXamarin.FomrsアプリからXAMLやロジックをコピーして、.NET MAUIアプリとして再構築を試したいと思います。

次回:

~Xamarin.FormsからMAUIへ~ .NET Upgrade Assistantを使って移行してみよう

前回:
hatsune.hatenablog.jp

新規作成したXamarin.Formsのソリューション構造と、新規作成した.NET MAUIのソリューション構造が全く違うことを前回紹介しました。
今回は、新規作成したXamarin.Formsのソリューションを.NET MAUIに移行します。

.NET Upgrade Assistantによる自動移行

今回紹介する方法は、 .NET Upgrade Assistantによる自動移行です。
learn.microsoft.com

.NET Upgrade Assistantのインストール

dotnet tool install -g upgrade-assistant

.NET Upgrade Assistantの実行

upgrade-assistant upgrade .\XamarinApp.sln --non-interactive --entry-point *

実行すると、移行するための操作内容や結果がどんどん表示されますが、かなり作業としては多いようです。
時間もそれなりに時間を要しますので、時間的に余裕のある時に試すのがいいでしょう。
なお、オリジナルのソリューション構成は自動的にバックアップが作成されますので、その点は安心して実行できます。

.NET Upgrade Assistantによる移行結果

.NET Upgrade Assistantを実行した結果を、実行前の状態と比較してます(Gitに事前にコミットしておいて実行後のファイルとの差分を検証)

XAMLファイル関連

Xamarin.Formsの画面定義である拡張子がxamlXAMLファイル関連の変更点としては名前空間の変更があります。

具体的には、Xamarin.Formsの名前空間「xmlns="http://xamarin.com/schemas/2014/forms"」→MAUIの名前空間「xmlns="http://schemas.microsoft.com/dotnet/2021/maui"」の置換が必要です。
基本的には名前空間の変更だけで、画面定義部分であるXAMLの他の部分は変更がかかっておりません。
実際のアプリ開発用プロジェクトでは、それだけでは期待した表示が得られない可能性もありますが、まずは、MAUI上で動作するように変更するポイントはここだけのようです。

XAMLC#部分関連

xamlファイルと対になるxaml.csファイルについても変更点は名前空間のみとなります。

usingのところで参照している「Xamarin」「Xamarin.Forms」を「Microsoft.Maui」「Microsoft.Maui.Controls」に変更します。
usingではなくコード本文中で「Xamarin.Forms.~」のように記載している部分があれば、そこも変更が必要です。
もともとXamarinで作成していたとしても、コード部分は.NET Frameworkと互換性があり、また、.NET Frameworkと.NET 6/7も基本的にコードの互換性はあるので、これだけシンプルな変更となっているのだと推測します。

csproj(プロジェクトファイル)のアップグレード

移行で一番変更がかかるのがこのプロジェクトファイルです。
.NET Framework形式から.NET SDK形式にプロジェクトファイルの変更します。

不安になるくらい要素が削除されます。なぜこのようにシンプルになるのかの答えはlearnにありました。
learn.microsoft.com

.NET Framework プロジェクトとは異なり、既定値がほとんどの一般的なユース ケースに対応しているため、これらの項目をプロジェクト ファイルで指定する必要はありません。 この動作により、プロジェクト ファイルのサイズがより小さく、より簡単に理解できるようになり、必要に応じて手作業で編集できます。

.NET SDK形式のプロジェクトファイルにすることでこのような恩恵を得られるのでシンプルになるわけです。

手動変更

.NET Upgrade Assistantだけで完結してくれたらよかったのですが、一部手動での変更が必要です。

AssemblyInfo.csの削除

AssemblyInfo.csの内容は、csproj側への記載(プロジェクトのプロパティ)に変更が必要です。
AssemblyInfo.csの内容をcsproj側に記載がおわったら、AssemblyInfo.cs自体は削除します。

Resource.designer.csの削除


こちらも.NET SDK契機にすることで不要になるので削除します。

MainActivity.csの変更

Xamarin時代のMainActivity.csの基底クラスは「global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity」でしたが、.NET MAUIにすると「MauiAppCompatActivity」となりますので、MainActivity.csを書き換えます。
OnCreateメソッドの中身も「base.OnCreate(savedInstanceState);」をのこしてFormsなどの初期化ロジックは削除します。

MainApplication.csの追加

Androidプロジェクトに「MainApplication.cs」を追加します。

MauiProgram.csの追加

共通プロジェクト側に「MauiProgram.cs」を追加します。

実機実行

実機実行が非常に大変でした。
アップグレードする前のXamarin.Formsのプロジェクトで実機実行できることを確認しておいたのですが、実行ターゲットに実機がでてこないのです。

<<<<<<調査継続中>>>>>>>

adbコマンドで実機転送して確認

実際に実機で動くのかどうか。とりあえずは、adbを使ってapkファイルを実機転送して実行できるかを試してみましょう。
これができるのであれば、Visual Studio側の問題だと切り分けられます。

実機接続確認

まずは、実機が接続されているか「adb devices」で確認します。

問題なく接続できていますね。

apkファイル作成

adbコマンドで実機転送できるのはapkファイルになります。releaseの生成物をaabではなくapkに変更する方法でもいいのですが、あとで戻し忘れそうなのでdebugで生成したapkを転送してみます。
ただし、debugビルドはファーストデプロイが有効で、ファーストデプロイが有効だとアーカイブ(apkファイル作成
)できないのでそこだけ変更します。

変更ができたら、ソリューションエキスプローラ―でAndroidプロジェクトを右クリックして「アーカイブ」を選択すればapkファイルが作成できます。

apkファイルに署名

apkファイルに署名せずに実機転送しようとすると「INSTALL_PARSE_FAILED_NO_CERTIFICATES」のエラーが出力されるので、アーカイブマネージャーで、[配布]-[アドホック]で署名付きapkファイルを作成します。

apkファイルを実機転送

adb -s L52A1ced3372 install com.companyname.xamarinapp.apk


実機実行

実機でXamarinAppを実行すれば、無事に動作しました。
これであとは、Visual Studioで実機が認識されて実機転送デバックできる手順が分かれば、安心してアップグレードを想定して使い始められそうですね。

.NET MAUIの新規プロジェクト構造について

前回:hatsune.hatenablog.jp

.NET MAUIで何ができるのかを知っていく前に、まずは、Visual Studio 2022を使って、.NET MAUIの新規ソリューションを作成してみましょう。

ターゲットフレームワークは?

.NET 6か.NET 7が選べるようですね。

新規ソリューション構成の違い

新規ソリューション構成(MAUI)

選んだ結果として作成されるソリューション構成は次のような構成です。

プロジェクトが1つで、Platformsフォルダに各種ターゲットごとの定義が含まれています。

新規ソリューション構成(Xamarin.Forms)

一方でXamarin.Formsだと次のような構成です。

アーカイブの作り方(配布形式の作成)

MAUI

どのプラットフォームでも[発行]で配布形式の作成ができます。
プラットフォームの切替はこんな感じで行えます。

例えば、Androidを指定して[発行]をすると従来のXamarinと同様にAndroidプラットフォームのアーカイブが作成されます。

これだけ違うと全面作り直しか?と思ったのですが、どうやらいろいろ調べてみると新規作成時こそソリューション構成は違いますが、Xamarin.Formsから.NET MAUIへの変換パスは(手動も含めて)用意されているようです。
次回は、そのあたりをさらに調べたいと思います。

次回:
hatsune.hatenablog.jp

そろそろ.NET MAUIを始めようか

C#XAMLスマホアプリが構築できるXamarin.Formsが大好きです。
そんなXamarinのサポートも約1年後の2024/5/1に終了します。
dotnet.microsoft.com
Android 13 と Xcode 14 SDK (iOS および iPadOS 16、macOS 13) よりも新しいOSバージョンにはXamarinは対応しないとのことです。
スマホOSは容赦なくバージョンが上がっていきますし、ストアへの登録要件も上がっていきますので後継フレームワークへの移行を考えないといけない時期になってきましたね。

すでに後継フレームワークは発表されています。

  • Xamarin→ .NET 7
  • Xamarin.Forms →.NET Multi-Platform App UI (MAUI)

互換性はあるようですが、非互換もあるようなのでLearnにあるドキュメントを読んで、まずは、移行するための大枠を知っていきたいと思います。
learn.microsoft.com

次回:
hatsune.hatenablog.jp

Nreal Airを買ったのでARCoreを使って6DoF化してみる

前回:
hatsune.hatenablog.jp

準備

開発環境

  • Unity 2021.3.15f1 <---今回から2021.3.14f1から変更
  • Visual Studio 2022 (Community 2019なども可)
  • NRSDK 1.10.5 <---今回から1.9.5から変更

環境整備:詳細は前回参照

  1. NRSDKのインポート
  2. NRSDKのTipsのFix
  3. GraphicsAPI is not OpenGLES3の対応

1.10.0でもOpenGLES3のFixについてはTipsからFixできませんでした。
そこで1.9.5同様に、[Build Settings]の中の[Player Settings]の[Android]-[Other Settings]の項目への設定なので、[Auto Graphics API」チェックを外して、「ES3.1」「ES3.1+AEP」「ES3.2」のチェック

新規プロジェクト作成

新規作成

Unity Hubを起動して[プロジェクト]→[新規作成]をクリックして、プロジェクトの新規作成を行います。

テンプレートの指定

テンプレートとして[3D]を選択して、プロジェクト名を指定したら[作成]をクリックします。

プラットフォームの変更

Unityを起動してUnityの新規プロジェクトが作成されたら、[File]-[Build Settings]メニューから設定画面を開きます。
プラットフォームを「Android」に変更して[Switch Platform]をクリックします。

C#エディタの設定

[Edit]-[Perferences]メニューから[External Tools]の[External Script Editor]で使用するVisual Studioを選択します。
VSCodeなども選べますが、今回は愛用している「Microsoft Visual Studio 2022」を選択しました。

ARCoreの導入

ARFoundationパッケージの導入

Unityの[Window]-[Pakage Manager]メニューで[パッケージマネージャー]ウィンドウを開きます。

[パッケージマネージャー]ウィンドウで「Packages]の場所を「Unity Registry」に切り替えます。

そして、「AR Foundation」と「ARCore XR Plugin」を指定して、ウィンドウ右下の[Install]ボタンでインストールします。

Main Cameraの削除

「MainCamera」は不要なので「Hierarchy」から削除します。

オブジェクト追加

「Hierarchy」を右クリックして、[XR]-[AR Session]メニューをクリックしてAR Sessionを追加します。
同様に[XR]-[AR Session Origin]メニューをクリックしてAR Session Originを追加します。

平面検知の追加

ARFundationで現実空間の平面を検知するには「AR Session Origin」に「ARPlane Maneger」を追加するだけで自動的に平面検知が行えます。
「Hierarchy」で「AR Session Origin」を選択し、「Inspector」で「ARPlane Maneger」を追加します。

検知した平面に平面を表示する

「ARPlane Maneger」が検知した平面は、そのままでは人が見える形で何か表示がされるわけではありません。
そこで、検知した平面に平面を表示するように設定します。
どのような表示かは、「ARPlane Maneger」の「Plane Prefab」に指定した内容できまります。

表示用プレハブフォルダの設置

「Project」に「Prefab」フォルダを作成します。

表示オブジェクトの用意

「Hierarchy」を右クリックして、[XR]-[AR Default plane]メニューであらかじめ用意されている平面オブジェクトを追加します。

表示オブジェクトをプレハブ化

「Hierarchy」に追加された「AR Default plane」を「Project」-「Prefab」フォルダにドラッグ&ドロップしてプレハブ化します。

「Hierarchy」上の「AR Default plane」は不要なので削除しておきます。

AR Session Originに表示用プレハブを指定


Player Settingsの設定

[Fille]-[Build Settings]-[Player Settings]で設定ウィンドウを開いたら、Androidの[Other Settings]の中にある設定を変更します。

Graphics APIs から Vulkan を削除

[Graphics APIs」から「Vulkan」を削除します。

Minimum API Levelの変更

Minimum API Levelを7.0以上に変更します。

XR Plug-in Managementの設定

[Edit]-[Project Settings]で設定ウィンドウを開いたら、[XR Plug-in Management]で[ARCore]にチェックを入れてARCoreの初期化するように指定します。

ARFoundationとNRSDKを接続する

ARFoundationで検出したスマホ側の6DoF検知した結果をNreal Airの移動(足りない3DoF分)に反映することで、Nreal Airを疑似的に6DoFにすることができます。
この辺りは、ホロラボのたるこすさんがすでに実現していて、今回は、その方法を教えてもらって実装しました。


今回、たるこすさんのご厚意でブログでの記載OKいただきましたので、その方法について少し解説します。

オブジェクト配置

NRCameraRigParentの配置

[Hierarchy]で「AR Session Origin」を右クリックして[Create Empty]メニューで空のゲームオブジェクトを配置し、「NRCameraRigParent」という名前を付けます。

NRCameraRigの配置

[Assets]-[NRSDK]-[Prefabs]にある「NRCameraRig」を[Hierarchy]の「AR Session Origin」にドラッグアンドドロップします。

Cubeの配置

[Hierarchy]を右クリックして、[3D Object]-[Cube]メニューでCubeをARFoundationの管理下で配置します。

Positionは(0, 0, 1)、Rotationは(30, 30, 0)、Scaleは(0,2, 0.2, 0.2)として、1m先に少し回転した立方体を配置します。

スクリプト作成

NRCameraRigParentに、ARFoundationカメラ(スマホカメラ)と移動をNRSDKカメラ(NrealAirの視野に相当)の移動に反映するスクリプトを記載します。
gist.github.com
このスクリプトのキモは「GetYawRotation」メソッドを使って、スマホ水平方向の回転と Nreal Airの回転を一致させる計算をして、NRCameraRigParentのrotationに反映している点です。
こうすることで、カメラから算出したスマホの位置をNreal Airの視野の位置に変換しています。

実機実行

実機準備

Android実機側では、まずは「開発者モード(Developer mode)」に変更して、さらに「USBデバッグ」ができるようにしておきます。

実機接続

Android実機側の準備ができたらUSBにて接続します。
準備がうまくできていると、ここで「USBデバッグを開始する」のようなダイアログが表示されるので、かならず「OK」をクリックします。

Unity側設定

[Run Device]には接続した実機を選択します。
[Development Build]と[Script Debugging]にもチェックをいれておきます。

実機実行

[Build And Run]をクリックして、ビルドと実機転送、そして実行を行います。
youtube.com

.NET(旧名称.NET Core)アプリの配布方法について(勘違いしていたので)

.NET 5以降のフレームワークWindowsアプリ(以下、.NET Coreアプリ)を作成したとき、配布した実行可能ファイルが.NET Frameworkのときとは異なっている点を最近まできちんと把握していなかったので、忘備録代わりに投稿します。

.NET Coreアプリの2つの展開

.NET Coreアプリを配布する形式は2つの配置モード(展開形式)があります。
例として、hogehogeというアプリ名のアプリを配布する場合について考えてみましょう。

フレームワーク依存

フレームワークに依存するという名称から、配布先のフレームワークx86かx64かなど配布先の環境を意識しないといけないように思えますが、そうではありません。

このファイル形式の良い点は2つ

  1. 配布ファイルはx86/x64の区別がない(1つだけ例外あり)
  2. 配布するファイルに.NETランタイムは入らないのでコンパクト(配布ファイルの例:66ファイル、合計62MB)
Any CPUでビルドしたものを配布できる

配布先にあるフレームワークに動作モードが依存するので、展開形式ではx86かx64かを意識しないでビルド、つまり、Any CPUでビルドすることができます。

配布先での実行はdll名指定で

hogehogeというアプリ名の場合、配布物の中では、hogehoge.dllがアプリファイルとなりますので、

dotnet hogehoge.dll

のようにして実行します。インストーラーの中で、アプリショートカットを作成して、このコマンドを実行するように設定するなどの工夫が必要です。

実行可能ファイル

hogehoge.dll以外にもhogehoge.exeというファイルも配布されますが、配布先でのhogehoge.exeの実行には注意が必要です。
dotnet hogehoge.dll」での実行は配布先がx86環境でもx64環境でも(なんならWindows環境以外でも場合によっては)実行ができます。
しかし「hogehoge.exe」での実行は、例えば、開発環境がx64だった場合、hogehoge.exeは64bitアプリとして作成されるので実行環境がx86環境の環境に配布しても実行できません
また、開発環境がx86だった場合、hogehoge.exeは86bitアプリとして作成されるのでx64環境に配布してもx64アプリではなくx86アプリとして動作しようとするので、x86の.NET6ランタイムがないと実行できません
この赤字の部分が勘違いしていて、「なんでx86環境で動かないんだ~」と1日悩んでいました。
x64環境でビルドして、フレームワーク依存で配布した場合、x86環境での実行は「dotnet hogehoge.dll」一択です!

自己完結

配置モードとして「自己完結」を選択すると、ターゲットランタイムも含めた形で実行に必要なファイルがすべて含んでファイルが生成されます。

このファイル形式の良い点は、次の点です。

  1. 配布先の環境で、を事前にインストールする必要がない(配布ファイルの例:350ファイル、合計214MB)

その代わり、Any CPUビルド指定していたとしても、ターゲットランタイムとして「win-x64」と指定するので、作成されたファイルは、DLLも含め、Windows x64環境に依存したものになります。
もし、x86とx64の両方に配布する予定があるのであれば、x86用自己完結インストーラーとx64用自己完結インストーラーの2つのmsiファイルを作成する必要があります。

Visual Studio Installer Projectでのmsiファイル作成

Visual Studio 2022と最新のVisual Studio Installer Project Templateを使えば、.NET Coreアプリもmsiファイルとしてインストーラーファイルを作成することができます。

配置モードが「自己完結」の時のインストーラープロジェクト

配置モードを「自己完結」としてVisual Studioから「発行」したものをVisual Studio Installer Projects 拡張機能を使ってmsiファイルを作る場合は次のような手順になります。

Setupプロジェクトの新規作成

Visual Studio Installer Projects 拡張機能をインストールしておくと、新規プロジェクトタイプして「Setup」が選択できます。

インストールターゲットの指定

インストーラープロジェクトが新規作成されたら、プロジェクトのTargetPlatformプロパティを発行時に選択したプラットフォームに合わせます。今回は「win-x64」としたので、「x64」を選びます。

「項目の公開」の追加

インストーラープロジェクトが新規作成されたら、プロジェクトを右クリックして[プロジェクト出力]を選択して、「項目の公開」をプロジェクトに追加します。

PublishProfilePathの設定

「項目の公開」がプロジェクトに追加されたら、そのPublishProfilePathプロパティに「発行」で作成ししたプロファイルファイルを指定します。

もちろん、この発行プロファイルの配置モードは「自己完結」にしておきます。
これにより、発行プロファイルに基づいたビルドが行われて、そこの出力を使ってmsiファイルが作成されます。

ビルドを開始しました...

            • Starting pre-build validation for project 'HogehogeTrialSetupCore' ------
            • Pre-build validation for project 'HogehogeTrialSetupCore' completed ------

1>------ ビルド開始: プロジェクト: HogehogeTrialSetupCore, 構成: Release ------
Building file 'C:\User\Project\dotNET\HogehogeTrialSetupCore\Trial\TrialSetup.msi'...
Packaging file 'System.Windows.Forms.Design.resources.dll'...
:
(中略)
:
Packaging file 'System.Net.Http.Json.dll'...
========== ビルド: 成功 1、失敗 0、最新の状態 1、スキップ 0 ==========
=========== 経過時間 01:19.271 ==========

配置モードが「フレームワーク依存」の時のインストーラープロジェクト

配置モードを「フレームワーク依存」としてVisual Studioから「発行」したものをVisual Studio Installer Projects 拡張機能を使ってmsiファイルを作る場合は次のような手順になります。

Setupプロジェクトの新規作成

Visual Studio Installer Projects 拡張機能をインストールしておくと、新規プロジェクトタイプして「Setup」が選択できます。

インストールターゲットの指定

インストーラープロジェクトが新規作成されたら、プロジェクトのTargetPlatformプロパティを「x86」とします。
こうすることで、x64環境でもx86環境でも動作するmsiファイルが作成できます。
なお、ここでx86と指定しても、インストールされるアプリ自体がx86アプリになるわけではありません。

「項目の公開」の追加

インストーラープロジェクトが新規作成されたら、プロジェクトを右クリックして[プロジェクト出力]を選択して、「項目の公開」をプロジェクトに追加します。

PublishProfilePathの設定

「項目の公開」がプロジェクトに追加されたら、そのPublishProfilePathプロパティに「発行」で作成ししたプロファイルファイルを指定します。

もちろん、この発行プロファイルの配置モードは「フレームワーク依存」にしておきます。
これにより、発行プロファイルに基づいたビルドが行われて、そこの出力を使ってmsiファイルが作成されます。

インストールプロセスの中でランタイムをインストール(前提条件の追加)

フレームワーク依存の場合、.NETランタイムが事前にインストールされていることが必要となりますので、インストーラーの実行プロセスの中で.NETランタイムもインストールするように設定します。
ソリューションエクスプローラーでプロジェクトを右クリックしてプロパティを表示します。
[Prerequisites]ボタンをクリックします。

必要なランタイムを指定します。

ランタイムのチェックだけでインストールは事前に実施

インストーラーの中でランタイムをインストールしないときは、前提条件は追加しないようにします。

配布先でのインストール結果の確認

配置モードが「自己完結」の時のインストール結果


アプリフォルダに.NETデスクトップランタイムに含まれるファイルもインストールされて、ファイル数350個がアプリフォルダに展開されます。

配置モードが「フレームワーク依存」の時のインストール結果


アプリフォルダに.NETデスクトップランタイムのファイルはインストールされないので、ファイル数66個となります。