📝 Standard Mission
소셜 로그인 한 가지 이상 구현해보기
- ex. 카카오, 네이버, 구글…
- 단순 화면 전환 뿐만 아니라 이름, 이메일 값 가져와서 TextView에 띄우기
- SDK 사용 가능
✅ 프로젝트 초기 설정
우선 프로젝트를 하나 생성하고 build.gradle(project) 파일 대신 settings.gradle 파일에 Android SDK 레파지토리(Repository)를 설정한다. (이유는 아래 블로그를 참고)
다음 코드를 적고 우측 상단에 있는 Sync Now를 누른다.
// 카카오 sdk 레포지토리 설정
maven { url 'https://devrepo.kakao.com/nexus/content/groups/public/' }
다음으로 build.gradle (app) 파일에 카카오 로그인 모듈을 추가하고 Sync Now를 해준다.
implementation "com.kakao.sdk:v2-user:2.0.1"
카카오 api를 통해 카카오 서버와 통신하기 위해 앱에 인터넷 사용 권한을 설정한다.
mainfests -> AndroidMainfest.xml에서 다음 코드를 적는다.
<!-- 인터넷 사용 권한 설정-->
<uses-permission android:name="android.permission.INTERNET" />
✅ 키 해시 구하기
MainActivity에서 다음 코드를 작성해 키 해시를 구한다. Log를 출력해보면 Hash 값이 나오는 것을 확인할 수 있다.
val keyHash = Utility.getKeyHash(this)
Log.d("Hash", keyHash)
이제 키 해시를 복사하여 android 플랫폼 등록에 사용한다.
플랫폼에 들어가 패키지명과 키 해시 값을 적어준다.
✅ GlobalApplication 생성
Kakao SDK를 사용하기 위해서 Native App Key로 초기화를 해야 한다.
GlobalApplication이란 이름으로 된 코틀린 class를 하나 생성한다.
생성된 class에 다음 코드를 작성하고 appKey에 네이티브 앱 키를 작성한다.
package com.example.sociallogin
import android.app.Application
import com.kakao.sdk.common.KakaoSdk
class GlobalApplication: Application() {
override fun onCreate() {
super.onCreate()
KakaoSdk.init(this, "네이티브 앱 키")
}
}
네이티브 앱 키는 '앱 키' 에서 확인할 수 있다.
✅ AndroidManifest.xml 설정
GlobalApplication을 생성했으면 Mainfset에서 GlobalApplication 클래스가 사용될 수 있도록 한다. 아래의 코드를 application 태그 안에 작성하여 애플리케이션 프로세스가 시작될 때, 애플리케이션의 다른 컴포넌트보다 먼저 실행되게 한다.
android:name=".GlobalApplication"
다음으로 로그인 창이 되는 액티비티를 추가한다. 네이티브 앱 키 부분에는 위에 사용했던 네이티브 앱 키를 복붙 하면 된다. 형식은 kakao + 네이티브 앱 키 를 작성해야 한다. kakao를 작성하지 않고 네이티브 앱 키만 작성할 경우 카카오 로그인 창으로 이동이 안될 수 있다.
<activity
android:exported="true"
android:name="com.kakao.sdk.auth.AuthCodeHandlerActivity">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data
android:host="oauth"
android:scheme="kakao네이티브 앱 키" />
</intent-filter>
</activity>
✅ 카카오 로그인 버튼
아래의 링크에서 버튼 이미지를 다운로드할 수 있다. 다운을 받고 res/drawable 폴더에 넣어준다.
activity_main.xml에 카카오 로그인 버튼을 생성한다.
<ImageButton
android:id="@+id/kakao_login_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/kakao_login_medium_narrow"
android:background="@android:color/transparent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
android:layout_marginBottom="40dp"
/>
MainActivity
이때 로그인 후 이동해야 하는 액티비티를 하나 만들어야 한다.
자신이 원하는 이름으로 액티비티를 하나 만들고 그 액티비티와 연결시킨다.
package com.example.sociallogin
import android.content.Intent
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.widget.Toast
import com.example.sociallogin.databinding.ActivityMainBinding
import com.kakao.sdk.auth.LoginClient
import com.kakao.sdk.auth.model.OAuthToken
import com.kakao.sdk.common.model.AuthErrorCause
import com.kakao.sdk.user.UserApiClient
class MainActivity : AppCompatActivity() {
private lateinit var binding : ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
// 로그인 정보 확인
UserApiClient.instance.accessTokenInfo { tokenInfo, error ->
if (error != null) {
Toast.makeText(this, "토큰 정보 보기 실패", Toast.LENGTH_SHORT).show()
}
else if (tokenInfo != null) {
Toast.makeText(this, "토큰 정보 보기 성공", Toast.LENGTH_SHORT).show()
val intent = Intent(this, SecondActivity::class.java)
startActivity(intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP))
finish()
}
}
// val keyHash = Utility.getKeyHash(this)
// Log.d("Hash", keyHash)
val callback: (OAuthToken?, Throwable?) -> Unit = { token, error ->
if (error != null) {
when {
error.toString() == AuthErrorCause.AccessDenied.toString() -> {
Toast.makeText(this, "접근이 거부 됨(동의 취소)", Toast.LENGTH_SHORT).show()
}
error.toString() == AuthErrorCause.InvalidClient.toString() -> {
Toast.makeText(this, "유효하지 않은 앱", Toast.LENGTH_SHORT).show()
}
error.toString() == AuthErrorCause.InvalidGrant.toString() -> {
Toast.makeText(this, "인증 수단이 유효하지 않아 인증할 수 없는 상태", Toast.LENGTH_SHORT).show()
}
error.toString() == AuthErrorCause.InvalidRequest.toString() -> {
Toast.makeText(this, "요청 파라미터 오류", Toast.LENGTH_SHORT).show()
}
error.toString() == AuthErrorCause.InvalidScope.toString() -> {
Toast.makeText(this, "유효하지 않은 scope ID", Toast.LENGTH_SHORT).show()
}
error.toString() == AuthErrorCause.Misconfigured.toString() -> {
Toast.makeText(this, "설정이 올바르지 않음(android key hash)", Toast.LENGTH_SHORT).show()
}
error.toString() == AuthErrorCause.ServerError.toString() -> {
Toast.makeText(this, "서버 내부 에러", Toast.LENGTH_SHORT).show()
}
error.toString() == AuthErrorCause.Unauthorized.toString() -> {
Toast.makeText(this, "앱이 요청 권한이 없음", Toast.LENGTH_SHORT).show()
}
else -> { // Unknown
Toast.makeText(this, "기타 에러", Toast.LENGTH_SHORT).show()
}
}
}
else if (token != null) {
Toast.makeText(this, "로그인에 성공하였습니다.", Toast.LENGTH_SHORT).show()
val intent = Intent(this, SecondActivity::class.java)
startActivity(intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP))
finish()
}
}
val kakao_login_button = binding.kakaoLoginButton // 로그인 버튼
kakao_login_button.setOnClickListener {
if(LoginClient.instance.isKakaoTalkLoginAvailable(this)){
LoginClient.instance.loginWithKakaoTalk(this, callback = callback)
}else{
LoginClient.instance.loginWithKakaoAccount(this, callback = callback)
}
}
}
}
✅ 로그아웃 버튼, 회원 탈퇴 버튼 생성
로그인을 하면 로그아웃도 필요하고 회원 탈퇴 기능도 필요하다.
그래서 로그인 후 이동되는 액티비티에 로그아웃 버튼과 회원 탈퇴 버튼을 만들었다.
activity_second.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=".SecondActivity">
<Button
android:id="@+id/kakao_logout_button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="20dp"
android:layout_marginBottom="10dp"
android:backgroundTint="#fee500"
android:paddingVertical="12dp"
android:text="로그아웃"
android:textColor="#181600"
android:textSize="20sp"
android:textStyle="bold"
app:layout_constraintBottom_toTopOf="@+id/kakao_unlink_button"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent" />
<Button
android:id="@+id/kakao_unlink_button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="20dp"
android:layout_marginBottom="30dp"
android:backgroundTint="#fee500"
android:paddingVertical="12dp"
android:text="회원탈퇴"
android:textColor="#181600"
android:textSize="20sp"
android:textStyle="bold"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
SecondActivity.kt
import android.content.Intent
import android.content.Intent.FLAG_ACTIVITY_CLEAR_TOP
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.widget.Toast
import com.example.sociallogin.MainActivity
import com.example.sociallogin.databinding.ActivitySecondBinding
import com.kakao.sdk.user.UserApiClient
class SecondActivity : AppCompatActivity() {
private lateinit var binding: ActivitySecondBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivitySecondBinding.inflate(layoutInflater)
setContentView(binding.root)
val kakao_logout_button = binding.kakaoLogoutButton // 로그아웃 버튼
kakao_logout_button.setOnClickListener {
UserApiClient.instance.logout { error ->
if (error != null) {
Toast.makeText(this, "로그아웃 실패 $error", Toast.LENGTH_SHORT).show()
}else {
Toast.makeText(this, "로그아웃 성공", Toast.LENGTH_SHORT).show()
}
val intent = Intent(this, MainActivity::class.java)
startActivity(intent.addFlags(FLAG_ACTIVITY_CLEAR_TOP))
finish()
}
}
val kakao_unlink_button = binding.kakaoUnlinkButton // 회원 탈퇴 버튼
kakao_unlink_button.setOnClickListener {
UserApiClient.instance.unlink { error ->
if (error != null) {
Toast.makeText(this, "회원 탈퇴 실패 $error", Toast.LENGTH_SHORT).show()
}else {
Toast.makeText(this, "회원 탈퇴 성공", Toast.LENGTH_SHORT).show()
val intent = Intent(this, MainActivity::class.java)
startActivity(intent.addFlags(FLAG_ACTIVITY_CLEAR_TOP))
finish()
}
}
}
}
}
✅ 카카오 설정 활성화
코드를 작성하고 실행하기 전에 카카오 로그인 설정을 활성화시켜줘야 정상적으로 실행시킬 수 있다.
✅ 사용자 정보 조회
위 링크를 통해 아래 창을 들어가서 자신이 필요한 정보를 동의를 구해 불러온다.
닉네임과 이메일을 예시로 하여 불러올 것이다.
동의 항목 설정은 위 창과 같이 설정하면 된다.
이제 정보를 받아올 액티비티와 레이아웃을 수정해야 하는데 로그인 후 실행되는 액티비티를 수정한다.
activity_second.xml
<TextView
android:id="@+id/nickname"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="닉네임: "
android:textSize="20sp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/email"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="60dp"
android:layout_marginTop="15dp"
android:text="이메일: "
android:textColor="#181600"
android:textSize="20sp"
android:textStyle="bold"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toBottomOf="@id/nickname" />
SecondActivity.kt
다음 액티비티 코드를 onCreate에 작성한다.
val nickname = binding.nickname // 닉네임
UserApiClient.instance.me { user, error ->
nickname.text = "닉네임: ${user?.kakaoAccount?.profile?.nickname}"
}
val email = binding.email // 이메일
UserApiClient.instance.me { user, error ->
email.text = "이메일: ${user?.kakaoAccount?.email}"
}
✅ 결과물
참고)
'🍞 대외활동 > Univ Makeus Challenge' 카테고리의 다른 글
[데모데이] 3rd UMC DemoDay 회고 (0) | 2023.02.17 |
---|---|
[UMC] Android 9주차 워크북 (Network) - Retrofit2 OpenAPI (0) | 2022.11.27 |
[UMC] 3rd UMC 해커톤 회고 (0) | 2022.11.22 |
[UMC] Android 8주차 워크북 (Database) (0) | 2022.11.21 |
[UMC] Android 7주차 워크북 (Thread) (0) | 2022.11.17 |