🥙

Jetpack Composeでメールアドレス・パスワードログイン

2023/11/28に公開

Overview

Androidのネイティブアプリで、メールアドレス・パスワード認証を組み込むのをやってみました。今回は、画面遷移のパッケージも必要みたいで、Firebase Authnavigation-composeを使っています。

画面遷移のパッケージ
https://developer.android.com/jetpack/compose/navigation?hl=ja

メールアドレス・パスワードでのログインのやり方
https://firebase.google.com/docs/auth/android/password-auth?hl=ja

ログインとアカウント作成をするメソッド

公式のものをそのまま記載

新規のユーザー作成
auth.createUserWithEmailAndPassword(email, password)
    .addOnCompleteListener(this) { task ->
        if (task.isSuccessful) {
            // Sign in success, update UI with the signed-in user's information
            Log.d(TAG, "createUserWithEmail:success")
            val user = auth.currentUser
            updateUI(user)
        } else {
            // If sign in fails, display a message to the user.
            Log.w(TAG, "createUserWithEmail:failure", task.exception)
            Toast.makeText(
                baseContext,
                "Authentication failed.",
                Toast.LENGTH_SHORT,
            ).show()
            updateUI(null)
        }
    }
ログイン
auth.signInWithEmailAndPassword(email, password)
    .addOnCompleteListener(this) { task ->
        if (task.isSuccessful) {
            // Sign in success, update UI with the signed-in user's information
            Log.d(TAG, "signInWithEmail:success")
            val user = auth.currentUser
            updateUI(user)
        } else {
            // If sign in fails, display a message to the user.
            Log.w(TAG, "signInWithEmail:failure", task.exception)
            Toast.makeText(
                baseContext,
                "Authentication failed.",
                Toast.LENGTH_SHORT,
            ).show()
            updateUI(null)
        }
    }

こちらを参考に、認証機能を作ってみました。

summary

まずは、build.gradleの設定をしてください。こちらの記事と設定方法は同じです。今回は、画面遷移のパッケージを追加しただけですね。

https://zenn.dev/jboy_blog/articles/811bb8941d13e9

上の方のbuild.gradle

// Top-level build file where you can add configuration options common to all sub-projects/modules.
plugins {
    id 'com.android.application' version '8.0.2' apply false
    id 'com.android.library' version '8.0.2' apply false
    id 'org.jetbrains.kotlin.android' version '1.7.20' apply false
    id("com.google.gms.google-services") version "4.4.0" apply false// Firebaseのコードを追加
}

下の方のの方のbuild.gradle

plugins {
    id 'com.android.application'
    id 'org.jetbrains.kotlin.android'
    id("com.google.gms.google-services")
}

android {
    namespace 'com.example.firebaseauthapp'
    compileSdk 34

    defaultConfig {
        applicationId "com.example.firebaseauthapp"
        minSdk 24
        targetSdk 34
        versionCode 1
        versionName "1.0"

        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
        vectorDrawables {
            useSupportLibrary true
        }
    }

    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
    kotlinOptions {
        jvmTarget = '1.8'
    }
    buildFeatures {
        compose true
    }
    composeOptions {
        kotlinCompilerExtensionVersion '1.3.2'
    }
    packagingOptions {
        resources {
            excludes += '/META-INF/{AL2.0,LGPL2.1}'
        }
    }
}

dependencies {

    implementation 'androidx.core:core-ktx:1.8.0'
    implementation platform('org.jetbrains.kotlin:kotlin-bom:1.8.0')
    implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.3.1'
    implementation 'androidx.activity:activity-compose:1.5.1'
    implementation platform('androidx.compose:compose-bom:2022.10.00')
    implementation 'androidx.compose.ui:ui'
    implementation 'androidx.compose.ui:ui-graphics'
    implementation 'androidx.compose.ui:ui-tooling-preview'
    implementation 'androidx.compose.material3:material3'
    testImplementation 'junit:junit:4.13.2'
    androidTestImplementation 'androidx.test.ext:junit:1.1.5'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
    androidTestImplementation platform('androidx.compose:compose-bom:2022.10.00')
    androidTestImplementation 'androidx.compose.ui:ui-test-junit4'
    debugImplementation 'androidx.compose.ui:ui-tooling'
    debugImplementation 'androidx.compose.ui:ui-test-manifest'

    // 画面遷移のパッケージを追加する
    def nav_version = "2.7.1"

    implementation "androidx.navigation:navigation-compose:$nav_version"
    // Firebase Authのパッケージ追加
    implementation platform('com.google.firebase:firebase-bom:31.0.0')
    implementation("com.google.firebase:firebase-auth-ktx")
}

最初は、同じファイルにコードをまとめていたのですが、コードの量が多すぎて見づらいので別ファイルに分けました。

こちらが最初に表示されるページです。新規登録のボタンを押すと、画面遷移して新規登録のページへ移動します。

ログインページ
LoginPage.kt
package com.example.firebaseauthapp.view

import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.height
import androidx.compose.material3.Button
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Text
import androidx.compose.material3.TextField
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import androidx.navigation.NavController
import com.google.firebase.auth.FirebaseAuth

@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun LoginPage(navController: NavController) {
    var email by remember { mutableStateOf("") }
    var password by remember { mutableStateOf("") }

    Column(
        modifier = Modifier.fillMaxSize(),
        horizontalAlignment = Alignment.CenterHorizontally,
        verticalArrangement = Arrangement.Center
    ) {
        TextField(
            value = email,
            onValueChange = { email = it },
            label = { Text("メールアドレス") }
        )
        TextField(
            value = password,
            onValueChange = { password = it },
            label = { Text("パスワード") }
        )
        Spacer(modifier = Modifier.height(16.dp))
        Button(onClick = { performLogin(email, password, navController) }) {
            Text("ログイン")
        }
        Button(onClick = { navController.navigate("signup") }) {
            Text("新規登録はこちら")
        }
    }
}

