6

Essentially what I want is for the app, once the user has allowed access to their Twitter account, to be able to tweet whatever the user has selected in a UITableView. Ideally I'd like to use the Twitter framework in iOS 5, but the main issue I'm having is the modal view controller for tweeting. Is this optional? Is it possible to tweet without it and if not, what do you suggest I do?

Thanks!

sooper
  • 5,991
  • 6
  • 40
  • 65

4 Answers4

11

It's definitely possible to tweet without it, the following is in production iOS 5 apps. It even takes the user to the requisite section of preferences if they haven't registered an account.

- (void)postToTwitter
{
    // Create an account store object.
    ACAccountStore *accountStore = [[ACAccountStore alloc] init];

    // Create an account type that ensures Twitter accounts are retrieved.
    ACAccountType *accountType = [accountStore accountTypeWithAccountTypeIdentifier:ACAccountTypeIdentifierTwitter];

    // Request access from the user to use their Twitter accounts.
    [accountStore requestAccessToAccountsWithType:accountType withCompletionHandler:^(BOOL granted, NSError *error) {
        if(granted) {
            // Get the list of Twitter accounts.
            NSArray *accountsArray = [accountStore accountsWithAccountType:accountType];


            if ([accountsArray count] > 0) {
                // Grab the initial Twitter account to tweet from.
                ACAccount *twitterAccount = [accountsArray objectAtIndex:0];
                TWRequest *postRequest = nil;

                postRequest = [[TWRequest alloc] initWithURL:[NSURL URLWithString:@"http://api.twitter.com/1/statuses/update.json"] parameters:[NSDictionary dictionaryWithObject:[self stringToPost] forKey:@"status"] requestMethod:TWRequestMethodPOST];



                // Set the account used to post the tweet.
                [postRequest setAccount:twitterAccount];

                dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void) {
                    [postRequest performRequestWithHandler:^(NSData *responseData, NSHTTPURLResponse *urlResponse, NSError *error) {
                        dispatch_async(dispatch_get_main_queue(), ^(void) {
                            if ([urlResponse statusCode] == 200) {
                                Alert(0, nil, @"Tweet Successful", @"Ok", nil);
                            }else {

                                Alert(0, nil, @"Tweet failed", @"Ok", nil);
                            }
                        });
                    }];
                });

            }
            else
            {
                [[UIApplication sharedApplication] openURL:[NSURL URLWithString:@"prefs:root=TWITTER"]];
            }
        }
    }];
}
james_womack
  • 10,028
  • 6
  • 55
  • 74
6

This would be an updated version using SLRequest instead of TWRequest, which was deprecated in iOS 6. Note this needs the Social and Accounts framework to be added to your project...

- (void) postToTwitterInBackground {

    // Create an account store object.
    ACAccountStore *accountStore = [[ACAccountStore alloc] init];

    // Create an account type that ensures Twitter accounts are retrieved.
    ACAccountType *accountType = [accountStore accountTypeWithAccountTypeIdentifier:ACAccountTypeIdentifierTwitter];

    // Request access from the user to use their Twitter accounts.
    [accountStore requestAccessToAccountsWithType:accountType options:nil completion:^(BOOL granted, NSError *error) {
        if(granted) {
            // Get the list of Twitter accounts.
            NSArray *accountsArray = [accountStore accountsWithAccountType:accountType];

            if ([accountsArray count] > 0) {
                // Grab the initial Twitter account to tweet from.
                ACAccount *twitterAccount = [accountsArray objectAtIndex:0];
                SLRequest *postRequest = nil;

                // Post Text
                NSDictionary *message = @{@"status": @"Tweeting from my iOS app!"};

                // URL
                NSURL *requestURL = [NSURL URLWithString:@"https://api.twitter.com/1.1/statuses/update.json"];

                // Request
                postRequest = [SLRequest requestForServiceType:SLServiceTypeTwitter requestMethod:SLRequestMethodPOST URL:requestURL parameters:message];

                // Set Account
                postRequest.account = twitterAccount;

                // Post
                [postRequest performRequestWithHandler:^(NSData *responseData, NSHTTPURLResponse *urlResponse, NSError *error) {
                     NSLog(@"Twitter HTTP response: %i", [urlResponse statusCode]);
                 }];

            }
        }
    }];

}
Leena
  • 2,678
  • 1
  • 30
  • 43
