放浪軍師のアプリ開発局

Xamarin.Forms+Prism+ReactivePropertyで素人がAndroidやUWPのアプリを右往左往しながら開発している様を発信していきます。性質上間違いも多いのでご注意ください。

Xamarin.Forms.UWP に Prism を後から適用する方法

放浪軍師の Xamarin.Forms によるアプリ開発
バーチャル蠱毒にドはまりして Xamarin のお勉強をかなりおざなりにしましたすいません許して。

さて、今回は Xamarin.Forms.UWP に Prism を後から適用する方法を探ってみました。
まず、はじめて訪問された方は以下をお読みください。
www.gunshi.info

乱ちゃんを WPF で作る必要が出てきたが…

乱ちゃんはゲーム実況者向けにパソコンで動かすことができる UWP で配布し、それを視聴した人がスマホで遊べるように AndroidiPhone で配布するのが基本的方針なのですが、その実況者から Windows 7 で動かせませんかと連絡を頂きました。ご存知の通り UWP は Windows 7 では動作できませんので、Windows 7 でも動かせるように WPF 版の乱ちゃん作成をしようと思います。

ちなみに今現在、 Xamarin.Forms は WPF も正式カバーしていますので、作ること自体は可能です。これについては rksoftware さんの以下に手順がわかりやすく記載してありますので、そっくりそのまま試すことが可能です。感謝ァ!
rksoftware.hatenablog.com

ただ、その Xamarin.Forms.WPF に Prism を適用する方法がどうしても見つかりませんでした…。というか、通常 Prism はテンプレートから作成しますので、後から Xamarin.Forms に Prism を追加する方法というのは WPF に限らず何処を探しても見つかりません。

その為まずは WPF に近い構成だと思われる UWP で後から Prism を追加する方法を検証しまてみました。WPF への適用は、この結果を元にやってみようと思います。

UWP で後から Prism を追加する方法を検証する下準備

  • C:\にフォルダーを2つ生成し、それぞれ XFPTemp 、 XFPAdd というフォルダー名にする。
  • Prism テンプレートから Xamarin.Forms → Prism Blank App(Xamarin.Forms) を選択。
  • 名前を XFP 場所を C:\XFPTemp に指定。
  • プラットフォームは UWP のみを指定して生成開始。
  • そのまま Visual Studio を終了する。
  • もう一度VSを起動し、 Prism テンプレートから Xamarin.Forms → Prism Blank App(Xamarin.Forms) を選択。
  • 名前を XFP 場所を C:\XFPAdd に指定。
  • プラットフォームは Android のみを指定して生成開始。
  • ソリューション右クリック→追加→新しいプロジェクト
  • Windows ユニバーサル→空白のアプリ(ユニバーサル Windows )を選択。
  • 名前を XFP.UWP 場所を C:\XFPAdd\XFP を指定。※こうしないとフォルダの階層がズレます。
  • OK を押すと UWP のプロジェクトが新しく追加される。
  • Android は不要なので削除する。
  • Visual Studio を終了し、 C:\XFPAdd\XFP\XFP\XFP.Android を削除する。

この操作により
Prism テンプレートから純粋に UWP プロジェクトを生成した C:\XFPTemp と、
Prism テンプレートに後から UWP を追加した C:\XFPAdd
ができ上がりますので、この2つの差を確認しながら、後から追加したプロジェクトに Prism を適用するにはどうすればいいかを検証していきたいと思います。
まぁ泥臭い検証方法ですが知識がないから仕方がないね!

構成比較

f:id:roamschemer:20181209145558p:plain
上図がフォルダの構成になります。ざっと見た感じ各ファイル構成は全く同じなようです。
…で、単純に考えた場合、共通部分 (PCL) はどちらも Prism テンプレートから生成した物なので、同じものであると推測されます。そこで、 C:\XFPAdd\XFP\XFP\XFP.UWP を C:\XFPTemp\XFP\XFP\XFP.UWP に差し替えただけでビルドしてみたところ、正常に動作しました。これにより、後から追加したプロジェクトに Prism を適用する際は、共通部分 (PCL) は扱わず、新規追加したプロジェクト内を書き換えるだけで動作可能であることが分かりました。

続いて XFP.UWP の内部を比較します。
このうち

  • \bin と \obj は消しても生成される部分なので比較する必要はないです。
  • \Assets は中を覗いてみると図のようにアイコンが格納されていますので、こちらも Prism には関係ありません。
  • Package.appxmanifest はパッケージの構成が格納されるので直接の編集は不要と思われます。
  • XFP.UWP_TemporaryKey.pfx は証明書なのでまず関係なし。
  • XFP.UWP.csproj はプロジェクトの情報でこちらも直接の編集は不要なはずです。

