Android Firebase Authentication (Google認証) メモ

Firebase AuthenticationをGoogle認証で試してみたのでメモ

公式サンプルを参考にしながら
https://github.com/firebase/quickstart-android/tree/master/auth

# 事前準備

Android Studioでプロジェクト作成
Firebase Consoleでプロジェクト作成

# Google認証の有効化

Firebase ConsoleでAuthのログイン方法からGoogleを有効にする

# フィンガープリントの確認

Google認証を使うには証明書フィンガープリントの設定が必要

この設定に気づかず、結構ハマった

詳細は公式ドキュメントで
https://developers.google.com/android/guides/client-auth

以下のコマンドで確認する(Linux)

```
keytool -exportcert -alias androiddebugkey -keystore ~/.android/debug.keystore -list -v -storepass android
```

表示されたフィンガープリントのSHA1を確認する

# google-services.jsonの生成

Firebase Consoleで以下の作業を行う。

- Overviewにある「AndroidアプリにFirebaseを追加」をクリック
- Android Studioで作成したアプリのパッケージ名を入力
- 先ほど確認したSHA1を入力
- 「アプリを追加」をクリック
- `google-services.json`がダウンロードされる

# Firebaseのセットアップ
Android Studioで以下の作業を行う。

## `google-services.json`をモジュール直下に配置

デフォルトなら

```
<PROJECT_ROOT>/app/google-services.json
```

## プロジェクトルートのbuild.gradleを編集

```&lt;PROJECT_ROOT&gt;/build.gradle
buildscript {
  dependencies {
    // 追加
    classpath 'com.google.gms:google-services:3.0.0'
  }
}
```

## モジュールのbuild.gradleを編集

```&lt;PROJECT_ROOT&gt;/&lt;APP_MODULE&gt;/build.gradle
dependencies {
  compile fileTree(dir: 'libs', include: ['*.jar'])
  testCompile 'junit:junit:4.12'
  compile 'com.android.support:appcompat-v7:24.1.1'

  // 以下を追加
  compile 'com.google.firebase:firebase-core:9.2.1'
  compile 'com.google.firebase:firebase-auth:9.2.1'
  compile 'com.google.android.gms:play-services-auth:9.2.1'
}

// 追加
apply plugin: 'com.google.gms.google-services'
```

## Manifestの編集

ネットワーク通信のPermissionを追加

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

# Google認証の実装

ログイン画面のレイアウト作成

```activity_login.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context=".LoginActivity">

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Login by Google"
        android:id="@+id/googleLoginButton"
        android:layout_centerVertical="true"
        android:layout_centerHorizontal="true" />
</RelativeLayout>
```

ログイン画面のActivityを生成

```LoginActivity.java
public class LoginActivity extends AppCompatActivity implements
GoogleApiClient.OnConnectionFailedListener {
    private static final int RC_SIGN_IN = 9001;

    private FirebaseAuth mAuth;

    private GoogleApiClient mGoogleApiClient;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_login);

        findViewById(R.id.googleLoginButton).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Intent signInIntent = Auth.GoogleSignInApi.getSignInIntent(mGoogleApiClient);
                startActivityForResult(signInIntent, RC_SIGN_IN);
            }
        });

        mAuth = FirebaseAuth.getInstance();

        GoogleSignInOptions gso = new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
                .requestIdToken(getString(R.string.default_web_client_id))
                .requestEmail()
                .build();

        mGoogleApiClient = new GoogleApiClient.Builder(this)
                .enableAutoManage(this, this)
                .addApi(Auth.GOOGLE_SIGN_IN_API, gso)
                .build();
    }

    private void changeActivity() {
        Intent intent = new Intent(LoginActivity.this, MainActivity.class);
        startActivity(intent);
    }

    @Override
    public void onConnectionFailed(@NonNull ConnectionResult connectionResult) {
        Toast.makeText(this, "Google Play Services error.", Toast.LENGTH_SHORT).show();
    }

    @Override
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);

        if (requestCode == RC_SIGN_IN) {
            GoogleSignInResult result = Auth.GoogleSignInApi.getSignInResultFromIntent(data);
            if (result.isSuccess()) {
                GoogleSignInAccount account = result.getSignInAccount();
                firebaseAuthWithGoogle(account);
            } else {
                System.out.println(result.getStatus());
                Toast.makeText(LoginActivity.this, "Error", Toast.LENGTH_SHORT).show();
            }
        }
    }

    private void firebaseAuthWithGoogle(GoogleSignInAccount acct) {
        AuthCredential credential = GoogleAuthProvider.getCredential(acct.getIdToken(), null);
        mAuth.signInWithCredential(credential)
                .addOnCompleteListener(this, new OnCompleteListener<AuthResult>() {
                    @Override
                    public void onComplete(@NonNull Task<AuthResult> task) {
                        if (task.isSuccessful()) {
                            changeActivity();
                        } else {
                            Toast.makeText(LoginActivity.this, task.getException().getMessage(), Toast.LENGTH_SHORT).show();
                        }
                    }
                });
    }
}
```

ログインした後の画面も作成

```activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context=".LoginActivity">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Login success!"
        android:id="@+id/textView"
        android:layout_alignParentTop="true"
        android:layout_centerHorizontal="true"
        android:layout_marginTop="48dp"
        android:textSize="32dp" />

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Logout"
        android:id="@+id/logoutButton"
        android:layout_centerVertical="true"
        android:layout_centerHorizontal="true"
        android:textSize="26dp" />
</RelativeLayout>
```

TextViewとログアウトボタンを配置

MainActivityはログアウト処理だけ行うようにした

```MainActivity.java
public class MainActivity extends AppCompatActivity {

    private FirebaseAuth mAuth;

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

        mAuth = FirebaseAuth.getInstance();

        findViewById(R.id.logoutButton).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                mAuth.signOut();
                Intent intent = new Intent(MainActivity.this, LoginActivity.class);
                startActivity(intent);
                finish();
            }
        });
    }
}
```

最後にManifestを編集

```AndroidManifest.xml
        <activity android:name=".LoginActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <activity android:name=".MainActivity" />
```

これでアプリからGoogle認証すると、Firebase ConsoleのAuthにユーザが追加されてる

前回のEmail・パスワード認証
http://qiita.com/Sert/items/36f1446afb1b694ebdaa
に比べるとコード量が減ってるな、といった印象

createAccountが無いのと、ログインもIntent飛ばしてるからかな、と