LoginSignup
5
4

More than 5 years have passed since last update.

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

Last updated at Posted at 2015-05-25

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を取得する。

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

    public override bool ShouldStartLoad(UIWebView webview, NSUrlRequest requesturl, UIWebViewNavigationType navitype)
    {
        if (URLlocalhostか判定(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を同様のコード)。

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 (URLlocalhostか判定(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取得

 項番3以降はPortableで作成するので、iOS/Androidで共通のコードとなる。項番2で取得したverify_codeを使用してサービスに必要なAccessTokenなど諸々のデータを取得する。

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の仕様を見ればのっているだろうけど、まずはアクセスできることが重要だったので後回し)。リフレッシュするタイミングは、項番3で取得する情報に含まれている。リフレッシュにはするには、RefreshTokenが必要である。これは、項番3に含まれている。なお、すでにログインは終わっている場合は、これを使用して最新のAccessTokenを得る。

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用なので手動で設定していく。

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

    public CustomMessageHandler(HttpMessageHandler innerHandler) : base(innerHandler)
    {
    }
}
GoogleHttpClientFactory
public class GoogleHttpClientFactory : HttpClientFactory
{
    protected override HttpMessageHandler CreateHandler (CreateHttpClientArgs args)
    {
        return new CustomMessageHandler();
    }
}
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に設定して実際にアクセスする(この場合はカレンダーであるが、別のサービスでは別の変数が必要かもしれない)。

サービス初期化
App.calservice = new CalendarService(new BaseClientService.Initializer()
{
    HttpClientInitializer = credential,
    ApplicationName = "App Name",
    HttpClientFactory = httpclientfactory
});
サービスアクセス(例)
IList<CalendarListEntry> list = calservice.CalendarList.List().Execute().Items;
foreach (CalendarListEntry item in list)
{
    Debug.WriteLine(item.Summary + ". Location: " + item.Location + ", TimeZone: " + item.TimeZone);
}

 
 
 
 
 

5
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
4