본문 바로가기

프로그램/iPhone

MGTwitterEngine 을 이용한 트위터(Twitter) 로그인.

아이폰 개발을 하면서 가장 고생한것이 트위터 연동입니다.
OAuth개념도 없는대다가.. 한국 커뮤니티에서는 좀처럼 자료를 찾기 어려웠습니다. 
되도 않는 영어 실력으로 번역기 돌려가며 구굴링하여 얻는 자료들입니다.
워낙 여기저기에서 얻은 자료들이라. 출처가 불분명합니다. 

여기서 사용한 트위터 연동에는 3가지 기능으로 나누어 놓았습니다. 

1. 로그인뷰 로그인을 하기위한 view. 
인터페이스 빌더로 모양을 잡아주시면됩니다. id입력과 비밀번호 입력창 로그인 버튼을 만들어주시면 됩니다. 

2. MGTwitterEngine 엔진 사용.
사용하기 위해서는 먼저 소스코드를 다운받으셔야합니다. 받아서 프로젝트에 추가해주시면됩니다(설명생략)
link1 : MGTwitterEngine  
link2 : OAuthConsumer 

그리고 연동에서 가장 중요한것을 까먹을뻔했는데 트위터를 이용하기 위해서는 API키가 필요합니다.
API키는 트위터 홈페이지에서 신청해서 받을수있습니다.
하지만 일반 API키로는 인증방식이 까다롭습니다. 트위터에서 제공하는 oauth인증방식은 사용자가
직접 인증코드를 입력해야하는 불편함이 있는데 이것을 개선하기위해서는 트위터에 앱 스크린샷과 함께
인증방식을 xAuth 하고싶다는 요청 메일을 보내셔야합니다. 요청이 성공한다면 xAuth key를 메일로 보내줍니다.
(자세한 내용은 인터넷 검색을 통해서 메일 예문을 찾아보시면 되겠습니다.)
(그래도 모르시는 분들깨는 죄송한 말씀 드립니다.)


3. Twitter Class
파일 새로 만들기로 object-c class 를 만들어줍니다.(이름은 아무거나 사용하셔도 무방합니다.)

일단 먼저 Twitter Class(이하 tc) 해더부터 봅시다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
#import <Foundation/Foundation.h>
#import "MGTwitterEngine.h"
#import "OAuthConsumer.h"
#import "NSXMLDocument.h"
 
extern NSString * const CONSUMER_KEY;
extern NSString * const CONSUMER_SECRET;
 
enum {
    doLogin = 1,
    doMessaging = 2,
};
 
@protocol TwitterDelegate;
 
@interface Twitter : NSObject {
    id<TwitterDelegate> delegate;
     
    MGTwitterEngine *twitterEngine;
    OAToken *token;
     
    NSString *userID;
    NSString *userPS;
    NSString *timestamp;
     
    int actionIndex;
}
@property (nonatomic, assign) id<TwitterDelegate> delegate;
- (id)init;
- (void)Login:(NSString *)name Password:(NSString *)password;
- (void)Logout;
- (BOOL)isLogin;
- (void)twitMessage:(NSString *)message;
- (BOOL)twitMessageWithTwipic:(NSString *)message Image:(UIImage *)image;
 
@end
#pragma mark method to call after response
@protocol TwitterDelegate <NSObject>
@optional
- (void)twloginDidSucceed:(NSString *)userName;
- (void)twloginDidFailWithError:(NSError*)error;
- (void)twmessagingDidSucceed;
- (void)twmessagingDidFailWithError:(NSError*)error;
@end


헤더파일에서 집고 넘어갈것이 있는데
#import "NSXMLDocument.h"
이것은 기본 라이브러리가 아니라 제가 사용하는 기본 xml파서 controller 입니다.
소스 전문은 이 블로그에 찾아보시면 있습니다.

자신이 사용하기 편리한 xml파서를 사용하시는게 좋고.. 이 글에서는 로그인만 다루기때문에
빼놓으셔도 됩니다. 로그인에서는 파서가 필요 없기 때문입니다.

이제 로그인 핵심 기능을 살펴보도록 하겠습니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#import "Twitter.h"
NSString * const CONSUMER_KEY = @"*********************";
NSString * const CONSUMER_SECRET = @"*****************************************";
 
@implementation Twitter
@synthesize delegate;
- (id)init{
    self = [super init];
    twitterEngine = [[MGTwitterEngine alloc] initWithDelegate:self];
    [twitterEngine setUsesSecureConnection:NO];
    [twitterEngine setConsumerKey:CONSUMER_KEY
                           secret:CONSUMER_SECRET];
      
    token = [[OAToken alloc] initWithUserDefaultsUsingServiceProviderName:@"twittertoken" prefix:@"token"];
 
    if (token!=nil) {
        [twitterEngine setAccessToken:token];
    }   
    return self;
}

