카카오 소셜로그인을 구현하기 위해서는 우선적으로 카카오 개발자 페이지에 회원가입 후 안드로이드 스튜디오에서 개발중인 내 애플리케이션을 추가해야 한다.
Kakao Developers
카카오 API를 활용하여 다양한 어플리케이션을 개발해보세요. 카카오 로그인, 메시지 보내기, 친구 API, 인공지능 API 등을 제공합니다.
developers.kakao.com
추가하면 네이티브앱 키를 얻을 수가 있다. 얻은 네이티브 앱 키를 strings.xml에 정의해준다.
<string name="kakao_app_key">네이티브앱 키</string>
작성 후 아래 화면처럼 카카오 로그인 활성화 버튼을 눌러준다.
그 다음 모듈을 설정해 주어야 한다. 모듈 설정 관련해서는 카카오 개발자 페이지를 보고 그대로 작성하였다.
maven { url 'https://devrepo.kakao.com/nexus/content/groups/public/' }
이 코드를 setting.gradle 파일에 추가해 주었다. 참고로 이 코드는 gradle을 설정하는 것으로 이 설정을 통해서 android.sdk를 간편하게 연동할 수 있다.
그 다음 모듈을 설정해준다.
implementation "com.kakao.sdk:v2-all:2.12.0" // 전체 모듈 설치, 2.11.0 버전부터 지원
implementation "com.kakao.sdk:v2-user:2.12.0" // 카카오 로그인
implementation "com.kakao.sdk:v2-talk:2.12.0" // 친구, 메시지(카카오톡)
implementation "com.kakao.sdk:v2-story:2.12.0" // 카카오스토리
implementation "com.kakao.sdk:v2-share:2.12.0" // 메시지(카카오톡 공유)
implementation "com.kakao.sdk:v2-navi:2.12.0" // 카카오내비
implementation "com.kakao.sdk:v2-friend:2.12.0" // 카카오톡 소셜 피커, 리소스 번들 파일 포함
자신이 필요한 모듈만 추가해 주어도 된다.
<안드로이드 플랫폼 등록>
안드로이드 플랫폼 등록을 해야하는데 이를 위해선 패키지명과 해시키가 필요하다.
해시키를 얻기 위해선 터미널로 구하는 방법과 코드를 작성해서 구하는 방법이 있는데 나는 코드를 작성하여 구현해 보았다.
*참고*
해시키: 안드로이드 개발 환경에서 가지고 있는 인증서에 대한 해쉬값이다. 즉 고유한 키값이다. 이를 등록하여 카카오 로그인 api를 앱에서 호출할 수 있다.
디버그 해쉬키-> 앱 개발시 디버그 용으로 사용한다.
릴리즈 해쉬키 -> 앱 개발 완료 후 apk 파일 추출시 사용한다
이때 디버그 apk, 릴리즈 apk 모두 릴리즈 해쉬키를 사용해야한다.
해시키를 얻기 위해서 MainActivity에서 코드작성을 통해 구했다.
@RequiresApi(Build.VERSION_CODES.P)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding= ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
try{
val information =
packageManager.getPackageInfo(packageName, PackageManager.GET_SIGNING_CERTIFICATES)
val signatures = information.signingInfo.apkContentsSigners
val md = MessageDigest.getInstance("SHA")
for(signature in signatures){
val md : MessageDigest
md = MessageDigest.getInstance("SHA")
md.update(signature.toByteArray())
var hashcode = String(Base64.encode(md.digest(),0))
Log.d("hashcode", ""+hashcode)
}
}catch(e:Exception){
Log.d("hashcode", "에러::" + e.toString())
}
그다음 build하여 logcat창에서 찍힌 hashcode값을 확인후 입력해준다.
<첫 로그인시 유저에게 받을 항목 설정>
다음으로 유저에게 동의받을 항목을 설정해 준다.
<GlobalApplication 생성>
kakao SDK를 사용하기 위해서 네이티브 앱키를 초기화 해야한다.
class GlobalApplication: Application()
{
override fun onCreate(){
super.onCreate()
KakaoSdk.init(this, getString(R.string.kakao_app_key))
}
}
그리고 GlobalApplication을 앱이 시작할때 다른 컴포넌트들 보다 먼저 실행되도록 Manifest 파일에서 설정한다.
(아래 코드 참조)
<application
android:name=".GlobalApplication"
<Redirect URL 설정>
그다음 카카오 개발자 페이지를 참고하여 Redirect URL을 설정한다. 이는 카카오 인증서버가 지정된 Redirect URL로 인가코드를 보내면 Android SDK가 인가코드를 받아 토큰 받기를 요청한다.
<activity
android:name="com.kakao.sdk.auth.AuthCodeHandlerActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<!-- Redirect URI: "kakao${NATIVE_APP_KEY}://oauth" -->
<data
android:host="oauth"
android:scheme="kakao네이티브앱키" />
</intent-filter>
</activity>
<카카오 로그인 구현>
내가 개발하고 있는 어플상에서는 로그인 페이지가 앱을 시작하자마자 뜨게하고 그다음 MainActivity가 호출될 수 있도록 계획하였다.
1. FirstActivity를 생성하고 앱 시작시 제일 먼저뜨게 해줘야 한다. 이를 위해 Manifest파일에서 intent-filter 부분을 MainActivity 부분에 쓰여져 있던걸 잘라내 FirstActivity 부분에 붙여 넣어준다. 이때 android:exported를 false로 설정해서는 안된다. 인텐트 필터가 없는 경우 android:exported 기본값은 false여야한다. true로 설정시 의미는 다른 앱에서 해당 액티비티가 시작가능하다는 의미이다.
2. 로그인 구현 코드를 작성해준다.
(activity_first)
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".FirstActivity"
android:orientation="vertical">
<ImageButton
android:id="@+id/kakaologin"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:src="@drawable/kakao_login_large_wide"
/>
</LinearLayout>
(FirstActivity)
class FirstActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_first)
//로그인 정보 확인
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, MainActivity::class.java)
startActivity(intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP))
finish()
}
}
val callback: (OAuthToken?, Throwable?) -> Unit={
token,error->
if(error != null){
when{
error.toString()== AccessDenied.toString()->
{
Toast.makeText(this, "접근이 거부됨", Toast.LENGTH_SHORT).show()
}
error.toString() == InvalidClient.toString() -> {
Toast.makeText(this, "유효하지 않은 앱", Toast.LENGTH_SHORT).show()
}
error.toString() == InvalidGrant.toString() -> {
Toast.makeText(this,"인증수단이 유효하지 않아 인증할 수 없는 상태", Toast.LENGTH_SHORT).show()
}
error.toString() == InvalidRequest.toString() -> {
Toast.makeText(this, "요청 파라미터 오류", Toast.LENGTH_SHORT).show()
}
error.toString() == InvalidScope.toString() -> {
Toast.makeText(this, "유효하지 않은 scope ID", Toast.LENGTH_SHORT).show()
}
error.toString() == Misconfigured.toString() -> {
Toast.makeText(this, "설정이 올바르지 않음", Toast.LENGTH_SHORT).show()
}
error.toString() == ServerError.toString() -> {
Toast.makeText(this, "서버 내부 에러", Toast.LENGTH_SHORT).show()
}
error.toString() == Unauthorized.toString() -> {
Toast.makeText(this, "앱이 요청 권한이 없음", Toast.LENGTH_SHORT).show()
}
else->{
Toast.makeText(this, "기타 에러", Toast.LENGTH_SHORT).show()
}
}
}
else if(token != null){
Toast.makeText(this, "로그인에 성공하였습니다", Toast.LENGTH_SHORT).show()
val intent = Intent(this, MainActivity::class.java)
startActivity(intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP))
finish()
}
}
val kakao_login_button = findViewById<ImageButton>(R.id.kakaologin)
kakao_login_button.setOnClickListener{
if(UserApiClient.instance.isKakaoTalkLoginAvailable(this)){
UserApiClient.instance.loginWithKakaoTalk(this, callback = callback)
}
else{
UserApiClient.instance.loginWithKakaoAccount(this, callback = callback)
}
}
}
}
(구현 결과)
<회원탈퇴, 로그아웃 구현>
나의 계획은 HomeFragment내 로그아웃 버튼을 두고 그 버튼 클릭시 로그아웃 및 회원 탈퇴가 구현되어 있는 SecondActivity로 넘어가도록 해줄 것이다.
아래 코드를 통해 HomeFragment -> SecondActivity로 넘어가도록 해준다.
(HomeFragment)
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val view = inflater.inflate(R.layout.fragment_home,container,false)
val outBtn = view.findViewById<ImageButton>(R.id.outBtn)
outBtn.setOnClickListener{
val intent = Intent(getActivity(), SecondActivity::class.java)
startActivity(intent)
}
return view
}
그 다음 SecondActivity를 구현해준다.
(activity_second)
<?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:text="로그아웃"
android:textSize="20sp"
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:text="회원 탈퇴"
android:textSize="20sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
(SecondActivity)
class SecondActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_second)
//로그아웃
val kakao_logout_button=findViewById<Button>(R.id.kakao_logout_button)
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, FirstActivity::class.java)
startActivity(intent.addFlags(FLAG_ACTIVITY_CLEAR_TOP))
finish()
}
}
//회원탈퇴
val kakao_unlink_button=findViewById<Button>(R.id.kakao_unlink_button)
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, FirstActivity::class.java)
startActivity(intent.addFlags(FLAG_ACTIVITY_CLEAR_TOP))
finish()
}
}
}
}
}
'Frontend > Kotlin' 카테고리의 다른 글
Unit 7-1 강의정리 (1) | 2023.01.21 |
---|---|
Unit 6 (0) | 2023.01.18 |
Unit 5 (0) | 2023.01.10 |
RecyclerView구현 (0) | 2022.12.09 |
Unit 3 solution (0) | 2022.11.20 |