/STTwitter

A stable, mature and comprehensive Objective-C library for Twitter REST API 1.1

Primary LanguageObjective-CBSD 3-Clause "New" or "Revised" LicenseBSD-3-Clause

STTwitter

A stable, mature and comprehensive Objective-C library for Twitter REST API 1.1

Like a FOSS version of Twitter Fabric TwitterKit, without the UI parts but with much more flexibility

Also includes a powerful Twitter dev console for OS X

[2015-03-28] Signed build of OS X demo app: STTwitterDemoOSX.app.zip
[2014-06-18] Swifter, A Twitter framework for iOS & OS X written in Swift, by @MatthewDonnelly
[2014-05-31] Follow STTwitter on Twitter: @STTLibrary
[2014-05-22] STTwitter was presented at CocoaHeads Lausanne (slides)
[2013-10-24] STTwitter was presented at SoftShake 2013 (slides).

Build Status

  1. Testimonials
  2. Installation
  3. Code Snippets
  4. Various Kinds of OAuth Connections
  5. Twitter Digits
  6. OAuth Consumer Tokens
  7. Demo / Test Project
  8. Integration Tips
  9. Troubleshooting
  10. Developers
  11. BSD 3-Clause License

Testimonials

"We are now using STTwitter" Adium developers

"An awesome Objective-C wrapper for Twitter’s HTTP API? Yes please!" @nilsou

"Your Library is really great, I stopped the development of my client because I was hating twitter APIs for some reasons, this Library make me want to continue, seriously thank you!" MP0w

"Powered by his own backend wrapper for HTTP calls, STTwitter writes most of the code for you for oAuth based authentication and API resource access like statuses, mentions, users, searches, friends & followers, favorites, lists, places, trends. The documentation is also excellent." STTwitter - Delightful Twitter Library for iOS / buddingdevelopers.com

Starting using STTwitter on a project. It is absolutely amazing. So easy to use. Thanks @nst021 @iOSDevZone

"I'm using this library for a WatchKit app and it works fantastically." inb4ohnoes

"I love STTwitter - it made things a breeze when building @entourageio" @_jeffreyjackson

Installation

Drag and drop STTwitter directory into your project.

Link your project with the following frameworks:

  • Accounts.framework
  • Social.framework
  • Twitter.framework (iOS only)
  • Security.framework (OS X only)

If you want to use CocoaPods, add the following two lines to your Podfile:

pod 'STTwitter'

Then, run the following command to install the STTwitter pod:

pod install

STTwitter does not depend on AppKit or UIKit and hence can be used in a command-line Twitter client.

STTwitter <= 0.2.2 requires iOS 5+ or OS X 10.7+.

STTwitter >= 0.2.3 requires iOS 7+ or OS X 10.9+.

Vea Software has a great live-demo tutorial about creating a simple iOS app using STTwitter's app only mode.

Code Snippets

Here are several ways to use STTwitter.

You'll find complete, minimal, command-line projects in the demo_cli directory:

  • streaming use the streaming API to filter all tweets with some word
  • streaming_with_bot same as above, but reply instantly from another account
  • reverse_auth perform reverse authentication
  • followers display your followers by following Twitter's API cursors, and waiting for a while before reaching rate limits
  • favorites display tweets favorited by people you follow, set a tweet's favorite status
  • conversation post several tweets in the same conversation
  • t2rss convert your timeline into an RSS feed
Instantiate STTwitterAPI
STTwitterAPI *twitter = [STTwitterAPI twitterAPIWithOAuthConsumerKey:@""
                                                      consumerSecret:@""
                                                            username:@""
                                                            password:@""];
Verify the credentials
[twitter verifyCredentialsWithUserSuccessBlock:^(NSString *username, NSString *userID) {
    // ...
} errorBlock:^(NSError *error) {
    // ...
}];
Get the timeline statuses
[twitter getHomeTimelineSinceID:nil
                          count:100
                   successBlock:^(NSArray *statuses) {
    // ...
} errorBlock:^(NSError *error) {
    // ...
}];
Streaming API
NSObject <STTwitterRequestProtocol> *request = [twitter getStatusesSampleDelimited:nil
                                                                     stallWarnings:nil
                                                                     progressBlock:^(id response) {
    // ...
} stallWarningBlock:nil
         errorBlock:^(NSError *error) {
    // ...
}];

// ...

[request cancel]; // when you're done with it
App Only Authentication
STTwitterAPI *twitter = [STTwitterAPI twitterAPIAppOnlyWithConsumerKey:@""
                                                        consumerSecret:@""];

