はつねの日記

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アプリとして再構築を試したいと思います。

次回:

iOSアプリでMulticast Networkingを許可する方法

iOS14以降 & XCode 12以降では、ローカルネットワークへの通信にユーザの許可が必要になりました。
そして、マルチキャスト/ブロードキャストで他の機器と通信をするためには、Appleへの申請やentitlementsへの追記など色々必要になっています。

ローカルネットワーク通信の許可

Info.plistに対して、「Privacy - Local Network Usage Description」を追加してローカルネットワーク上の別デバイスとの通信を行うときに許可ダイアログが表示されるようにします。
ただし、Xamarinの場合、2021/07/19現在の最新版では「Privacy - Local Network Usage Description」が選択肢の中にでてきません。
f:id:hatsune_a:20210719200453p:plain
そこで、直接Info.plistファイルを編集して「NSLocalNetworkUsageDescription」を追加します。
f:id:hatsune_a:20210719200741p:plain

マルチキャスト/ブロードキャストで他の機器と通信を許可

Multicast Networking Entitlement申請

Bonjourでサービスを検索するときには不要ですが、それ以外でマルチキャストやブロードキャストをするときには、Appleに「Multicast Networking Entitlement申請」を行う必要があります。
申請方法は下記のURLに開発者アカウントでサインインして申請します。申請してから3~5営業日くらいで「Multicast Networking Entitlement」を取得できます。
https://developer.apple.com/contact/request/networking-multicast
申請時の注意するのは、「Explain why your app needs to send multicast or broadcast traffic, or browse for all Bonjour service types.」という項目の内容です。ここには、次のような内容が含まれていないと、追加情報を要求されて余計に日数がかかります。

  • Multicastなのかbroadcastなのか
  • なんの目的で通信するのか
  • 通信するIPアドレスやポート番号
  • 通信するデータ(例えば、JSON形式で端末で計測したデータなど)
Capabilitiesの追加

「Multicast Networking Entitlement」が取得できたとの連絡メールがAppleからくると、Apple Developer Programのサイトの「Identifiers」にて、Multicast NetworkingのCapabilitiesをEnableにできます。
f:id:hatsune_a:20210719203739p:plain
Enableにチェックをつけて[Save]をクリックすると確認ダイアログが出るので[Confirm]をクリックします。
f:id:hatsune_a:20210719203837p:plain

プロビジョニングプロファイルの再作成

Capabilitiesの追加確認のダイアログには「機能を追加または削除すると、このアプリIDを含むプロビジョニングプロファイルが無効になり、今後使用するためには再生成する必要があります。」と記載があるのでプロビジョニングプロファイルの再作成が必要です。
f:id:hatsune_a:20210719204227p:plain

Entitlements.plsitでエンタイトルメントを有効にする

f:id:hatsune_a:20210719205003p:plain
アプリの.entitlementsファイルに、ブール値が true のcom.apple.developer.networking.multicastエントリを追加します。

実機に転送して動作を確認する

Multicast Networkingを許可する設定がない場合でも実機でなければ影響をうけません。
実機でデバッグ実行をしてマルチキャスト通信でエラーにならないことを確認できれば、設定は終了です。

iOSアプリ作成に必要な証明書についてまとめてみた

.NET 6やMAUIなど、今年、MicrosoftがGA(一般公開)する技術では、マルチプラットフォームのXamarin.Formsよりも更に促進されることが期待されるものが多いと感じています。

そこで、じゃあC#を使ってAndroidiOSのアプリを作成しようと思ったときに、意外にネックになるのが、iOSアプリを作成するときに必要な証明書の作成です。
しかも本番用証明書の期限は1年なので、私だけなのかもしれませんが、毎年どうやったのか思い出しながら不安になりつつ作業しています。
そこで、心理的安全が欲しいということもあり、ちょっとこの辺りを自分の言葉でまとめておきたいと思います。
この分野は専門外なので、何かおかしな記述があればご指摘いただき、随時、本文に反映させていくという若干他力本願な内容となりますが、最後までお付き合いいただければ幸いです。

登場人物

  • Apple Developer Program
  • MacOS上で作成する証明書(便宜上、アカウント証明書とします)
  • Apple Development 証明書(または、iOS App Development証明書)
  • Apple Distribution 証明書(または、iOS Distribution証明書)