먼저 초기화 부분인데 엔진을 초기화 및 생성해주며 트위터로부터 발급받은 키를 세팅해줍니다.
그리고 토큰을 받는데 기존에 받아논 토큰이 있는지 확인하고 없을경우 토큰을 생성합니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
- (void)Login:(NSString *)name Password:(NSString *)password {
    actionIndex = doLogin;
    userID = name;
    userPS = password;
    [twitterEngine setUsername:name password:password];
    //토큰 받기
    [twitterEngine getXAuthAccessTokenForUsername:userID password:userPS];
}
- (void)Logout {
    NSArray *keys = [NSArray arrayWithObjects:@"key", @"secret", @"created", @"duration", @"session", @"attributes", @"renewable", nil];
    for(NSString *name in keys) {
        [[NSUserDefaults standardUserDefaults] removeObjectForKey:[OAToken settingsKey:name provider:@"twittertoken" prefix:@"token"]];
    }
    [token release];
    token = nil;
}

로그인&로그아웃 메소드 입니다. 로그인 버튼을 눌렀을경우 이 메소드에 아이디와 비밀번호를 넘겨주면
엔진에서 토큰을 받아옵니다.
로그아웃 요청시 저장된 토큰을 모두 삭제하게 됩니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
-(void) accessTokenReceived:(OAToken *)token forRequest:(NSString *)connectionIdentifier
{
    NSLog(@"accessToken Received  %@", connectionIdentifier);
    [token storeInUserDefaultsWithServiceProviderName:@"twittertoken" prefix:@"token"];
    [twitterEngine setAccessToken:token];
    [delegate twloginDidSucceed:userID];
}
- (void)requestSucceeded:(NSString *)requestIdentifier
{
    switch (actionIndex) {
        case doMessaging:
            [delegate twmessagingDidSucceed];
            break;
        default:
            break;
    }
}
- (void)requestFailed:(NSString *)requestIdentifier withError:(NSError *)error
{
     
    /* 트위터 공식 사이트 Response Codes
     * 200 OK: Success!
     * 304 Not Modified: There was no new data to return.
     * 400 Bad Request: The request was invalid.  An accompanying error message will explain why. This is the status code will be returned during rate limiting.
     * 401 Unauthorized: Authentication credentials were missing or incorrect.
     * 403 Forbidden: The request is understood, but it has been refused.  An accompanying error message will explain why. This code is used when requests are being denied due to update limits.
     * 404 Not Found: The URI requested is invalid or the resource requested, such as a user, does not exists.
     * 406 Not Acceptable: Returned by the Search API when an invalid format is specified in the request.
     * 420 Enhance Your Calm: Returned by the Search and Trends API  when you are being rate limited.
     * 500 Internal Server Error: Something is broken.  Please post to the group so the Twitter team can investigate.
     * 502 Bad Gateway: Twitter is down or being upgraded.
     * 503 Service Unavailable: The Twitter servers are up, but overloaded with requests. Try again later.
     */
     
    NSLog(@"%@",error);
    switch (actionIndex) {
        case doLogin://로그인요청 실패
            [delegate twloginDidFailWithError:error];
            break;
        case doMessaging:
            [delegate twmessagingDidFailWithError:error];
            break;
        default:
            break;
    }
}

토큰 요청이 성공하면 accessTokenReceived 메소드가 호출됩니다.
그리고 토큰을 저장하게됩니다.

만약 실패를 한다면 requestFailed 메소드가 호출되는데 에러코드에 따른 예외처리를 해주시면 됩니다.
저의 경우 로그인 요청과 메세지 요청 두가지를 구분해서 나누어 놨는데 정석이 아니기때문에
원하는 방식으로 예외 처리해주시면 되겠습니다.

[delegate twloginDidSucceed:userID]; 를 보면 알겠지만
tc 를 선언한 클래스의 델리게이트 메소를 호출합니다. 로그인 뷰에서 메소드를 만들어 사용하시면됩니다.
이곳 메소드에서는 로그인 성공시 해야하는 동작들을 구현해주시면 되고 파라미터로 유저명이 넘어가기때문에
따로 보여주거나 처리하시면 됩니다. 유저 패스워드는 따로 저장은 안하고 토큰만 저장합니다.

로그인 뷰에서도 따로 에러났을때 메소드를 구현하셔도 되고 아니면 tc에서 통합적으로 예외처리하셔도 됩니다.
하지만 로그인 실패시 메시지를 띄어주는것이 좋기때문에 이 메소드를 구현하셔야합니다.
[delegate twloginDidFailWithError:error];

(델리게이트에 대해서 모호 하거나 잘 이해가 안되시는분은 따로 뎃글을 달아주시거나 메일로 문의해주시기 바랍니다.)

이제 로그인 확인하는 메소드만 남았습니다.
1
2
3
4
5
6
7
- (BOOL)isLogin {
     
    if (token==nil) {
        token = [[OAToken alloc] initWithUserDefaultsUsingServiceProviderName:@"twittertoken" prefix:@"token"];
    }
    return token==nil ? NO : YES;
}

저장된 토큰이 있는 확인합니다 만약 로그인 한 기록이 있다면 토큰이 남아있을 것이기 때문에
미리 저장된 토큰을 이용하면 됩니다.
지금 사용하는 방식은 한번 로그인하면 토큰을 저장했다가 재사용하는 방식이기때문에 자동로그인과같은
효과가 있습니다. 불필요하면 토큰 저장부분을 삭제하고 로그인 확인하는 방식도 조금 수정이 필요합니다.

이걸로 로그인 부분은 대강 끝난 것 같습니다.