안녕하세요. 앱 실행 시에 카카오 세션 연결 여부 확인 후 카카오 회원 ID를 받아서 서버에 전송 후 해당 유저의 정보들을 다시 내려받아서 앱 동작에 활용하려고 합니다.
문제는 앱 재실행 시 if (session.isOpen) 구문을 타고 카카오 회원정보를 받아서 전역 변수에 저장을 합니다.
[KOSessionTask meTaskWithCompletionHandler:^(KOUser* result, NSError *error) {
if (result) {
// success
NSLog(@"userId=%@", result.ID);
[GlobalVars sharedInstance].current_user.mb_id = [NSString stringWithFormat:@"%@",result.ID];
NSLog(@"nickName=%@", [result propertyForKey:@"nickname"]);
[GlobalVars sharedInstance].current_user.mb_name = [NSString stringWithFormat:@"%@",[result propertyForKey:@"nickname"]];
} else {
// failed
NSLog(@"failed get user info.");
}
}];
이 부분으로 바로 넘어오게 되어 있는데 위 소스 부분을 무시하고 넘어갑니다… 타이밍이 맞지 않는건지…
KOSession *session = [KOSession sharedSession]; 으로 초기화는 되어 있습니다.
보통 카카오 계정을 활용한 자동로그인 구현 시에 이런 방식 말고 다른 방식을 쓰나요?
위 부분은 제가 그냥 이렇게 하면 되겠다 싶어 구현한 부분인데 혹시나 잘못된 방법이 아닌지 문의드립니다.
@iffu 보통 사용자 id, nickname등을 저장할 때는 앱이 실행될 때 매번 호출하는 것이 좋습니다(user/me, 내정보요청). 따라서 기존에 저장하고 있던것과 id가 바뀌지 않았는지 한번 확인도 하면 보안상 좋을것 같습니다.
isOpen의 경우 내정보 요청에 대한것이 아닌, 로그인이 되어 있는지의 여부로서, oauth2에서 말하는 토큰의 만료/재갱신과 관련이 있습니다.
정리를 하자면 위의 meTask… 의 경우 앱이 실행될때 isOpen과는 관련없이 매번 호출하는 것이 좋구요, isOpen을 통해서는 로그인 화면으로 튕겨야 할지 말지를 결정하시면 될것 같습니다~
답변 감사드립니다.
meTask 부분을 appdelegate와
- (void)applicationWillEnterForeground:(UIApplication *)application
- (void)applicationDidBecomeActive:(UIApplication *)application
에도 넣어서 정보를 받아오게 했는데 디버깅을 해보니 통신 시간 때문인지 정보를 받아 오기도 전에 세션 확인 후 로그인 프로세스가 진행 되는 것 같습니다.
[GlobalVars sharedInstance].current_user.mb_id 가 nil 값이 아닐 때까지 시간 여유를 주려고 하는데 방법이 있을까요? 첫 개발이라… 어렵네요
정보를 받아오기 전에 로그인 프로세스가 진행된다는 말씀으로 미뤄어 보아 토큰이 만료(또는 네트워크 이슈로 토큰 갱신이 불가)되어 발생하는 현상으로 보이는데요.
앱의 최초 실행 후 얼마의 시간이 지난 후 앱 재실행을 테스트 해보시는건가요?
if (session.isOpen) {
NSLog(@"accessToken: %@",[KOSession sharedSession].accessToken);
[self kakaoAutoLogin];
}
세션 확인 후 카카오 로그인 프로세스 진입 전에 토큰을 찍어 봤더니 로그에는 찍히고 있습니다.
@iffu
네~ 현재 앱에서 소유한 access token 이 찍힐 순 있습니다. 하지만 그 토큰이 유효한 녀석인지가 문제인데요
앱 최초 실행 후 재 실행까지 얼마의 시간이 소요되었나요?
그리고 찍혔다는 access_token 을 개인 메세지로 좀 보내주세요. 유효성 확인이 필요합니다.
(현재 테스트 중인 앱이 마xx쿨 이란 앱이 맞으신가요?)
@iffu
보내주신 메세지는 잘 읽어보았습니다. 토큰도 유효함을 확인하였구요.
(의심했던 토큰 유효성 만료와는 관련이 없는 현상인 것 같습니다)
로그를 확인해보니 톡을 통해서 로그인 후 토큰을 발급받으시는 것 같은데요
"로그인 프로세스 진입"이라는 게 어떤 현상이 발생하는 건가요?
톡이 잠시 떴다가 다시 앱 화면으로 전환되는 현상인가요? 아니면 동의화면이 다시 보이는 현상인가요?
@openapi_ie 음. 저희 현재 시스템이 카카오 계정만을 쓰는 것은 아니구요, 마xx쿨 자체 계정을 사용 중에 현재 업데이트로 카카오 계정 연동을 추가하려고 합니다.
최초에 카카오 계정 연결 시 숫자로된 카카오 회원 ID를 이용하여 그 아이디를 서비스 서버에 저장을 합니다.
카카오 계정으로 연결된 회원들은 패스워드를 입력 받을 수 없으니 앱 실행 시에 카카오 세션이 열려 있는지 확인을 하고, 열려 있으면 카카오 회원 ID를 받아서 그 값을 서버에 날려 해당 ID에 연결되어 있는 회원정보를 서버에서 응답을 통해 앱이 내려받게 되어있습니다. 이것이 제가 말씀드리는 저희 로그인 프로세스의 의미입니다.
(물론 여러 명이 한개의 폰을 쓰는 경우를 고려하여 로그아웃 및 탈퇴 등의 기능은 모두 대비가 되어 있습니다.)
앱 실행 시에 세션 열려 있는 것 확인 후
- 카카오 회원 정보 요청
- 받은 정보로 서버에 해당 회원이 존재하는지 확인 후 있으면 해당 회원정보 내려줌.
그런데 카카오 회원 ID가 내려오기도 전에 2번을 진행 해버리니 null 파라미터를 서버로 전송하게 되고 서버에서 응답이 제대로 내려오지 않아 바로 앱이 크래쉬가 되는 상황입니다.
@iffu
음 상세한 설명 감사합니다. 제가 저희 로그인 프로세스랑 혼동을 했었군요.
결국 meTaskWithCompletionHandler: 가 호출되지 않아서 발생하는 문제군요.
코드는 있는데 호출되지 않는다면 혹시 UIViewController 의 loadView 또는 viewDidLoad 등(앱의 최초 실행시에는 메모리에 load 되어 있지 않기 때문에 실행되었다가 다른 앱으로 전환 후 다시 재실행할 경우 이미 메모리에 load 가 된 상태라 실행이 되지 않는 함수)에서 meTaskWithCompletionHandler: 를 호출하고 계시진 않나요?
@openapi_ie
메소드 호출 위치를 옮겨 보았으나 meTaskWithCompletionHandler: 가 호출되지 않습니다.
조금 더 살펴보고 댓글 달도록 하겠습니다 답변 감사드립니다.
혹시 해당 현상이 재현되는 샘플 프로젝트롤 간단히 만들어서 올려주실 수 있으실까요?
그러면 제가 원인을 파악하는데 많은 도움이 될 것 같습니다. 감사합니다. 
@iffu
보내주신 샘플 소스를 확인했는데 역시나 제가 말씀드렸던 ViewController.m 의
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
[kakaoLoginBtn setImage:[KOImages kakaoLogoForButton] forState:UIControlStateNormal];
[self.view addSubview:kakaoLoginBtn];
[kakaoLoginBtn addTarget:self
action:@selector(invokeLoginWithTarget:)
forControlEvents:UIControlEventTouchUpInside];
KOSession *session = [KOSession sharedSession];
// 최초 실행 시에는 세션이 열려있지 않을 테니 카카오 계정 연동이 진행되고,
// 다음 앱 실행 시에 세션 오픈 확인 후 카카오 회원정보 요청 및 해당 정보로 로그인 진행합니다.
if (session.isOpen) {
[self getKakaoUserInfo];
[self kakaoAutoLogin];
}
}
이 부분이 문제 인 것 같아요.
이 부분이 제대로 동작하려면 최초 실행시에 카카오 계정 연동 진행 후 토큰을 제대로 발급받은 상태에서
앱을 강제 종료 시킨 후 재실행해야 합니다.
KOSession *session = [KOSession sharedSession];
// 최초 실행 시에는 세션이 열려있지 않을 테니 카카오 계정 연동이 진행되고,
// 다음 앱 실행 시에 세션 오픈 확인 후 카카오 회원정보 요청 및 해당 정보로 로그인 진행합니다.
if (session.isOpen) {
[self getKakaoUserInfo];
[self kakaoAutoLogin];
}
을 적당한 다른 곳에서 호출할 수 있도록 해주세요~
@openapi_ie
네… 그래서 이곳저곳 적당한 곳에 옮겼는데도 해당 부분이 호출이 되지 않네요.
그런데 한가지 이상한 점을 발견했습니다.
- (void)kakaoSessionDidChangeWithNotification:(NSNotification *)notification
{
if ( ! [[KOSession sharedSession] isOpen] ) {
// do something for unauthenticated user
NSLog(@"kakao session disconnect.");
}
else if ( [[KOSession sharedSession] isOpen] ) {
NSLog(@"kakao session connect.");
}
}
이 부분을 통해서 세션 상태를 모니터링해서 로그를 찍어봤는데
앱과 카카오 계정 link 시에
[session openWithCompletionHandler:^(NSError *error) {
if (session.isOpen) {
NSLog(@"login succeeded.");
NSLog(@"accessToken: %@",[KOSession sharedSession].accessToken);
[self kakaoLoginContinue];
}
}];
if (session.isOpen) 이후에 NSLog(@“kakao session disconnect.”); 가 찍힌 다음
NSLog(@“login succeeded.”); 가 찍힙니다.
NSLog(@“login succeeded.”); 가 찍히려면 세션이 오픈되어야 하는 것이 아닌가요?
그 사이나 이후에 세션 커넥트 로그가 찍히지 않습니다. 카카오 accessToken은 제대로 발행되고요.
아무리 봐도 모르겠습니다. ㅠㅠ
@iffu
말씀하신 상황은 카카오 로그인 프로세스 처리 로직상 정상적인 상황입니다.
보내주신 샘플 프로그램 상으로 카카오 로그인 프로세스의 처리는 모두 이상없이 처리됩니다.
문제는 앱 재실행시에 원하는 메소드가 호출되지 않기 때문인데 제가 위에 말씀드렸던 상황에 따라서
viewDidLoad 는 호출될 수도 호출되지 않을 수도 있습니다. 따라서 그 부분을 재실행시(상황에 따라서 호출되는 메소드들이 다를 수 있음)에 항상 실행될 수 있는 적당한 곳으로 옮겨야 하는데요. 제가 실제 앱이 어떻게 동작하는지 알 수 없기 때문에 정확한 위치를 말씀드릴 수 없는 상황입니다.
KOSession *session = [KOSession sharedSession];
// 최초 실행 시에는 세션이 열려있지 않을 테니 카카오 계정 연동이 진행되고,
// 다음 앱 실행 시에 세션 오픈 확인 후 카카오 회원정보 요청 및 해당 정보로 로그인 진행합니다.
if (session.isOpen) {
[self getKakaoUserInfo];
[self kakaoAutoLogin];
}
}
부분을 AppDelegate.m 의 applicationWillEnterForeground: (background에 있다가 foreground로 다시 올라올때 호출)로 옮겨보신 후 아래처럼 한번 해보시겠어요?
- 앱을 제거 후 다시 재설치
- 앱을 최초 실행해서 카카오 로그인 진행 완료.
- 앱을 홈버튼을 눌러서 중지시켰다가 재실행해보면 원하시는 동작이 수행될 것 같아요.
@openapi_ie
답변 감사드립니다.
이런저런 방법을 시도해봤는데 결국은 네트워크 상의 문제로 타이밍이 늦다는 결론을 얻었습니다. 결국은 마지막 로그인 ID를 NSUserdefault에 저장하여 앱 실행 시 사용하는 방법으로 진행하였습니다. 로그아웃, 회원탈퇴 시에 대한 처리도 같이요 ㅎㅎ
도움 주셔서 감사합니다.