private fun performLogin(email: String, password: String, navController: NavController) {
    FirebaseAuth.getInstance().signInWithEmailAndPassword(email, password)
        .addOnCompleteListener { task ->
            if (task.isSuccessful) {
                // ログイン成功、ホーム画面に遷移
                navController.navigate("home")
            } else {
                // エラーハンドリング
            }
        }
}

新規作成のページでアカウントがない人は新しく作成します。ログインページへ戻れるように、AppBarを配置して、バックボタンもつけました。

新規作成ページ
SignUpPage.kt
package com.example.firebaseauthapp.view

import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.ArrowBack
import androidx.compose.material3.Button
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.material3.TextField
import androidx.compose.material3.TopAppBar
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import androidx.navigation.NavController
import com.google.firebase.auth.FirebaseAuth

@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun SignUpPage(navController: NavController) {
    var email by remember { mutableStateOf("") }
    var password by remember { mutableStateOf("") }

    Scaffold(
        topBar = {
            TopAppBar(title = { Text("新規登録") },
                navigationIcon = {
                    IconButton(onClick = { navController.navigateUp() }) {
                        Icon(Icons.Filled.ArrowBack, contentDescription = "戻る")
                    }
                }
            )
        }
    ) {
        Column(
            modifier = Modifier
                .fillMaxSize()
                .padding(it)
                .padding(16.dp),
            horizontalAlignment = Alignment.CenterHorizontally,
            verticalArrangement = Arrangement.Center
        ) {
            TextField(
                value = email,
                onValueChange = { email = it },
                label = { Text("メールアドレス") }
            )
            TextField(
                value = password,
                onValueChange = { password = it },
                label = { Text("パスワード") }
            )
            Spacer(modifier = Modifier.height(16.dp))
            Button(onClick = { performSignUp(email, password, navController) }) {
                Text("新規登録")
            }
        }
    }
}


private fun performSignUp(email: String, password: String, navController: NavController) {
    FirebaseAuth.getInstance().createUserWithEmailAndPassword(email, password)
        .addOnCompleteListener { task ->
            if (task.isSuccessful) {
                // 登録成功、ログイン画面に遷移
                navController.navigate("login")
            } else {
                // エラーハンドリング
            }
        }
}

ログインしたら表示されるページには、ユーザーのメールアドレス表示を表示するテキストと、ログアウトボタンを配置してます。

ログイン後のページ
HomePage.kt
package com.example.firebaseauthapp.view

import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.height
import androidx.compose.material3.Button
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import androidx.navigation.NavController
import com.google.firebase.auth.FirebaseAuth

@Composable
fun HomePage(navController: NavController) {
    val user = FirebaseAuth.getInstance().currentUser

    Column(
        modifier = Modifier.fillMaxSize(),
        horizontalAlignment = Alignment.CenterHorizontally,
        verticalArrangement = Arrangement.Center
    ) {
        Text(text = "ようこそ、${user?.email ?: "ゲスト"}さん!")
        Spacer(modifier = Modifier.height(16.dp))
        Button(onClick = { performLogout(navController) }) {
            Text("ログアウト")
        }
    }
}

private fun performLogout(navController: NavController) {
    FirebaseAuth.getInstance().signOut()
    navController.navigate("login")
}

アプリを実行するMainActivity.ktには、画面遷移のルートの定義してます。

アプリを実行するファイル
MainActivity.kt
package com.example.firebaseauthapp

import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.*
import androidx.compose.material3.*
import androidx.compose.ui.Modifier
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
import androidx.navigation.compose.rememberNavController
import com.example.firebaseauthapp.ui.theme.FirebaseAuthAppTheme
import com.example.firebaseauthapp.view.HomePage
import com.example.firebaseauthapp.view.LoginPage
import com.example.firebaseauthapp.view.SignUpPage

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            FirebaseAuthAppTheme {
                Surface(
                    modifier = Modifier.fillMaxSize(),
                    color = MaterialTheme.colorScheme.background
                ) {
                    FirebaseAuthAppTheme {
                        val navController = rememberNavController()
                        // 最初に表示するページをstartDestinationで指定
                        NavHost(navController = navController, startDestination = "login") {
                            composable("login") { LoginPage(navController) }
                            composable("signup") { SignUpPage(navController) }
                            composable("home") { HomePage(navController) }
                        }
                    }
                }
            }
        }
    }
}

🚗画面遷移はこんな感じです

ログイン前

新規登録

ログイン後

thoughts

いかがでしたでしょうか?
今回は、Androidのネイティブアプリにメールアドレス・パスワード認証を組み込んでみました。新規登録のページも必要なので、画面遷移のパッケージも今回導入してます。

画面遷移のやり方を紹介した記事
https://zenn.dev/jboy_blog/articles/d48e7ef51ee53f

補足情報

build.gradleで、compileOptionskotlinOptionsを11にしておくと、良いとAndroidに詳しい方から教わりました!

こんな感じ! ビルドは通る

compileOptions {
        sourceCompatibility JavaVersion.VERSION_11// 1.8から11に変更
        targetCompatibility JavaVersion.VERSION_11// 1.8から11に変更
    }
    kotlinOptions {
        jvmTarget = '11'// 1.8から11に変更
    }
Jboy王国メディア

Discussion