Contents
Xamarin.Formsプロジェクトを新規作成→Android実機で起動を確認
っていう、真っサラなプロジェクトを移行してみる、という簡単なお試し体験談。
意外と詰まりまくったので、書き記しておく。
なお、2023年11月時点のお話です。
しかも結論から述べると、Xamarin.FormsプロジェクトをMAUIにそのまま変換するのはオススメしない。
事前に必要な環境をインストールしておく
Visual Studio 2022でXamarin.Formsプロジェクト開発していたとして、その他、移行に必要なものをいれる。
.NET SDK
下記の記載があるので、2023年11月時点では.NET 8はまだPreviewだし、.NET 7のSDKをインストールしておく。
一応.NET 8で試してもいて、最後に記載しています。
Xamarin ネイティブ プロジェクトを .NET にアップグレードするには、まずプロジェクトを SDK スタイルのプロジェクトに更新してから、依存関係を .NET 7 以降に更新する必要があります。
Xamarin から .NET へのアップグレード
workload
本当に必要かはわからないけど、試行錯誤中は求められたので、入れておこう。
Visual Studioのメニューの [ツール] → [コマンドライン] → [開発者コマンドプロンプト]で起動して、叩きまくる。
dotnet workload install maui
dotnet workload install wasm-tools
dotnet workload install android
dotnet workload install ios
OSの再起動が保留されている旨が表示されたので、念のため再起動した。
必要なら.NET アップグレード アシスタント
移行の手順をある程度、自動化してくれる。
どうも、バージョンによってやってくれることが違うらしいので、sourceを指定してインストールした方が良さそう。
Visual Studioのメニューの [ツール] → [コマンドライン] → [開発者コマンドプロンプト]で起動して叩く。
dotnet tool install -g upgrade-assistant --add-source https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-tools/nuget/v3/index.json
こちらのいわささんの記事を参考にさせていただきました。
記事では0.4.336902だったけど、私が試したときは0.5.261.51392でした。
移行する
.NET アップグレード アシスタントにお願い
Visual Studioのソリューションプロジェクトから右クリックでも、コマンドプロンプトからも実施できる。
一応どっちも試したけど、コマンドプロンプトからの方が良さげかなぁ。
Visual Studioのメニューの [ツール] → [コマンドライン] → [開発者コマンドプロンプト]で起動して叩く。
upgrade-assistant upgrade slnファイル名
あとは自動的にUpgradeしたいプロジェクトや、方法を聞いてくるので、
- 共通プロジェクトを.NET 7へ
- AndroidプロジェクトをSDKスタイルへ
- Androidプロジェクトを.NET 7へ
- iOSプロジェクトをSDKスタイルへ
- iOSプロジェクトを.NET 7へ
の順に5回ほど同じコマンドを叩いた。
これで、このへんをやってくれる。
- usingの置き換え
- xmlnsの置き換え
- Xamarin.Forms系クラスの置き換え
- プロジェクトファイルの書き換え
- 共通プロジェクトにMauiProgram.csの追加
たぶんバージョンによってはMainApplication.csの追加もやってくれたけど、最後に試したときはやってくれかった。
困ったらbin/objフォルダを削除してVisual Studioを再起動
やるとエラーの内容が変わるので、困ったらとにかくbin/objフォルダを削除してVisual Studioを再起動だ。
構成マッピングのエラーはとりあえず構成マネージャーを開く
ひとまず、構成マネージャーを開いて、なにもせず閉じれば消えるが、Visual Studioを起動する度に出るのはかなり気になる。
Androidプロジェクトの修正
プロジェクトファイルの修正
TargetFrameworkがnet7.0だったので、net7.0-androidに修正。
<UseMaui>true</UseMaui>が追加されていないので、追加。
ただ、これを追加すると接続した実機が見えなくなっちゃう。
でも、これをいれないとMicrosoft.Mauiを名前解決できないエラーが出る。
やんなっちゃう。
ひとまず実機が選べなくてもデバッグを開始すれば実機を探してくれたので、無視して進める。
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<AndroidResgenFile>Resources\Resource.designer.cs</AndroidResgenFile>
<AndroidHttpClientHandlerType>Xamarin.Android.Net.AndroidClientHandler</AndroidHttpClientHandlerType>
</PropertyGroup>
<PropertyGroup>
<TargetFramework>net7.0-android</TargetFramework>
<UseMaui>true</UseMaui>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\SampleApp\SampleApp.csproj" />
</ItemGroup>
</Project>
MainActivity.csの修正
解説サイトさん達、みなさんFormsAppCompatActivityをMauiAppCompatActivityにするだけっぽかったので、それにならう。
プロジェクトファイルに追加した<UseMaui>true</UseMaui>を調べていたら、メソッドを呼び出して.NET MAUI を初期化せえって言うので、意味があるかわからないけどやっておく。
using System;
using Android.App;
using Android.Content.PM;
using Android.OS;
using Microsoft.Maui;
using Microsoft.Maui.Hosting;
using Microsoft.Maui.Embedding;
namespace SampleApp.Droid
{
[Activity(Label = "SampleApp", Icon = "@mipmap/icon", Theme = "@style/MainTheme", MainLauncher = true, ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation | ConfigChanges.UiMode | ConfigChanges.ScreenLayout | ConfigChanges.SmallestScreenSize )]
public class MainActivity : MauiAppCompatActivity
{
MauiContext _mauiContext;
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
MauiAppBuilder builder = MauiApp.CreateBuilder();
builder.UseMauiEmbedding<Microsoft.Maui.Controls.Application>();
MauiApp mauiApp = builder.Build();
_mauiContext = new MauiContext(mauiApp.Services, this);
}
}
}
AssembleInfo.csをコメントアウト
削除でも良いんだが、ビビリなのでコメントアウトだけにしておく。
MainApplication.csを追加
なくても起動はする&onCreate関数でnullポするので、気づくまでかなり時間がかかったが、こいつが追加されていなかったことが原因だった。
using Android.App;
using Android.Runtime;
using Microsoft.Maui.Hosting;
using Microsoft.Maui;
using System;
namespace SampleApp.Android
{
[Application]
public class MainApplication : MauiApplication
{
public MainApplication(IntPtr handle, JniHandleOwnership ownership)
: base(handle, ownership)
{
}
protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiApp();
}
}
iOSプロジェクトを修正
Androidと同様、TargetFrameworkがnet7.0だったので、net7.0-iosに修正。
<UseMaui>true</UseMaui>が追加されていないので、追加。
AssembleInfo.csをコメントアウト
これもAndroidと同様。
AppDelegate.csを修正
解説サイトさんにならって、継承クラスを置き換えて、FinishedLaunching関数は削除して、CreateMauiAppをoverrideする。
using System;
using System.Collections.Generic;
using System.Linq;
using Foundation;
using UIKit;
using Microsoft.Maui.Hosting;
namespace SampleApp.iOS
{
// The UIApplicationDelegate for the application. This class is responsible for launching the
// User Interface of the application, as well as listening (and optionally responding) to
// application events from iOS.
[Register("AppDelegate")]
public partial class AppDelegate : Microsoft.Maui.MauiUIApplicationDelegate
{
protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiApp();
}
}
実機で確認
ひとまず手元にあったAndroidで試す。
Xamarin.Formsプロジェクトでデバッグは出来ていた機種なので、機種側の設定は割愛。
「Start」をクリックすると、デバイスは探してくれるっぽい。
ビルドを開始しました...
1>------ ビルド開始: プロジェクト: SampleApp, 構成: Debug Any CPU ------
2>------ 配置開始: プロジェクト: SampleApp.Android, 構成: Debug Any CPU ------
2>Sony SO-41B に対する配置を開始しています...
2>Sony SO-41B に配置しています...
配置が終わると普通にデバッグができた。
実機を引っこ抜くと配置失敗で起動できなかった。
エミュレーターを起動してくれるとか、ないんかい。
iOSはそもそも配置が選べなくなってる。なんでや。
.NET 8で試す
Visual Studio 2022 Previewを別途インストールして、各種プロジェクトのターゲットを.NET 8に変更。
Androidプロジェクトだけ、33がないって怒ってきた。
エラー NETSDK1181 パックバージョンの取得エラー。パック 'Microsoft.Android.Ref.33' がワークロード マニフェストに存在しませんでした。 SampleApp.Android C:\Program Files\dotnet\sdk\8.0.100-rc.2.23502.2\Sdks\Microsoft.NET.Sdk\targets\Microsoft.NET.Sdk.FrameworkReferenceResolution.targets 90
プロジェクトファイルを開いて、
<TargetFramework>net8.0-android33.0</TargetFramework>
→<TargetFramework>net8.0-android</TargetFramework>に修正。
だけでAndroid端末でデバッグ実行できた。
しかもVisua Studio 2022 Previewなら実機がちゃんと選択肢に出てきた。
Visua Studio 2022で、新規MAUIプロジェクトを作成しても選択できたんだよなぁ。
新規作成時は<UseMaui>true</UseMaui>がデフォルトで入ってるしなぁ。
なにが根本的な原因なんだろう?
結論
今あるプロジェクトをMAUIに変換するのは、トラブルが多い。
新規MAUIプロジェクトを同じ名前で作成して、Xamarinのソースコードから変換しながら引っ越してくる、が良いのかな。
新規MAUIプロジェクトなら、「Androidローカルデバイス」を選択すると、Windowsに接続したAndroid実機。
「iOSリモートデバイス」を選択すると、ペアリングしたMacに接続したiPhone。
「iOSローカルデバイス」を選択すると、Windowsに接続したiPhone、がそれぞれ選択できた。
私の環境だと「iOSリモートデバイス」じゃないとプロビジョニングでエラーになってしまうので、iPhoneはMacに繋いでる。
まぁ、どんな形であれ、AndroidとiPhoneの実機でデバッグ実行できるのだから、良しとしよう。
いざ実践
こちらからどうぞ。
他にもニッチなIT関連要素をまとめていますので、よければ一覧記事もご覧ください。