Статьи

Авторизация Twitter в iOS

Вступление

В моей предыдущей статье мы создали простое приложение, которое взаимодействует с API-интерфейсом Twitter и передает один твит из общедоступной временной шкалы. В типичном приложении мы хотим извлечь твиты из временной шкалы пользователя.

iOS5 предоставляет API для централизованной защиты деталей авторизации и предоставления доступа к ним любому приложению, которое этого хочет. Это означает, что у пользователей есть только одно место для перехода, если они хотят деавторизовать или изменить данные учетной записи. Ухоженная.

Документация

Платформа учетных записей имеет заметно скудную документацию для платформы iOS. Это, однако, относительно просто в использовании. API документирован, но нет никакого руководства для разработчиков по его использованию на момент написания.

Мы сейчас покажем, как добавить новую учетную запись в хранилище аутентификации, но подробности о том, как это сделать, можно найти в справочнике по классам ACAccountStore.

Опираясь на предыдущие работы

Добавление структуры учетных записей

Прежде чем мы сможем использовать код в платформе учетных записей, нам нужно добавить его в наше приложение. Прокрутите вниз до «Связанные фреймворки и библиотеки» в разделе «Сводка» вашего проекта.

добавить структуру учетных записей

Нажмите «Добавить», и все готово.

Изменение заголовков

Мы собираемся добавить новое свойство в наш viewController, ‘store’. Это дескриптор ACAccountStore, который нам понадобится в нескольких моментах жизненного цикла нашего приложения.

Измените TWAPIExampleViewController.h, чтобы он выглядел следующим образом:

#import <UIKit/UIKit.h>
    #import <Accounts/Accounts.h>
    #import <Twitter/Twitter.h>

    @interface TWAPIExampleViewController : UIViewController
        @property (nonatomic, retain) ACAccountStore *store;
        @property (nonatomic, retain) UILabel *tweetLabel;

    -(void)getTweet;

    @end

Мы добавили оператор #import для инфраструктуры учетных записей и добавили хранилище @property.

Как обычно, когда мы добавляем @property, мы должны @synthesize его методы доступа и мутатора — в TWAPIExampleViewController.m измените строку, которая гласит:

 @synthesize tweetLabel;

Быть:

 @synthesize store, tweetLabel;

И сделано.

Получение доступа к учетной записи магазина

Когда приложение загрузится, нам нужно получить доступ к магазину аккаунтов. Платформа учетных записей попросит пользователя авторизовать это через всплывающее окно. Если пользователь примет это, мы получим доступ к учетным записям, хранящимся в хранилище учетных записей (которые на пустом экземпляре iOS Simulator будут… нет!)

Помните, мы работаем с кодом из последней статьи , которую я написал , доступ к которой вы можете получить через учетную запись BuildMobile GitHub .

В TWAPIExampleViewController.m мы изменим viewDidLoad, чтобы он выглядел следующим образом:

 - (void)viewDidLoad
    {
        [super viewDidLoad];
        // Do any additional setup after loading the view, typically from a nib.

        self.store = [[ACAccountStore alloc] init];
        ACAccountType *twitterAccountType = [self.store accountTypeWithAccountTypeIdentifier:ACAccountTypeIdentifierTwitter];

        [self.store requestAccessToAccountsWithType:twitterAccountType withCompletionHandler:^(BOOL granted, NSError *error) {
            if(!granted) {
                abort();
                // We didn't get access, so we'll show an error and exit.
                // TODO: Show an error screen to the user and re-request permission!
            }
            return;
        }];

        self.tweetLabel = (UILabel*)[self.view viewWithTag:1];


        [self getTweet];
    }

Посмотрите, как мы использовали abort () там? Наличие вызовов abort () в вашем коде, вероятно, будет означать, что ваше приложение не попадет в App Store. Вам нужно будет заменить этот вызов на хороший экран ошибок для пользователя, сообщив ему, что пошло не так, и предоставив способ его исправить.

