メリークリスマス!!!今年もこの季節がやってきました Xamarin Advent Calendar 2020 !!!24日目の記事を担当させていただきます。
UnoPlatform を使って Xamarin.Forms で WebAssembly を作る
みなさんご存じ(!?) UnoPlatform 。こいつを簡単に説明すると
あ…、ありのまま、今起こった事を話すぜ!
「おれは UWP でアプリを作っていた思ったら、いつのまにか Android / iOS / macOS / WebAssembly アプリもできていた」
な…、何を言っているのかわからねーと思うが、おれも何をされたのかわからなかった。
頭がどうにかなりそうだった。催眠術だとか超スピードだとか、そんなチャチなもんじゃあ断じてねえ。もっと恐ろしいものの片鱗を味わったぜ。
というもの。UWP アプリを作る技術があれば最早なんでも作れる…そんな夢のような代物です。
いやぁ世の中便利になったものですなぁ…ではさっそく使ってみたいと…
あ、UWP アプリの作り方がわっかんねーーー!!!
そう、わたくし放浪軍師は UWP アプリを Xamarin.Forms からしか作成したことが無いのであった!こいつは困った! WebAssembly 作ってみたい! でもその為に UWP 学ぶのめんどくさいヨ! だって Xamarin.Forms からなら UWP 作れるのに、WebAssembly の為に UWP を学ぶっておかしくね!????
ああ、、、Xamarin.Forms から WebAssembly が作れたら い い の に な ぁ 、、、
なんと!そんなニッチな要望にも UnoPratform は答えてくれています。それが今回のテーマ Uno Platform WebAssembly Renderers for Xamarin.Forms なのです。
環境
- Windows 10 Pro
- Visual Studio 2019
- Xamarin.Forms 4.5.0.356
- ReactiveProperty 7.5.1
- Reactive.Wasm 1.2.2
- Uno.Xamarin.Forms.Platform 4.8.0-uno.1322
GitHub
今回作ったサンプルプロジェクトです。
github.com
実践
公式サイトに書いてある通りで恐縮ですがやってみましょう。
Xamarin.Forms アプリを普通に作る
Xamarin.Forms プロジェクトを作成します
「プロジェクトとソリューションを同じディレクトリに配置する」にチェックを入れる
入れましょうとあるので入れましょう。
開発対象に Windows(UWP) を入れる
WebAssembly プロジェクトは UWP のプロジェクトを参照しますので必須です。チェックを忘れないようにしましょう。
Xamarin.Forms のバージョンを 4.5.0.356 にする
公式にバージョンの指定があるので、Nuget パッケージマネージャより Xamarin.Forms のバージョンを 4.5.0.356 に変更します。
(※ただし、依存関係を調べると 4.8.0.1451 になっているのでこちらの方が良いのかも?)Androidプロジェクトの styles.xml に以下を追加する
今回の件に限りませんが、Xamarin.Forms のバージョンを 4.6 以上からそれ未満に落とした場合、Resources/values/styles.xml にコードの追加が必要になります。これは styles.xml 内のコメントにもあるように、4.6 以上では一部のコードがバイナリに移動されている影響で、4.6 未満にバージョンダウンした場合に呼び出せないコードが出てきてしまう為です。なお、この件は田淵 義人@エクセルソフト (@ytabuchi) | Twitterさんにお世話になりました。ありがとうございます!
4.8で作成して4.5に落としたらバイナリにMainTheme Baseは存在しないのでビルドエラーになりましたね。手動で<style name="MainTheme.Base" parent="Theme.AppCompat.Light.DarkActionBar">と<style name="AppCompatDialogStyle" parent="Theme.AppCompat.Light.Dialog">を
— 田淵 義人@エクセルソフト (@ytabuchi) 2020年12月18日追加したらビルド通りました。(AppCompat.Light.DarkActionBar とかは標準のスタイルなので継承できるけど、MainTheme.BaseはXFオリジナルのスタイルなので手動で作成する必要がある。ということですね、きっと)
— 田淵 義人@エクセルソフト (@ytabuchi) 2020年12月18日
<?xml version="1.0" encoding="utf-8" ?> <resources> <style name="MainTheme" parent="MainTheme.Base"> <!-- As of Xamarin.Forms 4.6 the theme has moved into the Forms binary --> <!-- If you want to override anything you can do that here. --> <!-- Underneath are a couple of entries to get you started. --> <!-- Set theme colors from https://aka.ms/material-colors --> <!-- colorPrimary is used for the default action bar background --> <!--<item name="colorPrimary">#2196F3</item>--> <!-- colorPrimaryDark is used for the status bar --> <!--<item name="colorPrimaryDark">#1976D2</item>--> <!-- colorAccent is used as the default value for colorControlActivated which is used to tint widgets --> <!--<item name="colorAccent">#FF4081</item>--> </style> <!-- ここから --> <style name="MainTheme.Base" parent="Theme.AppCompat.Light.DarkActionBar"> <item name="windowNoTitle">true</item> <item name="windowActionBar">false</item> <item name="colorPrimary">#2196F3</item> <item name="colorPrimaryDark">#1976D2</item> <item name="colorAccent">#FF4081</item> <item name="windowActionModeOverlay">true</item> <item name="android:datePickerDialogTheme">@style/AppCompatDialogStyle</item> </style> <style name="AppCompatDialogStyle" parent="Theme.AppCompat.Light.Dialog"> <item name="colorAccent">#FF4081</item> </style> <!-- ここまでを追加 --> </resources>
ここまで行ったら普通に Xamarin.Forms アプリを作成します。今回はボタンを押すと抽選してくれるアプリを作ってみました。小規模ではありますが ReactiveProperty を使って MVVM アーキテクチャを実現しています。ここにはコードを載せませんが気になる方は前述の GitHub をご覧ください。
Android | iOS | UWP |
---|---|---|
![]() |
![]() |
![]() |
WebAssembly のプロジェクトを追加する
WebAssembly プロジェクトは VS Developer から作成します。
スタート → Visual Studio 2019 → Developer PowerShell for VS 2019 を起動
以下コマンドを実行してディレクトリを移動します
cd ソリューション.slnのあるディレクトリ
以下コマンドを実行して最新のテンプレートをインストールします
dotnet new -i Uno.ProjectTemplates.Dotnet::*
以下コマンドを実行して WebAssembly のプロジェクト(.Wasm)を追加します
dotnet new wasmxfhead
Visual Studio を再読み込みします
Nuget パッケージマネージャを開き、Wasm プロジェクトの Uno.Xamarin.Forms.Platform を最新のpreパッケージに更新します
以上です。びっくりこれだけ!簡単ですね!
また、今回のように ReactiveProperty を使用する場合は以下の操作を行う必要があります。
こちらの記事を参考にさせていただきました。
qiita.com
ReactiveProperty の参照追加
Nuget パッケージマネージャよりWasmプロジェクトにも ReactiveProprty を追加します。Reactive.Wasm の追加
Nuget パッケージマネージャよりWasmプロジェクトに Reactive.Wasm を追加します。Wasm プロジェクト配下にある program.cs にて以下を追加します。
static int Main(string[] args) { ConfigureFilters(Uno.Extensions.LogExtensionPoint.AmbientLoggerFactory); #pragma warning disable CS0618 // 型またはメンバーが旧型式です PlatformEnlightenmentProvider.Current.EnableWasm(); // これを追加 #pragma warning restore CS0618 // 型またはメンバーが旧型式です Windows.UI.Xaml.Application.Start(_ => new UnoPlatformForXamarinForms.UWP.App()); return 0; }
では、早速動かしてみましょう。
WebAssembly |
---|
![]() |
はい。起動はするもののボタンが動きませんでした。。。。何故ェ・・・。
ReactiveProperty が動かない
動かない原因を自分なりに調査してみたのですがどうやら WebAssembly でのみ ReactiveProperty が動いていないっぽいという事が発覚。そこで先ほどの記事を執筆された ReactiveProperty のメンテナーであるかずき(Kazuki Ota) (@okazuki) | Twitterさんにご協力頂いた結果、以下の事がわかりました。
ここまで書いて原因がわかりました
— かずき(Kazuki Ota) (@okazuki) 2020年12月13日
WASMってサイズを少なくするために使われてないメソッドやらなんやらを消し込む処理がビルドで走ってるみたいなんですが、そいつにValueプロパティが消されてるのが原因ですね
なので正攻法は、LinkerConfig.xmlでReactiveProperty系は無視するように指定するとOK pic.twitter.com/8MQNqdf6hy
な、なるほど!そんな機能が WebAssembly に・・・これは自力ではわからんわ。かずきさんに圧倒的感謝をしつつ早速やってみましょう。
Wasm プロジェクト配下にある LinkerConfig.xml を開きます
以下を追加します。
<linker> <assembly fullname="UnoPlatformForXamarinForms.Wasm" /> <assembly fullname="Uno.UI" /> <assembly fullname="UnoPlatformForXamarinForms" /> <!-- ここから --> <assembly fullname="ReactiveProperty" /> <assembly fullname="ReactiveProperty.Core" /> <!-- ここまでを追加 --> <assembly fullname="System.Core"> <!-- This is required by Json.NET and any expression.Compile caller --> <type fullname="System.Linq.Expressions*" /> </assembly> </linker>
これにより ReactiveProperty の持つ Value プロパティが不当に消されてしまうのを回避できるそうです。普通の UnoPlatform で WebAssembly を動かす際にも起きる症状だと思われますので ReactiveProperty を使用する際はご注意ください。
動作
WebAssembly |
---|
![]() |
無事 Xamarin.Forms から WebAssembly を作成できました。やったぜ!
まとめ
Uno Platform WebAssembly Renderers for Xamarin.Forms の使い方でした。UWP より Xamarin.Forms に慣れているという方は扱ってみても良いかもしれませんね。