証明書を発行しよう

Apple Developer Programの登録/更新

iOSアプリを開発してストアで公開してとなると、Apple Developer Programに加入する必要があります。
アプリ作成するだけなら加入必須ではないという話もあるようですが、そこについては今回は触れません。
developer.apple.com
Apple Developer Programの年間メンバーシップの料金は11,800円です。iOSなどのベータ版も入手できたり、様々な情報も得られますから、実際にストアに登録する作業を別部署でやり開発する人が直接できないようなジャパニーズトラディショナルカンパニーさんだったとしても、開発している部署でも(会社のお金で)登録しておくとよいと思います。

アカウントについて

ここで重要なのは、登録するときに記入するメールアドレスです。これが、今後の様々なところで「アカウント」として一意に識別されるための情報となります。

Team IDについて

メンバーシップに登録されるとTeam IDというものが払い出されます。このIDも重要で、要はアプリの発行元IDのようなものになります。
後々作成する証明書について、どの証明書かわからなくなったらこのTeam IDを他よりに判断することになります。

年間メンバーシップの更新について

なお、年間なので1年後にはメンバーシップの更新が必要になります。近づいてくるとメールで「そろそろ期限がきれますよ」とお知らせが飛んでくる新設設計なので、メール無視せずに期限切れになるまえにちゃんと更新しておくようにしましょう。
忘れない!絶対!

アカウント証明書の作成

Apple Developer Programの登録がおわったら、Macでの作業となります。

認証局に証明書を要求

f:id:hatsune_a:20210616190711p:plain
[キーチェーンアクセス]-[証明書アシスタント]-[認証局に証明書を要求]メニューをクリックします。

f:id:hatsune_a:20210616191257p:plain

  • [ユーザーのメールアドレス]欄には、メンバーシップのアカウントに指定したメールアドレスを指定
  • [通称]欄には任意の名前を指定
  • [ディスクに保存]を選択
  • [鍵ペア情報を指定]チェックにチェック

[続ける]ボタンをクリックしてから、次のように設定されていることを確認します。

デスクトップを指定して[保存]ボタンをクリックすれば、これで、Apple Developer Programのアカウントに紐付いたアカウント証明書が作成できました。
この証明書の有効期限も、作成してから1年間となります。また、作成するときには有効な年間メンバーシップの契約が必要です。
そのため、年間メンバーシップを更新したら、アカウント証明書も再作成しておくとよいでしょう。

Apple Development 証明書の発行

アカウント証明書が作成できたならば、Apple Developer Programのサイトにいって作業します。
事前に登録したアカウントでサインイン
「Certificate, Identifiers & Profiles」のページに移動します。
f:id:hatsune_a:20210616085707p:plain

新しいApple Development 証明書の発行

Certificatesの後ろの[+]を押して、新しい証明書を発行します。
f:id:hatsune_a:20210616091338p:plain
開発用のApple Development証明書ならば、「Apple Development」を指定します。

Apple DevelopmentとiOS App Developmentの違い

XCode 11以降はApple Developmentを指定します。
それより以前のものはiOS App Developmentを指定しますが、古いXCodeを積極的に使う理由はないので、実質「Apple Development」一択です。

Maximum number of certificates generated について

「Maximum number of certificates generated」とでているのは、すでに発行しているApple Development 証明書に紐付いている「Provisioning Profile (Development)」で有効期限切れのものがあるからです。

アカウント証明書をアップロードする

f:id:hatsune_a:20210616093534p:plain
Macで作成したアカウント証明書を選択します。
これでApple Development 証明書が作成できました。
Certificatesの一覧には、Apple Developer Programのアカウント名=メンバーシップの「Account Holder」が証明書名として表示されます。

Apple Development 証明書をMacにダウンロードする

Apple Development 証明書が作成できたので、Macにダウンロードしておきましょう。

Apple Distribution 証明書の発行

アカウント証明書が作成できたならば、Apple Developer Programのサイトにいって作業します。
事前に登録したアカウントでサインイン
「Certificate, Identifiers & Profiles」のページに移動します。
f:id:hatsune_a:20210616085707p:plain

