Tuesday, January 12, 2016

How To: Using SLRequest to Upload Image or Video To Twitter

Hi guys what's up. This is a simple tutorial so it doesn't have any downloadable project.

Today I'd like to share with you how to upload an image (like JPEG or GIF animation) to Twitter from the iOS app.

For a normal JPEG and status upload, you can use SLComposeViewController but you will face problem if you want to upload GIF animation or video file. That is because SLComposeViewController only has "addImage" method that takes up a UIImage object.


So you have to use SLRequest - a low level API communicator.

There was a simple API request called "upload_with_media" but Twitter has DEPRECATED it. It works now, but it may not work anymore in the near future and thus may break your app if you use that. So now you need to use 2 APIs to tweet text and image in one tweet. The processes involved is basically 2 - tiered jobs:

1. Upload image first - you will get the media id after upload completes
2. Update status with text and the media ID

As usual you have to request access to Twitter account before you can do anything with it. Once access is granted by user, you can then proceed to instantiate requests to twitter API host. Here's how to upload a media to Twitter's Media server:




NSData *imageData = [NSData dataWithContentsOfURL:fileURL];
NSURL *requestURL = [NSURL URLWithString:@"https://upload.twitter.com/1.1/media/upload.json"];
                    
SLRequest *postRequest = [SLRequest 
                                              requestForServiceType:SLServiceTypeTwitter
                                              requestMethod:SLRequestMethodPOST
                                              URL:requestURL parameters:nil;
                    
postRequest.account = twitterAccount;
[postRequest addMultipartData:imageData
                                         withName:@"media"
                                             type:@"image/gif"
                                         filename:@"test.gif"];
                    
[postRequest performRequestWithHandler:^(NSData *responseData,
                                                 NSHTTPURLResponse *urlResponse, NSError *error)
                     {

First, convert your image/video into NSData. Then create an SLRequest with NIL PARAMETERS with POST method as in code above. Set the request's account. Then add multipart data to the request.

The data type must be matching to what you're uploading. If it's a JPG then use "image/jpeg" if it's a GIF then use "image/gif" etc. Finally perform the request to start uploading the image to twitter's media server. This may take a while so you should have a UIActivityViewController pop up when doing this.

When the request is completed, the method will return responseData in JSON format. Convert this data into JSON.

Example of JSON data returned from twitter:

{
    "expires_after_secs" = 86400;
    image =     {
        h = 400;
        "image_type" = "image/gif";
        w = 400;
    };
    "media_id" = 687171095254859776;
    "media_id_string" = 687171095254859776; ---- THIS IS WHAT YOU NEED
    size = 705439;
}

Retrieve the media ID string as follows:

NSDictionary *json = [NSJSONSerialization JSONObjectWithData:responseData options:0 error:nil];
NSString *mediaID = [json objectForKey:@"media_id_string"];

Once you get the mediaID, you can then tweet a text with this ID using /statuses/update.json API.

 
NSURL *requestURL2 = [NSURL URLWithString:@"https://api.twitter.com/1.1/statuses/update.json"];
NSDictionary *message2 = @{@"status": @"Here is image",
                                                    @"media_ids": mediaID };
                         
SLRequest *postRequest2 = [SLRequest
                                                   requestForServiceType:SLServiceTypeTwitter
                                                   requestMethod:SLRequestMethodPOST
                                                   URL:requestURL2 parameters:message2];
postRequest2.account = twitterAccount;
                         
[postRequest2 performRequestWithHandler:^(NSData *responseData,
                                                      NSHTTPURLResponse *urlResponse, NSError *error)
                          {

The second request is just the same method performRequestWithHandler but with different requestURL. And that's how it's done.

Here is the complete code (including requesting access to twitter account):



-(void)uploadImageToTwitter {


        
        ACAccountStore *account = [[ACAccountStore alloc] init];
        ACAccountType *accountType = [account accountTypeWithAccountTypeIdentifier:
                                      ACAccountTypeIdentifierTwitter];
        
        [account requestAccessToAccountsWithType:accountType options:nil
                                      completion:^(BOOL granted, NSError *error)
        {
            if (granted == YES)
            {
                NSArray *arrayOfAccounts = [account
                                            accountsWithAccountType:accountType];
                
                if ([arrayOfAccounts count] > 0)
                {
                    ACAccount *twitterAccount =
                    [arrayOfAccounts lastObject];
                    
                    
                    NSURL *furl = [NSURL fileURLWithPath:NSTemporaryDirectory()];
                    NSURL *fileURL = [furl URLByAppendingPathComponent:@"animation.gif"];
                    NSData *imageData = [NSData dataWithContentsOfURL:fileURL];
                   
                    NSURL *requestURL = [NSURL URLWithString:@"https://upload.twitter.com/1.1/media/upload.json"];
                    
                    SLRequest *postRequest = [SLRequest 
                                              requestForServiceType:SLServiceTypeTwitter
                                              requestMethod:SLRequestMethodPOST
                                              URL:requestURL parameters:nil];
                    
                    postRequest.account = twitterAccount;
                    
                    [postRequest addMultipartData:imageData
                                         withName:@"media"
                                             type:@"image/gif"
                                         filename:@"test.gif"];
                    
                    [postRequest
                     performRequestWithHandler:^(NSData *responseData,
                                                 NSHTTPURLResponse *urlResponse, NSError *error)
                     {
                         
                         
                          NSDictionary *json = [NSJSONSerialization JSONObjectWithData:responseData options:0 error:nil];
                         
                         NSString *mediaID = [json objectForKey:@"media_id_string"];
                         
                         
                         if (mediaID!=nil) {
                             
                         
                             NSURL *requestURL2 = [NSURL URLWithString:@"https://api.twitter.com/1.1/statuses/update.json"];
                         NSDictionary *message2 = @{@"status": @"Here is the image",
                                                    @"media_ids": mediaID };
                         
                         SLRequest *postRequest2 = [SLRequest
                                                   requestForServiceType:SLServiceTypeTwitter
                                                   requestMethod:SLRequestMethodPOST
                                                   URL:requestURL2 parameters:message2];
                         postRequest2.account = twitterAccount;
                         
                         [postRequest2
                          performRequestWithHandler:^(NSData *responseData,
                                                      NSHTTPURLResponse *urlResponse, NSError *error)
                          {
                             // DONE!!!

                          }];
                             
                         }
                         
                     }];
                }
            }
         }];


That's all FOLKS!

3 comments:

  1. Man, this is great! I just found out about the 'SLReqeust' method here today. I recently used Twitter's Fabric Kit to authenticate login and I'm trying to get follower count of userID in session but to no avail and its quite frustrating. Can you throw some light? I'd appreciate it big time.

    ReplyDelete
  2. How can upload multiple images?

    http://stackoverflow.com/questions/36581617/upload-multiple-images-to-facebook-using-slrequest

    ReplyDelete
  3. Thanks for sharing this solution Gene, it works excellent!!

    Here's your code adapted to Swift 3 and iOS 10, hope it helps those devs who are unfamiliar with objc

    https://gist.github.com/nahuelDeveloper/e225b9a0bff1ac5f8076e941d24d5ab9

    ReplyDelete