Google Sign-In

 - [Google Developers](https://developers.google.com/identity/sign-in/?hl=ja)

転載元: [Android : Google Sign-In](http://yuki312.blogspot.jp/2015/04/android-google-sign-in.html)

## Prerequisites

 - Android 2.3 以上, あるいは最新のGoogle Play Storeを搭載していること. 
 - 最新のAndroid SDK Toolsをインストールしていること.
 - Google Play Service SDKをインストールしていること.
 - コンパイルバージョンがAndroid2.3以上であること.

## Step 1: Google Sign-In APIの有効化

 1. [Google Developers Console](https://console.developers.google.com/)へ移動
 2. プロジェクトを作成する
 3. AndroidアプリケーションとしてクライアントIDを作成する

**NOTE**  
デバッグ用.keystoreのSHA1ハッシュを確認するには次のコマンドを参照. 

```bash
keytool -exportcert -alias androiddebugkey -keystore path-to-debug-or-production-keystore -list -v
```

デバッグ用.keystoreはMacだと`~/.android/debug.keystore`. Windowsでは`%USERPROFILE%\.android\debug.keystore`に標準で格納されている. 

デバッグ用keystoreのパスワードは`android`. 


## Step 2: Android Studio Project の設定

build.gradleのdependenciesセクションにGoogle Play Serviceを追加. 

```gradle

dependencies {
    compile 'com.google.android.gms:play-services:7.0.0'
}
```

## Step 3: Permission宣言

アプリケーションが使用するGoogle Play ServiceのバージョンをAndroidManifestの`application`タグ配下に宣言する. 

```xml
<meta-data android:name="com.google.android.gms.version" android:value="@integer/google_play_services_version" />
```

Google APIにアクセスするためINTERNETパーミッションを宣言する. 

```xml
<uses-permission android:name="android.permission.INTERNET" />
```

アカウント名を取得するためGET_ACCOUNTパーミッションを宣言する. 

```xml
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
```

OAuth 2.0 tokenを取得するためUSE_CREDENTIALSパーミッションを宣言する. 

```xml
<uses-permission android:name="android.permission.USE_CREDENTIALS" />
```


## GoogleApiClient の初期化

GoogleApiClientはGoogle Play Serviceに接続される[ServiceConnection](http://developer.android.com/reference/android/content/ServiceConnection.html)のラッパーとして作用する. 
GoogleApiClientはGoogle Sign-In APIと通信し, 非同期通信によりサービスを有効化した後機能する. そのためには, 

 - Google Play Serviceがデバイス上で実行されており, あなたのActivityがService connectionに接続できていること.
 - ユーザがあなたのアプリでアカウントを選択し, ユーザのアカウントがあなたのアプリに権限を与えていること. 

GoogleApiClientのライフサイクルをActivityのライフサイクルの中で管理するための一般的な方法は下記. 

 1. Activity.onCreateでGoogleApiClientを初期化
 2. Activity.onStartでGoogleApiClient.connectを起動
 3. Activity.onStopでGoogleApiClient.disconnectを起動

これを実行するとActivityにはコネクションが有効化あるいは接続失敗したことがConnectionCallbacksとOnConnectionFailedListenerに通知される. 

[addScope](https://developer.android.com/reference/com/google/android/gms/common/api/GoogleApiClient.Builder.html#addScope(com.google.android.gms.common.api.Scope))メソッドでアプリが許容を求めるスコープを定義できる. 

 - 基本的なプロフィール情報が必要であれば[profile](https://developers.google.com/+/api/oauth?hl=ja#login-scopes)
 - ユーザのGoogle account emailアドレスが必要であれば[email](https://developers.google.com/+/api/oauth?hl=ja#login-scopes)

```java
import android.app.Activity;
import android.content.IntentSender.SendIntentException;
import android.os.Bundle;
import android.view.View;

import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.common.api.Scope;
import com.google.android.gms.plus.Plus;

public class MainActivity extends Activity implements
        GoogleApiClient.ConnectionCallbacks,
        GoogleApiClient.OnConnectionFailedListener,
        View.OnClickListener {

    /* Request code used to invoke sign in user interactions. */
    private static final int RC_SIGN_IN = 0;

    /* Client used to interact with Google APIs. */
    private GoogleApiClient mGoogleApiClient;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mGoogleApiClient = new GoogleApiClient.Builder(this)
                .addConnectionCallbacks(this)
                .addOnConnectionFailedListener(this)
                .addApi(Plus.API)
                .addScope(new Scope("profile"))
                .build();

       findViewById(R.id.sign_in_button).setOnClickListener(this);
    }

    @Override
    protected void onStart() {
        super.onStart();
        mGoogleApiClient.connect();
    }

    @Override
    protected void onStop() {
        super.onStop();
        mGoogleApiClient.disconnect();
    }

    @Override
    public void onClick(View v) {
      // ...
    }

    // ...

  }
```

GoogleApiClientがコネクションを有効化できなかった時, onConnectionFailedのコールバックが呼ばれる. これにはConnectionResultが渡されるためエラーの解決に使用できる. ConnectionResult.getResolution()を呼ぶとユーザにアカウントを選択する操作を促すためのPendingIntentを得ることができる. 
(例えば年とワーク接続を有効かするように求めたり, アカウントの選択をユーザに求めたりする)

```java
@Override
public void onConnectionFailed(ConnectionResult result) {
  if (!mIntentInProgress && result.hasResolution()) {
    try {
      mIntentInProgress = true;
      result.startResolutionForResult(this, RC_SIGN_IN);
    } catch (SendIntentException e) {
      // The intent was canceled before it was sent.  Return to the default
      // state and attempt to connect to get an updated ConnectionResult.
      mIntentInProgress = false;
      mGoogleApiClient.connect();
    }
  }
}

@Override
public void onConnected(Bundle connectionHint) {
  // We've resolved any connection errors.  mGoogleApiClient can be used to
  // access Google APIs on behalf of the user.
}

@Override
protected void onActivityResult(int requestCode, int responseCode, Intent intent) {
  if (requestCode == RC_SIGN_IN) {
    mIntentInProgress = false;

    if (!mGoogleApiClient.isConnected()) {
      mGoogleApiClient.reconnect();
    }
  }
}
```

クライアントのサービス接続が確立されたらGoogleApiClient.disconnectをonStopメソッドの中で呼び出しこれを切断する必要がある. 

Google Play ServiceはActivityがサービスコネクションをロストした際に呼ばれるonConnectionSuspendedコールバックを呼び出す. 一般的にこの場合はユーザが解決を試みることができるようにサービスへの再接続を試みる. 

```java
@Override
public void onConnectionSuspended(int cause) {
  mGoogleApiClient.connect();
}
```

## Google Sign-In ボタンの追加

 1. アプリケーションのレイアウトに[SignInButton](https://developer.android.com/reference/com/google/android/gms/common/SignInButton.html)を追加

```xml
<com.google.android.gms.common.SignInButton
    android:id="@+id/sign_in_button"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content" />
```

 2. OnClickListenerを登録する

```java
findViewById(R.id.sign_in_button).setOnClickListener(this);
```

 3. Sign-Inボタンを使用するにはActivityのSign-Inフローを変更する必要がある. ActivityがOnCnnectionFaildコールバックを受け取ったらすぐに問題解決のためのユーザインタラクションを開始する. Activityはその間Sing-inボタンのクリックを抑止するべき. 

```java
/**
 * True if the sign-in button was clicked.  When true, we know to resolve all
 * issues preventing sign-in without waiting.
 */
private boolean mSignInClicked;

/**
 * True if we are in the process of resolving a ConnectionResult
 */
private boolean mIntentInProgress;

@Override
public void onConnectionFailed(ConnectionResult result) {
  if (!mIntentInProgress) {
    if (mSignInClicked && result.hasResolution()) {
      // The user has already clicked 'sign-in' so we attempt to resolve all
      // errors until the user is signed in, or they cancel.
      try {
        result.startResolutionForResult(this, RC_SIGN_IN);
        mIntentInProgress = true;
      } catch (SendIntentException e) {
        // The intent was canceled before it was sent.  Return to the default
        // state and attempt to connect to get an updated ConnectionResult.
        mIntentInProgress = false;
        mGoogleApiClient.connect();
      }
    }
  }
}
```

 4. ユーザがSign-Inボタンをクリックした後, mSignInClickedフラグをセットし, onConnectionFailedで接続エラーを解決する必要がある. 解決可能なエラーはユーザにサービスへの接続とアプリへの権限承認を促す. 

```java
public void onClick(View view) {
  if (view.getId() == R.id.sign_in_button && !mGoogleApiClient.isConnecting()) {
    mSignInClicked = true;
    mGoogleApiClient.connect();
  }
}
```

 5. 接続が確立された場合はmSignInClickedフラグをリセットする. 

```java
protected void onActivityResult(int requestCode, int responseCode, Intent intent) {
  if (requestCode == RC_SIGN_IN) {
    if (responseCode != RESULT_OK) {
      mSignInClicked = false;
    }

    mIntentInProgress = false;

    if (!mGoogleApiClient.isConnected()) {
      mGoogleApiClient.reconnect();
    }
  }
}
```

 6. ユーザがSign-Inを無事終えるとonConnectedが呼ばれる. この時点でユーザの名前を取得するか認証リクエストを作成することができる. 

```java
@Override
public void onConnected(Bundle connectionHint) {
  mSignInClicked = false;
  Toast.makeText(this, "User is connected!", Toast.LENGTH_LONG).show();
}
```

 - [GitHub](https://github.com/YukiMatsumura/GoogleSignInSample)  


以上.