[twitter verifyCredentialsWithUserSuccessBlock:^(NSString *username, NSString *userID) {

    [twitter getUserTimelineWithScreenName:@"barackobama"
                              successBlock:^(NSArray *statuses) {
        // ...
    } errorBlock:^(NSError *error) {
        // ...
    }];

} errorBlock:^(NSError *error) {
    // ...
}];
Enumerate results with cursors, pause according to rate limits
[_twitter fetchAndFollowCursorsForResource:@"followers/ids.json"
                                HTTPMethod:@"GET"
                             baseURLString:@"https://api.twitter.com/1.1"
                                parameters:@{@"screen_name":@"0xcharlie"}
                       uploadProgressBlock:nil
                     downloadProgressBlock:nil
                              successBlock:^(id request, NSDictionary *requestHeaders, NSDictionary *responseHeaders, id response, BOOL morePagesToCome, BOOL *stop) {
    NSLog(@"-- success, more to come: %d, %@", morePagesToCome, response);
} pauseBlock:^(NSDate *nextRequestDate) {
    NSLog(@"-- rate limit exhausted, nextRequestDate: %@", nextRequestDate);
} errorBlock:^(id request, NSDictionary *requestHeaders, NSDictionary *responseHeaders, NSError *error) {
    NSLog(@"-- %@", error);
}];

Various Kinds of OAuth Connections

You can instantiate STTwitterAPI in three ways:

  • use the Twitter account set in OS X Preferences or iOS Settings
  • use a custom consumer key and consumer secret (four flavors)
    • get an URL, fetch a PIN, enter it in your app, get oauth access tokens
    • set username and password, get oauth access tokens with XAuth, if the app is entitled to
    • set oauth token and oauth token secret directly
    • open Safari (or a UIWebView instance if you prefer), authenticate on Twitter and receive access tokens in your app through a custom URL scheme
  • use the Application Only authentication and get / use a "bearer token"

So there are five cases altogether, hence these five methods:

+ (STTwitterAPI *)twitterAPIOSWithFirstAccount;

+ (STTwitterAPI *)twitterAPIWithOAuthConsumerKey:(NSString *)consumerKey
                                  consumerSecret:(NSString *)consumerSecret;

+ (STTwitterAPI *)twitterAPIWithOAuthConsumerKey:(NSString *)consumerKey
                                  consumerSecret:(NSString *)consumerSecret
                                        username:(NSString *)username
                                        password:(NSString *)password;

+ (STTwitterAPI *)twitterAPIWithOAuthConsumerKey:(NSString *)consumerKey
                                  consumerSecret:(NSString *)consumerSecret
                                      oauthToken:(NSString *)oauthToken
                                oauthTokenSecret:(NSString *)oauthTokenSecret;

+ (STTwitterAPI *)twitterAPIAppOnlyWithConsumerKey:(NSString *)consumerKey
                                    consumerSecret:(NSString *)consumerSecret;
Callbacks URLs

