⬆️ ⬇️

Add the ability to log in via VKontakte in iOS application

Introduction


Good afternoon, Habr!

Having "exits" on social networks in your application is a very useful thing. And today I would like to share my little experience in "screwing" all the well-known social network to your application. What is interesting about this? And the fact that in some cases the use of full-fledged SDK just does not make sense (we also take into account the fact that the official VKontakte does not have). I just needed to find out the user_id and add the "Tell a Friend " feature. In general, all those who are interested, please under the cat! For sweetness - a bit of coding.



Who will be useful?


Beginners in iOS development, those who want to expand the capabilities of their applications, but do not want to use third-party SDK, and, of course, those who are just keen on this business.



Let's start


For starters, you can read a small " entry " in the official documentation, as well as register your application as Standalone, having received all the necessary keys.

Okay, to get access_token (then without which we can’t live) you will need to send a request of the following type:



http://oauth.vk.com/authorize? client_id=APP_ID& scope=SETTINGS& redirect_uri=REDIRECT_URI& display=DISPLAY& response_type=token 


I will not repeat what all these parameters mean, they are at least painted on the page above, as a maximum - intuitively understandable by name.

')

And now the code!


Hooray hooray, everyone was waiting for this! Let's say in your application there is a certain ViewController , in which there is a button “ Log in via VKontakte”. Good.



We get access_token
Add a few methods to this class. In short: after clicking on the button, we show UIWebView , log in, get tokens, and happily run the rest of the requests.

