로그인 구현 관련 문의

KakaoAuthViewModel.kt
import android.app.Application
import android.util.Log
import androidx.lifecycle.AndroidViewModel
import com.kakao.sdk.auth.AuthApiClient
import com.kakao.sdk.auth.model.OAuthToken
import com.kakao.sdk.common.model.ClientError
import com.kakao.sdk.common.model.ClientErrorCause
import com.kakao.sdk.user.UserApiClient
import com.kakao.sdk.auth.model.Prompt
import com.kakao.sdk.common.model.KakaoSdkError

const val CUSTOM_PROPERTY_VALUE = “custom_value”
const val CUSTOM_PROPERTY_KEY = “custom_key”
const val TAG = “com.example.test111.KakaoAuthViewModel”

class KakaoAuthViewModel(application: Application) : AndroidViewModel(application) {

private val context = application.applicationContext

fun handleKakaoLogin() {
    val callback: (OAuthToken?, Throwable?) -> Unit = { token, error ->
        if (error != null) {
            Log.e(TAG, "카카오 로그인 실패", error)
        } else if (token != null) {
            Log.i(TAG, "카카오 로그인 성공 ${token.accessToken}")
        }
    }

    val serviceTerms = listOf("service")


    if (UserApiClient.instance.isKakaoTalkLoginAvailable(context)) {
        UserApiClient.instance.loginWithKakaoAccount(context, prompts = listOf(Prompt.SELECT_ACCOUNT)) { token, error ->
            if (error != null) {
                Log.e(TAG, "로그인 실패", error)
            }
            else if (token != null) {
                Log.i(TAG, "로그인 성공 ${token.accessToken}")
            }
        }
        UserApiClient.instance.loginWithKakaoTalk(context, serviceTerms = serviceTerms) { token, error ->
            if (error != null) {
                Log.e(TAG, "카카오톡으로 로그인 실패", error)
                if (error is ClientError && error.reason == ClientErrorCause.Cancelled) {
                    return@loginWithKakaoTalk
                }
                UserApiClient.instance.loginWithKakaoAccount(context, callback = callback)
            } else if (token != null) {
                Log.i(TAG, "카카오톡으로 로그인 성공 ${token.accessToken}")
            }
        }
    } else {
        UserApiClient.instance.loginWithKakaoAccount(context, prompts = listOf(Prompt.LOGIN), callback = callback)
    }

    // 추가 동의 받기
    UserApiClient.instance.me { user, error ->
        if (error != null) {
            Log.e(TAG, "사용자 정보 요청 실패", error)
        } else if (user != null) {
            var scopes = mutableListOf<String>()

            if (user.kakaoAccount?.emailNeedsAgreement == true) { scopes.add("account_email") }
            if (user.kakaoAccount?.birthdayNeedsAgreement == true) { scopes.add("birthday") }
            if (user.kakaoAccount?.birthyearNeedsAgreement == true) { scopes.add("birthyear") }
            if (user.kakaoAccount?.genderNeedsAgreement == true) { scopes.add("gender") }
            if (user.kakaoAccount?.phoneNumberNeedsAgreement == true) { scopes.add("phone_number") }
            if (user.kakaoAccount?.profileNeedsAgreement == true) { scopes.add("profile") }
            if (user.kakaoAccount?.ageRangeNeedsAgreement == true) { scopes.add("age_range") }
            if (user.kakaoAccount?.ciNeedsAgreement == true) { scopes.add("account_ci") }

            if (scopes.count() > 0) {
                Log.d(TAG, "사용자에게 추가 동의를 받아야 합니다.")

                UserApiClient.instance.loginWithNewScopes(context, scopes) { token, error ->
                    if (error != null) {
                        Log.e(TAG, "사용자 추가 동의 실패", error)
                    } else {
                        Log.d(TAG, "allowed scopes: ${token!!.scopes}")

                        // 사용자 정보 요청 재시도
                        UserApiClient.instance.me { user, error ->
                            if (error != null) {
                                Log.e(TAG, "사용자 정보 요청 실패", error)
                            } else if (user != null) {
                                Log.i(TAG, "사용자 정보 요청 성공")
                                // 여기서 로그인 완료 처리 등을 할 수 있음
                                Log.i(TAG, "사용자 정보 요청 성공" +
                                        "\n회원번호: ${user.id}" +
                                        "\n이메일: ${user.kakaoAccount?.email}" +
                                        "\n닉네임: ${user.kakaoAccount?.profile?.nickname}" +
                                        "\n프로필사진: ${user.kakaoAccount?.profile?.thumbnailImageUrl}")
                            }
                        }
                    }
                }
            }
        }
    }
    // 사용자 정보 저장 부분 추가
    val properties = mapOf("${CUSTOM_PROPERTY_KEY}" to "${CUSTOM_PROPERTY_VALUE}")

    UserApiClient.instance.updateProfile(properties) { error ->
        if (error != null) {
            Log.e(TAG, "사용자 정보 저장 실패", error)
        }
        else {
            Log.i(TAG, "사용자 정보 저장 성공")
        }
    }

    UserApiClient.instance.loginWithKakaoAccount(context, prompts = listOf(Prompt.CREATE), callback = callback)

    if (AuthApiClient.instance.hasToken()) {
        UserApiClient.instance.accessTokenInfo { tokenInfo, error ->
            if (error != null) {
                Log.e(TAG, "토큰 정보 보기 실패", error)
            }
            else if (tokenInfo != null) {
                Log.i(TAG, "토큰 정보 보기 성공" +
                        "\n회원번호: ${tokenInfo.id}" +
                        "\n만료시간: ${tokenInfo.expiresIn} 초")
            }
        }
    } else {
        Log.i(TAG, "로그인 필요")
    }
    UserApiClient.instance.logout { error ->
        if (error != null) {
            Log.e(TAG, "로그아웃 실패. SDK에서 토큰 삭제됨", error)
        }
        else {
            Log.i(TAG, "로그아웃 성공. SDK에서 토큰 삭제됨")
        }
    }
    UserApiClient.instance.unlink { error ->
        if (error != null) {
            Log.e(TAG, "연결 끊기 실패", error)
        } else {
            Log.i(TAG, "연결 끊기 성공. SDK에서 토큰 삭제 됨")
        }
    }
}

}

