Пользователь
0,0
рейтинг
4 марта 2014 в 18:00

Разработка → Создание кастомного UIActivity для публикации фото и текста в социальной сети ВКонтакте tutorial

Во время работы над очередной версией приложения возникла задача сделать публикацию фото в социальной сети ВКонтакте через стандартный контроллер UIActivityViewController.

image

Поиск в сети дал следующие результаты:
  1. Готовой реализации не обнаружено
  2. Есть официальное sdk ВКонтакте: содержит механизмы авторизации, работы с картинками, но не имеет готового класса для загрузки через UIActivityViewController
  3. Есть документация Apple для создания кастомного UIActivity

 

Подготовка к использованию VK SDK


Перед началом работы с VK SDK необходимо создать Standalone-приложение на странице создания приложения. Сохранить ID приложения и заполнить поле «App Bundle для iOS».
Для настройки авторизации через VK App, необходимо настроить URL-протокол приложения:
  • Откройте настройки проекта, выберите раздел «Info».
  • В секции «URL Types» нажмите на +.
  • Введите vk+APP_ID (например, vk1234567) в поля «Indentifier» и «URL Schemes».


 

Работа с SDK


Необходимо инициализировать SDK при запуске приложения методом
[VKSdk initialize:delegate andAppId:APP_ID];

Для авторизации можно использовать метод:
[VKSdk authorize:scope];

В случае успеха у делегата будет вызван метод
-(void) vkSdkDidReceiveNewToken:(VKAccessToken*) newToken;

В случае ошибки (например, пользователь запретил авторизацию)
-(void) vkSdkUserDeniedAccess:(VKError*) authorizationError;

 

UIActivity для ВКонтакте


Следуя документации Apple, создаём наследник UIActivity:

#import <UIKit/UIKit.h>
 
@interface VKontakteActivity : UIActivity
 
- (id)initWithParent:(UIViewController*)parent;
 
@end

Вспомогательный контроллер parent нужен для ввода капчи, вывода сообщений и пр.

Далее переопределяем методы для отображения элемента UIActivity (тип, название и иконку)
- (NSString *)activityType {
    return @"VKActivityTypeVKontakte";
}
 
- (NSString *)activityTitle {
    return @"ВКонтакте";
}
 
- (UIImage *)activityImage {
    return [UIImage imageNamed:@"vk_activity"];
}


Проверяем поддерживает ли наш класс шаринг передаваемых ему activityItems:
- (BOOL)canPerformWithActivityItems:(NSArray *)activityItems {
    for (UIActivityItemProvider *item in activityItems) {
        if ([item isKindOfClass:[UIImage class]]) {
            return YES;
        }
        else if ([item isKindOfClass:[NSString class]])
        {
            return YES;
        }
    }
    return NO;
}


Запоминаем  поддерживаемые нами activityItems:
- (void)prepareWithActivityItems:(NSArray *)activityItems {
    for (id item in activityItems) {
        if ([item isKindOfClass:[NSString class]]) {
            self.string = item;
        }
        else if([item isKindOfClass:[UIImage class]]) {
            self.image = item;
        }
        else if([item isKindOfClass:[NSURL class]]) {
            self.URL = item;
        }
    }
}


Непосредственно при выборе нашего UIActivity проверяем авторизован ли пользователь:
- (void)performActivity{
    [VKSdk initializeWithDelegate:self andAppId:@"3974615"];
    if ([VKSdk wakeUpSession])
    {
        [self postToWall];
    }
    else{
        [VKSdk authorize:@[VK_PER_WALL, VK_PER_PHOTOS]];
    }
}



При успешной авторизации публикуем пост.
-(void)postToWall{
    [self begin];
    if (self.image) {
        [self uploadPhoto];
    }
    else{
        [self uploadText];
    }
}
 
//публикация текста на стене
-(void)uploadText{
	 [self postParameters:@{ VK_API_FRIENDS_ONLY : @(0),
                            VK_API_OWNER_ID : [VKSdk getAccessToken].userId,
                            VK_API_MESSAGE : self.string}];
}
 
