XamarinでFirebaseを使ってみる（iOS版）

以前Qiitaにこんな記事が投稿されていました．
[Amazon, Google, Microsoft の mBaaS の比較と Xamarin の対応状況](http://qiita.com/amay077/items/2d4c01de7607fb8edae2)

このようにXamarinではAzureだけではなく様々なmBaaSに対応しているので，こういう用途ではこのサービスを，ではこちらの用途ではあちらのサービスを使うのが適しているかもしれない，など多くの選択肢が与えられます．

そこで今回は無料でPush通知を行えたり，またアプリケーション分析が容易に行えるFirebaseを取りあえげてみたいと思います．

追記：
[Android版はこちら](http://qiita.com/yamachu/items/1d3466844e1ba2802a52)

## Xamarin.FormsのiOSへのFirebaseの対応状況
本記事を書いている2016年11月3日なんとXamarin公式からFirebase対応のライブラリがnugetで提供されています．
例えば

* アプリケーション分析の [Firebase APIs Analytics iOS Library](https://www.nuget.org/packages/Xamarin.Firebase.iOS.Analytics/)
* Push通知などに利用する [Firebase APIs Cloud Messaging iOS Library](https://www.nuget.org/packages/Xamarin.Firebase.iOS.CloudMessaging/)

開発は [xamarin / GoogleApisForiOSComponents](https://github.com/xamarin/GoogleApisForiOSComponents)で結構前からラップが行われていて，自前ビルドで試すこともできました． ([筆者が試した例](http://teitoku-window.hatenablog.com/entry/2016/09/09/224201))
iOS10対応が少しなんだこれ？という感じの対応であったり，ビルド時のバグがあるためつまづく点も少々ありますが，アプリケーション分析やPush通知に関しては自分のプロダクトにも組み込み実用範囲...かなという段階まできているかと思います．


## 実際に試してみる
それでは実際に試してみましょう．
以下紹介するコードなどは筆者のリポジトリの [yamachu / TryFirebaseXamarin](https://github.com/yamachu/TryFirebaseXamarin) に対応しています．

適当にXamarin.FormsまたはiOSでプロジェクトを作ったらnugetで上記のライブラリを導入します．
その後 Firebase にアクセスしてプロジェクトを作成し，そのプロジェクトにiOSアプリを追加します．その時にアプリのBundle IDが必要となりますので，先ほど作ったXamarinのプロジェクトの`Info.plist`あたりから引っ張ってきてください．
Firebaseのプロジェクトの作り方は http://dev.classmethod.jp/smartphone/firebase-notification-ios/ あたりが参考になるかと思います．

アプリケーションの追加が完了するとアプリケーションに対応した`GoogleService-Info.plist`という設定ファイルがダウンロードできますので，それをダウンロードした後，iOSのプロジェクトに追加します．その後追加したファイルを右クリックしてBuild Action -> BundleResource と選択しチェックします．

これでFirebaseを利用する準備は大体揃いました，あとはコードを書くだけです！
と行きたいところですが，現在ビルド時のバグがあるためビルドの設定を変更します．
手順としては
1. iOSのProject Optionsを開く
2. iOS Buildのタブを開く
3. Enable incremental buildsのチェックを外す
これでビルドが通るようになります．

それではコードを書いていきましょう．

### Analyticsを試す
[Analytics向けのブランチのAppDelegate.cs](https://github.com/yamachu/TryFirebaseXamarin/blob/iOS/Analytics/iOS/AppDelegate.cs#L20)
Analyticsは非常に試すのが簡単で，上記のリンク先のファイルのように`FinishedLaunching`内で
`Firebase.Analytics.App.Configure();`
の一行を呼び出すだけです，簡単ですよね？

これだけでユーザのセッション開始だったり端末だったり簡単な地域だったりいろんな情報が取れますやったー
...なんてうまくいくわけもなくですね，Analyticsを利用する上でさらに変更が必要となります．
自分で定義したイベントを取ったり，上で述べたような情報を取得するには
`GoogleService-Info.plist`内の`IS_ANALYTICS_ENABLED`の`NO`となっている部分を`YES`に書き換える必要があります．
`YES`に書き換える必要があります．
`YES`に書き換える必要があります．

ここを見落としがちなのでしっかりと設定しましょう（本番プロダクトで設定し忘れて数は見れてもユーザ情報が取れないミスをしてしまった私がいます）

これでFirebaseが標準で定めているイベントに関して取得できるようになりました．
しかしユーザの利用状況を詳しく知りたい場合（どのページにどこから遷移したかとか，どのページにアクセスしたかとか）カスタムイベントを取りたくなると思います．もちろんそれも対応していて

    NSString[] keys = { new NSString("Open_ID") };
    NSObject[] values = { new NSString("1234") };
    var parameters = NSDictionary<NSString, NSObject>.FromObjectsAndKeys(keys, values, keys.Length);
    // Send custom event
    Firebase.Analytics.Analytics.LogEvent("PageID", parameters);

のようにユーザ定義をNSDictionaryで囲んでしまえば使用することができます（イベント名だったり数などに制限があるためドキュメントを参照してみてください）．

自由にイベントも取れるし，ユーザ情報も取得できるし最高だなーという感じではあるのですが，少しつらい部分も紹介します．

* Analyticsのリアルタイム性がない
* Analyticsの数値は見れるけど，実際送られてきた値を見るには従量課金性のプランに移行しBigQueryに流す必要がある

１点目は最初のイベントを発火してから早くて10時間，私のプロジェクトでは24時間ぐらいかかったんじゃないかってぐらいの時にFirebaseのコンソールに現れました．すぐ確認しなきゃいけない，というプロダクトには難しいんじゃないかなぁと思いました．
２点目は従量課金とは言ってはいますが，Analyticsで送られてきたデータをGoogleのBigQueryに流し込んでそれを見る分にはタダなので，実際にQuery発行とかしない限り料金は発生しません．けどクレカ登録が学生には少しキツかったという感じではありました．


### Cloud Messagingを試す
[Cloud Messaging向けのブランチのAppDelegate.cs](https://github.com/yamachu/TryFirebaseXamarin/blob/iOS/CloudMessaging/iOS/AppDelegate.cs)
iOSでPush通知を使用する場合結構面倒な工程が必要です．これはFirebaseに限らず他のPush通知を使うサービスでも同様の手順なので割愛します．
参考になったのは
[プッシュ通知に必要な証明書の作り方2016](http://qiita.com/natsumo/items/d5cc1d0be427ca3af1cb)
です．この記事の7. で作成したAPNs用証明書(.p12)をFirebaseのコンソールにアップロードします．その手順も[ここ](http://dev.classmethod.jp/smartphone/firebase-notification-ios/)に記されているので参考にしてみてください．

その後Info.plistに`FirebaseAppDelegateProxyEnabled`というキーを追加し，`NO`に設定します．
公式ドキュメントを読んでもここはよく理解ができませんでした（今までのPush通知のコードをほとんど流用したいならこれの方が良さそうという認識）

これでPush通知の環境に関する準備は整ったと思うので，コードを書いていきましょう．

Analyticsと同様に`FinishedLaunching`内で
`Firebase.Analytics.App.Configure();`
を呼ぶのは変わらないのですが，その他に


	Firebase.Analytics.App.Configure();

	Firebase.InstanceID.InstanceId.Notifications.ObserveTokenRefresh((sender, e) => {
		var newToken = Firebase.InstanceID.InstanceId.SharedInstance.Token;
		// if you want to send notification per user, use this token
		System.Diagnostics.Debug.WriteLine(newToken);
		
		connectFCM();
	});

のように通知などに使用するInstanceIdが変更を受け取るように設定します．
ここに記述されているconnectFCMに関してはリポジトリのファイルをごらんください．
あとは通知を受け取る時の実装で概ね動くかと思います（GCMからの移行の人はいけるんじゃないかなと思います，未確認）

基本的には上記のリポジトリのテンプレ実装でPush通知が利用することができます．

実際にテストしてみる環境としてFirebaseのコンソールにあるNotificationから通知を送ってみるか，curlなどを使用して

    curl --header "Authorization: key=YOUR_SERVER_KEY" \       
         --header Content-Type:"application/json" \
         https://fcm.googleapis.com/fcm/send  \
         -d "{\"to\": \"/topics/all\",\"priority\":\"high\",\"notification\": {\"title\": \"Azure以外でも使えるよ！\",\"body\": \"Xamarin x Firebase\"}}"

みたいに送ると通知を送ることができます．ここでの`YOUR_SERVER_KEY`はFirebaseのプロジェクトの設定のクラウドメッセージングタブにあるサーバーキーを指します．
またこの通知はアプリケーションが一度でも /topics/all を[Subscribe](https://github.com/yamachu/TryFirebaseXamarin/blob/iOS/CloudMessaging/iOS/AppDelegate.cs#L108)している必要があります．

実際こんな感じで簡単に書きましたが，実際にサーバーから送るなどとなると他にも多くのパラメータが存在するので，確認してみてください（Androidにも送る時はiconを指定したり，そのアイコンのバックグラウンドの色を指定できたり）


## 最後に
簡単に導入部と実際の使い方について紹介しました．
AnalyticsやCloud Messaging以外にもラップされているライブラリがありますが，自分が利用するケースに遭遇していないため試していません．使い方については[公式リポジトリ](https://github.com/xamarin/GoogleApisForiOSComponents)にも記載されているため，こちらを確認してみてください．AnalyticsもCloud Messagingも公式にドキュメントが公開されているようです（プロダクト開発時は自前ビルドしないといけない&Firebaseのドキュメントとラッパーライブラリの差異を埋めるなどで大変でした）ので，こちらを読むと一層理解ができるかと思います．

またサンプルとして，ボタンを押したらカスタムイベントを送るような Android/iOS のインターフェースを実装したサンプルを用意してみましたので，そちらも参考にしていただければと思います．
https://github.com/yamachu/TryFirebaseXamarin/tree/sample/custom_event_service

以上お疲れ様でした．