その為、これらを除いた部分をVisual Studio Cordを用いて、1つずつ比較してみました。

XFP.UWP\Properties\Assemblyinfo.cs

f:id:roamschemer:20181209150318p:plain
違いは13行目のみで、Copyright の年が変わっているだけです。どうやらこのファイルは修正せずに行けそうです。

XFP.UWP\Properties\Default.rd.xml

f:id:roamschemer:20181209150249p:plain
コメントが英語か日本語かの違いだけなので、このファイルも修正不要です。これにより XFP.UWP\Properties も修正する必要がないことが分かりました。

XFP.UWP\App.xaml

f:id:roamschemer:20181209150217p:plain
6行目。RequestedTheme="Light" があるかないかの違いがありました。この RequestedTheme="Light" に関して調べてみると、アプリケーションのテーマに関わる部分らしいので、これも Prism には直接関係なさそうです。

XFP.UWP\App.xaml.cs

f:id:roamschemer:20181209231125p:plain
こちらもコメントが英語と日本語なので差異が発生しており分かりにくいですが、それ以外に注目します。
XFPTemp 側の55行目。 Xamarin.Forms.Forms.Init(e); が XFPTemp の方にだけあります。Xamarin.Forms のお約束の部分ですね。当然追加する必要があります。
次に、XFPTemp 側の65行目と66行目の間。 if (e.PrelaunchActivated == false) { } が XFPApp の方にだけあります。これはアプリの事前起動に関わるようで、 Prism テンプレートで作成した方は、{ } 内部に必ず行くようになっていますね。

XFP.UWP\MainPage.xaml

f:id:roamschemer:20181209231431p:plain
最初と最後の行目。XFPApp側が Page XFPTemp側が forms:WindowsPage となっています。こちらも Xamarin.Forms を使う際の指定だと思われます。
XFPTemp側の4行目。 xmlns:forms="using:Xamarin.Forms.Platform.UWP" が追加されています。これも Xamarin.Forms の記述ですね。
12行目。XFPTemp側だけに Background="{ThemeResource ApplicationPageBackgroundThemeBrush}" がありますが、これはGridのバックグラウンドの指定なので関係ないと思います。

XFP.UWP\MainPage.xaml.cs

f:id:roamschemer:20181209231339p:plain
1,2行目。using でPrismを呼び出しています。当然必須。
20行目。XFPAppのみPageを継承していますので、これを消す必要があるようです。
25~32行目。ここではIPlatformInitializerを継承したClassを生成しています。固有プラットフォームの記述に使う部分ですね。Prismの機能です。

実装してみる

以上を踏まえて、以下手順で Prism を後から適用して動くのか試してみました。

  • C:\XFP\XFPAdd\XFP\XFP.sin を起動する。
  • Nuget パッケージ→インストール済み→ Prism.Dryloc.Forms と Xamarin.Forms をUWPにも適用する。
  • XFP.UWPの参照を右クリック→参照の追加→プロジェクト→ソリューション→XFPを選択
  • XFP.UWP\App.xaml.cs にて
  • Xamarin.Forms.Forms.Init(e); を追加
  • if (e.PrelaunchActivated == false) をコメントアウト
  • XFP.UWP\MainPage.xaml にて
  • Page を forms:WindowsPage に変更。
  • XFP.UWP\MainPage.xaml.cs にて
  • Page の継承部分をコメントアウト
  • class UwpInitializer の部分を追加

念のため再起動。してビルド!…してもダメでした。以下例外が発生しています。

エラー NU1201 プロジェクト XFP は uap10.0.15063 (UAP,Version=v10.0.15063) と互換性がありません。
プロジェクト XFP がサポートするもの: netstandard2.0 (.NETStandard,Version=v2.0)

これはフレームワークが .NETStandard2.0 に指定されていないよ!って事ですかね。
という事で、 UWP の Properties をダブルクリックしてアプリケーションのターゲットを見比べてみました。
f:id:roamschemer:20181209231916p:plainf:id:roamschemer:20181209231925p:plain
最小バージョンが違う!
という事で最小バージョンをWindows 10 version 1803に変更してビルドすると…
f:id:roamschemer:20181209232826p:plain
いけました!やったぜ!

…という事で、Prism テンプレートで作成したプロジェクトに UWP を後から追加した場合は上記方法を取れば追加できることが分かりました。

例えば AndroidiOS しか考えてなかったが、後から UWP を追加しなくてはならなくなった!
…という場合には使えるテクニックですかね。うわーニッチだ!でもあり得ないとも言えないですかね?

さて、今回はあくまで調査です。次回は本命、 Xamarin.Forms.WPF に Prism 適用を実践してみます。