Xamarin.Formsを使った感想と困ったことなど（Android中心）

## 自己紹介
- 仕事での携帯（スマホ）アプリ開発経験はありません。
- 普段はC#を中心とした.Net系でWebベースの業務システムを作成しています。

## 内容と目的
- 対象者はこれからXamarin.Formsを使おうと思っている方。私と境遇が近い方。
- 内容はXamarin.Formsを使ってAndroidとiOSのマルチプラットフォーム開発を行った過程で調べたことや困ったことなどのまとめ。
- Xamarin（Xamarin.Forms）の使用期間は約2ヶ月です。
- Xamarin.Formsの日本語の情報が少ないので、これからはじめる人の参考になると良いなと考えています。  

※ WindowsPhoneは対象外です。
※ iOSの開発環境が無い為、Androidでの開発の話です。

## 資料
XLsoft（エクセルソフト）（Xamarin日本代理店）
http://www.xlsoft.com/jp/products/xamarin/xamarin_forms_intro.html

エクセルソフトの資料は公式ガイドの資料の一部を日本語にしたものです。
最初に読むことでふんわりと全体像がつかめます。


Xamarin公式ガイド
https://developer.xamarin.com/guides/cross-platform/xamarin-forms/

詳しく書いてくれているので参考になります。
公式以外の記事は新旧バージョンの精査など正確な情報を探すのが難しいです。
ですので、いろいろ検索するよりもまずはこちらを読むことをお勧めします。
正確な情報を掴むためにも、まずは公式ガイドを読みましょう。

## **Xamarin.Forms**で画面を作成
**ポイント：画面はXamarin.Formsを使う**

Xamarin.FormsはUIを作る機能であり、
**プラットフォームに依存しないコード**で画面を作成することができます。
1つのXamarin.Formsの画面コードでAndroidとiOSの両方の画面が作れます。

Xamarinは製品としては下記の3種類があります。

- Xamarin.Android
- Xamarin.iOS
- Xamarin.Mac

各プラットフォームの開発をするためには、対応する製品が必要です。
Xamarinは各APIを100%ラップしているのでC#でコーディングが可能となりますが、ただラップしているだけなのでUIの実装は各プラットフォームに依存します。

Xamarin.Formsを使わない場合は、各プラットフォームの知識が必要となります。
AndroidだとActivityとaxmlを使います。
iOSだとstoryboardでしょうか。

これを解決するのがXamarin.Formsです。
Xamarin.FormsではXAMLというXML言語で画面を構築します。
XAMLはXamarin固有のものではなく、WPFなどで利用されているものです。

なおXamarin.Formsを使った場合でも、
各プラットフォーム固有の画面との併用も可能です。

## IDE（VisualStudioかXamarinStudio）
**ポイント：IDEはVisualStudioを使う**

C#を使うので素直にVisualStudioを選択します。
XamarinStudioの使用感、メリット・デメリットはわかりませんが、
Macでも使えますのでマックユーザーには良いのかもしれないです。

## PCL（Portable Class Libraries）とShared Projects
**ポイント：PCLを使う**

VisualStudioでXamarin.Formsアプリを作成しようとすると、
PCLとShared Projectsの2種類から選択する形になります。

両者はコードを共通化するという目的は一緒ですが、
共通化する仕組みが異なります。そして細かい差があります。