新しいApple Distribution証明書の発行

Certificatesの後ろの[+]を押して、新しい証明書を発行します。
f:id:hatsune_a:20210616094512p:plain
発行用の証明書が必要なので、「Apple Distribution」を指定します。

Apple DistributionとiOS Distributionの違い

XCode 11以降はApple Distributionを指定します。
それより以前のものはiOS Distributionを指定しますが、古いXCodeを積極的に使う理由はないので、実質「Apple Distribution」一択です。

Apple Distribution証明書の発行上限数について

Apple Distribution証明書は、合計で3つ作成できます。
Apple Distribution証明書は、基本的にアプリごとに作成するのではなく、発行者ごと、つまり、Apple Developer Programのメンバーシップごとに1つ作るような運用イメージになります。

アカウント証明書をアップロードする

f:id:hatsune_a:20210616093534p:plain
Macで作成したアカウント証明書を選択します。
これでApple Distribution 証明書が作成できました。
Certificatesの一覧には、メンバーシップの「Team Name」が証明書名として表示されます。

Apple Distribution証明書をMacにダウンロードする

Apple Distribution証明書が作成できたので、Macにダウンロードしておきましょう。

キーチューンに登録する

Apple Develoment証明書と、Apple Distribution 証明書がダウンロードできたら、キーチューンに登録しておきましょう。
登録は簡単で、証明書をダブルクリックすればキーチューンが立ち上がって追加されます。
f:id:hatsune_a:20210616221344p:plain
これで新しい有効期限の証明書がキーチューンアクセスのログイン証明書に登録することができました。
証明書の中の秘密鍵の名前は、アカウント証明書を作成するときに認証局に証明書を要求した時の通称が設定されています。
有効期限の更新で証明書を作成した場合は、この時点で古い有効期限の証明書は削除しておきましょう。

最後に

来年の年間メンバーシップの更新時に新しい証明書を作成するときや、開発機を変更するときなども、きっと、このエントリ見ながらやると思います。忘備録大切!

iOSアプリの開発環境の2台目を設定する

Xamarin.Formsを使ってiOSアプリを作っています。
Windows上でVisual Studio 16.9を使って作成して、Visual Studio for Macが入ったMacMiniとペアリングしてビルドするような開発環境となっています。
docs.microsoft.com

今月、ちょっとした事情(主に在宅勤務時に自宅で実機デバッグができるように)2台目の開発用MacMiniを入手しました。
もちろんM1 MacMiniです。

さて、ここで悩んだのが1台目と同じビルド結果となるように2台目に設定するのかということです。
1台目の開発環境を作る方法は、いろいろなblogに書かれているのですが、その作った環境と同じものを2台目として作る方法がよくわからない。。。
下手にやって1台目の環境でアプリがビルドできなくなったらストア公開しているものが更新できなくなったら本末転倒ですからね、どうしても慎重になってします。

悩んで「なんもわからーん」とホロラボ社内に聞いてみたら、即回答もらえました。
事前に1台目のApple開発者アカウントを2台目にも設定してあれば、残る手順は以下の通り。

  1. 1台目のキーチェーンでDistribution証明書とDeveloper証明書からそれぞれ「書き出す」でp12ファイルを作成
  2. 2台目にp12ファイルをコピーしてダブルクリックでキーチェーンに登録

なんとこれだけで良かったみたい。
簡単でした。

Xamarinで作成したAndroid App Bundleを端末にインストールする

2021年8月からは、Google Playに新しくアプリを登録するには、従来のapkではなくAndroid App Bundle(aab)で登録することが必要になります。
Visual Studio + XamarinでAndroid向けアプリを作成するときも、もちろん、apkだけではなくaabで作成できます。
初期のころはaab作成がVisual Studioからはできず、MSBuildを使ってコマンドラインでaabファイルをつくらなければなりませんでしたが、最近のVisual Studioではアーカイブでも可能です。

Androidオプションを設定する

aabを作成するには、Androidアプリのプロジェクトのプロパティを表示して、Androidオプション画面で設定します。
aab作成には本当に時間がかかるので、Release構成のみの設定が推奨されています。

Release構成で設定する

