チャレンジ！クロスプラットフォーム開発（Xamarin.Forms編）

この記事は[リンク情報システム](https://www.lis.co.jp/)の[2019 Tech Connect Summer](https://qiita.com/dgkz/items/2862d5e6b77203a126b3)のリレー記事です。
engineer.hanzomon のグループメンバによってリレーされます。

本日8月8日は『世界猫の日(World Cat Day)』です。

#1. はじめに
複数の異なる仕様の機種やOSで同じように動作するソフトウェアの作成を目指すクロスプラットフォーム開発。近年は新たなフレームワークが続々登場し、選択肢が増えて嬉しいかぎりですね。
今回はそうした中から Xamarin.Forms に挑戦します！

#2. Xamarin.Formsとは？
まず、.NET Framework互換の環境を実現するMonoというオープンソースのプロジェクトがあり、様々なプロジェクトがMonoの成果物を利用してクロスプラットフォーム化を果たしました(ゲームアプリ開発に特化したUnityなど)。
Xamarinは、主にモバイルアプリ開発に特化したMonoベースの開発環境です。
ただし、プラットフォーム毎の差異があまりにも大きいため、GUIについてはそれぞれのネイティブAPIを使って描画する必要がありました。
GUIを共通化するために登場したのがXamarin.Formsです！

#3. Xamarin.Formsを試してみよう
Microsoftが開発企業を買収したことにより、VisualStudio上でXamarinを利用することが簡単にできるようになりました。さっそく試してみましょう。


##3.1. 準備
最初に開発環境を整えます。

- VisualStudio

Xamarin.Formsの開発にはVisualStudio2017（バージョン15.8以降) が必要です。
VisualStudioInstallerのワークロードにて「.NETによるモバイル開発」にチェックを入れます。

- .NET Framework

