🕌

[Android Studio] Firebase UI Authを実装してみた

2022/06/21に公開

はじめに

最近、Firebaseを使用してアプリを作成してみようと思い、まずは認証機能の実装だ!!と意気込んでいたのですが、思ったより躓いてしまったのでメモしておきます。
Firebase初心者なので完全に理解できておらず、ミス等ございましたらコメントください。。
今回は下記サイトを参考に実装しました。
https://firebase.google.com/docs/auth/android/firebaseui?hl=ja


Firebase UI Authとは

公式では、

FirebaseUI は Firebase Authentication SDK の上に構築されるライブラリで、アプリにドロップイン UI フローを追加できます。

と記載があります。
要するにFirebase UI Authを使用すれば、複数のプロバイダ(メールアドレス、Facebook、Twitter、Google等)によるユーザ登録、ログイン、ログイン後のページ遷移などのログインフローを任せることができる機能です。
UIなども勝手に用意してくれるので、工数削減に役立ちますがUIや処理のカスタマイズ性は低いので、自分好みのUIにしたい!自分好みの処理にしたい!というかたは、以下サイトを参考に実装してみてください。
https://firebase.google.com/docs/auth/android/start?hl=ja


事前準備

・Androidプロジェクトの作成
・FirebaseをAndroidプロジェクトへ追加
 (https://firebase.google.com/docs/android/setup?hl=ja)


実装

・依存関係の設定

buid.gradle
plugins {
    id 'com.android.application'
    id 'com.google.gms.google-services'     // gms追加
}

dependencies {

    implementation 'androidx.appcompat:appcompat:1.4.2'
    implementation 'com.google.android.material:material:1.6.1'
    implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
    testImplementation 'junit:junit:4.13.2'
    androidTestImplementation 'androidx.test.ext:junit:1.1.3'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'


    // 今回は多分いらないけど記載してあったので一応載せておきます。。いらないと思うけど
    implementation platform('com.google.firebase:firebase-bom:30.1.0')
    implementation 'com.google.firebase:firebase-analytics'
    implementation 'com.google.firebase:firebase-auth'

    implementation 'com.firebaseui:firebase-ui-auth:8.0.1'
    implementation 'com.facebook.android:facebook-login:14.0.0'  // facebookのログイン用
    // googleのログインは「'com.google.gms.google-services'」に入っているらしい。。
}

・strings.xmlに文字列を指定
「facebook_application_id」と「facebook_client_token」の値は適当に設定しました。
また、「facebook_client_token」に関してはそもそもいるのか疑問です。。

string.xml
<resources>
    <string name="app_name">test_firebase</string>
    <string name="facebook_application_id">1000</string>
    <string name="facebook_client_token">20000</string>
</resources>

・Layoutファイルの作成

activity_firebase_ui.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".FirebaseUIActivity">
</androidx.constraintlayout.widget.ConstraintLayout>

・ログイン処理の実装
実装は下記サイト参考に、というかコピペです。
https://github.com/firebase/snippets-android/blob/8184cba2c40842a180f91dcfb4a216e721cc6ae6/auth/app/src/main/java/com/google/firebase/quickstart/auth/FirebaseUIActivity.java

FirebaseUIActivity.java
public class FirebaseUIActivity extends AppCompatActivity {
    private final String TAG = "FirebaseUIActivity";

    // FirebaseUI Activity の結果コントラクトのコールバックを登録する ActivityResultLauncher を作成します。
    private final ActivityResultLauncher<Intent> signInLauncher = registerForActivityResult(
            new FirebaseAuthUIActivityResultContract(),
            new ActivityResultCallback<FirebaseAuthUIAuthenticationResult>() {
                @Override
                public void onActivityResult(FirebaseAuthUIAuthenticationResult result) {
                    onSignInResult(result);
                }
            }
    );

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

        createSignInIntent();
    }

    public void createSignInIntent() {
        // FirebaseUI ログインフローを開始するには、任意のログイン方法を含むログイン インテントを作成します。
        // サインインプロバイダーを有効にする。
        List<AuthUI.IdpConfig> providers = Arrays.asList(
                new AuthUI.IdpConfig.EmailBuilder().build(),
                new AuthUI.IdpConfig.PhoneBuilder().build(),
                new AuthUI.IdpConfig.GoogleBuilder().build(),
                new AuthUI.IdpConfig.FacebookBuilder().build(),
                new AuthUI.IdpConfig.TwitterBuilder().build());

        // Create and launch sign-in intent
        Intent signInIntent = AuthUI.getInstance()
                .createSignInIntentBuilder()
                .setAvailableProviders(providers)
                .build();
        signInLauncher.launch(signInIntent);
    }

    // ログインフローが完了すると、onSignInResult に結果が返されます。
    private void onSignInResult(FirebaseAuthUIAuthenticationResult result) {
        IdpResponse response = result.getIdpResponse();
        if (result.getResultCode() == RESULT_OK) {
            // Successfully signed in
            FirebaseUser user = FirebaseAuth.getInstance().getCurrentUser();
        } else {
            // Sign in failed. If response is null the user canceled the
            // sign-in flow using the back button. Otherwise check
            // response.getError().getErrorCode() and handle the error.
            // ...
        }
    }

    public void signOut() {
        AuthUI.getInstance()
                .signOut(this)
                .addOnCompleteListener(new OnCompleteListener<Void>() {
                    public void onComplete(@NonNull Task<Void> task) {
                        // ...
                    }
                });
    }

    public void delete() {
        AuthUI.getInstance()
                .delete(this)
                .addOnCompleteListener(new OnCompleteListener<Void>() {
                    @Override
                    public void onComplete(@NonNull Task<Void> task) {
                        // ...
                    }
                });
    }

    public void themeAndLogo() {
        List<AuthUI.IdpConfig> providers = Collections.emptyList();

        Intent signInIntent = AuthUI.getInstance()
                .createSignInIntentBuilder()
                .setAvailableProviders(providers)
                .setLogo(R.drawable.my_great_logo)      // Set logo drawable
                //.setTheme(R.style.MySuperAppTheme)      // Set theme  // FIXME エラー取れない
                .build();
        signInLauncher.launch(signInIntent);
    }

    public void privacyAndTerms() {
        List<AuthUI.IdpConfig> providers = Collections.emptyList();

        Intent signInIntent = AuthUI.getInstance()
                .createSignInIntentBuilder()
                .setAvailableProviders(providers)
                .setTosAndPrivacyPolicyUrls(
                        "https://example.com/terms.html",
                        "https://example.com/privacy.html")
                .build();
        signInLauncher.launch(signInIntent);
    }

    public void emailLink() {
        // EmailBuilderインスタンスのenableEmailLinkSignInを呼び出すことで、FirebaseUIのメールリンクログインを有効にできます。
        ActionCodeSettings actionCodeSettings = ActionCodeSettings.newBuilder()
                .setAndroidPackageName(
                        /* yourPackageName= */   "~~~",
                        /* installIfNotAvailable= */ true,
                        /* minimumVersion= */ null)
                .setHandleCodeInApp(true) // This must be set to true
                .setUrl("https://google.com") // This URL needs to be whitelisted(URLを許可リストに登録する)
                .build();

        List<AuthUI.IdpConfig> providers = Arrays.asList(
                new AuthUI.IdpConfig.EmailBuilder()
                        .enableEmailLinkSignIn()
                        .setActionCodeSettings(actionCodeSettings)  // 有効な ActionCodeSettings オブジェクトを指定する
                        .build()
        );
        Intent signInIntent = AuthUI.getInstance()
                .createSignInIntentBuilder()
                .setAvailableProviders(providers)
                .build();
        signInLauncher.launch(signInIntent);
    }

    public void catchEmailLink() {
        List<AuthUI.IdpConfig> providers = Collections.emptyList();

        // ディープリンクを取得したら、処理できるように verify を呼び出す必要があります。
        // 可能であれば、setEmailLink を介してこれを Google に渡す必要があります。
        if (AuthUI.canHandleIntent(getIntent())) {
            if (getIntent().getExtras() == null) {
                return;
            }
            @SuppressLint("RestrictedApi") String link = getIntent().getExtras().getString(ExtraConstants.EMAIL_LINK_SIGN_IN);
            if (link != null) {
                Intent signInIntent = AuthUI.getInstance()
                        .createSignInIntentBuilder()
                        .setEmailLink(link)
                        .setAvailableProviders(providers)
                        .build();
                signInLauncher.launch(signInIntent);
            }
        }
    }
}

