본문 바로가기
TIL(Today I Learned)

2024.05.07 Today I Learned

by 승환파크 2024. 5. 7.

이번에는 swift 에서 직접 카카오톡 로그인을 만드는 예제를 진행했다.

카카오 로그인 어플 만들기

우선 https://developers.kakao.com/ <- Kakao Developers 에 들어가서 어플을 만들어줘야 한다.

어플리케이션 추가하기를 누른 다음 앱 이름과 사업자명, 카테고리 까지 정해준 다음 저장을 눌러 어플을 만들어준다.

그 이후 들어가보면 이런 화면이 나올것이다.

앱 키는 소중하니 아무한테나 보여주지 말고 혼자 간직하는거로 한다.

 

그런 다음 아래의 사진처럼 플랫폼에 들어가 iOS 플랫폼을 등록한다.

따로 앱스토어에 등록하지 않았으므로 번들 ID 만 입력한다. 번들 ID는 xCode 에서 프로젝트를 생성한 이후 아래의 사진 처럼 프로젝트를 열고 Bundle Identifier 을 보면 확인할 수 있다.

 

그런 다음 아래의 사진 처럼 카카오 로그인을 활성화 시켜주고 OpenID Connect 활성화도 시켜준다.

위의 모든 과정을 완료했으면 일단 사이트에서 해줄 수 있는 기본 설정은 다 마친것이다.

 

카카오 로그인 코드 작성하기

일단 카카오 로그인을 하기 위해서는 Info.plist 를 설정해줘야 한다.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
	<key>CFBundleURLTypes</key>
	<array>
		<dict>
			<key>CFBundleTypeRole</key>
			<string>Editor</string>
			<key>CFBundleURLSchemes</key>
			<array>
				<string>kakao{앱 키}</string>
			</array>
		</dict>
	</array>
	<key>KAKAO_APP_KEY</key>
	<string>{앱 키}</string>
	<key>LSApplicationQueriesSchemes</key>
	<array>
		<string>kakaokompassauth</string>
		<string>kakaolink</string>
		<string>storykompassauth</string>
		<string>storylink</string>
	</array>
	<key>UIApplicationSceneManifest</key>
	<dict>
		<key>UIApplicationSupportsMultipleScenes</key>
		<false/>
		<key>UISceneConfigurations</key>
		<dict>
			<key>UIWindowSceneSessionRoleApplication</key>
			<array>
				<dict>
					<key>UISceneConfigurationName</key>
					<string>Default Configuration</string>
					<key>UISceneDelegateClassName</key>
					<string>$(PRODUCT_MODULE_NAME).SceneDelegate</string>
					<key>UISceneStoryboardFile</key>
					<string>Main</string>
				</dict>
			</array>
		</dict>
	</dict>
</dict>
</plist>

 

일단 Info.plist 를 위의 코드처럼 설정하고 {앱 키} 부분에 카카오 디벨로퍼에서 만든 어플에서 네이티브 앱 키를 입력해서 넣어주면 된다.

 

그런 다음 AppDelegate 에서 아래처럼 코드를 수정 및 추가해주면 된다.

import UIKit
import KakaoSDKCommon
import KakaoSDKAuth

@main
class AppDelegate: UIResponder, UIApplicationDelegate {
    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        KakaoSDK.initSDK(appKey: "{앱 키}")
        return true
    }

    func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {
        if (AuthApi.isKakaoTalkLoginUrl(url)) {
            return AuthController.handleOpenUrl(url: url)
        }
        return false
    }

}

 

위의 코드 처럼 수정한 이후 {앱 키} 부분에 똑같이 네이티브 앱 키를 입력해주면 된다.

이후 ViewController 와 Main.StroyBoard 를 사용해서 코드를 작성하면 된다.

ViewController 부분

import UIKit
import KakaoSDKCommon
import KakaoSDKAuth
import KakaoSDKUser

class ViewController: UIViewController {
    
