[Xamarin]バックグラウンドで定期的に処理する方法

#概要
iOSでは当記事のとおり実装することで、アプリがバックグラウンドに移った場合でもいろいろと処理させることができます。
今回はバックグラウンドに移っても、処理が停止せず、一定タイミングでイベントを発生させる方法を書きます。

<font color="red">
2016/9/25 追記
タイトルに「Xamarin.Forms.iOS」と書いていましたが、
誤解を招く記載であったため修正しました。
また、末尾のコメントにてshagaさんに教えていただきましたとおり、
位置情報を使わずともバックグラウンド処理は可能であるため、
純粋にバックグラウンドの処理を知りたい方は、コメント欄をご確認ください。
調べ方が良くなかったですね。反省・・・。
</font>

#バックグラウンド処理の実装準備
Xamarin.Formsでバックグラウンド処理を実装するにあたり、iOSの「位置情報サービス」の設定が必要となります。
そもそもiOSのバックグラウンド処理を行うには、位置情報を取得するCLLocationManagerDelegateクラスを継承し、ロジックを組み込む必要があり、PCLのみでは実装出来ない仕組みとなっています。（他の方法もあるらしいのですが今回は位置情報で実装します。）
そのため、iOS側の設定が必須であり、この設定が不足しているとバックグラウンドのロジックを実装しても正常に動きません。

##info.plistの設定
###Background Modesの設定
「バックグラウンドモード（Background Modes）」の「位置情報の更新（Location updates）」をチェックします。
![スクリーンショット 2016-09-19 20.41.01.png](https://qiita-image-store.s3.amazonaws.com/0/136009/49d6bbc7-0df1-bc47-ca83-2bd39fe0faa7.png)

###Location Always Usage Descriptionの追加
「新しいエントリの追加」で「Location Always Usage Description」を追加し、文字列を設定します。
この設定は、位置情報を利用する際の確認メッセージで表示される文字列です。
この設定を行わなければ、以降のロジックを組み込んでもバックグラウンドで処理は行われません。
![ScreenShot 7.png](https://qiita-image-store.s3.amazonaws.com/0/136009/e172efc9-f553-eb3f-7724-12f972e519b2.png)

以下の赤枠部分に表示されます。
![ss2.png](https://qiita-image-store.s3.amazonaws.com/0/136009/3c701097-5612-0ef2-1e30-f42b45fb6eed.png)

##バックグラウンド処理用のクラスの追加
iOSプロジェクトに以下のクラスを追加します。

```csharp:BackgroundManager.cs
using System;
using System.Threading;
using CoreLocation;

namespace BackgroundTest.iOS
{
    public class BackgroundManager : CLLocationManagerDelegate
    {
        private Timer _timer;
        private CLLocationManager _locationManager;
        private int _starttime = 0;     	//タイマーの開始時刻（ミリ秒）
        private int _interval = 1 * 1000;	//呼び出し間隔（ミリ秒）

        public BackgroundManager()
        {
            _locationManager = new CLLocationManager();

            if (CLLocationManager.LocationServicesEnabled)
            {
				_locationManager.Delegate = this;
				_locationManager.DesiredAccuracy = CLLocation.AccurracyBestForNavigation;
                _locationManager.ActivityType = CLActivityType.Fitness;
                _locationManager.PausesLocationUpdatesAutomatically = false;
                _locationManager.DistanceFilter = 1.0;
				_locationManager.AllowsBackgroundLocationUpdates = true;
				_locationManager.RequestAlwaysAuthorization();
				_timer = new Timer(new TimerCallback(CallWriteLine));
            }
        }

        public void Start()
        {
            _timer.Change(_starttime, _interval);
            _locationManager.StartUpdatingLocation();
        }

        public void Stop()
        {
            _timer.Change(Timeout.Infinite, Timeout.Infinite);
            _locationManager.StopUpdatingLocation();
        }

		private static void CallWriteLine(object args)
        {
			Console.WriteLine(DateTime.Now.ToString());
        }
    }
}
```

TimerクラスのTimerCallbackで、定期的に処理させたいメソッドを呼び出す設定を行い、呼び出し先のCallWriteLineで、現在時刻を出力するだけのロジックを組み込んでいます。

また、TimerクラスのChangeメソッドにて、インターバルを設定する必要があり、今回は1,000ミリ秒を指定し、1秒ごとにCallWriteLineを呼び出すようにしています。
※CLLocationManagerについては、当記事の最後のURLに詳細が記載されています。

##バックグラウンド処理の呼び出し
バックグランド処理を呼び出します。
今回はアプリを立ち上げた時点でバックグラウンド処理を呼び出すため、iOSプロジェクトのAppDelegate.csに記述します。

```csharp:AppDelegate.cs
using Foundation;
using UIKit;

namespace BackgroundTest.iOS
{
	[Register("AppDelegate")]
	public partial class AppDelegate : global::Xamarin.Forms.Platform.iOS.FormsApplicationDelegate
	{
		BackgroundManager _backgroundManager = null;

		public override bool FinishedLaunching(UIApplication app, NSDictionary options)
		{
			global::Xamarin.Forms.Forms.Init();

			_backgroundManager = new BackgroundManager();
			_backgroundManager.Start();

			LoadApplication(new App());

			return base.FinishedLaunching(app, options);
		}
	}
}
```

##バックグラウンド処理の確認
前述までの設定やロジックを組み込み後、実際に起動させて確認します。
起動後にホームボタンを押し、ホーム画面の状態でもログが出力されていれば成功です。

1. 初回起動時に以下のメッセージが表示されますので、許可を選択します。
![ss1.png](https://qiita-image-store.s3.amazonaws.com/0/136009/874b248d-d26d-126f-99d4-3e5afebeca25.png)

2. 許可後にアプリケーション出力を確認し、1秒ごとにログが表示されることを確認します。
![ScreenShot 8.png](https://qiita-image-store.s3.amazonaws.com/0/136009/3d0e3e82-794a-ddf6-2d44-52b3cd1aaf4b.png)

3. ホームボタンを押し、ホーム画面が表示されている状態で、2と同様にログが出力され続けていれば成功です。


#参考
Takahiro Octopress Blog　－　Backgroundで位置情報を取得しよう！
http://grandbig.github.io/blog/2013/09/27/location-nstimer/