・Manifestの編集

AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    package="test.com.test_firebase">

    <application
        android:allowBackup="true"
        android:dataExtractionRules="@xml/data_extraction_rules"
        android:fullBackupContent="@xml/backup_rules"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/Theme.Test_Firebase"
        tools:targetApi="31">

        <activity
            android:name=".MainActivity"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

        <activity
            android:name=".FirebaseUIActivity">
        </activity>

        <meta-data android:name="com.facebook.sdk.ApplicationId" android:value="@string/facebook_application_id"/>
        <meta-data android:name="com.facebook.sdk.ClientToken" android:value="@string/facebook_client_token"/>
    </application>
</manifest>

・MainActivityの作成

MainActivity.java
public class MainActivity extends AppCompatActivity {

    private static final String TAG = "MainActivity";

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

        Intent intent = new Intent(getApplication(), FirebaseUIActivity.class);
        startActivity(intent);
    }
}

参考サイト

https://stackoverflow.com/questions/30213369/facebook-sdk-has-not-been-initialized-facebooksdk-sdkinitialize
https://github.com/firebase/FirebaseUI-Android/blob/master/auth/README.md
https://github.com/facebook/facebook-android-sdk
https://stackoverflow.com/questions/51665890/facebook-provider-unconfigured-make-sure-to-add-a-facebook-application-id-str
https://developers.facebook.com/docs/android/getting-started/
https://github.com/facebookarchive/react-native-fbsdk/issues/485

Discussion