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!
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.
ReplyDeleteHow can upload multiple images?
ReplyDeletehttp://stackoverflow.com/questions/36581617/upload-multiple-images-to-facebook-using-slrequest
Thanks for sharing this solution Gene, it works excellent!!
ReplyDeleteHere'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