0

I am attempting to get a user to sign in using their Google account. The android API I am using for to achieve this is the Activity Results API.

When a user clicks the Google button the intent will fire and they're able to select an account to sign-in with. However, the result code of the intent is always RESULT_CANCELLED.

The code below is my attempt.

build.gradle.kts

plugins {
    id("com.android.application")
    id("org.jetbrains.kotlin.android")
}

android {
    namespace = ""
    compileSdk = 33

    defaultConfig {
        applicationId = ""
        minSdk = 24
        targetSdk = 33
        versionCode = 3
        versionName = "1.0"

        testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"

        manifestPlaceholders["appAuthRedirectScheme"] = "SCHEME_TODO"
    }

    buildTypes {
        getByName("release") {
            isMinifyEnabled = 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"
    }
}

dependencies {
    implementation("androidx.core:core-ktx:1.9.0")
    implementation("androidx.appcompat:appcompat:1.5.1")
    implementation("com.google.android.material:material:1.6.1")
    implementation("androidx.constraintlayout:constraintlayout:2.1.4")
    implementation("com.google.android.gms:play-services-auth:20.3.0")
    testImplementation("junit:junit:4.13.2")
    androidTestImplementation("androidx.test.ext:junit:1.1.3")
    androidTestImplementation("androidx.test.espresso:espresso-core:3.4.0")
    // Coil for image loading
    implementation("io.coil-kt:coil-compose:2.2.2")
    val composeBom = platform("androidx.compose:compose-bom:2022.10.00")
    implementation(composeBom)
    androidTestImplementation(composeBom)
    implementation("androidx.compose.material3:material3")
    implementation("androidx.compose.ui:ui-tooling-preview")
    debugImplementation("androidx.compose.ui:ui-tooling")
    androidTestImplementation("androidx.compose.ui:ui-test-junit4")
    debugImplementation("androidx.compose.ui:ui-test-manifest")
    implementation("androidx.compose.material3:material3-window-size-class")
    implementation("androidx.activity:activity-compose:1.5.1")
    implementation("androidx.lifecycle:lifecycle-viewmodel-compose:2.5.1")
    implementation("androidx.compose.runtime:runtime-livedata")
}

MainActivity.kt

class MainActivity : AppCompatActivity() {
    private val GCP_ID = "****************"

    private val TAG = this.javaClass.simpleName

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        val googleLauncher = getStartForResult(
            onSuccess = {
                Toast.makeText(this, it.toString(), Toast.LENGTH_SHORT).show()
            },
            onFailure = {
                Toast.makeText(this, it.toString(), Toast.LENGTH_SHORT).show()
            })
        setContent {
            LoginScreen(onGoogleClick = {
                googleLauncher.launch(getGoogleLoginAuth(this).signInIntent)
            })
        }
    }
    
    private fun getStartForResult(
        onSuccess: (ContinueWithGoogleResult) -> Unit,
        onFailure: (Exception?) -> Unit
    ): ActivityResultLauncher<Intent> {
        return registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
            if (it.resultCode == Activity.RESULT_OK) {
                val intent = it.data
                if (it.data != null) {
                    val task = GoogleSignIn.getSignedInAccountFromIntent(intent)
                    handleSignInResult(task, onSuccess, onFailure)
                } else {
                    Log.e(TAG, "Intent data for sign-in request was unexpectedly null.")
                }
            } else {
                Log.e(TAG, "Sign-in request was unexpectedly cancelled.")
            }
        }
    }

    private fun getGoogleLoginAuth(activity: Activity): GoogleSignInClient =
        GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN).run {
            requestEmail()
            requestIdToken(GCP_ID)
            requestId()
            requestProfile()
            GoogleSignIn.getClient(activity, build())
        }

    private fun handleSignInResult(
        task: Task<GoogleSignInAccount>,
        onSuccess: (ContinueWithGoogleResult) -> Unit,
        onFailure: (Exception?) -> Unit
    ) {
        task.addOnCompleteListener {
            if (it.isSuccessful) {
                val acc = task.result
                val res = ContinueWithGoogleResult(
                    acc.email,
                    acc.displayName,
                    acc.familyName,
                    acc.givenName,
                    acc.id,
                    acc.photoUrl,
                    acc.isExpired
                )
                onSuccess(res)
            } else {
                val ex = task.exception
                onFailure(ex)
            }
        }
    }

    data class ContinueWithGoogleResult(
        val email: String?,
        val displayName: String?,
        val familyName: String?,
        val givenName: String?,
        val id: String?,
        val photoUrl: Uri?,
        val isExpired: Boolean?
    )

    @Composable
    fun LoginScreen(
        onGoogleClick: () -> Unit,
        modifier: Modifier = Modifier
    ) {
        Button(
            onClick = {
                onGoogleClick()
            },
            modifier = Modifier
                .fillMaxWidth()
                .padding(start = 16.dp, end = 16.dp),
            shape = RoundedCornerShape(6.dp),
            colors = ButtonDefaults.buttonColors(
                containerColor = Color.Black,
                contentColor = Color.White
            )
        ) {
            Image(
                painter = rememberAsyncImagePainter(
                    model = ContextCompat.getDrawable(
                        this@MainActivity,
                        R.drawable.btn_google_light_normal_hdpi
                    )
                ),
                contentDescription = ""
            )
            Text(text = "Sign in with Google", modifier = Modifier.padding(6.dp))
        }
    }

}

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">

    <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.MyApp"
        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>

            <meta-data
                android:name="android.app.lib_name"
                android:value="" />
        </activity>
    </application>

</manifest>
dnrandom
  • 71
  • 3
  • Have you considered using the [New Google Sign-In API](https://developers.google.com/identity/sign-in/android/sign-in-identity) that replaces the Google Sign-In APIs you're using here? There was a [previous question](https://stackoverflow.com/q/70850989/1676363) on how to get that working with Jetpack Compose. – ianhanniballake Nov 04 '22 at 18:32

0 Answers0