    // 로그인 상태 확인 레이블
    @IBOutlet weak var loginStatusLableOutlet: UILabel!
    // 로그인 시 보여줄 프로필 사진
    @IBOutlet weak var imageViewOutlet: UIImageView!
    // 로그인 시 보여줄 닉네임 레이블
    @IBOutlet weak var nameLabelOutlet: UILabel!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // 내용 및 사진 초기화
        loginStatusLableOutlet.text = "로그아웃 상태"
        imageViewOutlet.isHidden = true
        imageViewOutlet.image = nil
        nameLabelOutlet.isHidden = true
        self.nameLabelOutlet.text = "닉네임 : "
        // 카카오 SDK 초기화
        KakaoSDK.initSDK(appKey: "{앱 키}")
        // 로그인 상태확인
        self.checkLoginAndAuthenticateIfNeeded()
    }
    
    // 로그인 버튼
    @IBAction func loginButton(_ sender: Any) {
        print("버튼 누름")
        loginWithKakao()
    }
    // 로그아웃 버튼
    @IBAction func logoutButton(_ sender: Any) {
        logout()
        loginStatusLableOutlet.text = "로그아웃 상태"
        self.imageViewOutlet.isHidden = true
        self.imageViewOutlet.image = nil
        self.nameLabelOutlet.isHidden = true
        self.nameLabelOutlet.text = "닉네임 : "
    }
    
    // 유저 정보 가져오기
    func fetchUserProfile() {
        UserApi.shared.me { (user, error) in
            if let error = error {
                print("사용자 정보 요청 실패:", error)
            } else {
                if let user = user {
                    print("사용자 정보 요청 성공: \(user)")
                    self.imageViewOutlet.isHidden = false
                    self.loginStatusLableOutlet.text = "로그인 상태"
                    self.nameLabelOutlet.isHidden = false
                    if let nickname = user.kakaoAccount?.profile?.nickname {
                        print("사용자 닉네임: \(nickname)")
                        self.nameLabelOutlet.text = "닉네임 : \(nickname)"
                    }
                    if let profileImageUrl = user.kakaoAccount?.profile?.thumbnailImageUrl {
                        print("프로필 사진 URL: \(profileImageUrl)")
                        self.imageViewOutlet.load(url: profileImageUrl)
                    }
                }
            }
        }
    }
    
    // 로그인 상태 확인하기
    func checkLoginAndAuthenticateIfNeeded() {
        UserApi.shared.accessTokenInfo { (accessTokenInfo, error) in
            if let error = error {
                print("로그인 상태 확인 실패:", error)
                self.loginWithKakao()
            } else {
                print("현재 로그인 상태 유지 중, AccessToken 유효")
                self.fetchUserProfile()
            }
        }
    }

    // 로그인하기
    func loginWithKakao() {
        // 카카오톡 어플로 로그인하기
        if UserApi.isKakaoTalkLoginAvailable() {
            UserApi.shared.loginWithKakaoTalk { (oauthToken, error) in
                if let error = error {
                    self.handleLoginError(error)
                } else {
                    print("카카오톡 로그인 성공")
                    self.fetchUserProfile()
                }
            }
        // 웹에서 카카오계정으로 로그인 하기
        } else {
            UserApi.shared.loginWithKakaoAccount { (oauthToken, error) in
                if let error = error {
                    self.handleLoginError(error)
                } else {
                    print("카카오계정 로그인 성공")
                    self.fetchUserProfile()
                }
            }
        }
    }
    
    // 로그인 실패 시 나오는 오류 확인하기
    func handleLoginError(_ error: Error) {
        if let sdkError = error as? SdkError {
            switch sdkError {
            case .ClientFailed(let reason, let errorMessage):
                print("클라이언트 오류 발생:", errorMessage ?? "알 수 없는 오류")
                switch reason {
                case .TokenNotFound:
                    print("토큰 없음: 다시 로그인 필요")
                default:
                    print("처리되지 않은 오류:", reason)
                }
            default:
                print("다른 SDK 오류:", sdkError)
            }
        } else {
            print("비SDK 오류:", error.localizedDescription)
        }
    }

    // 로그아웃 기능
    func logout() {
        UserApi.shared.logout { (error) in
            if let error = error {
                print("로그아웃 실패:", error)
            } else {
                print("로그아웃 성공")
            }
        }
    }
}

// 사진에 url 을 삽입하여 출력하기 위한 확장
extension UIImageView {
    func load(url: URL) {
        DispatchQueue.global().async { [weak self] in
            if let data = try? Data(contentsOf: url) {
                if let image = UIImage(data: data) {
                    DispatchQueue.main.async {
                        self?.image = image
                    }
                }
            }
        }
    }
}

 

이건 실제 사용한 코드이고 상황에 따라 내용을 변경 및 수정해서 처리할 수 있다.

위 사진은 Main.Storyboard 사진이다. 이렇게 설정하고 로그인을 진행하면 이름과 프로필 사진을 확인할 수 있다.

 

 

이 사진들은 실제 어플을 테스트해본 사진들이다. 그런데 핸드폰으로 진행하면 아직 오류가 발생한다... 이유는 다음에 더 찾아보는걸로...

'TIL(Today I Learned)' 카테고리의 다른 글

2024.05.10 Today I Learned  (0) 2024.05.10
2024.05.09 Today I Learned  (0) 2024.05.09
2024.05.03 Today I Learned  (1) 2024.05.03
2024.05.02 Today I Learned  (0) 2024.05.02
2024.04.30 Today I Learned  (0) 2024.04.30