.NET Framework 4.7 未満の場合、後述するXamarin.Forms.Platform.GTK でエラーが発生します。
必要ならば、[Download .NET SDKs for Visual Studio](https://dotnet.microsoft.com/download/visual-studio-sdks)から予めインストールしておきましょう。


- Mono

Linux上で.NETアプリケーションを動かすためには Monoランタイムが必要です。
[Download Mono](https://www.mono-project.com/download/stable/#download-lin)に記述されたプラットフォーム毎の手順に従い、インストールしておきましょう。

##3.2. プロジェクトの作成
準備ができたら、いよいよ作成開始です。

VisualStudioを起動したら、「ファイル(F)」→「新規作成(N)」→「プロジェクト(P)」の順に選択し、新しいプロジェクトを作成します。
「インストール済み」→「Visual C#」→「Cross-Platform」の順に選択し、「モバイルアプリ(Xamarin.Forms)」のプロジェクトテンプレートを選択します。
任意のプロジェクト名をつけましょう(記事内では「TestApp」とします)。

「新しいクロスプラットフォームアプリ」ダイアログが表示されます。

| テンプレート名         | 概要| 
|:----------------------|:------------|
| Blank　               | デスクトップアプリのような、メインページのみを持つアプリのサンプルプロジェクトです。|
| Master-Detail         | 親項目を表示するマスターページと、詳細を表示する詳細ページを持つアプリのサンプルプロジェクトです。 
| Tabbed　              | タブ付きページのサンプルプロジェクトです。|

今回は 「Blank」をクリックし、コード共有方法として「.NET Standard」を選択し、 OKボタンをクリックします。

以下のような構成でソリューションが作成されました。

・TestApp
プラットフォーム特有の機能を使わない共有ロジックを記述するプロジェクトです。

・TestApp.Android
・TestApp.iOS
・TestApp.UWP
各プラットフォーム専用のネイティブAPIを呼び出すコードを記述するプロジェクトです。
初期状態ではスタートアップ用のコードのみ組み込まれています。

最後にビルドしてエラーが出ないことを確認しましょう。
モバイル用アプリケーションの雛型プロジェクトが完成しました！

##3.3. プロジェクトの追加
この記事を書いた2019年8月時点では、デスクトップアプリケーション開発用のプロジェクトは残念ながらテンプレートに含まれていません。
さっそく追加しましょう。

### 3.3.1. WPF
(1) WPF のプロジェクトを作成します。
ソリューションエクスプローラにてTestAppソリューションを選択し、右クリックメニュー→「追加(D)」→「新しいプロジェクト(N)...」の順に選択します。
「WPFアプリ(.NET Framework)」のプロジェクトテンプレートを選択し、「TestApp.WPF」という名前を付けてOKボタンをクリックします。
※この時、フレームワークには必ず「.NET Framework 4.7」以降を選択するようにしてください。

(2) 追加されたWPFプロジェクトを選択し、右クリックメニュー→「NuGetパッケージの管理(N)...」の順に選択します。
「NuGetパッケージマネージャ」ダイアログが表示されます。
Xamarin.Forms.Platform.WPF および Xamarin.Forms を検索し、インストールします。

(3) 追加されたWPFプロジェクトを選択し、右クリックメニュー→「追加(D)」→「参照(R)...」の順に選択します。
「参照マネージャー」ダイアログが表示されます。
プロジェクトを選択し、「TestApp」にチェックを入れます。


(4) 続いて生成されたソースコードを修正します。
MainWindow クラスを Xamarin.Forms.Platform.WPF.FormsApplicationPage 継承に変更します。 

```C#:MainWindows.xaml
<xf:FormsApplicationPage x:Class="TestApp.WPF.MainWindow"
        xmlns:xf="clr-namespace:Xamarin.Forms.Platform.WPF;assembly=Xamarin.Forms.Platform.WPF"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:TestApp.WPF"
        mc:Ignorable="d"
        Title="MainWindow" Height="300" Width="400" FontSize="18">
    <Grid>
        
    </Grid>
</xf:FormsApplicationPage>
 ```
コンストラクタにスタートアップ用のコードを追加します。

```C#:MainWindows.xaml.cs

namespace TestApp.WPF
{
    /// <summary>
    /// MainWindow.xaml の相互作用ロジック
    /// </summary>
    public partial class MainWindow : Xamarin.Forms.Platform.WPF.FormsApplicationPage
    {
        public MainWindow()
        {
            InitializeComponent();

            Xamarin.Forms.Forms.Init();
            LoadApplication(new TestApp.App());
        }
    }
}
 ```

最後にビルドしてエラーが出ないことを確認しましょう。
これでWindowsデスクトップ用の雛型プロジェクトが完成しました！

### 3.3.2. GTK
(1) GTK のプロジェクトを作成します。
ソリューションエクスプローラにてTestAppソリューションを選択し、右クリックメニュー→「追加(D)」→「新しいプロジェクト(N)...」の順に選択します。
「コンソールアプリ(.NET Framework)」のプロジェクトテンプレートを選択し、「TestApp.GTK」という名前を付けてOKボタンをクリックします。

(2) 追加されたGTKプロジェクトを選択し、右クリックメニュー→「NuGetパッケージの管理(N)...」の順に選択します。
「NuGetパッケージマネージャ」ダイアログが表示されます。
Xamarin.Forms.Platform.GTK および Xamarin.Forms を検索し、インストールします。

(3) 追加されたGTKプロジェクトを選択し、右クリックメニュー→「追加(D)」→「参照(R)...」の順に選択します。
「参照マネージャー」ダイアログが表示されます。
アセンブリ→拡張の順に選択し、「glib-sharp」「gtk-sharp」にチェックを入れます。
プロジェクトを選択し、「TestApp」にチェックを入れます。

(4) 追加されたGTKプロジェクトを選択し、右クリックメニュー→「プロパティ(R)...」の順に選択します。
アプリケーションタブにて、出力の種類を「Windowsアプリケーション」に変更します。

(5) 続いて生成されたソースコードを修正します。
Main関数にスタートアップ用のコードを追加します。

```C#:Program.cs
using System;
using Xamarin.Forms;
using Xamarin.Forms.Platform.GTK;

namespace TestApp.GTK
{
    public class Program
    {
        [STAThread]
        static void Main(string[] args)
        {
            Gtk.Application.Init();
            Forms.Init();
            var app = new App();
            var window = new FormsWindow();
            window.LoadApplication(app);
            window.SetApplicationTitle("TestApp");
            window.Show();
            Gtk.Application.Run();
        }
    }
}
 ```

最後にビルドしてエラーが出ないことを確認しましょう。
これでLinuxデスクトップ用の雛型プロジェクトが完成しました！

##3.4 実行
各プラットフォームのプロジェクトが問題なくビルドできたら、実行してみましょう。
(実機が用意できなかったので、今回はシミュレートです)。

- Android版
![WS000033.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/456694/8cd97ade-a9e3-dfff-1bbc-454c63e8fff5.png)

- WPF版
![WS000034.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/456694/7a76bc8a-8186-e36b-7daf-0c9aefd41322.png)

- GTK版
![WS000035.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/456694/a83f3a92-9b27-63e1-658b-25d6879b7a1c.png)

**Xamarin.Formsの世界へようこそ！**

無事に雛型プロジェクトでつくったアプリケーションを動かすことができたので、今度はモバイル版の[ライフゲーム](https://docs.microsoft.com/ja-jp/samples/xamarin/xamarin-forms-samples/boxview-gameoflife/)や[アナログ時計](https://docs.microsoft.com/ja-jp/samples/xamarin/xamarin-forms-samples/boxview-boxviewclock/)をデスクトップに移植してみます。
移植といっても、リンク先のウェブページからソースコード一式をダウンロードし、これまでの手順に従ってWPF版・GTK版のプロジェクトを追加するだけです。

![WS000036.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/456694/bc15851c-7289-6571-a18d-73a664d445d3.png)
![WS000037.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/456694/64571956-c4dc-8655-484f-116ac3051d22.png)

**あっさり動いたぁッッッ！**

#4. おわりに
今回参考にさせていただいたtan-y様の記事によれば、少し前までは[GitHub のソースコードからビルドしたり](https://qiita.com/tan-y/items/cf5088c6853ebb1b6c64)、[Nightly Build を使わなければならなかった](https://qiita.com/tan-y/items/e08d297c2d013214eb83)そうですが、今では誰でも気軽に試せるようになりました。
初めはXamarin.Formsで開発を進め、凝ったGUIが必要になったらネイティブAPIを使うこともできます。
今後の展開が楽しみですね！

---
明日はいよいよ最終日です！