Это выходит за рамки того, что я хочу продемонстрировать здесь, поэтому, как любой хороший писатель, я буду ленив и пропущу это.

Получение твита

Теперь нам нужно изменить наш метод getTweet, чтобы получить доступ к авторизации, которую мы (должны) иметь.

URL-адрес Twitter API для получения доступа к временной шкале пользователя: «https://api.twitter.com/1/statuses/home_timeline.json». Таким образом, мы изменим URL, к которому мы обращаемся соответственно.

 -(void)getTweet
    {

        NSURL *url = [NSURL URLWithString:@"https://api.twitter.com/1/statuses/home_timeline.json"];   
        NSDictionary *parameters = [NSDictionary dictionaryWithObjectsAndKeys:@"1", @"count", nil];

        TWRequest *tweetRequest = [[TWRequest alloc] initWithURL:url parameters:parameters requestMethod:TWRequestMethodGET];    

        ACAccountType *twitterAccountType = [self.store accountTypeWithAccountTypeIdentifier:ACAccountTypeIdentifierTwitter];
        NSArray *accounts = [self.store accountsWithAccountType:twitterAccountType];

        if([accounts count] == 0) {
            // We need to get the user to add an account!
            // This is pretty cheap, but we'll zap them out to the Settings app, where they can add an account.
            // When they return, we'll re-run viewDidLoad to get access to the account.
            // TODO: Show a nice UI to your users to add/select which account they wish to use.
            [[UIApplication sharedApplication] openURL:[NSURL URLWithString:@"prefs:root=TWITTER"]];
            [self viewDidLoad];
            return;
        }

        ACAccount *account = [accounts objectAtIndex:0];
        //TODO: We should let the user choose which account they're using

        tweetRequest.account = account;

        [tweetRequest performRequestWithHandler:^(NSData *responseData, NSHTTPURLResponse *urlResponse, NSError *error) {
            // Request completed and we have data
            // Output it!

            NSError *jsonError = nil;
            id timelineData = [NSJSONSerialization JSONObjectWithData:responseData options:NSJSONReadingMutableContainers error:&jsonError];

            if(timelineData == NULL) {
                NSString *myString = [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding];
                NSLog(@"Conversion to object failed.");
                NSLog(@"%d", [urlResponse statusCode]);
                NSLog(@"%@", myString);
                NSLog(@"%@", [jsonError localizedDescription]);
                abort();
                // TODO: Show a graceful error message here
            }

            NSDictionary *timelineDict = (NSDictionary*) timelineData;
            NSLog(@"%@", timelineDict);
            self.tweetLabel.text = [[(NSArray*)timelineDict objectAtIndex:0] objectForKey:@"text"];
        }];
    }

Все еще занятая функция, но не даже еще более занятая! Как и в прошлый раз, на практике вы действительно захотите немного разбить эту функциональность и не делать глупостей, таких как повторный вызов viewDidLoad. Я пытаюсь сжать мой код в как можно меньше функций для иллюстрации.

Итак, сверху мы:

  1. Определение нового URL для доступа через API Twitter (строка 88 этого файла)
  2. Получение списка учетных записей Twitter в магазине (строки 93 и 94)
  3. Передача пользователя в приложение «Настройки», если учетные записи не настроены (строка 96). (Мы также снова вызываем viewDidLoad, что перезапустит наш процесс авторизации, когда пользователь повторно войдет в приложение. Это плохая форма.)
  4. Мы получаем первый аккаунт в стеке (строка 106)
  5. Мы настраиваем учетную запись по запросу в твиттере (строка 109).

И затем, как и прежде, мы показываем твит, который мы возвращаем на этикетке.

Вывод

Это очень простой пример того, как использовать платформу учетных записей с платформой Twitter, чтобы получить доступ к учетной записи пользователя в Twitter. На практике вы хотите использовать библиотеку OAuth, чтобы позволить пользователю создавать учетные записи (в хранилище учетных записей) из вашего приложения и выбирать, какую учетную запись использовать.

Код для этого примера доступен в ветке на GitHub .