そのため、[構成]を「Release」にしてから設定を変更します。
f:id:hatsune_a:20210218073903p:plain
設定は簡単で、Androidパッケージ形式を「バンドル」にするとaab作成となります。このとき次の2つのチェックボックスが、値固定でグレーアウトします。

  • [選択したABIごとに1つのパッケージにします]はOFF
  • [インクリメンタルAndroidパッケージシステム(aapt2)を使用します]はON
aapt2とは

aapt2(Android Asset Packaging Tool)は、アプリのリソースをコンパイル、パッケージ化するために使用するビルドツールです。AAPT2 はリソースを解析してインデックスに登録し、Android プラットフォーム向けに最適化されたバイナリ形式にコンパイルします。

Debug構成で設定する

2つの設定が固定化されるのであれば、Debug構成でも同じ設定にしておいてデバッグしておくことが安全です。
aapt2については新規プロジェクト作成時はデフォルトONになっていますが、以前から使っているプロジェクトではOFFになっているものも多いでしょう。
それでは、[構成]を「Debug」にしてaapt2をONに設定しましょう。
f:id:hatsune_a:20210218075244p:plain
Visual Studioが至れり尽くせりだなーと思うのは、Release構成側で「バンドル」を指定すると、Debug構成側も自動的に2つのチェックボックスが同じ値でグレーアウトしていました。
もちろん、パッケージ形式は「apk」のままです。

アーカイブを実行する

構成ごとの設定がおわったら、Release構成をアクティブにしてアーカイブします。
f:id:hatsune_a:20210218080119p:plain
アーカイブが成功すると、アーカイブマネージャーにバンドル形式「aab」のエントリが表示されます。
f:id:hatsune_a:20210218080434p:plain

配布用に署名する

アーカイブができたら、[配布]ボタンをクリックして「アドホック」でファイル作成して手動でGoogle Play Consoleにアップロードするか、「Google Play」でアップロードまで行うかを選んで、署名付きaabを作成します。
実機にインストールするためには、「アドホック」を選択して署名付きaabファイルを作成しましょう。

aabを実機にインストールする

署名付きaabを実機にインストールしたいときは、adbコマンドを使って実行します。
f:id:hatsune_a:20210218100427p:plain
Visual Studioのメニューからコマンドラインを起動して、USBに実機を接続してUSBデバッグを許可したらadb installします。
f:id:hatsune_a:20210218100918p:plain
Successが出たら終了です。
実機で動作を確認してみましょう。

Google Play Consoleにアップロードする

実機確認できたら、署名付きaabをGoogle Playに登録してみましょう。
試しに、登録済のapkと同じバージョンとバージョンコードで作成して登録してみると次のようなエラーとなりました。
f:id:hatsune_a:20210218090633p:plain
当然ですが、apkとaabで同じバージョンをアップロードはできないようですね。

Google Playでアプリを署名する

ついでといっては何ですが、配布するならば「Google Playで署名されています」マークを付けておきたいですよね。
新規に登録するときは自動的にGoogle Play Consoleで次のような表示になります。
f:id:hatsune_a:20210218090543p:plain
既存登録済でこの表示がない場合は、手動で設定しないといけないのですが、次のQuitaが分かりやすかったです。
qiita.com
qiita.com
上から順番に読んでみると理解しやすくお勧めです。

それではVisual StudioでのAndroidアプリ開発、楽しんでいきましょう!

.NET 5.0リリース候補版(RC)が公開されました。

devblogs.microsoft.com

.NET Core 3.1の後継になる.NET 5.0のリリース候補版が公開されました。

Visual Studioから使いたいときは、Visual Studio 2019 (v16.8, Preview 3)をインストールするとよいみたいです。

 

.NET 5.0の良いところは、WPFWindows Form、UWP、Xamarin、Unityなどのクライアントアプリの共通フレームワークとして居続けられる点です(ASP.NETも)。

そして、生成するバイナリとしては、x86/x64/ARMに加えてARM64にも対応しており、WindowsLinuxMac向けに単一ファイルで実行可能(つまり必要な.NET 5なDLLも含んだ実行ファイル)の生成に対応している点も大きいでしょう。

長期サポート版は.NET 6.0までは提供されないようですが、いまから、.NET 5.0で動くようなコードを前提として準備しておくのがいいと思います。