123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552 |
- //
- // SinaWeibo.m
- // sinaweibo_ios_sdk
- //
- // Created by Wade Cheng on 4/19/12.
- // Copyright (c) 2012 SINA. All rights reserved.
- //
- #import "SinaWeibo.h"
- #import "SinaWeiboRequest.h"
- #import "SinaWeiboAuthorizeView.h"
- #import "SinaWeiboConstants.h"
- @interface SinaWeibo ()
- @property (nonatomic, copy) NSString *appKey;
- @property (nonatomic, copy) NSString *appSecret;
- @property (nonatomic, copy) NSString *appRedirectURI;
- @end
- @implementation SinaWeibo
- @synthesize userID;
- @synthesize accessToken;
- @synthesize expirationDate;
- @synthesize refreshToken;
- @synthesize ssoCallbackScheme;
- @synthesize delegate;
- @synthesize appKey;
- @synthesize appSecret;
- @synthesize appRedirectURI;
- #pragma mark - Memory management
- /**
- * @description 初始化构造函数,返回采用默认sso回调地址构造的SinaWeibo对象
- * @param _appKey: 分配给第三方应用的appkey
- * @param _appSecrect: 分配给第三方应用的appsecrect
- * @param _appRedirectURI: 微博开放平台中授权设置的应用回调页
- * @return SinaWeibo对象
- */
- - (id)initWithAppKey:(NSString *)_appKey appSecret:(NSString *)_appSecrect
- appRedirectURI:(NSString *)_appRedirectURI
- andDelegate:(id<SinaWeiboDelegate>)_delegate
- {
- return [self initWithAppKey:_appKey appSecret:_appSecrect appRedirectURI:_appRedirectURI ssoCallbackScheme:nil andDelegate:_delegate];
- }
- /**
- * @description 初始化构造函数,返回采用默认sso回调地址构造的SinaWeibo对象
- * @param _appKey: 分配给第三方应用的appkey
- * @param _appSecrect: 分配给第三方应用的appsecrect
- * @param _ssoCallbackScheme: sso回调地址,此值应与URL Types中定义的保持一致
- * 若为nil,则初始化为默认格式 sinaweibosso.your_app_key;
- * @param _appRedirectURI: 微博开放平台中授权设置的应用回调页
- * @return SinaWeibo对象
- */
- - (id)initWithAppKey:(NSString *)_appKey appSecret:(NSString *)_appSecrect
- appRedirectURI:(NSString *)_appRedirectURI
- ssoCallbackScheme:(NSString *)_ssoCallbackScheme
- andDelegate:(id<SinaWeiboDelegate>)_delegate
- {
- if ((self = [super init]))
- {
- self.appKey = _appKey;
- self.appSecret = _appSecrect;
- self.appRedirectURI = _appRedirectURI;
- self.delegate = _delegate;
-
- if (!_ssoCallbackScheme)
- {
- _ssoCallbackScheme = [NSString stringWithFormat:@"sinaweibosso.%@://", self.appKey];
- }
- self.ssoCallbackScheme = _ssoCallbackScheme;
-
- requests = [[NSMutableSet alloc] init];
- }
-
- return self;
- }
- - (void)dealloc
- {
- delegate = nil;
-
- for (SinaWeiboRequest* _request in requests)
- {
- _request.sinaweibo = nil;
- }
-
- [request disconnect];
- [request release], request = nil;
- [userID release], userID = nil;
- [accessToken release], accessToken = nil;
- [expirationDate release], expirationDate = nil;
- [appKey release], appKey = nil;
- [appSecret release], appSecret = nil;
- [appRedirectURI release], appRedirectURI = nil;
- [ssoCallbackScheme release], ssoCallbackScheme = nil;
-
- [super dealloc];
- }
- /**
- * @description 清空认证信息
- */
- - (void)removeAuthData
- {
- self.accessToken = nil;
- self.userID = nil;
- self.expirationDate = nil;
-
- NSHTTPCookieStorage* cookies = [NSHTTPCookieStorage sharedHTTPCookieStorage];
- NSArray* sinaweiboCookies = [cookies cookiesForURL:
- [NSURL URLWithString:@"https://open.weibo.cn"]];
-
- for (NSHTTPCookie* cookie in sinaweiboCookies)
- {
- [cookies deleteCookie:cookie];
- }
- }
- #pragma mark - Private methods
- - (void)requestAccessTokenWithAuthorizationCode:(NSString *)code
- {
- NSDictionary *params = [NSDictionary dictionaryWithObjectsAndKeys:
- self.appKey, @"client_id",
- self.appSecret, @"client_secret",
- @"authorization_code", @"grant_type",
- self.appRedirectURI, @"redirect_uri",
- code, @"code", nil];
- [request disconnect];
- [request release], request = nil;
-
- request = [[SinaWeiboRequest requestWithURL:kSinaWeiboWebAccessTokenURL
- httpMethod:@"POST"
- params:params
- delegate:self] retain];
-
- [request connect];
- }
- - (void)requestDidFinish:(SinaWeiboRequest *)_request
- {
- [requests removeObject:_request];
- _request.sinaweibo = nil;
- }
- - (void)requestDidFailWithInvalidToken:(NSError *)error
- {
- if ([delegate respondsToSelector:@selector(sinaweibo:accessTokenInvalidOrExpired:)])
- {
- [delegate sinaweibo:self accessTokenInvalidOrExpired:error];
- }
- }
- - (void)notifyTokenExpired:(id<SinaWeiboRequestDelegate>)requestDelegate
- {
- NSDictionary *userInfo = [NSDictionary dictionaryWithObjectsAndKeys:
- @"Token expired", NSLocalizedDescriptionKey, nil];
-
- NSError *error = [NSError errorWithDomain:kSinaWeiboSDKErrorDomain
- code:21315
- userInfo:userInfo];
-
- if ([delegate respondsToSelector:@selector(sinaweibo:accessTokenInvalidOrExpired:)])
- {
- [delegate sinaweibo:self accessTokenInvalidOrExpired:error];
- }
-
- if ([requestDelegate respondsToSelector:@selector(request:didFailWithError:)])
- {
- [requestDelegate request:nil didFailWithError:error];
- }
- }
- - (void)logInDidCancel
- {
- if ([delegate respondsToSelector:@selector(sinaweiboLogInDidCancel:)])
- {
- [delegate sinaweiboLogInDidCancel:self];
- }
- }
- - (void)logInDidFinishWithAuthInfo:(NSDictionary *)authInfo
- {
- NSString *access_token = [authInfo objectForKey:@"access_token"];
- NSString *uid = [authInfo objectForKey:@"uid"];
- NSString *remind_in = [authInfo objectForKey:@"remind_in"];
- NSString *refresh_token = [authInfo objectForKey:@"refresh_token"];
- if (access_token && uid)
- {
- if (remind_in != nil)
- {
- int expVal = [remind_in intValue];
- if (expVal == 0)
- {
- self.expirationDate = [NSDate distantFuture];
- }
- else
- {
- self.expirationDate = [NSDate dateWithTimeIntervalSinceNow:expVal];
- }
- }
-
- self.accessToken = access_token;
- self.userID = uid;
- self.refreshToken = refresh_token;
-
- if ([delegate respondsToSelector:@selector(sinaweiboDidLogIn:)])
- {
- [delegate sinaweiboDidLogIn:self];
- }
- }
- }
- - (void)logInDidFailWithErrorInfo:(NSDictionary *)errorInfo
- {
- NSString *error_code = [errorInfo objectForKey:@"error_code"];
- if ([error_code isEqualToString:@"21330"])
- {
- [self logInDidCancel];
- }
- else
- {
- if ([delegate respondsToSelector:@selector(sinaweibo:logInDidFailWithError:)])
- {
- NSString *error_description = [errorInfo objectForKey:@"error_description"];
- NSDictionary *userInfo = [NSDictionary dictionaryWithObjectsAndKeys:
- errorInfo, @"error",
- error_description, NSLocalizedDescriptionKey, nil];
- NSError *error = [NSError errorWithDomain:kSinaWeiboSDKErrorDomain
- code:[error_code intValue]
- userInfo:userInfo];
- [delegate sinaweibo:self logInDidFailWithError:error];
- }
-
- }
- }
- #pragma mark - Validation
- /**
- * @description 判断是否登录
- * @return YES为已登录;NO为未登录
- */
- - (BOOL)isLoggedIn
- {
- return userID && accessToken && expirationDate;
- }
- /**
- * @description 判断登录是否过期
- * @return YES为已过期;NO为未为期
- */
- - (BOOL)isAuthorizeExpired
- {
- NSDate *now = [NSDate date];
- return ([now compare:expirationDate] == NSOrderedDescending);
- }
- /**
- * @description 判断登录是否有效,当已登录并且登录未过期时为有效状态
- * @return YES为有效;NO为无效
- */
- - (BOOL)isAuthValid
- {
- return ([self isLoggedIn] && ![self isAuthorizeExpired]);
- }
- #pragma mark - LogIn / LogOut
- /**
- * @description 登录入口,当初始化SinaWeibo对象完成后直接调用此方法完成登录
- */
- - (void)logIn
- {
- if ([self isAuthValid])
- {
- if ([delegate respondsToSelector:@selector(sinaweiboDidLogIn:)])
- {
- [delegate sinaweiboDidLogIn:self];
- }
- }
- else
- {
- [self removeAuthData];
-
- ssoLoggingIn = NO;
-
- // open sina weibo app
- UIDevice *device = [UIDevice currentDevice];
- if ([device respondsToSelector:@selector(isMultitaskingSupported)] &&
- [device isMultitaskingSupported])
- {
- NSDictionary *params = [NSMutableDictionary dictionaryWithObjectsAndKeys:
- self.appKey, @"client_id",
- self.appRedirectURI, @"redirect_uri",
- self.ssoCallbackScheme, @"callback_uri", nil];
-
- // 先用iPad微博打开
- NSString *appAuthBaseURL = kSinaWeiboAppAuthURL_iPad;
- if (SinaWeiboIsDeviceIPad())
- {
- NSString *appAuthURL = [SinaWeiboRequest serializeURL:appAuthBaseURL
- params:params httpMethod:@"GET"];
- ssoLoggingIn = [[UIApplication sharedApplication] openURL:[NSURL URLWithString:appAuthURL]];
- }
-
- // 在用iPhone微博打开
- if (!ssoLoggingIn)
- {
- appAuthBaseURL = kSinaWeiboAppAuthURL_iPhone;
- NSString *appAuthURL = [SinaWeiboRequest serializeURL:appAuthBaseURL
- params:params httpMethod:@"GET"];
- ssoLoggingIn = [[UIApplication sharedApplication] openURL:[NSURL URLWithString:appAuthURL]];
- }
- }
-
- if (!ssoLoggingIn)
- {
- // open authorize view
-
- NSDictionary *params = [NSMutableDictionary dictionaryWithObjectsAndKeys:
- self.appKey, @"client_id",
- @"code", @"response_type",
- self.appRedirectURI, @"redirect_uri",
- @"mobile", @"display", nil];
-
- SinaWeiboAuthorizeView *authorizeView = \
- [[SinaWeiboAuthorizeView alloc] initWithAuthParams:params
- delegate:self];
- [authorizeView show];
- [authorizeView release];
- }
- }
- }
- /**
- * @description 退出方法,需要退出时直接调用此方法
- */
- - (void)logOut
- {
- [self removeAuthData];
-
- if ([delegate respondsToSelector:@selector(sinaweiboDidLogOut:)])
- {
- [delegate sinaweiboDidLogOut:self];
- }
- }
- #pragma mark - Send request with token
- /**
- * @description 微博API的请求接口,方法中自动完成token信息的拼接
- * @param url: 请求的接口
- * @param params: 请求的参数,如发微博所带的文字内容等
- * @param httpMethod: http类型,GET或POST
- * @param _delegate: 处理请求结果的回调的对象,SinaweiboRequestDelegate类
- * @return 完成实际请求操作的SinaWeiboRequest对象
- */
- - (SinaWeiboRequest *)requestWithURL:(NSString *)url
- params:(NSMutableDictionary *)params
- httpMethod:(NSString *)httpMethod
- delegate:(id<SinaWeiboRequestDelegate>)_delegate
- {
- if (params == nil)
- {
- params = [NSMutableDictionary dictionary];
- }
-
- if ([self isAuthValid])
- {
- [params setValue:self.accessToken forKey:@"access_token"];
- NSString *fullURL = [kSinaWeiboSDKAPIDomain stringByAppendingString:url];
-
- SinaWeiboRequest *_request = [SinaWeiboRequest requestWithURL:fullURL
- httpMethod:httpMethod
- params:params
- delegate:_delegate];
- _request.sinaweibo = self;
- [requests addObject:_request];
- [_request connect];
- return _request;
- }
- else
- {
- //notify token expired in next runloop
- [self performSelectorOnMainThread:@selector(notifyTokenExpired:)
- withObject:_delegate
- waitUntilDone:NO];
-
- return nil;
- }
- }
- #pragma mark - SinaWeiboAuthorizeView Delegate
- - (void)authorizeView:(SinaWeiboAuthorizeView *)authView didRecieveAuthorizationCode:(NSString *)code
- {
- [self requestAccessTokenWithAuthorizationCode:code];
- }
- - (void)authorizeView:(SinaWeiboAuthorizeView *)authView didFailWithErrorInfo:(NSDictionary *)errorInfo
- {
- [self logInDidFailWithErrorInfo:errorInfo];
- }
- - (void)authorizeViewDidCancel:(SinaWeiboAuthorizeView *)authView
- {
- [self logInDidCancel];
- }
- #pragma mark - SinaWeiboRequest Delegate
- - (void)request:(SinaWeiboRequest *)_request didFailWithError:(NSError *)error
- {
- if (_request == request)
- {
- if ([delegate respondsToSelector:@selector(sinaweibo:logInDidFailWithError:)])
- {
- [delegate sinaweibo:self logInDidFailWithError:error];
- }
-
- [request release], request = nil;
- }
- }
- - (void)request:(SinaWeiboRequest *)_request didFinishLoadingWithResult:(id)result
- {
- if (_request == request)
- {
- NSLog(@"access token result = %@", result);
-
- [self logInDidFinishWithAuthInfo:result];
- [request release], request = nil;
- }
- }
- #pragma mark - Application life cycle
- /**
- * @description 当应用从后台唤起时,应调用此方法,需要完成退出当前登录状态的功能
- */
- - (void)applicationDidBecomeActive
- {
- if (ssoLoggingIn)
- {
- // user open the app manually
- // clean sso login state
- ssoLoggingIn = NO;
-
- if ([delegate respondsToSelector:@selector(sinaweiboLogInDidCancel:)])
- {
- [delegate sinaweiboLogInDidCancel:self];
- }
- }
- }
- /**
- * @description sso回调方法,官方客户端完成sso授权后,回调唤起应用,应用中应调用此方法完成sso登录
- * @param url: 官方客户端回调给应用时传回的参数,包含认证信息等
- * @return YES
- */
- - (BOOL)handleOpenURL:(NSURL *)url
- {
- NSString *urlString = [url absoluteString];
- if ([urlString hasPrefix:self.ssoCallbackScheme])
- {
- if (!ssoLoggingIn)
- {
- // sso callback after user have manually opened the app
- // ignore the request
- }
- else
- {
- ssoLoggingIn = NO;
-
- if ([SinaWeiboRequest getParamValueFromUrl:urlString paramName:@"sso_error_user_cancelled"])
- {
- if ([delegate respondsToSelector:@selector(sinaweiboLogInDidCancel:)])
- {
- [delegate sinaweiboLogInDidCancel:self];
- }
- }
- else if ([SinaWeiboRequest getParamValueFromUrl:urlString paramName:@"sso_error_invalid_params"])
- {
- if ([delegate respondsToSelector:@selector(sinaweibo:logInDidFailWithError:)])
- {
- NSString *error_description = @"Invalid sso params";
- NSDictionary *userInfo = [NSDictionary dictionaryWithObjectsAndKeys:
- error_description, NSLocalizedDescriptionKey, nil];
- NSError *error = [NSError errorWithDomain:kSinaWeiboSDKErrorDomain
- code:kSinaWeiboSDKErrorCodeSSOParamsError
- userInfo:userInfo];
- [delegate sinaweibo:self logInDidFailWithError:error];
- }
- }
- else if ([SinaWeiboRequest getParamValueFromUrl:urlString paramName:@"error_code"])
- {
- NSString *error_code = [SinaWeiboRequest getParamValueFromUrl:urlString paramName:@"error_code"];
- NSString *error = [SinaWeiboRequest getParamValueFromUrl:urlString paramName:@"error"];
- NSString *error_uri = [SinaWeiboRequest getParamValueFromUrl:urlString paramName:@"error_uri"];
- NSString *error_description = [SinaWeiboRequest getParamValueFromUrl:urlString paramName:@"error_description"];
-
- NSDictionary *errorInfo = [NSDictionary dictionaryWithObjectsAndKeys:
- error, @"error",
- error_uri, @"error_uri",
- error_code, @"error_code",
- error_description, @"error_description", nil];
-
- [self logInDidFailWithErrorInfo:errorInfo];
- }
- else
- {
- NSString *access_token = [SinaWeiboRequest getParamValueFromUrl:urlString paramName:@"access_token"];
- NSString *expires_in = [SinaWeiboRequest getParamValueFromUrl:urlString paramName:@"expires_in"];
- NSString *remind_in = [SinaWeiboRequest getParamValueFromUrl:urlString paramName:@"remind_in"];
- NSString *uid = [SinaWeiboRequest getParamValueFromUrl:urlString paramName:@"uid"];
- NSString *refresh_token = [SinaWeiboRequest getParamValueFromUrl:urlString paramName:@"refresh_token"];
-
- NSMutableDictionary *authInfo = [NSMutableDictionary dictionary];
- if (access_token) [authInfo setObject:access_token forKey:@"access_token"];
- if (expires_in) [authInfo setObject:expires_in forKey:@"expires_in"];
- if (remind_in) [authInfo setObject:remind_in forKey:@"remind_in"];
- if (refresh_token) [authInfo setObject:refresh_token forKey:@"refresh_token"];
- if (uid) [authInfo setObject:uid forKey:@"uid"];
-
- [self logInDidFinishWithAuthInfo:authInfo];
- }
- }
- }
- return YES;
- }
- @end
- BOOL SinaWeiboIsDeviceIPad()
- {
- #if __IPHONE_OS_VERSION_MAX_ALLOWED >= 30200
- if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad)
- {
- return YES;
- }
- #endif
- return NO;
- }
|