想要拉到到新浪微博的數據,首先讓本身成爲開發者。申請成爲開發者帳號很簡單,只要有新浪微博的帳號便可。javascript
申請地址:http://open.weibo.com/html
在開發的過程當中,咱們須要拿到幾下幾個值:java
AppKey :分配給每一個第三方應用的 app key。用於鑑權身份,顯示來源等功能。ios
AppSecret :分配給每一個第三方應用的 app 私鑰。git
RedirectURI:應用回調頁面,可在新浪微博開放平臺->個人應用->應用信息->高級應用->受權設置->應用回調頁中找到。github
爲了方便測試,除了可使用當前開發者帳戶外,還能夠本身添加15個關聯測試帳號。web
受權相關文檔:http://open.weibo.com/wiki/%E6%8E%88%E6%9D%83%E6%9C%BA%E5%88%B6json
實現思路:api
直接在cocoapods裏導入如下的類庫網絡
platform :ios,'7.0' pod "AFNetworking","2.5.4" pod 'MBProgressHUD', '~> 0.9.1'
因爲在不少地方都會使用到AFNetworking,爲了避免讓該第三方庫類「污染」,特地給AFNetworking封裝一層,方便之後切換第三方網絡請求類,同時也方便引用管理。
HttpTool.h
#import <Foundation/Foundation.h> @interface HttpTool : NSObject + (void)get:(NSString *)url params:(NSDictionary *)params success:(void (^)(id json))success failure:(void (^)(NSError *error))failure; + (void)post:(NSString *)url params:(NSDictionary *)params success:(void (^)(id json))success failure:(void (^)(NSError *error))failure; @end
HttpTool.m
#import "HttpTool.h" #import "AFNetworking.h" @implementation HttpTool + (void)get:(NSString *)url params:(NSDictionary *)params success:(void (^)(id json))success failure:(void (^)(NSError *error))failure { // 1.建立請求管理者 AFHTTPRequestOperationManager *mgr = [AFHTTPRequestOperationManager manager]; mgr.responseSerializer.acceptableContentTypes = [NSSet setWithObjects:@"application/json", @"text/html", @"text/json", @"text/javascript",@"text/plain", nil]; // 2.發送請求 [mgr GET:url parameters:params success:^(AFHTTPRequestOperation *operation, id responseObject) { if (success) { success(responseObject); } } failure:^(AFHTTPRequestOperation *operation, NSError *error) { if (failure) { failure(error); } }]; } + (void)post:(NSString *)url params:(NSDictionary *)params success:(void (^)(id json))success failure:(void (^)(NSError *error))failure { // 1.建立請求管理者 AFHTTPRequestOperationManager *mgr = [AFHTTPRequestOperationManager manager]; mgr.responseSerializer.acceptableContentTypes = [NSSet setWithObjects:@"application/json", @"text/html", @"text/json", @"text/javascript",@"text/plain", nil]; // 2.發送請求 [mgr POST:url parameters:params success:^(AFHTTPRequestOperation *operation, id responseObject) { if (success) { success(responseObject); } } failure:^(AFHTTPRequestOperation *operation, NSError *error) { if (failure) { failure(error); } }]; } @end
申請下來的帳號信息,咱們使用經常使用來存儲,固然,一些經常使用的不變的通用字符串,咱們也統一放在常量裏,須要避免使用宏。能夠參考:http://www.jianshu.com/p/f83335e036b5
Const.h
#import <Foundation/Foundation.h> extern NSString * const AppKey; extern NSString * const RedirectURI; extern NSString * const AppSecret;
Const.m
#import "Const.h" // 帳號信息 NSString * const AppKey = @"762197719"; NSString * const RedirectURI = @"http://www.baidu.com"; NSString * const AppSecret = @"89d739c387e3a69aaad0270da66c02ff";
因爲access_token不常常變,咱們須要將拿到的access_token歸檔存起來,每次登陸的時候,先判斷access_token是否有效(存在且不過時)。
歸檔使用模型,須要實現NSCoding協議,定義模型
Account.h
#import <Foundation/Foundation.h> @interface Account : NSObject<NSCoding> /** string 用於調用access_token,接口獲取受權後的access token。*/ @property (nonatomic, copy) NSString *access_token; /** string access_token的生命週期,單位是秒數。*/ @property (nonatomic, copy) NSNumber *expires_in; /** string 當前受權用戶的UID。*/ @property (nonatomic, copy) NSString *uid; /** access token的建立時間 */ @property (nonatomic, strong) NSDate *created_time; /** 用戶的暱稱 */ @property (nonatomic, copy) NSString *name; + (instancetype)accountWithDict:(NSDictionary *)dict; @end
Account.m
#import "Account.h" @implementation Account +(instancetype)accountWithDict:(NSDictionary *)dict { Account *account = [[self alloc] init]; account.access_token = dict[@"access_token"]; account.uid = dict[@"uid"]; account.expires_in = dict[@"expires_in"]; // 得到帳號存儲的時間(accessToken的產生時間) account.created_time = [NSDate date]; return account; } /** * 當一個對象要歸檔進沙盒中時,就會調用這個方法 * 目的:在這個方法中說明這個對象的哪些屬性要存進沙盒 */ - (void)encodeWithCoder:(NSCoder *)encoder { [encoder encodeObject:self.access_token forKey:@"access_token"]; [encoder encodeObject:self.expires_in forKey:@"expires_in"]; [encoder encodeObject:self.uid forKey:@"uid"]; [encoder encodeObject:self.created_time forKey:@"created_time"]; [encoder encodeObject:self.name forKey:@"name"]; } /** * 當從沙盒中解檔一個對象時(從沙盒中加載一個對象時),就會調用這個方法 * 目的:在這個方法中說明沙盒中的屬性該怎麼解析(須要取出哪些屬性) */ - (id)initWithCoder:(NSCoder *)decoder { if (self = [super init]) { self.access_token = [decoder decodeObjectForKey:@"access_token"]; self.expires_in = [decoder decodeObjectForKey:@"expires_in"]; self.uid = [decoder decodeObjectForKey:@"uid"]; self.created_time = [decoder decodeObjectForKey:@"created_time"]; self.name = [decoder decodeObjectForKey:@"name"]; } return self; } @end
爲了方便直接歸檔和從歸檔裏讀取模型,定義一個AccountTool工具類
AccountTool.h
#import <Foundation/Foundation.h> #import "Account.h" @interface AccountTool : NSObject /** * 存儲帳號信息 * * @param account 帳號模型 */ + (void)saveAccount:(Account *)account; /** * 返回帳號信息 * * @return 帳號模型(若是帳號過時,返回nil) */ + (Account *)getAccount; @end
AccountTool.m
// // AccountTool.m // Weibo // // Created by jiangys on 15/10/17. // Copyright © 2015年 Jiangys. All rights reserved. // #import "AccountTool.h" #import "Account.h" // 帳號的存儲路徑 #define AccountPath [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:@"account.archive"] @implementation AccountTool /** * 存儲帳號信息 * * @param account 帳號模型 */ + (void)saveAccount:(Account *)account { // 自定義對象的存儲必須用NSKeyedArchiver,再也不有什麼writeToFile方法 [NSKeyedArchiver archiveRootObject:account toFile:AccountPath]; } /** * 返回帳號信息 * * @return 帳號模型(若是帳號過時,返回nil) */ + (Account *)getAccount { // 加載模型 Account *account = [NSKeyedUnarchiver unarchiveObjectWithFile:AccountPath]; /* 驗證帳號是否過時 */ // 過時的秒數 long long expires_in = [account.expires_in longLongValue]; // 得到過時時間 NSDate *expiresTime = [account.created_time dateByAddingTimeInterval:expires_in]; // 得到當前時間 NSDate *now = [NSDate date]; // 若是expiresTime <= now,過時 /** NSOrderedAscending = -1L, 升序,右邊 > 左邊 NSOrderedSame, 同樣 NSOrderedDescending 降序,右邊 < 左邊 */ NSComparisonResult result = [expiresTime compare:now]; if (result != NSOrderedDescending) { // 過時 return nil; } return account; } @end
控制器須要調用authorize得到的code值,再經過code值獲取access_token
OAuthViewController.h
#import <UIKit/UIKit.h> @interface OAuthViewController : UIViewController @end
OAuthViewController.m
// // OAuthViewController.m // Weibo // // Created by jiangys on 15/10/17. // Copyright © 2015年 Jiangys. All rights reserved. // #import "OAuthViewController.h" #import "Const.h" #import "HttpTool.h" #import "MBProgressHUD+YS.h" #import "Account.h" #import "AccountTool.h" @interface OAuthViewController() <UIWebViewDelegate> @end @implementation OAuthViewController - (void)viewDidLoad { [super viewDidLoad]; // 1.建立一個webView UIWebView *webView=[[UIWebView alloc] init]; webView.frame=self.view.bounds; webView.delegate=self; [self.view addSubview:webView]; // 2.用webView加載新浪登陸頁面 NSString *urlStr=[NSString stringWithFormat:@"https://api.weibo.com/oauth2/authorize?client_id=%@&redirect_uri=%@",AppKey,RedirectURI]; NSURLRequest *requestUrl=[NSURLRequest requestWithURL:[NSURL URLWithString:urlStr]]; [webView loadRequest:requestUrl]; } #pragma mark - webView代理方法 -(void)webViewDidStartLoad:(UIWebView *)webView { [MBProgressHUD showMessage:@"正在加載..."]; } -(void)webViewDidFinishLoad:(UIWebView *)webView { [MBProgressHUD hideHUD]; } -(void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error { [MBProgressHUD hideHUD]; } /** * 監聽全部跳轉方法 */ -(BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType { NSString *url=request.URL.absoluteString; NSRange range=[url rangeOfString:@"code="]; if (range.length != 0) { // 截取code=後面的參數值 NSUInteger fromIndex=NSMaxRange(range); NSString *code=[url substringFromIndex:fromIndex]; // 利用code換取一個accessToken [self accessTokenWithCode:code]; // 禁止加載回調地址 return NO; } return true; } /** * 獲取token * * @param code 受權碼 */ - (void)accessTokenWithCode:(NSString *)code { NSMutableDictionary *params=[NSMutableDictionary dictionary]; params[@"client_id"] = AppKey; params[@"client_secret"] = AppSecret; params[@"grant_type"] = @"authorization_code"; params[@"redirect_uri"] = RedirectURI; params[@"code"] = code; [HttpTool post:@"https://api.weibo.com/oauth2/access_token" params:params success:^(id json) { [MBProgressHUD hideHUD]; // 將返回的帳號字典數據 --> 模型,存進沙盒 Account *account = [Account accountWithDict:json]; // 存儲帳號信息 [AccountTool saveAccount:account]; // 切換窗口的根控制器 UIWindow *window = [UIApplication sharedApplication].keyWindow; [window switchRootViewController]; }failure:^(NSError *error) { [MBProgressHUD hideHUD]; YSLog(@"--MBProgressHUD_error--%@",error); }]; } @end
每次登陸的時候,都須要判斷access_token是否有效(存在且不過時)
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { self.window=[[UIWindow alloc]init]; self.window.frame=[UIScreen mainScreen].bounds; // 2.設置根控制器 Account *account = [AccountTool getAccount]; if (account) { // 以前已經登陸成功過 [self.window switchRootViewController]; } else { self.window.rootViewController = [[OAuthViewController alloc] init]; } [self.window makeKeyAndVisible]; return YES; }
章節源代碼下載:http://pan.baidu.com/s/1sjmoEw1
新浪微博Github:https://github.com/jiangys/Weibo