Добрый вечер!
Всё началось с того, что необходим был более или менее удобный инструмент для работы с API социальной сети ВКонтакте под iOS. Однако Google меня достаточно быстро расстроил результатами поиска:
Вроде бы всё хорошо, самое главное есть, но вот использование не вызывает приятных ощущений.
Под катом я расскажу, как работает новая версия ВКонтакте iOS SDK, с чего всё начиналось и к чему в итоге пришли.
Предпроект
Началось всё с того, что на работе получили задание подключить к приложению социальные сети. Мы хотели, чтобы пользователь не заметил никакой разницы при взаимодействии с разными социальными сетями (постинг фотографии на стену, отправка сообщения, загрузка фотографий и т.п.).
Было решено поискать готовые решения, которые бы содержали в себе несколько социальных сетей вроде ВКонтакте, Одноклассники, Твиттер и Фэйсбук, но ничего не удалось найти. Использование готовых решений по отдельности не давало нужных результатов, поэтому решили писать свои велосипеды, предварительно изучив Facebook iOS SDK, MGTwitterEngine и несколько других приметных библиотек.
В итоге мы получили ASASocialServices (GitHub).
Проект получился простым в использовании и установке, большее внимание уделялось работе с Twitter и Vkontakte, на Facebook было решено не концентрироваться.
В ASASocialServices работа с тремя социальными сетями (далее речь будет идти только о двух) осуществлялась по единому принципу: программист создаёт UIWebView, позиционирует его и отображает, затем запускает процесс авторизации пользователем приложения и, в зависимости от принятого пользователем решения, вызывается один из трёх блоков-обработчиков (success, error, cancel).
Если рассматривать в контексте, то ViewController.h выглядит примерно так:
#import <UIKit/UIKit.h>
#import "ASASocialServices.h"
@interface ViewController : UIViewController
@property UIWebView *webView;
@property ASATwitterCommunicator *tw;
@end
ViewController.m
#import "ViewController.h"
NSString *const kTWITTER_CONSUMER_KEY = @"v8146mdwpo05uEroMnhozg";
NSString *const kTWITTER_CONSUMER_SECRET = @"5AFkvjCKxqGBRId2fpSQFLClJLKtGcPGS1DzK7o";
@implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// устанавливает WebView в нужной позиции и с нужными размерами
CGRect frame = [[UIScreen mainScreen] bounds];
_webView = [[UIWebView alloc] initWithFrame:frame];
[self.view addSubview:_webView];
// создаем TwitterCommunicator для получения токенов
_tw = [[ASATwitterCommunicator alloc]
initWithWebView:_webView];
// инициируем запрос по получению доступа к пользовательскому аккаунту
[_tw startOnCancelBlock:^{
NSLog(@"User canceled app authorization...");
} onErrorBlock:^(NSError *error) {
NSLog(@"error during app authorization...%@", error);
} onSuccessBlock:^(ASATwitterUserAccount *account) {
NSLog(@"Account: %@", account);
}];
}
@end
Достаточно было заменить ASATwitterCommunicator на ASAVkontakteCommunicator или ASAFacebookCommunicator, чтобы подключить и начать работать с другой социальной сетью.
В последний блок — success, происходила передача пользовательской учетной записи соответствующей сети (токен доступа, идентификатор пользователя, время истечения действия токена доступа и т.д.)
Последующие запросы от лица текущего пользователя можно было производить таким образом:
[account performTwitterMethod:kTWITTER_FOLLOWERS_LIST_URL
HTTPMethod:@"GET"
options:@{@"user_id" : account.twitterUserID,
@"include_entities": @"true"}
success:^(id response) {
NSLog(@"response: %@", response);
}
failure:^(NSError *error) {
NSLog(@"error: %@", error);
}];
Вот как выглядит обновление статуса пользователя в Twitter:
[account performTwitterMethod:kTWITTER_STATUSES_UPDATE_URL
HTTPMethod:@"POST"
options:@{@"status": @"Hello from ASASocialServices Framework!"}
success:^(id response) {
NSLog(@"response: %@", response);
} failure:^(NSError *error) {
NSLog(@"error: %@", error);
}];
Всё бы хорошо, но в ходе использование, поняли, что оставлять за программистом сохранение токена, последующую загрузку было не совсем правильно потому, что наша-то основная цель настолько упростить работу с библиотекой, чтобы не приходилось думать о мелочах вроде этой (библиотека на данном этапе умерла и её разработкой/поддержкой пришлось заниматься одному, как и всеми последующими разработками).
Минусы:
- Программисту необходимо было помнить, что токен доступа можно сохранить и использовать в последующих запросах, а не вешать запросы в success-блок
- Оставлять на программиста настройку и работу с UIWebView было тоже ошибкой
- Библиотека казалась слишком сложной и непонятной, большинству не хотелось думать о том POST или GET использовать при запросах
ВКонтакте iOS SDK v1.0
С ASASocialServices мне больше не хотелось возиться, поэтому решил, что начну писать в свободное время SDK для ВКонтакта. Набросал на листке схему взаимодействия классов, дня два над ней «висел», в итоге решил, что на первую версию похоже — приступил к реализации.
Я люблю Ruby и мне нравятся Rails и, почему-то всегда и до сих пор кажется, что именно они в некоторой степени повлияли на вид Вконтакте iOS SDK.
Пользователь связан с такими объектами, как:
- Группы
- Стена
- Друзья
- Аудио альбомы
- Видео альбомы
- Фотоальбомы
- Записи
- Документы
- тд
У каждого объекта есть список действий, который пользователь может осуществить от своего лица:
- Создать фотоальбом
- Вступить в группу
- Установить/изменить статус
- Получить список друзей, которые сейчас на сайте
- и тд
Вот, как приведенные выше действия будут выглядеть во ВКонтакте iOS SDK v1.0:
Создание фотоальбома:
VKUser *me = [VKUser currentUser];
[[me photoAlbums] createTitle:@"Привет!" description:@"Альбом с фотографиями для Хабра"];
Вступить в группу:
VKUser *me = [VKUser currentUser];
[[me groups] joinGroupID:100500];
Установить статус:
VKUser *me = [VKUser currentUser];
[[me status] setStatus:@"Привет!"];
Получить список друзей, которые сейчас на сайте:
[[[VKUser currentUser] friends] online];
С чего начать?
Предположим, что Вы уже добавили Vkontakte IOS SDK v1.0 к себе в проект и не знаете что делать дальше с этим.
Мы будем работать с классом VKConnector, который позволит нам получит+сохранить+использовать полученный токен доступа единожды, а в нужный момент он уведомит нас, что необходимо обновить токен и вызовет соответствующий метод делегата, который может следовать (а может и нет) VKConnectorProtocol.
Вот, как будет выглядеть самый простой способ подключения в ASAAppDelegate.m:
//
// ASAAppDelegate.m
// Vkontakte iOS SDK_Project
//
// Created by AndrewShmig on 05/27/13.
// Copyright (c) 2013 AndrewShmig. All rights reserved.
//
#import "ASAAppDelegate.h"
#import "ASAViewController.h"
#import "VKUser.h"
static NSString *const kVKAppID = @"3541027";
static NSString *const kVKPermissionsArray = @"photos,friends,wall,audio,video,docs,notes,pages,status,groups,messages";
@implementation ASAAppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
[[VKConnector sharedInstance] setDelegate:self];
[[VKConnector sharedInstance] startWithAppID:kVKAppID
permissons:[kVKPermissionsArray componentsSeparatedByString:@","]];
// Override point for customization after application launch.
self.viewController = [[ASAViewController alloc] initWithNibName:@"ASAViewController" bundle:nil];
self.window.rootViewController = self.viewController;
[self.window makeKeyAndVisible];
return YES;
}
- (void)VKConnector:(VKConnector *)connector willShowModalView:(KGModal *)view
{
NSLog(@"%s", __FUNCTION__);
}
- (void)VKConnector:(VKConnector *)connector willHideModalView:(KGModal *)view
{
NSLog(@"%s", __FUNCTION__);
}
- (void)VKConnector:(VKConnector *)connector accessTokenInvalidated:(VKAccessToken *)accessToken
{
NSLog(@"%s", __FUNCTION__);
NSLog(@"%@", accessToken);
}
- (void)VKConnector:(VKConnector *)connector accessTokenRenewalFailed:(VKAccessToken *)accessToken
{
NSLog(@"%s", __FUNCTION__);
}
- (void)VKConnector:(VKConnector *)connector accessTokenRenewalSucceeded:(VKAccessToken *)accessToken
{
NSLog(@"%s", __FUNCTION__);
VKUser *me = [VKUser currentUser];
[[me friends] online];
}
- (void)VKConnector:(VKConnector *)connector connectionErrorOccured:(NSError *)error
{
NSLog(@"%s", __FUNCTION__);
NSLog(@"error: %@", error);
}
- (void)VKConnector:(VKConnector *)connector parsingErrorOccured:(NSError *)error
{
NSLog(@"%s", __FUNCTION__);
NSLog(@"error: %@", error);
}
@end
После запуска перед пользователем возникает примерно такое модальное окно (использовался KGModal) для авторизации приложения:
Если возникают вопросы или вы не знаете для чего нужен (за что отвечает) тот или иной метод, то обращайтесь смело к документации. Документация сгенерирована при помощи AppleDoc и выглядит в целом следующим образом:
XCode поможет в этом:
В завершение
Статья, как мне кажется, получилась достаточно длинной, так что на этом пока остановлюсь, хотя к сожалению многое не упомянул из того, что планировал (загрузка файлов, обновление токена, обработка ошибок и тд)
Хочу отметить, что проект активно развивается и поддерживается. Текущий статус проекта — «Готов», поэтому в v1.0 будут только исправляться ошибки и вноситься мелкие коррективы. Все глобальные изменения переносятся в v2.0.
Найти самую актуальную версию можно по этой ссылке: https://bitbucket.org/AndrewShmig/vkontakte-ios-sdk-v1.0
Некоторую информацию по Vkontakte iOS SDK v2.0, правда очень краткую, можно найти здесь: https://bitbucket.org/AndrewShmig/vkontakte-ios-sdk-v2.0/wiki/Home
Благодарю за внимание.
Автор: AndrewShmig