//публикация поста на стене
-(void)postParameters:(NSDictionary *)params{
    VKRequest *post = [[VKApi wall] post:params];
    [post executeWithResultBlock: ^(VKResponse *response) {
        NSNumber * postId = response.json[@"post_id"];
        [[UIApplication sharedApplication] openURL:[NSURL URLWithString:[NSString stringWithFormat:@"http://vk.com/wall%@_%@", [VKSdk getAccessToken].userId, postId]]];
        [self end];
    } errorBlock: ^(NSError *error) {
        NSLog(@"Error: %@", error);
        [self end];
    }];
}


При этом если пост содержит картинку, то предварительно загружаем её на сервер.
- (void)uploadPhoto {
    NSString *userId = [VKSdk getAccessToken].userId;
    //предварительная загрузка фото на сервер
    VKRequest *request = [VKApi uploadWallPhotoRequest:self.image parameters:[VKImageParameters jpegImageWithQuality:1.f] userId:[userId integerValue] groupId:0];
	[request executeWithResultBlock: ^(VKResponse *response) {
	    VKPhoto *photoInfo = [(VKPhotoArray*)response.parsedModel objectAtIndex:0];
	    NSString *photoAttachment = [NSString stringWithFormat:@"photo%@_%@", photoInfo.owner_id, photoInfo.id];
       	//публикация текста на стене
	[self postParameters:@{ VK_API_ATTACHMENTS : photoAttachment,
                                VK_API_FRIENDS_ONLY : @(0),
                                VK_API_OWNER_ID : userId,
                                VK_API_MESSAGE : [NSString stringWithFormat:@"%@ %@",self.string, [self.URL absoluteString]]}];
    } errorBlock: ^(NSError *error) {
	    NSLog(@"Error: %@", error);
        [self end];
	}];
}



Пример публикации фото с помощью VKontakteActivity:
  NSArray *items = @[[UIImage imageNamed:@"example.jpg"], @"Example" , [NSURL URLWithString:@"https://www.youtube.com/watch?v=S59fDUZIuKY"]];
    VKontakteActivity *vkontakteActivity = [[VKontakteActivity alloc] initWithParent:self];
    
    UIActivityViewController *activityViewController = [[UIActivityViewController alloc]
                                                        initWithActivityItems:items
                                                        applicationActivities:@[vkontakteActivity]];
    
    [self presentViewController:activityViewController animated:YES completion:nil];



Исходный код проекта можно скачать здесь.
@shpygar
карма
11,0
рейтинг 0,0
Реклама помогает поддерживать и развивать наши сервисы

Подробнее
Спецпроект

Самое читаемое Разработка

Комментарии (18)

  • +1
    Если есть желание, можете сделать Pull-request, и я включу ваш UIActivity в SDK
    • 0
      сделал
      • 0
        Окей. Подшаманю для универсальности и добавлю)
        • 0
          Ok, буду ждать апдейт либы)
        • 0
          Я извиняюсь за археологические раскопки, но видимо что-то пошло не так и UIActivity не замечено :)
          • 0
            Ваще. Прошу прощения, всё никак не могу выделить время на это.
            Всё время надо делать какие-то другие штуки.
            Попробую сделать на выходных, или в начале следующей недели
            • 0
              Я тоже давно уже жду, когда же появится. Очень удобно было бы :)
    • 0
      Есть активити для WhatsApp :)
      Не желаете? :)
      • 0
        Не вижу связи между VK и WhatsApp :)
        • 0
          Сорри, подумал речь идет о либе с коллекцией UIActivity :)
      • 0
        Можно ссылочку на гитхаб? Лучше в личку, чтоб офтопиков не разводить.
  • 0
    Где Вы были 2 недели назад? )) Практически тот же код написал по причине, что ничего готового не смог найти…
  • 0
    Простите, что лезу, но почему вы инстаграм и вконтакте добавили вниз, когда все приложения должны быть сверху в прокручивающейся строке, а все экшены — снизу? Кастомные иконки вам как бы подсказывают, что сделано не так.
    • 0
      Если знаете как это сделать, расскажите: я решения данной проблемы не нашёл в рамках стандартного UIActivityViewController :(
      • 0
        Очень просто делается:

        + (UIActivityCategory)activityCategory {
            return UIActivityCategoryShare;
        }
        
        • 0
          спасибо
  • 0
    Выпустили апдейт sdk, где поддерживается UIActivityViewController. Пример кода можно посмотреть здесь
    • 0
      отлично, спасибо)

Только зарегистрированные пользователи могут оставлять комментарии. Войдите, пожалуйста.