Attention! The project included Automatic Reference Counting.



 -(IBAction)vkontakteButton:(id)sender { // webView authWebView = [[UIWebView alloc] initWithFrame:CGRectMake(10, 20, 300, 400)]; authWebView.tag = 1024; authWebView.delegate = self; UIButton* closeButton = [UIButton buttonWithType:UIButtonTypeRoundedRect]; [self.view addSubview:authWebView]; [authWebView loadRequest: [NSURLRequest requestWithURL:[NSURL URLWithString:@"http://oauth.vk.com/authorize?client_id=3038779&scope=wall,offline&redirect_uri=oauth.vk.com/blank.html&display=touch&response_type=token"]]]; //     [self.view.window makeKeyAndVisible]; //      closeButton.frame = CGRectMake(5, 15, 20, 20); closeButton.tag = 1025; [closeButton addTarget:self action:@selector(closeWebView:) forControlEvents:UIControlEventTouchUpInside]; [closeButton setTitle:@"x" forState:UIControlStateNormal]; [self.view addSubview:closeButton]; } -(void) closeWebView { [[self.view viewWithTag:1024] removeFromSuperview]; [[self.view viewWithTag:1025] removeFromSuperview]; } -(IBAction)closeWebViewButton:(id)sender { [self closeWebView]; } 


Actually, here we have made all the necessary preparations. I will dwell on the most important thing - the request.



 http://oauth.vk.com/authorize?client_id=APP_ID&scope=wall,offline&redirect_uri=oauth.vk.com/blank.html&display=touch&response_type=token 


client_id = APP_ID - instead of APP_ID , we substitute what we get after registering the application on the site;

scope = wall, offline - we ask for access to work with the wall and to work offline (so that the token does not expire for a long time);

redirect_uri = oauth.vk.com / blank.html - here we find the requested token, the main task is to track the redirection to this page and immediately close the authorization window (the page is completely ugly and the user does not need to see it at all);

display = touch - on the iPhone looks like a native, everything is optimized to work with touch devices;

response_type = token - well, actually, what we want to receive.

Next, we need to track the transition to oauth.vk.com/blank.html . Well, remember, UIWebView has a great webViewDidFinishLoad method that is called after loading the next page (don't forget to add it to the header!).



 -(void) webViewDidFinishLoad:(UIWebView *)webView { // -    NSMutableDictionary* user = [[NSMutableDictionary alloc] init]; //     NSString *currentURL = webView.request.URL.absoluteString; NSRange textRange =[[currentURL lowercaseString] rangeOfString:[@"access_token" lowercaseString]]; //,        if(textRange.location != NSNotFound){ //, ,   NSArray* data = [currentURL componentsSeparatedByCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@"=&"]]; [user setObject:[data objectAtIndex:1] forKey:@"access_token"]; [user setObject:[data objectAtIndex:3] forKey:@"expires_in"]; [user setObject:[data objectAtIndex:5] forKey:@"user_id"]; [self closeWebView]; //      [[VkontakteDelegate sharedInstance] loginWithParams:user]; } else { //    ... textRange =[[currentURL lowercaseString] rangeOfString:[@"access_denied" lowercaseString]]; if (textRange.location != NSNotFound) { UIAlertView* alert = [[UIAlertView alloc] initWithTitle:@"Ooops! something gonna wrong..." message:@"Check your internet connection and try again!" delegate:self cancelButtonTitle:@"Ok" otherButtonTitles: nil]; [alert show]; [self closeWebView]; } } } 


It would be good to handle the moments associated with improper loading, etc., but I will not write an extra code here so as not to clutter up the page.



Tokens got what next?


Then create a singleton to work with the API (the possibilities, of course, can be expanded, here they are small)

Header:



 #import <Foundation/Foundation.h> @interface VkontakteDelegate : NSObject @property NSString *username, *realName, *ID, *link, *email, *access_token; @property UIImage* photo; + (id)sharedInstance; -(void) loginWithParams: (NSMutableDictionary*) params; -(void) postToWall; @end 




Implementation:



 #import "VkontakteDelegate.h" @implementation VkontakteDelegate @synthesize username, realName, ID, photo, access_token, email, link; + (id)sharedInstance { static VkontakteDelegate *__sharedInstance; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ __sharedInstance = [[VkontakteDelegate alloc]init]; }); return __sharedInstance; } - (id) init { access_token = [[NSUserDefaults standardUserDefaults] objectForKey:@"vk_token"]; ID = [[NSUserDefaults standardUserDefaults] objectForKey:@"vk_id"]; return self; } -(void) loginWithParams:(NSMutableDictionary *)params { ID = [params objectForKey:@"user_id"]; access_token = [params objectForKey:@"access_token"]; //, ! [[NSUserDefaults standardUserDefaults] setValue:access_token forKey:@"vk_token"]; [[NSUserDefaults standardUserDefaults] setValue:ID forKey:@"vk_id"]; [[NSUserDefaults standardUserDefaults] synchronize]; //     NSString *urlString = [NSString stringWithFormat:@"https://api.vk.com/method/users.get?uid=%@&access_token=%@", ID, access_token] ; NSURL *url = [NSURL URLWithString:urlString]; NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url]; NSHTTPURLResponse *response = nil; NSError *error = nil; NSData *responseData = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error]; NSString *responseString = [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding]; //    -     ,  ! //      . // , ... NSArray* userData = [responseString componentsSeparatedByCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@"\":{},[]"]]; realName = [userData objectAtIndex:14]; realName = [realName stringByAppendingString:@" "]; realName = [realName stringByAppendingString:[userData objectAtIndex:20]]; // ,  [[NSUserDefaults standardUserDefaults] setValue:@"vkontakte" forKey:@"SignedUpWith"]; [[NSUserDefaults standardUserDefaults] setValue:realName forKey:@"RealUsername"]; [[NSUserDefaults standardUserDefaults] synchronize]; } -(void) postToWall { // -   (   "+") NSString* message = @"vkontakte+wall+posting"; NSString *urlString = [NSString stringWithFormat:@"https://api.vk.com/method/wall.post?uid=%@&message=%@&attachments=http://google.com&access_token=%@", ID, message,access_token] ; NSURL *url = [NSURL URLWithString:urlString]; //,   ,     NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url]; NSHTTPURLResponse *response = nil; NSError *error = nil; NSData *responseData = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error]; NSString *responseString = [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding]; } 




And this is how everything should look like the moment of parsing the server response:



 NSError *jsonParsingError = nil; NSMutableDictionary *userInfo = [NSJSONSerialization JSONObjectWithData:responseData options:0 error:&jsonParsingError]; userInfo = [userInfo objectForKey:@"response"]; realName = [userInfo objectForKey:@"first_name"]; realName = [realName stringByAppendingFormat:[userInfo objectForKey:@"last_name"]]; 


Request for information about the user elementary ( documentation ):



 https://api.vk.com/method/users.get?uid=%@&access_token=%@ 


I will not explain it, we will consider request more difficult. Here he is:



 https://api.vk.com/method/wall.post?uid=%@&message=%@&attachments=http://google.com&access_token=%@ 




What is he like?

uid =% @ - substitute user_id ;

message =% @ - the message we need;

attachments = http: //google.com - add a link to the site;

access_token =% @ - substitute, in fact, the token.

Read more here .



Total


Well, we have achieved our goal. It cost us cheap - hundreds and a half lines of simple code. We avoided searching for ready-made SDKs - we do not need this.

If you want more, please . Just do not forget to ask the user's permission if you want to do something besides the one described above.



At this I will take my leave, I hope, it will be useful for beginners (“hellish progres” - hardly). Waiting for your comments and comments. Thank you for reading, as they say, "thumbs up, subscribe to our channel!"



PS The code may be dirty, but it clearly illustrates the pattern of interaction with the API.

Source: https://habr.com/ru/post/148207/



All Articles