AndroidでのGoogle Account OAuth認証方法

[Google APIs Client for Java](http://code.google.com/p/google-api-java-client/) を使う。

- インストール方法

 Gradleを使う場合、build.gradleのdependencyに

```
    compile 'com.google.apis:google-api-services-youtube:v3-rev79-1.17.0-rc'
    compile 'com.google.apis:google-api-services-oauth2:v2-rev51-1.17.0-rc'
    compile 'com.google.apis:google-api-services-plus:v1-rev99-1.17.0-rc'
    compile 'com.google.api-client:google-api-client:1.17.0-rc'
    compile 'com.google.api-client:google-api-client-android:1.17.0-rc'

```

のようなもの(上のものはYouTube,OAuth2,Google Plusのライブラリも追加されている。)を書けば良いはず。

直接使う場合はlibs配下にjarを配置して、同様にビルド環境毎の依存関係を設定する。

- まずはアカウントを選択して貰う。

```java

Intent accountChooserIntent =
                AccountPicker.newChooseAccountIntent(null, null,
                        new String[]{GoogleAuthUtil.GOOGLE_ACCOUNT_TYPE}, true, getString(R.string.please_select_account), null,
                        null, null);
        startActivityForResult(accountChooserIntent, REQUEST_PICK_ACCOUNT);

```

これでアカウント選択ダイアログが表示される。

- 選択すると、onActivityResultに返る。

```java

    protected void onActivityResult(int requestCode, int resultCode, Intent data) {

...

            case REQUEST_PICK_ACCOUNT:
                if (resultCode == RESULT_OK) {
                    mChosenAccountName = data.getStringExtra(AccountManager.KEY_ACCOUNT_NAME);
                    tryAuthenticate();
                } else {

                }
                break;

```

- 実際の認証

GoogleAuthUtil.getTokenを用いる。
Scopeとして必要なものを`oauth2:`の後にスペース区切りで指定する。
ライブラリを使えば定数が設定されているが、使わない場合それを調べるのも面倒で、
http://stackoverflow.com/questions/10664868/where-can-i-find-a-list-of-scopes-for-googles-oauth-2-0-api にあるリンクなどを参考にする必要がある。

サービス毎のライブラリに関しては、[ここ](https://developers.google.com/api-client-library/java/apis/)からそれぞれのサービスのページに飛べる。


```java

//void tryAuthenticate
...
AsyncTask<Void, Void, Boolean> task = new AsyncTask<Void, Void, Boolean>() {
            @Override
            protected Boolean doInBackground(Void... params) {
                try {
                    String SCOPE_STRING = "oauth2:"
            + Scopes.PLUS_PROFILE + " " + YouTubeScopes.YOUTUBE + " "
            + YouTubeScopes.YOUTUBE_UPLOAD + " " + YouTubeScopes.YOUTUBE_READONLY + " " + Oauth2Scopes.USERINFO_PROFILE;
                    mToken =
                            GoogleAuthUtil.getToken(LoginActivity.this, mChosenAccountName, SCOPE_STRING);
                } catch (GooglePlayServicesAvailabilityException playEx) {
                    GooglePlayServicesUtil.getErrorDialog(playEx.getConnectionStatusCode(),
                            LoginActivity.this, REQUEST_GMS_ERROR_DIALOG).show();
                } catch (UserRecoverableAuthException userAuthEx) {
                    startActivityForResult(userAuthEx.getIntent(), REQUEST_AUTHENTICATE);
                    return false;
                } catch (IOException transientEx) {
                    Log.e(this.getClass().getSimpleName(), transientEx.getMessage());
                } catch (GoogleAuthException authEx) {
                    Log.e(this.getClass().getSimpleName(), authEx.getMessage());
                }
                return true;
            }
        };

```

- 認証が済んでいない場合

例えば初回時にはUserRecoverableAuthExceptionが投げられる。その場合、

```java

startActivityForResult(userAuthEx.getIntent(), REQUEST_AUTHENTICATE);
                    return false;

```
のように、例外自体からIntentを取り出してそのまま`startActivityForResult`することで、
今度はOAuthの権限承認用ダイアログが表示される。
この戻り値もonActivityResultでハンドリングする必要がある。

```java

//onActivityResult

            case REQUEST_AUTHENTICATE:
                if (resultCode == RESULT_OK) {
                    tryAuthenticate();
                }

```

認証を通ればUserRecoverableAuthExceptionは投げられないので、`doInBackground`が成功する。
これでアクセストークンが取得できた。

- トークンを使う

例えば自分のYouTubeのチャンネルをリストする。

```java

     String APP_NAME = "Test";
     HttpTransport HTTP_TRANSPORT = new NetHttpTransport();

     JsonFactory JSON_FACTORY = new AndroidJsonFactory();
List<String> SCOPES = Arrays.asList(Scopes.PLUS_PROFILE,
            YouTubeScopes.YOUTUBE, YouTubeScopes.YOUTUBE_UPLOAD,
            YouTubeScopes.YOUTUBE_READONLY, Oauth2Scopes.USERINFO_PROFILE);

     GoogleAccountCredential accountCredential = GoogleAccountCredential.usingOAuth2(LoginActivity.this, SCOPES);
     accountCredential.setSelectedAccountName(mChosenAccountName);
     YouTube youTube = new YouTube.Builder(HTTP_TRANSPORT, JSON_FACTORY, credential).setApplicationName(APP_NAME).build();
    try {
                    YouTube.Channels.List channelRequest = youTube.channels().list("id, snippet");
                    channelRequest.setMine(true);
                    channelRequest.setFields("items(id,snippet/title)");
                    channelRequest.setOauthToken(mToken);
                    ChannelListResponse channels = channelRequest.execute();
                    List<Channel> listOfChannels = channels.getItems();
          ...

      }catch(UserRecoverableAuthIOException e){
          ...
          

```

ここでもトークンの期限切れなどによってUserRecoverableAuthIOExcaptionが発生する可能性がある。
発生した場合には初回同様`startActivityForResult`すると、認証がリボークされていなければ、
ユーザ操作無しにトークンを更新して`onActivityResult`に戻ってくる。
その場合再度上のコードを走らせれば今度は例外が発生しないはず。