After authenticating in Safari or in a web view, Twitter redirects to the callback URL with some additional parameters. (Your Twitter app' settings MUST allow the usage of callbacks by specifying a dummy URL, such as http://www.cnn.com. This URL is then overriden by the oauthCallback parameter in:

- (void)postTokenRequest:(void(^)(NSURL *url, NSString *oauthToken))successBlock
authenticateInsteadOfAuthorize:(BOOL)authenticateInsteadOfAuthorize
              forceLogin:(NSNumber *)forceLogin
              screenName:(NSString *)screenName
           oauthCallback:(NSString *)oauthCallback
              errorBlock:(void(^)(NSError *error))errorBlock;

STTwitter Twitter App Settings

Reverse Authentication

Reference: https://dev.twitter.com/docs/ios/using-reverse-auth

The most common use case of reverse authentication is letting users register/login to a remote service with their OS X or iOS Twitter account.

iOS/OSX     Twitter     Server
-------------->                 reverse auth.
< - - - - - - -                 access tokens

----------------------------->  access tokens

               <--------------  access Twitter on user's behalf
                - - - - - - ->

Here is how to use reverse authentication with STTwitter:

STTwitterAPI *twitter = [STTwitterAPI twitterAPIWithOAuthConsumerName:nil
                                                          consumerKey:@"CONSUMER_KEY"
                                                       consumerSecret:@"CONSUMER_SECRET"];

[twitter postReverseOAuthTokenRequest:^(NSString *authenticationHeader) {

    STTwitterAPI *twitterAPIOS = [STTwitterAPI twitterAPIOSWithFirstAccount];

    [twitterAPIOS verifyCredentialsWithUserSuccessBlock:^(NSString *username, NSString *userID) {

        [twitterAPIOS postReverseAuthAccessTokenWithAuthenticationHeader:authenticationHeader
                                                            successBlock:^(NSString *oAuthToken,
                                                                           NSString *oAuthTokenSecret,
                                                                           NSString *userID,
                                                                           NSString *screenName) {

                                                                // use the tokens...

                                                            } errorBlock:^(NSError *error) {
                                                                // ...
                                                            }];

    } errorBlock:^(NSError *error) {
        // ...
    }];

} errorBlock:^(NSError *error) {
    // ...
}];

Contrary to what can be read here and there, you can perfectly access direct messages from iOS Twitter accounts.

Twitter Digits

https://docs.fabric.io/ios/digits/digits.html

In this flow, you start with consumer tokens and app only mode, and end up with access tokens, after verifying a phone number with a PIN sent by SMS.

It goes like this:

1. start with consumer tokens
2. get a bearer token (ie. app only mode)
2. get a guest token, (ie. temporary user id)
3. post a phone number, using the guest token
4. post the received PIN code for the phone number, using the guest token
5. receive access tokens in return

See a working example in STAuthenticationVC.m.

OAuth Consumer Tokens

In Twitter REST API v1.1, each client application must authenticate itself with consumer key and consumer secret tokens. You can request consumer tokens for your app on Twitter's website: https://apps.twitter.com/.

STTwitter demo project comes with TwitterClients.plist where you can enter your own consumer tokens.

Demo / Test Project

There is a demo project for OS X in demo_osx, which lets you choose how to get the OAuth tokens (see below).

An archive generated on 2013-10-20 10:35 is available at http://seriot.ch/temp/STTwitterDemoOSX.app.zip.

Once you got the OAuth tokens, you can get your timeline and post a new status.

There is also a simple iOS demo project in demo_ios.

STTwitter Demo iOS STTwitter Demo iOS sample tweet

Integration Tips

Concurrency

STTwitter is supposed to be used from the main thread. The HTTP requests are performed anychronously and the callbacks are guaranteed to be called on main thread.

Credentials verification

There's no need to verify the credentials before each request.

Doing so when the application starts and when the application enters foreground sounds reasonable, though.

Timeout

Unless told otherwise, STTwitter will use the underling classes default timeouts.

You can also set the timeout by yourself:

[twitter setTimeoutInSeconds:5.0];
Remove Asserts in Release Mode

There are several asserts in the code. They are very useful in debug mode but you should not include them in release.

New projects created with Xcode 5 already remove NSAssert logic by default in release.

In older projects, you can set the compilation flag -DNS_BLOCK_ASSERTIONS=1.

Number of Characters in a Tweet

Use the method -[NSString st_numberOfCharactersInATweet] to let the user know how many characters she can enter before the end of the Tweet. The method may also return a negative value if the string exceeds a tweet's maximum length. The method considers the shortened URL lengths.

Date Formatter

In order to convert the string in the created_at field from Twitter's JSON into an NSDate instance, you can use the +[NSDateFormatter st_TwitterDateFormatter].

NSDateFormatter *df = [NSDateFormatter st_TwitterDateFormatter];
NSString *dateString = [d valueForKey:@"created_at"]; // "Sun Jun 28 20:33:01 +0000 2009"
NSDate *date = [df dateFromString:dateString];
URLs Shorteners

In order to expand shortened URLs such as Twitter's t.co service, use:

[STHTTPRequest expandedURLStringForShortenedURLString:@"http://t.co/tmoxbSfDWc" successBlock:^(NSString *expandedURLString) {
    //
} errorBlock:^(NSError *error) {
    //
}];
API Responses Text Processing

You may want to use Twitter's own Objective-C library for text processing: https://github.com/twitter/twitter-text-objc/.

twitter-text-objc provides you with methods such as:

+ (NSArray*)entitiesInText:(NSString*)text;
+ (NSArray*)URLsInText:(NSString*)text;
+ (NSArray*)hashtagsInText:(NSString*)text checkingURLOverlap:(BOOL)checkingURLOverlap;
+ (NSArray*)symbolsInText:(NSString*)text checkingURLOverlap:(BOOL)checkingURLOverlap;
+ (NSArray*)mentionedScreenNamesInText:(NSString*)text;
+ (NSArray*)mentionsOrListsInText:(NSString*)text;
+ (TwitterTextEntity*)repliedScreenNameInText:(NSString*)text;
Logout

The correct approach to logout a user is setting the STTwitterAPI instance to nil.

You'll create a new one at the next login.

Boolean Parameters

There are a lot of optional parameters in Twitter API. In STTwitter, you can ignore such parameters by passing nil. Regarding boolean parameters, STTwitter can't just use Objective-C YES and NO because NO has the same value as nil (zero). So boolean parameters are wrapped into NSNumber objects, which are pretty easy to use with boolean values thanks to Objective-C literals. So, with STTwitter, you will assign an optional parameter of Twitter API either as @(YES), @(NO) or nil.

Long Methods

STTwitter provides a full, "one-to-one" Objective-C front-end to Twitter REST API. It often results in long methd names with many parameters. In your application, you may want to add your own, simplified methods on top of STTwitterAPI. A good idea is to create an Objective-C category for your application, such as in the following code.

STTwitterAPI+MyApp.h

#import "STTwitterAPI.h"

@interface STTwitterAPI (MyApp)

- (void)getStatusesShowID:(NSString *)statusID
             successBlock:(void(^)(NSDictionary *status))successBlock
               errorBlock:(void(^)(NSError *error))errorBlock;

@end

STTwitterAPI+MyApp.m

#import "STTwitterAPI+MyApp.h"

@implementation STTwitterAPI (MyApp)

- (void)getStatusesShowID:(NSString *)statusID
             successBlock:(void(^)(NSDictionary *status))successBlock
               errorBlock:(void(^)(NSError *error))errorBlock {

    [self getStatusesShowID:statusID
                   trimUser:@(YES)
           includeMyRetweet:nil
            includeEntities:@(NO)
               successBlock:^(NSDictionary *status) {

                   successBlock(status);

               } errorBlock:^(NSError *error) {

                   errorBlock(error);

               }];
}

@end
Stream Request and Connection Losses

Streaming requests may be lost when your iOS application comes back to foreground after a while in background. In order to handle this case properly, you can detect the connection loss in the error block and restart the stream request from there.

// ...
} errorBlock:^(NSError *error) {

    if([[error domain] isEqualToString:NSURLErrorDomain] && [error code] == NSURLErrorNetworkConnectionLost) {
        [self startStreamRequest];
    }

}];

