GoogleApiの.NETライブラリを使用するメモ


#1.はじめに
　XamarinのiOS/Androidでアプリを作成するのにGoogleのサービスにアクセスする必要があったが、Xamarin.AuthやNugetを使用してApiのライブラリを組み込むもエラーで動作しない。やり方を調べながらコードを書いたので、要点のみ記録に残しておく。ただし、抜けや間違えがあるかもしれない。また、かなりのやっつけコードである（笑）。
　このコードを理解するには、GoogleのOAuth2についての知識がちょっと必要となる。
#2.ログイン
ログインはWebViewを使いGoogleのWeb画面を表示し、http://localhostにリダイレクトしてverificationCodeを取得する。
###2.1 iOSの場合
UIWebViewDelegateから派生したClassを作成してWebViewに設定します。何か処理がされると横取りできるので、そのタイミングでverificationCodeを取得する。

```CSharp:MyWebViewDelegate
public class MyWebViewDelegate : UIWebViewDelegate
{
	public MyWebViewDelegate() {}

	public override bool ShouldStartLoad(UIWebView webview, NSUrlRequest requesturl, UIWebViewNavigationType navitype)
	{
		if (URLがlocalhostか判定(requesturl.Url)) {
     		var dic = Jsonから辞書形式に変換(requesturl.Url.Query);
       		if (dic.ContainsKey("code") == true) {
         		// 正常に認証された
         		verificationCode = dic["code"];
        	} else {
        	    // エラー
        	    if (dic.ContainsKey("error") == true) {
        	    	error = dic["error"];
        	    }
      			return true;
      		}
      	}
	}
}
```

###2.2 Android
WebViewClientから派生したClassを作成してWebViewに設定する（ほぼ、iOSを同様のコード）。

```CSharp:MyWebViewClient
public class MyWebViewClient : WebViewClient
{
	public MyWebViewClient(LoginWebViewControlRenderer owner) {}

	public override void OnPageStarted (Android.Webkit.WebView view, string url, Android.Graphics.Bitmap favicon)
	{
		base.OnPageStarted (view, url, favicon);
		if (URLがlocalhostか判定(uri))
		{
			view.StopLoading ();
			var dic = Jsonから辞書形式に変換(uri.Query);
       		if (dic.ContainsKey("code") == true) {
         		// 正常に認証された
         		verificationCode = dic["code"];
        	} else {
        	    // エラー
        	    if (dic.ContainsKey("error") == true) {
        	    	error = dic["error"];
        	    }
      			return true;
      		}
      	}
	}
}
```
#3.AccessToken取得
　項番３以降はPortableで作成するので、iOS/Androidで共通のコードとなる。項番２で取得したverify_codeを使用してサービスに必要なAccessTokenなど諸々のデータを取得する。

```CSharp:GetAccessToken
public static async Task<string> GetAccessToken(string verificationCode) 
{
	using (var client = new HttpClient())
	{
		var content = new FormUrlEncodedContent(new[] 
		{
			new KeyValuePair<string, string>("client_id", ClientId),
			new KeyValuePair<string, string>("client_secret", ClientSecret),
			new KeyValuePair<string, string>("code", verificationCode),
			new KeyValuePair<string, string>("redirect_uri", RedirectUrl),
			new KeyValuePair<string, string>("grant_type", "authorization_code")
		});
		var result = client.PostAsync(GoogleAuthConsts.TokenUrl, content).Result;
		return await result.Content.ReadAsStringAsync();
	}
}
```

#4.AccessTokenのリフレッシュ
　AccessTokenは一定時間が経過するとリフレッシュが必要みたいだ（GoogleApiの仕様を見ればのっているだろうけど、まずはアクセスできることが重要だったので後回し）。リフレッシュするタイミングは、項番３で取得する情報に含まれている。リフレッシュにはするには、RefreshTokenが必要である。これは、項番3に含まれている。なお、すでにログインは終わっている場合は、これを使用して最新のAccessTokenを得る。

```CSharp:GetRefreshAccessToken
public static async Task<string> GetRefreshAccessToken(string refresh_token) 
{
	using (var client = new HttpClient())
	{
		var content = new FormUrlEncodedContent(new[] 
		{
			new KeyValuePair<string, string>("client_id", ClientId),
			new KeyValuePair<string, string>("client_secret", ClientSecret),
			new KeyValuePair<string, string>("refresh_token", refresh_token),
			new KeyValuePair<string, string>("grant_type", "refresh_token")
		});
		var result = client.PostAsync(GoogleAuthConsts.AuthorizationUrl, content).Result;
		return await result.Content.ReadAsStringAsync();
	}
}
```

#5.GoogleApiでアクセス
 NugetでGoogleのCalendarApiを追加しても、Googleが公開しているサンプルコードはWindows用なのでほぼ動かない。Googleの.netライブラリを使用してApiにアクセスするにか、ライブラリ固有の変数を初期化し設定する必要がある(UserCredentialの生成)。ヘルパー関数は、Windows用なので手動で設定していく。

```CSharp:CustomMessageHandler
class CustomMessageHandler : DelegatingHandler
{
	public CustomMessageHandler() : this(new HttpClientHandler())
	{
	}

	public CustomMessageHandler(HttpMessageHandler innerHandler) : base(innerHandler)
	{
	}
}
```
        
```CSharp:GoogleHttpClientFactory
public class GoogleHttpClientFactory : HttpClientFactory
{
	protected override HttpMessageHandler CreateHandler (CreateHttpClientArgs args)
	{
		return new CustomMessageHandler();
	}
}
```

```CSharp:UserCredential

var token = new TokenResponse()
{
	AccessToken = アクセストークン,
	ExpiresInSeconds = 更新期限,
	Issued = アクセストークンを取得したDateTime,
	RefreshToken = リフレッシュトークン,
	Scope = スコープ（カレンターAPI),
	TokenType = トークンタイプ,
};

var httpclientfactory = new GoogleHttpClientFactory();

credential = new UserCredential(
	new GoogleAuthorizationCodeFlow(
	new GoogleAuthorizationCodeFlow.Initializer() 
	{
		HttpClientFactory = httpclientfactory,
		ClientSecrets = new ClientSecrets()
		{
			ClientId = クライアントID,
			ClientSecret = クライアントシークレット
		}
	}
),
"user",
token);
```

#6.Serviceへアクセス
項番5の変数が生成できたら、Apiに設定して実際にアクセスする（この場合はカレンダーであるが、別のサービスでは別の変数が必要かもしれない）。

```CSharp:サービス初期化
App.calservice = new CalendarService(new BaseClientService.Initializer()
{
	HttpClientInitializer = credential,
	ApplicationName = "App Name",
	HttpClientFactory = httpclientfactory
});
```

```CSharp:サービスアクセス（例）
IList<CalendarListEntry> list = calservice.CalendarList.List().Execute().Items;
foreach (CalendarListEntry item in list)
{
	Debug.WriteLine(item.Summary + ". Location: " + item.Location + ", TimeZone: " + item.TimeZone);
}
```