放浪軍師のアプリ開発局

VTuberみたいなアプリケーション夏狂乱など、自由気ままにアプリを開発したりしています。他にもいろいろやってます。尚、このブログはわからないところを頑張って解決するブログであるため、正しい保証がありません。ご注意ください。

【Xamarin Advent Calendar 2020】UnoPlatform を使って Xamarin.Forms で WebAssembly を作る

メリークリスマス!!!今年もこの季節がやってきました Xamarin Advent Calendar 2020 !!!24日目の記事を担当させていただきます。

UnoPlatform を使って Xamarin.Forms で WebAssembly を作る

みなさんご存じ(!?) UnoPlatform 。こいつを簡単に説明すると

あ…、ありのまま、今起こった事を話すぜ!
「おれは UWP でアプリを作っていた思ったら、いつのまにか Android / iOS / macOS / WebAssembly アプリもできていた」
な…、何を言っているのかわからねーと思うが、おれも何をされたのかわからなかった。
頭がどうにかなりそうだった。催眠術だとか超スピードだとか、そんなチャチなもんじゃあ断じてねえ。もっと恐ろしいものの片鱗を味わったぜ。

というもの。UWP アプリを作る技術があれば最早なんでも作れる…そんな夢のような代物です。

platform.uno

いやぁ世の中便利になったものですなぁ…ではさっそく使ってみたいと…

あ、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

実践

platform.uno

公式サイトに書いてある通りで恐縮ですがやってみましょう。

Xamarin.Forms アプリを普通に作る

  1. Xamarin.Forms プロジェクトを作成します

  2. 「プロジェクトとソリューションを同じディレクトリに配置する」にチェックを入れる

    入れましょうとあるので入れましょう。

  3. 開発対象に Windows(UWP) を入れる

    WebAssembly プロジェクトは UWP のプロジェクトを参照しますので必須です。チェックを忘れないようにしましょう。

  4. Xamarin.Forms のバージョンを 4.5.0.356 にする

    公式にバージョンの指定があるので、Nuget パッケージマネージャより Xamarin.Forms のバージョンを 4.5.0.356 に変更します。
    (※ただし、依存関係を調べると 4.8.0.1451 になっているのでこちらの方が良いのかも?)

  5. Androidプロジェクトの styles.xml に以下を追加する

    今回の件に限りませんが、Xamarin.Forms のバージョンを 4.6 以上からそれ未満に落とした場合、Resources/values/styles.xml にコードの追加が必要になります。これは styles.xml 内のコメントにもあるように、4.6 以上では一部のコードがバイナリに移動されている影響で、4.6 未満にバージョンダウンした場合に呼び出せないコードが出てきてしまう為です。なお、この件は田淵 義人@エクセルソフト (@ytabuchi) | Twitterさんにお世話になりました。ありがとうございます!

<?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
f:id:roamschemer:20201220005423g:plain:h400 f:id:roamschemer:20201220005455g:plain:h400 f:id:roamschemer:20201220005530g:plain:h400

WebAssembly のプロジェクトを追加する

WebAssembly プロジェクトは VS Developer から作成します。

  1. スタート → Visual Studio 2019 → Developer PowerShell for VS 2019 を起動

  2. 以下コマンドを実行してディレクトリを移動します
    cd ソリューション.slnのあるディレクトリ

  3. 以下コマンドを実行して最新のテンプレートをインストールします
    dotnet new -i Uno.ProjectTemplates.Dotnet::*

  4. 以下コマンドを実行して WebAssembly のプロジェクト(.Wasm)を追加します
    dotnet new wasmxfhead

  5. Visual Studio を再読み込みします

  6. Nuget パッケージマネージャを開き、Wasm プロジェクトの Uno.Xamarin.Forms.Platform を最新のpreパッケージに更新します

以上です。びっくりこれだけ!簡単ですね!
また、今回のように ReactiveProperty を使用する場合は以下の操作を行う必要があります。
こちらの記事を参考にさせていただきました。
qiita.com

  1. ReactiveProperty の参照追加
    Nuget パッケージマネージャよりWasmプロジェクトにも ReactiveProprty を追加します。

  2. Reactive.Wasm の追加
    Nuget パッケージマネージャよりWasmプロジェクトに Reactive.Wasm を追加します。

  3. 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
f:id:roamschemer:20201220010027g:plain:h400

はい。起動はするもののボタンが動きませんでした。。。。何故ェ・・・。

ReactiveProperty が動かない

動かない原因を自分なりに調査してみたのですがどうやら WebAssembly でのみ ReactiveProperty が動いていないっぽいという事が発覚。そこで先ほどの記事を執筆された ReactiveProperty のメンテナーであるかずき(Kazuki Ota) (@okazuki) | Twitterさんにご協力頂いた結果、以下の事がわかりました。

な、なるほど!そんな機能が WebAssembly に・・・これは自力ではわからんわ。かずきさんに圧倒的感謝をしつつ早速やってみましょう。

  1. Wasm プロジェクト配下にある LinkerConfig.xml を開きます

  2. 以下を追加します。

<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
f:id:roamschemer:20201220005722g:plain:h400

無事 Xamarin.Forms から WebAssembly を作成できました。やったぜ!

まとめ

Uno Platform WebAssembly Renderers for Xamarin.Forms の使い方でした。UWP より Xamarin.Forms に慣れているという方は扱ってみても良いかもしれませんね。