Troubleshooting

xAuth

Twitter restricts the xAuth authentication process to xAuth-enabled consumer tokens only. So, if you get an error like The consumer tokens are probably not xAuth enabled. while accessing https://api.twitter.com/oauth/access_token, see Twitter's website https://dev.twitter.com/docs/oauth/xauth and ask Twitter to enable the xAuth authentication process for your consumer tokens.

Anything Else

Please fill an issue on GitHub or use the STTwitter tag on StackOverflow.

Developers

The application only interacts with STTwitterAPI.

STTwitterAPI maps Objective-C methods with all Twitter API endpoints.

You can create your own convenience methods with fewer parameters. You can also use this generic method directly:

  - (id)fetchResource:(NSString *)resource
           HTTPMethod:(NSString *)HTTPMethod
        baseURLString:(NSString *)baseURLString
           parameters:(NSDictionary *)params
  uploadProgressBlock:(void(^)(NSInteger bytesWritten, NSInteger totalBytesWritten, NSInteger totalBytesExpectedToWrite))uploadProgressBlock
downloadProgressBlock:(void(^)(NSObject<STTwitterRequestProtocol> *request, id response))downloadProgressBlock
         successBlock:(void(^)(NSObject<STTwitterRequestProtocol> *request, NSDictionary *requestHeaders, NSDictionary *responseHeaders, id response))successBlock
           errorBlock:(void(^)(NSObject<STTwitterRequestProtocol> *request, NSDictionary *requestHeaders, NSDictionary *responseHeaders, NSError *error))errorBlock;
Layer Model
 +------------------------------------------------------------------------+
 |                         Your Application                               |
 +--------------------------------------------------------+---------------+
 |                  STTwitterAPI                          | STTwitterHTML |
 +--------------------------------------------------------+               |
 + - - - - - - - - - - - - - - - - - - - - - - - - - - - -+               |
 |              STTwitterOAuthProtocol                    |               |
 + - - - - - - - - - - - - - - - - - - - - - - - - - - - -+               |
 +--------------------+----------------+------------------+               |
 |    STTwitterOS     | STTwitterOAuth | STTwitterAppOnly |               |
 +--------------------+----------------+------------------+---------------+
 | STTwitterOSRequest |                   STHTTPRequest                   |
 +--------------------+---------------------------------------------------+
  |
  + Accounts.framework
  + Social.framework
Summary
 * STTwitterAPI
    - can be instantiated with the authentication mode you want
    - provides methods to interact with each Twitter API endpoint

 * STTwitterHTML
    - a hackish class to login on Twitter by parsing the HTML code and get a PIN
    - it can break at anytime, your app should not rely on it in production

 * STTwitterOAuthProtocol
    - provides generic methods to POST and GET resources on Twitter's hosts

 * STTwitterOS
    - uses Twitter accounts defined in OS X Preferences or iOS Settings
    - uses OS X / iOS frameworks to interact with Twitter API

 * STTwitterOSRequest
    - block-based wrapper around SLRequest's underlying NSURLRequest
    
 * STTwitterOAuth
    - implements OAuth and xAuth authentication

 * STTwitterAppOnly
    - implements the 'app only' authentication
    - https://dev.twitter.com/oauth/application-only

 * STHTTPRequest
    - block-based wrapper around NSURLConnection
    - https://github.com/nst/STHTTPRequest

BSD 3-Clause License

See LICENCE.txt.