jesses.co.tt
  • 2,689
  • 1
  • 30
  • 49
5

Update: The TwitterKit in Fabric by Twitter is quite handy and if you aim to post from your Twitter app when the user tries to Tweet in your app then it might be a good option to consider.

(YES, this method will allow you to post to twitter without any dialog box or confirmation).

The TwitterKit will handle the permissions part and using the TWTRAPIClient we perform the tweet through the Twitter rest APIs.

 //Needs to performed once in order to get permissions from the user to post via your twitter app.
[[Twitter sharedInstance]logInWithCompletion:^(TWTRSession *session, NSError *error) {
    //Session details can be obtained here
    //Get an instance of the TWTRAPIClient from the Twitter shared instance. (This is created using the credentials which was used to initialize twitter, the first time) 
    TWTRAPIClient *client = [[Twitter sharedInstance]APIClient];

    //Build the request that you want to launch using the API and the text to be tweeted.
    NSURLRequest *tweetRequest = [client URLRequestWithMethod:@"POST" URL:@"https://api.twitter.com/1.1/statuses/update.json" parameters:[NSDictionary dictionaryWithObjectsAndKeys:@"TEXT TO BE TWEETED", @"status", nil] error:&error];

   //Perform this whenever you need to perform the tweet (REST API call)
   [client sendTwitterRequest:tweetRequest completion:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
   //Check for the response and update UI according if necessary.            
   }];
}];

Hope this helps.

etayluz
  • 15,920
  • 23
  • 106
  • 151
Vijay Tholpadi
  • 2,135
  • 1
  • 15
  • 20
  • Thank you! This worked perfectly and your example was really the only one that I could find. I wish twitter had this in their docs. – YoungDinosaur Mar 17 '15 at 18:00
  • Happy to know that it helped you @dirkoneill. BTW initWithConsumerKey no longer works with TwitterKit v1.4.0 which was released a couple of days back. Have updated the answer appropriately. – Vijay Tholpadi Mar 18 '15 at 02:00
  • Please note that the loginWithCompletionHandler should be called only once and not every-time you are trying to post to twitter like how the edit by @etayluz shows. But would be helpful to have it in the completion block the first time around. – Vijay Tholpadi Jun 05 '15 at 12:01
  • That's true - but it doesn't hurt to call it anyway in case the user is no longer signed it, otherwise you need separate logic to check if user is logged in or not, and even if user is signed in the completion block is still invoked – etayluz Jun 05 '15 at 18:06
2

The accepted answer is no longer valid due to several changes. This one works with iOS 10, Swift 3, and version 1.1 of Twitter's API.

** UPDATE **

This answer has been updated as the previous one relied upon a deprecated Twitter endpoint.

import Social
import Accounts

func postToTwitter() {
    let accountStore = ACAccountStore()
    let accountType = accountStore.accountType(withAccountTypeIdentifier: ACAccountTypeIdentifierTwitter)

    accountStore.requestAccessToAccounts(with: accountType, options: nil) { (granted, error) in
        if granted, let accounts = accountStore.accounts(with: accountType) {
            // This will default to the first account if they have more than one

            if let account = accounts.first as? ACAccount {
                let requestURL = URL(string: "https://api.twitter.com/1.1/statuses/update.json")
                let parameters = ["status" : "Tweet tweet"]
                guard let request = SLRequest(forServiceType: SLServiceTypeTwitter, requestMethod: .POST, url: requestURL, parameters: parameters) else { return }
                request.account = account
                request.perform(handler: { (data, response, error) in
                    // Check to see if tweet was successful
                })
            } else {
                // User does not have an available Twitter account
            }
        }
    }
}

This is the API that is being used.

CodeBender
  • 35,668
  • 12
  • 125
  • 132
  • Does this still work? It had some problems with Swift. Also getting 403 error back. – Jonny Mar 28 '17 at 09:24
  • @Jonny I updated the answer, just tested now to confirm it works. – CodeBender Mar 28 '17 at 14:39
  • Thanks a lot! In the meantime however, I got it working using the TwitterKit sdk installed through Fabric. The flow is very similar... I guess the difference is ACAccountStore uses the existing app of iOS in Twitter ,whereas TwitterKit uses an app which we have to register ourselves at apps.twitter.com ... – Jonny Mar 28 '17 at 15:24