Googleアカウント認証+FirebaseAuth with JetpackCompose
OneTapAuthじゃない方(今までのやり方)のGoogle認証+FirebaseAuth認証を実装していきます。
OneTap認証で実装したクラスを拡張していきます。
関連記事
エンドポイント
Googleアカウントのエンドポイント
エンドポイント | |
---|---|
googleSignInClient.signInIntent | Googleアカウント認証画面(アカウント一覧が出る画面)を表示します |
GoogleSignIn.getSignedInAccountFromIntent | 認証画面の戻り値をGoogleAccountに変換します |
FirebaseAuthのエンドポイント
エンドポイント | |
---|---|
GoogleAuthProvider.getCredential(idToken, accessToken) | GoogleアカウントのidTokenからFirebaseAuthのCredentialに取得します |
Firebase.auth.signInWithCredential(firebaseCredential) | FirebaseAuthのCredentialでサインイン処理を行います |
処理の流れ
流れはフローチャートにしました。OneTap認証とほぼ同じ流れになります。
build.gradle
android {
+ def properties = new Properties()
+ properties.load(project.rootProject.file('local.properties').newDataInputStream())
+ def googleOauthServerClientId = properties.getProperty('google_oauth_server_client_id')
+ defaultConfig {
+ buildConfigField("String", "GOOGLE_OAUTH_SERVER_CLIENT_ID", "${googleOauthServerClientId}")
+ }
}
+ // for GoogleSignIn
+ implementation 'com.google.android.gms:play-services-auth:20.6.0'
def googleOauthServerClientId = properties.getProperty('google_oauth_server_client_id')
buildConfigField("String", "GOOGLE_OAUTH_SERVER_CLIENT_ID", "${googleOauthServerClientId}")
GoogleアカウントとFirebaseAuthを紐付けるのに、GoogleアカウントのIdTokenが必要です。
このIdTokenを取得するには、GoogleCloudConsole>対象アプリ>認証情報>OAuth 2.0 クライアント IDのうち、Web clientのクライアントIDが必要になります。
秘密の情報にしておいた方が無難かと思いますので、クライアントIDは「local.properties」に保存しておいて、kotlinからはBuildConfig経由で取得できるようにするための設定になります。
implementation 'com.google.android.gms:play-services-auth:20.6.0'
Googleアカウントの認証には、play-services-authが必要です。
DIの実装
Googleアカウントの認証に使用するGoogleSignInなどのインスタンス生成を追記します。
GoogleSignInOptions.Builder().requestIdToken(oauth_web_client_id)を呼び出すと、GoogleアカウントのIdTokenを取得できるようになります。
@Module
@InstallIn(SingletonComponent::class)
object FirebaseModule {
@Provides
fun auth(): FirebaseAuth = Firebase.auth
/** Google認証(OneTap)用の認証画面構築クラス */
@Provides
fun provideBeginSignInRequest(): BeginSignInRequest =
BeginSignInRequest.builder()
.setGoogleIdTokenRequestOptions(
BeginSignInRequest.GoogleIdTokenRequestOptions.builder()
.setSupported(true)
.setServerClientId(BuildConfig.GOOGLE_OAUTH_SERVER_CLIENT_ID)
.setFilterByAuthorizedAccounts(true)
.build()
)
.build()
/** Google認証(OneTap)用の認証クライアント */
@Provides
fun provideSignInClient(
@ApplicationContext context: Context,
): SignInClient = Identity.getSignInClient(context)
+ /** Google認証(Legacy)用のオプション定義 */
+ @Provides
+ fun provideGoogleSignInOptions(): GoogleSignInOptions =
+ GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
+ .requestIdToken(BuildConfig.GOOGLE_OAUTH_SERVER_CLIENT_ID)
+ .build()
+ /** Google認証(Legacy)用の認証クライアント */
+ @Provides
+ fun provideGoogleSignInClient(
+ @ApplicationContext context: Context,
+ googleSignInOptions: GoogleSignInOptions,
+ ): GoogleSignInClient = GoogleSignIn.getClient(context, googleSignInOptions)
}
インフラ層の実装
Googleアカウント認証画面を起動するためのIntentを生成する関数と、
認証画面からの戻り値を使用してFirebaseAuthでsigninする関数の2つを追加します。
処理の流れは、前述のフローチャートの通りです。
+ fun requestGoogleLegacyAuth(): Intent
+ suspend fun signinGoogleLegacy(resultData: Intent)
class AccountRepositoryImpl @Inject constructor(
private val auth: FirebaseAuth,
private val signInRequest: BeginSignInRequest,
private val signInClient: SignInClient,
+ private val googleSignInClient: GoogleSignInClient,
) : AccountRepository {
+ override fun requestGoogleLegacyAuth(): Intent {
+ return googleSignInClient.signInIntent
+ }
+ override suspend fun signinGoogleLegacy(resultData: Intent) {
+ val googleSignInAccount: GoogleSignInAccount = GoogleSignIn.getSignedInAccountFromIntent(resultData).await()
+ val firebaseCredential = GoogleAuthProvider.getCredential(googleSignInAccount.idToken, null)
+ auth.signInWithCredential(firebaseCredential).await()
+ }
}
UseCaseの実装
class GoogleLegacySigninCase @Inject constructor(
private val accountRepository: AccountRepository,
) {
// ①signin関数
fun signin(launcher: ActivityResultLauncher<Intent>) {
val intent = accountRepository.requestGoogleLegacyAuth()
launcher.launch(intent)
}
// ②onResultSignin関数
suspend fun onResultSignin(result: ActivityResult) {
if (result.resultCode != Activity.RESULT_OK) {
Log.d("GoogleLegacySigninCase", "onResultSignin ${SigninGoogleLegacyError(result.data).resultMessage}")
return
}
val resultData = result.data ?: let {
Log.d("GoogleLegacySigninCase", "onResultSignin result.data is null")
return
}
accountRepository.signinGoogleLegacy(resultData)
}
}
①signin関数
Google認証用のアカウント一覧画面を起動します。
②onResultSignin関数
Google認証用のアカウント一覧画面の戻り値を処理します。
result.resultCodeがActivity.RESULT_OKの場合は、Signin処理を行っています
ViewModelの実装
これはUseCaseを呼び出すだけなので説明は割愛です。
@HiltViewModel
class SigninViewModel @Inject constructor(
private val signinUsecase: SigninUsecase,
private val signupUsecase: SignupUsecase,
private val signOutUsecase: SignOutUsecase,
private val googleOneTapSigninCase: GoogleOneTapSigninCase,
+ private val googleLegacySigninCase: GoogleLegacySigninCase,
accountRepository: AccountRepository,
) : ViewModel() {
/* ...いろいろ実装... */
+ fun onClickSignInWithGoogleLegacy(launcher: ActivityResultLauncher<Intent>) {
+ try {
+ googleLegacySigninCase.signin(launcher)
+ } catch (e: Exception) {
+ val message = e.toSnackbarMessage()
+ SnackbarManager.showMessage(e.toSnackbarMessage())
+ }
+ }
+ fun onResultSignInWithGoogleLegacy(result: ActivityResult) {
+ viewModelScope.launch(
+ context = CoroutineExceptionHandler { _, throwable ->
+ val message = throwable.toSnackbarMessage()
+ SnackbarManager.showMessage(throwable.toSnackbarMessage())
+ },
+ block = {
+ googleLegacySigninCase.onResultSignin(result)
+ },
+ )
+ }
Screenの実装
@Composable
+ private fun GoogleLegacySigninButton(viewModel: SigninViewModel) {
+ // ① Google認証画面ランチャの生成
+ val startForResult = rememberLauncherForActivityResult(
+ contract = ActivityResultContracts.StartActivityForResult(),
+ onResult = viewModel::onResultSignInWithGoogleLegacy,
+ )
+
+ BasicButton(
+ text = R.string.sign_in_with_google_legacy,
+ modifier = Modifier.basicButton(),
+ ) {
+ // ② ボタンクリック
+ viewModel.onClickSignInWithGoogleLegacy(startForResult)
+ }
+ }
① Google認証画面ランチャの生成
rememberLauncherForActivityResultを使って、ActivityResultLauncherを作成します。
ActivityResultLauncherのonResultに、「viewModel.onResultSignInWithGoogleLegacy」を指定して、結果処理を行います。
② ボタンクリック
Googleアカウント認証画面を起動するトリガーです
いざ実行
コードはこちらです。