MainActivity.kt
package com.example.test111

import android.os.Bundle
import androidx.activity.enableEdgeToEdge
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat

class MainActivity : AppCompatActivity() {

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    enableEdgeToEdge()
    setContentView(R.layout.activity_main)
    ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main)) { v, insets ->
        val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars())
        v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom)
        insets
    }
}

}

MyApplication.kt
package com.example.test111

import android.app.Application
import com.kakao.sdk.common.KakaoSdk

class MyApplication : Application() {
override fun onCreate() {
super.onCreate()
// 다른 초기화 코드들

    // Kakao SDK 초기화
    KakaoSdk.init(this, "{kakao889595c19cf42c64b1e6b101ed398cbe}")
}

}

build.gradle.kts(Module ;app)
import java.util.Properties

plugins {
alias(libs.plugins.androidApplication)
alias(libs.plugins.jetbrainsKotlinAndroid)
}

android {
namespace = “com.example.test111”
compileSdk = 34

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

    testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
}

buildTypes {
    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"
}

}

dependencies {

implementation(libs.androidx.core.ktx)
implementation(libs.androidx.appcompat)
implementation(libs.material)
implementation(libs.androidx.activity)
implementation(libs.androidx.constraintlayout)
testImplementation(libs.junit)
androidTestImplementation(libs.androidx.junit)
androidTestImplementation(libs.androidx.espresso.core)

implementation("com.kakao.sdk:v2-all:2.20.1") // 전체 모듈 설치, 2.11.0 버전부터 지원
implementation("com.kakao.sdk:v2-user:2.20.1") // 카카오 로그인 API 모듈
implementation("com.kakao.sdk:v2-share:2.20.1") // 카카오톡 공유 API 모듈
implementation("com.kakao.sdk:v2-talk:2.20.1") // 카카오톡 채널, 카카오톡 소셜, 카카오톡 메시지 API 모듈
implementation("com.kakao.sdk:v2-friend:2.20.1") // 피커 API 모듈
implementation("com.kakao.sdk:v2-navi:2.20.1") // 카카오내비 API 모듈
implementation("com.kakao.sdk:v2-cert:2.20.1")// 카카오톡 인증 서비스 API 모듈

}

settings.gradle.kts
pluginManagement {
repositories {
google {
content {
includeGroupByRegex(“com\.android.")
includeGroupByRegex("com\.google.
”)
includeGroupByRegex(“androidx.*”)
}
}
mavenCentral()
gradlePluginPortal()
}
}
dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
repositories {
google()
mavenCentral()
maven { url = java.net.URI(“Repository - Nexus Repository Manager”) }
}
}

rootProject.name = “test111”
include(“:app”)

activity_main.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:id=“@+id/main”
android:layout_width=“match_parent”
android:layout_height=“match_parent”
tools:context=“.MainActivity”>

<!-- 카카오톡 버튼 1 - 상단 배치 -->
<ImageButton
    android:id="@+id/kakaoButton1"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:src="@drawable/kakao_login_medium_narrow"
    app:layout_constraintTop_toTopOf="parent"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintEnd_toEndOf="parent"
    android:layout_marginTop="16dp"/>

</androidx.constraintlayout.widget.ConstraintLayout>

지금 이렇게 되어있습니다.
카카오 로그인 버튼을 누르면 로그인이 구현이 되게끔 할려고 계획을 세우고 있습니다.
하지만 문서 페이지에 올라온 예시들 토대로 했으나 코틀린으로 앱 만드는게 익숙치 않아 계속 실패를 합니다.
어떤 것을 수정해야 하는지 알 수 있을까요,?

안녕하세요

우선 KakaoSdk를 초기화할 때는 kakao${app_key} 형식이 아닌 ${app_key} 형식으로 앱 키를 등록하셔야 합니다.
ex) 앱 키가 1a2b3c4d인 경우 `KakaoSdk.init(context, “1a2b3c4d”)

또한 activity_main.xml 파일에 선언된 kakaoButton1에 클릭 리스너 등록이 되어 있지 않아서 버튼을 눌러도 별다른 동작이 없을 것으로 예상됩니다. kakaoButton1에 클릭 리스너를 등록하고 KakaoAuthViewModel.handleKakaoLogin()을 호출한다면 원하시는대로 동작할 것 같아요.

첨부해주신 내용만으로는 어떤 앱을 어떤 방식으로 구현하려고 하는지를 정확하게 알 수 없어서 구체적인 답변을 드리지 못하는 점 양해 부탁드립니다.