[公式：Sharing Code Options](http://developer.xamarin.com/guides/cross-platform/application_fundamentals/building_cross_platform_applications/sharing_code_options/)

#### 両者の仕組み
PCLはコンパイルされてDLLとして各プラットフォームに参照される。
Shared Projectsはコンパイルされず、ビルド時にコードが各プラットフォームにコピーされて利用される。

#### メリット・デメリット
以下は上記公式に書いてあるメリットとデメリットを抜粋したものです。

Shared Projects

- プラットフォームごとのコンパイラーディレクティブが使用可能
- プラットフォーム固有の参照を含めることが可能
- dllがない(コンパイルされないので)
- コンパイラーディレクティブのリファクタリングが出来ない

PCL

- リファクタリングで有利
- コンパイラーディレクティブは使用不可
- プロファイルによって使えるサブセットが異なる。

プロファイルについては田淵さん（日本代理店営業さん）のブログを見ると良いです。
[Visual Studio での PCL (Portable Class Library) の Profile について]
(http://ytabuchi.hatenablog.com/entry/2014/12/10/174116)


まず、Shared Projectsにコンパイラディレクティブが使えることがメリットとしてあがっていますが、そもそも使わないほうが良いと考えています。
プラットフォームごとのコードをif文で記述するのはコード共通化として美しくないと思います。
またリファクタリングも効かないということなので、保守性が低いのも良くないです。

Shared Projectsでメリットに上がっている項目は
PCLでは**DependencyService**という仕組みでカバーされていますので、
なんら問題ありません。

ということでPCLでいいと思います。

## AndroidSDK導入時の注意
**ポイント：システムイメージはダウンロードしない**

Androidの開発を行うには、まずSDKをインストール必要があります。
インストールにはAndroid SDK Managerを使います。
VSからは「ツール」→「Android」→「Android SDK Manager」で起動できます。

さてここで注意して欲しいことは、適当にインストールしないことです。
デフォルトでは最新版のAPIにチェックが入っていると思いますが、
その中でも「~~~ System Image」となっているものは、
デバッグ時に利用するエミュレート用のAndroidイメージデータでありかなり巨大です。
本当に必要な場合だけDLすることを強くお勧めしますが不要だと思います。
詳細は次デバッグの章で述べます。

## Androidのデバッグは実機が一番、エミュレーターは公式以外のものを
**ポイント：デバッグには実機を使う**

Androidのデバッグには当然Android環境が必要となりますので、
実機でUSBデバッグを行うか、Androidエミュレーターを使うことになります。

ただし標準で搭載されているAndroidエミュレーターは動作が重くパフォーマンスに問題があります。
ゲームなど操作性を要求されるものはデバッグ不可能です。

パフォーマンスを考慮するとデバッグには基本的に実機を使うことを強くお勧めします。
エミュレーターが必要な場合は、サードパーティー製のエミュレーターを使うことをお勧めします。

全機能を使うためには有償となるが、個人的にはGenyMotionがお勧めです。

また、USBデバッグするためにはUSBドライバのインストールとは別に
設定ファイルの変更が必要となります。

参考：[Xamarin StudioからAndroidデバイスで実機デバッグする方法]
(http://biz-crew.com/archives/1216)

## Androidデバッグのトラブルシューティング
以下は実際に体験したことなど。

- ビルドしたら「Couldn't connect to logcat, GetProcessId returned: 0」と出る。  
Xamarin評価版を使用していて前回のビルドから24時間経過している場合に発生。  
アプリを手動でアンインストールすれば解消する。
- USBデバッグが認識しない  
スマホでUSBデバッグONとなっているにもかかわらずUSBデバッグにならない場合がある。  
USBデバッグのON/OFFを切り替えると認識するようになる。
- リソースファイル（画像等）のファイル名に半角英数字以外（-ハイフンなど）を入れる謎の例外が発生する。
- APIレベルの設定を間違えると動かない
プロジェクトから「プロパティ」→「Application」にある
「Compile using Android version」あたりを対象とするAndroidのバージョンにしておかないと動きません。
- Androidマニュフェストの設定忘れると動かない  
プロジェクトから「プロパティ」→「Android Manifest」で使用する機能権限設定があります。  
例えばカメラ機能を使う場合は「CAMERA」にチェックを付けないと動きません。


## nuGetの使用の注意事項（PCLの場合）
**ポイント：ソリューション単位でnuGetを行う**
nuGetでライブラリを導入する際は、共通コードプロジェクト、Androidプロジェクト、iOSプロジェクトの各プロジェクトそれぞれに同じバージョンのライブラリを導入する必要があります。
各プロジェクトのライブラリのバージョンが統一されていないと動かないことがあるので注意が必要です。
nuGetを使う際は、プロジェクト単位ではなくソリューション単位で設定します。

## Xamarin.Formsのアップデートでビルド出来なくなった場合
Xamarin.Formsは頻繁にアップデートがありますが、
Version1.5から2.0にアップデートを行ったところ、エラーが発生するようになりました。
以下の2点をを行ったところ解消しました。

1. [UserFolder]\AppData\Local\Xamarinの中身を全部消す  
2. コンパイルするAPIレベルを最新に変更

1番の詳細は田淵さんがまとめてくれています。
http://ytabuchi.hatenablog.com/entry/2015/10/30/163231

2番の対応は、最新版のAndroidのAPIレベルでしか実装されていない項目が追加されたことによって古いAPIレベルではビルド自体が出来なくなってしましまいました。


## 画面作成はXAMLとC#コードをどのように使い分けるか
**ポイント：XAMLのデメリットを理解してコードと併用するか、XAMLを一切使わない選択もあり。**  

Xamarin.FormsではWPF等で使うXAMLというXMLで画面を作成しますが、
サンプルは大体C#コードで書かれており、XAMLサンプルを探す方が苦労します。
個人的な意見としてはデザイン部分とコード部分は分離したいので、
XAMLをメインで使っていますがXAMLを使うと以下の欠点に気づきます。

XAMLのデメリット

- XAMLは構文エラーが実行時エラーになる。
- XAMLにはデザイナが無い。
- XAMLにはリファクタリング機能がきかない。
- XAMLはインテリセンスがいまいち動作しない。

この欠点はXAMLに慣れるまで重くのしかかります。
XAMLで出来ることはC#コードでも実現可能です。
※C#で出来ることはXAMLで出来るといった方が正しいけど。

デメリットを考えるとXAMLを一切使わないですべてC#で記述するのもありだと考えます。

強いてXAMLのメリットをいえば、
複雑なデザインのレイアウトを作成する場合に限って、
階層構造が一目でわかるXAMLのほうが良いかと思います。

XAMLを使うからといってコードを全く使わないかというと、多分無理です。
既存のコントロールを継承したカスタムコントロールを作る場合などは、
コードで作成したほうが断然楽です。

まとめると、C#コードは必須です。
あとはXAMLを使って画面を作るか判断すると良いでしょう。

公式参考：[Chapter 7. XAML vs. Code](https://download.xamarin.com/developer/xamarin-forms-book/BookPreview2-Ch07-Rel0203.pdf)

## Xamarin.Forms（XAML）のレイアウトの基本
**ポイント：基本はStackLayout。PaddingはあるがMarginがない。**

画面を構成するビューの基本構造は、

各種Pageビュー
　└ 各種Layoutビュー
　　└ 各種ビュー（ButtonやLabel）

という形が基本です。
一番外郭にPageビューを置き、直下にStackLayoutを基本とするレイアウトビューを配置します。
レイアウトビュー自身も入れ子にして使います。

StackLayoutは水平か垂直方向にビューを順番に配置するレイアウトです。
ビューを重ねたり、絶対指定、相対指定したい場合には、別のビューを使用しますが、
それらのレイアウトもStackLayoutの中に入れ子にして使うことが基本になると思います。

そして最終的にButtonやLabelといったビューをレイアウトの中に配置しますが、
Marginが無い為、Buttonから余白を指定することが出来ません。
ButtonやLabelの余白を設定する為には、ButtonやLabelの親レイアウトのPaddingを設定する形となります。
そういった事情もあり基本的にStackLayoutを配置して中に様々なビューを配置します。

## Xamarin.Forms（XAML）のスタイル定義方法
**ポイント：CSSのような機能はあるが機能が少ない。定義するのは色ぐらいに留めるべき。**

Xamarin.FormsにはCSSのようなスタイル統一機能（Styles）がありますが貧弱です。
公式：[Working with Styles](https://developer.xamarin.com/guides/cross-platform/xamarin-forms/working-with/styles/)

レイアウト方法の基本で述べたように、Marginプロパティが存在しない為、
Buttonのスタイル定義をしても、自身の余白の設定が出来ません。

またスタイル定義は、

- 対象とするクラス（ビュー）を指定する必要があり、
- 定義できる属性値は対象となるクラス（ビュー）が持っているプロパティに限ります。

異なる2つのビューに同じプロパティ（例えば背景色）があっても、
それぞれのビュー用に2個のスタイルを定義する必要があります。

また属性値についても、
C#コードなら共通化も可能ですが、
XAMLで定義する場合は、2回同じ記述が必要です。

あまり汎用性はありません。
適用する範囲は、グローバル指定、ページ指定と選択可能ですが、
グローバル指定する場合には、色ぐらいに留めておく方が良いと思います。

## MVVMは必要なのか
**ポイント：メリットがあるなら使う。自分でコーディング規約決めれば厳守する必要なし**
Xamarin.Formsを調べてくると出てくるのがMVVMデザインパターンです。
一言で言うとXAML用のMVCパターンということですが、説明できるほど詳しくありませんので参考リンクだけ書いておきます。

参考：[MVVMパターンの常識 ― 「M」「V」「VM」の役割とは？](http://www.atmarkit.co.jp/fdotnet/chushin/greatblogentry_02/greatblogentry_02_01.html)
※Xamarin.Formsは関係なく純粋にXAMLのMVVMパターンの説明です。

Xamarin.Forms上でもMVVMを実装することは可能であり、公式ガイドにもMVVMの説明があります。
標準では完全対応とまではいかないようで、必要に応じてコーディングも必要になります。

私はXAMLだから必ずMVVMで作成するといった考え方はいらないと考えています。
私自身のMVVMについての理解は深くありませんが、上記の参考ページでは、

*ビジネス・ロジックとプレゼンテーション・ロジックを分割する」という目的とともに、開発者がUIデザイナーと協業でアプリケーションを作っていく未来を見据えたパターンでもあります。*

と記載されていますが、自分のところではデザインとロジックを分離して開発なんて無いですし、あまりメリットが無さそうなので、自分なりの規約を作って開発しています。

私がMVVMの考え方の中で利用しているのは、
ViewModel、Command、INotifyPropertyChangedの3つだけです。
それ以外は必要が出てきたら使う予定ですが、現状は必要になっていないです。

## DependencyService
**ポイント：プラットフォーム固有機能の呼び出しの必須機能**
DependencyServiceはプラットフォーム固有の機能(※1)を利用するための仕組みです。
固有機能の呼び出しを共通プロジェクト側で各プラットフォームに依存しない形(※2)で実装することが出来ます。

※1  プラットフォーム固有の機能は、AndroidやiOS間で仕様が異なるもので、例えばファイルアクセスやカメラ機能などです。
※2  if文やswitch文などで分岐して処理を記述するのではなく、カメラ機能呼び出しといった感じでコードが記述できます。

必ず使用しますので必ず抑えておきましょう。
検索すればサンプルも多いので詳細は省きますが、

共通の呼び出し方法（インターフェース）を定義して、
実処理を各プラットフォームごとに実装するだけです。

## カスタムレンダラー
**ポイント：Xamarin.Forms既存ビューは機能が少ないのでカスタム必須です。自作もいいがライブラリの導入や購入をまず検討しましょう。**
この機能もまず使います。
ソースを共通化したいという目的を考えると、出来れば使いたく無いけど現状は避けて通れないものです。

カスタムレンダラーとは、ビュー（例：ボタン等）のレンダー処理をカスタマイズするもので、

- 既存のビューを拡張したい場合
- 新しいビューを作成したい場合
- Xamarin.Formsに用意されていないプラットフォーム固有のビューを使いたい場合

などに使います。

既存のビューを拡張したい場合なんて殆ど無いと思うでしょう？
Xamarin.Formsにはビューが沢山用意されているので、新しいビューを作成したいなんてことはないと思うでしょ？

残念ながら、そんなことありません。
枠線つけたいな、背景色変えたいなといってビューのプロパティ調べると、
BorderもBackgroundColorも無いなんてことが日常茶飯事。
ぐぐるとカスタムレンダラーで自作しろって出てきます。

HTMLのCSS感覚でいじれると思ったら大間違いです。

カスタムレンダラーを作成する詳細な方法は調べれば沢山出てきますので省略します。
カスタムレンダラーはプラットフォーム毎に実装する必要がありますので、
AndroidやiOSのAPIを見る必要が出てきて非常に面倒です。

まずは良いライブラリが無いか調べて見ましょう。
公式：https://components.xamarin.com/

無料のライブラリだとこれが良いです。
[XLabs/Xamarin-Forms-Labs](https://github.com/XLabs/Xamarin-Forms-Labs)

カスタムレンダラーを作成する場合、
レンダラーとビューの対応は下記の資料を参考にすると良いです。
公式：[Renderer Base Classes and Native Controls](https://developer.xamarin.com/guides/cross-platform/xamarin-forms/custom-renderer/renderers/)


参考までに私が作成したカスタムレンダーは下記のようなものになります。

- チェックボックス  
- スワイプによるタブ移動が出来るTabbedPage  
- ドラッグ＆ドロップで項目の並び替えが出来るListView

iOSにはチェックボックスが存在しません。
Androidにはチェックボックスが存在しますが、背景色やボーダー色を変更するのが難しいです。デザインを共通化したいこともあり、自作となりました。

TabbedPageはXamarin.Formsにある既存ページビューです。
が、スワイプでのページ切り替え機能がありませんでした。

ListViewも既存ビューです。
ドラッグ＆ドロップなんて洒落た機能はもちろん実装されていません。

ここまで記載しましたが、Xamarin.Formsは決して出来ない子ではありません。
コンセプトはAndroid、iOS、WindowsPhoneの共通部分を実装してくれているだけなので、
込み入ったことは出来ないのです。そしてまだまだ発展途上なんです。

少し余談ですが、Buttonビューのテキストは太字や斜字は対応していますが下線には対応していません。
カスタムレンダーに逃げてもいいですが、高さ0.5~1にしたBoxViewとAbsoluteLayout（相対指定レイアウト）を組み合わせることで擬似的に下線を引くことも可能です。