抓取數據,須要經過網站的受權web
https://api.weibo.com/oauth2/authorize?client_id=2699927613&redirect_uri=http://digtime.cn json
該連接受權後返回一個code,而後獲取信息api
#import "IWOAuthViewController.h" #import "AFNetworking.h" #import "IWAccount.h" #import "IWTabBarViewController.h" #import "IWNewfeatureViewController.h" @interface IWOAuthViewController () <UIWebViewDelegate> @end @implementation IWOAuthViewController - (void)viewDidLoad { [super viewDidLoad]; // 1.添加webView UIWebView *webView = [[UIWebView alloc] init]; webView.frame = self.view.bounds; [self.view addSubview:webView]; // 2.加載受權頁面(新浪提供的登錄頁面) NSURL *url = [NSURL URLWithString:@"https://api.weibo.com/oauth2/authorize?client_id=2699927613&redirect_uri=http://digtime.cn"]; // 訪問的URL NSURLRequest *request = [NSURLRequest requestWithURL:url]; // 請求該URL [webView loadRequest:request]; }
經過新浪受權後,頁面會直接跳轉到重定向的地址,可是這裏但願受權後,獲取code碼,拿到Token,而後獲取到用戶的數據,而不是直接跳轉到重定向的地址,因此,這裏須要監聽webView的加載,因此,須要攔截webView的全部請求,解決方法,能夠經過添加代理<UIWebViewDelegate>,而後攔截數據。服務器
攔截webView自動請求http://digtime.cn/?code=8b1c66a777fe49b26fd650a4f2dacd98的路徑,而後截取code碼,app
經過code碼獲取accessToken。框架
#pragma mark - webView代理方法 /** * 當webView發送一個請求以前都會先調用這個方法, 詢問代理可不能夠加載這個頁面(請求) * * @param request * * @return YES : 能夠加載頁面, NO : 不能夠加載頁面 */ -(BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType { // 1.請求的URL路徑 NSString *urlStr = request.URL.absoluteString; // 2.判斷字符串裏邊含有'code='字符,目的是攔截該連接,不讓其自動加載,並獲取code碼 // http://digtime.cn/?code=8b1c66a777fe49b26fd650a4f2dacd98 NSRange range = [urlStr rangeOfString:@"code="]; // 3.若是urlStr中包含了code= // if(range.location != NSNotFound) if(range.length) { // 4.獲取code=後面的請求標記(通過用戶受權成功的) int loc = range.location + range.length; NSString *code = [urlStr substringFromIndex:loc]; // 5.發送POST請求給新浪,經過code換取一個accessToken // 發送請求通常用別人封裝好的請求框架 // ASI:HTTP終結者,已經被淘汰 // AFN(AFNetworking)\AFN [self accessTokenWithCode:code]; } NSLog(@"%@", request.URL); return YES; }
具體步驟:網站
1.建立請求管理對象ui
2.封裝請求參數(參數用字典封裝)atom
3.發送請求,請求成功後服務器端響應一個對象responseObjecturl
4.先將字典轉爲模型(建立model,IWAccount.h 取數據放數據很是方便)
5.存儲模型數據---存儲accessToken信息 ---歸檔
5.1獲取沙盒路徑
5.2 拼接文件路徑
5.3 Account.h 須要遵照 NSCoding協議,哪些屬性須要歸檔,哪些須要解檔
5.4 而後須要在IWAppDelegate.m中當應用加載完後,須要判斷用戶之前是否有登錄成功過,沙盒裏邊有數據,而後判斷沙盒數據受權信息是否有過時,若是沒有過時則直接進入微博。
注意:IOS會將服務器返回的json解析成字典
經過code換取一個accessToken方法:
// IWOAuthViewController.m /** * 經過code換取一個accessToken redirect_uri true string 回調地址,需需與註冊應用裏的回調地址一致。 */ -(void)accessTokenWithCode:(NSString *)code { // 發送POST請求給新浪,經過code換取一個accessToken // 發送請求通常用別人封裝好的請求框架,如ASI,AFN(項目中使用這個) // ASI:HTTP終結者,已經被淘汰 // AFN(AFNetworking)\AFN // 1.建立請求管理對象 AFHTTPRequestOperationManager *mgr = [AFHTTPRequestOperationManager manager]; // 說明服務器返回的爲JSON mgr.responseSerializer = [AFJSONResponseSerializer serializer]; // 2.封裝請求參數 NSMutableDictionary *params = [NSMutableDictionary dictionary]; params[@"client_id"] = @"2699927613"; params[@"client_secret"] = @"737ea9bf1343d************"; params[@"grant_type"] = @"authorization_code"; params[@"code"] = code; params[@"redirect_uri"] = @"http://digtime.cn"; // 3.發送請求,參數用字典封裝,請求成功後服務器端響應一個對象responseObject [mgr POST:@"https://api.weibo.com/oauth2/access_token" parameters: params success:^(AFHTTPRequestOperation *operation, id responseObject) { // IWLog(@"請求成功:%@", [responseObject class]);從字典中取出數據 // 4.先將字典轉爲模型(建立model,IWAccount.h 取數據放數據很是方便) IWAccount *account = [IWAccount accountWithDict:responseObject]; // NSString *accessToken = responseObject[@"access_token"]; // 經過返回的數據,判斷受權是否過時,若是過時,則從新受權,打開登錄頁面 // 5.存儲模型數據---存儲accessToken信息 ---歸檔 // 5.1獲取沙盒路徑 NSString *doc = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject]; // 5.2 拼接文件路徑 NSString *file = [doc stringByAppendingPathComponent:@"account.data"]; [NSKeyedArchiver archiveRootObject:account toFile:file]; // 5.3 Account.h 須要遵照 NSCoding協議,哪些屬性須要歸檔,哪些須要解檔 // 5.4 而後須要在IWAppDelegate.m代理中當應用加載完後,須要判斷用戶之前是否有登錄成功過,沙盒裏邊有數據,而後判斷沙盒數據受權信息是否有過時,若是沒有過時則直接進入微博 // 6.新特性去首頁 } failure:^(AFHTTPRequestOperation *operation, NSError *error) { IWLog(@"請求失敗:%@", error); }]; }
帳戶模型:
IWAccount.h
// // IWAccount.h // ItcastWeibo // 賬號模型 #import <Foundation/Foundation.h> // 須要遵照 NSCoding協議,哪些屬性須要歸檔,哪些須要解檔 @interface IWAccount : NSObject <NSCoding> @property (nonatomic, copy) NSString *access_token; // 若是服務器返回的數字很大, 建議用long long(好比主鍵, ID) @property (nonatomic, assign) long long expires_in; @property (nonatomic, assign) long long remind_in; @property (nonatomic, assign) long long uid; + (instancetype)accountWithDict:(NSDictionary *)dict; - (instancetype)initWithDict:(NSDictionary *)dict; @end
IWAccount.m
// // IWAccount.m // ItcastWeibo // #import "IWAccount.h" @implementation IWAccount + (instancetype)accountWithDict:(NSDictionary *)dict{ return [[self alloc] initWithDict:dict]; } - (instancetype)initWithDict:(NSDictionary *)dict{ if(self = [super init]){ // KVC [self setValuesForKeysWithDictionary:dict]; } return self; } // 協議方法1-從文件中解析對象的時候調用 -(id)initWithCoder:(NSCoder *)decoder{ if(self = [super init]){ self.access_token = [decoder decodeObjectForKey:@"access_token"]; self.remind_in = [decoder decodeInt64ForKey:@"remind_in"]; self.expires_in = [decoder decodeInt64ForKey:@"expires_in"]; self.uid = [decoder decodeInt64ForKey:@"uid"]; } return self; } // 協議方法2-將對象寫入文件的時候調用 -(void)encodeWithCoder:(NSCoder *)encoder{ [encoder encodeObject:self.access_token forKey:@"access_token"]; [encoder encodeInt64:self.remind_in forKey:@"remind_in"]; [encoder encodeInt64:self.expires_in forKey:@"expires_in"]; [encoder encodeInt64:self.uid forKey:@"uid"]; } @end
程序代理IWAppDelegate.m中判斷有沒有存儲帳號信息及版本號
// // IWAppDelegate.m // ItcastWeibo #import "IWAppDelegate.h" #import "IWTabBarViewController.h" #import "IWNewfeatureViewController.h" #import "IWOAuthViewController.h" #import "IWAccount.h" @implementation IWAppDelegate - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; // 先判斷有無存儲帳號信息 NSString *doc = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject]; NSString *file = [doc stringByAppendingPathComponent:@"account.data"]; IWAccount *account = [NSKeyedUnarchiver unarchiveObjectWithFile:file]; if (account) { // 以前登陸成功 NSString *key = @"CFBundleVersion"; // 取出沙盒中存儲的上次使用軟件的版本號 NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; NSString *lastVersion = [defaults stringForKey:key]; // 得到當前軟件的版本號 NSString *currentVersion = [NSBundle mainBundle].infoDictionary[key]; if ([currentVersion isEqualToString:lastVersion]) { // 顯示狀態欄 application.statusBarHidden = NO; self.window.rootViewController = [[IWTabBarViewController alloc] init]; } else { // 新版本 self.window.rootViewController = [[IWNewfeatureViewController alloc] init]; // 存儲新版本 [defaults setObject:currentVersion forKey:key]; [defaults synchronize]; } } else { // 以前沒有登陸成功 self.window.rootViewController = [[IWOAuthViewController alloc] init]; } [self.window makeKeyAndVisible]; return YES; }
完整的受權控制器IWOAuthViewController.m代碼:
// // IWOAuthViewController.m // ItcastWeibo // #import "IWOAuthViewController.h" #import "AFNetworking.h" #import "IWAccount.h" #import "IWTabBarViewController.h" #import "IWNewfeatureViewController.h" @interface IWOAuthViewController () <UIWebViewDelegate> @end @implementation IWOAuthViewController - (void)viewDidLoad { [super viewDidLoad]; // 1.添加webView UIWebView *webView = [[UIWebView alloc] init]; webView.frame = self.view.bounds; webView.delegate = self; [self.view addSubview:webView]; // 2.加載受權頁面(新浪提供的登錄頁面) NSURL *url = [NSURL URLWithString:@"https://api.weibo.com/oauth2/authorize?client_id=2699927613&redirect_uri=http://digtime.cn"]; // 訪問的URL NSURLRequest *request = [NSURLRequest requestWithURL:url]; // 請求該URL [webView loadRequest:request]; } #pragma mark - webView代理方法 /** * 當webView發送一個請求以前都會先調用這個方法, 詢問代理可不能夠加載這個頁面(請求) * * @param request * * @return YES : 能夠加載頁面, NO : 不能夠加載頁面 */ -(BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType { // 1.請求的URL路徑 NSString *urlStr = request.URL.absoluteString; // 2.判斷字符串裏邊含有'code='字符,目的是攔截該連接,不讓其自動加載,並獲取code碼 // http://digtime.cn/?code=8b1c66a777fe49b26fd650a4f2dacd98 NSRange range = [urlStr rangeOfString:@"code="]; // 3.若是urlStr中包含了code= // if(range.location != NSNotFound) if(range.length) { // 4.獲取code=後面的請求標記(通過用戶受權成功的) int loc = range.location + range.length; NSString *code = [urlStr substringFromIndex:loc]; // 5.發送POST請求給新浪,經過code換取一個accessToken // 發送請求通常用別人封裝好的請求框架 // ASI:HTTP終結者,已經被淘汰 // AFN(AFNetworking)\AFN [self accessTokenWithCode:code]; } NSLog(@"%@", request.URL); return YES; } /** * 經過code換取一個accessToken redirect_uri true string 回調地址,需需與註冊應用裏的回調地址一致。 */ -(void)accessTokenWithCode:(NSString *)code { // 發送POST請求給新浪,經過code換取一個accessToken // 發送請求通常用別人封裝好的請求框架,如ASI,AFN(項目中使用這個) // ASI:HTTP終結者,已經被淘汰 // AFN(AFNetworking)\AFN // 1.建立請求管理對象 AFHTTPRequestOperationManager *mgr = [AFHTTPRequestOperationManager manager]; // 說明服務器返回的爲JSON mgr.responseSerializer = [AFJSONResponseSerializer serializer]; // 2.封裝請求參數 NSMutableDictionary *params = [NSMutableDictionary dictionary]; params[@"client_id"] = @"2699927613"; params[@"client_secret"] = @"737ea9bf1343****************"; params[@"grant_type"] = @"authorization_code"; params[@"code"] = code; params[@"redirect_uri"] = @"http://digtime.cn"; // 3.發送請求,參數用字典封裝,請求成功後服務器端響應一個對象responseObject [mgr POST:@"https://api.weibo.com/oauth2/access_token" parameters: params success:^(AFHTTPRequestOperation *operation, id responseObject) { // IWLog(@"請求成功:%@", [responseObject class]);從字典中取出數據 // 4.先將字典轉爲模型(建立model,IWAccount.h 取數據放數據很是方便) IWAccount *account = [IWAccount accountWithDict:responseObject]; // NSString *accessToken = responseObject[@"access_token"]; // 經過返回的數據,判斷受權是否過時,若是過時,則從新受權,打開登錄頁面 // 5.存儲模型數據---存儲accessToken信息 ---歸檔 // 5.1獲取沙盒路徑 NSString *doc = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject]; // 5.2 拼接文件路徑 NSString *file = [doc stringByAppendingPathComponent:@"account.data"]; [NSKeyedArchiver archiveRootObject:account toFile:file]; // 5.3 Account.h 須要遵照 NSCoding協議,哪些屬性須要歸檔,哪些須要解檔 // 5.4 而後須要在IWAppDelegate.m中當應用加載完後,須要判斷用戶之前是否有登錄成功過,沙盒裏邊有數據,而後判斷沙盒數據受權信息是否有過時,若是沒有過時則直接進入微博 // 6.新特性去首頁 } failure:^(AFHTTPRequestOperation *operation, NSError *error) { IWLog(@"請求失敗:%@", error); }]; } @end