Search code examples
iosobjective-ctwittertwitter-fabric

Attach GIF to TWTRComposer?


In my iOS app, I would like to enable users to tweet GIFs.

I have a working TWTRComposer and tried attaching a GIF by using the SetImage method:

[composer setImage:[UIImage imageWithData:[NSData dataWithContentsOfURL:self.localGifURL]]];

The image then appears in the composer view, but when the image gets posted to Twitter, it's a static image rather than a GIF.

Is it possible to attach a GIF to a tweet created with TWTRComposer?

Edit

I tried integrating this library to create an animated UIImage:

https://github.com/mayoff/uiimage-from-animated-gif

Updating my code, I have the following:

[composer setImage:[UIImage animatedImageWithAnimatedGIFURL:self.localGifURL]];

But this still results in a static image on Twitter.

Edit #2

One other observation - if I save the GIF to my phone and try to share it on Twitter directly from the Photo library (which opens up what looks to be a TWTRComposer window), it posts as an image, not a GIF. Which leads me to that you may not be able to attach a GIF to a TWTRComposer...


Solution

  • I posted this question a while ago but finally got around to implementing this feature.

    TWTRComposer still doesn't support adding anything but images, so I used the media/upload REST API as suggested. I am able to tweet both GIFs and Videos. Before tweeting either media, I create a custom UIAlertView that lets someone composer a tweet:

    enter image description here

    Then when they tap the tweet button, a GIF gets tweeted if it's small enough; otherwise, a video is tweeted.

    Resulting GIF tweet: https://twitter.com/spinturntable/status/730609962817294336

    Resulting Video tweet: https://twitter.com/spinturntable/status/730609829128081408

    Here is how I implemented this feature (lots of help from this post https://stackoverflow.com/a/31259870/1720985).

    Create the initial UIAlertView for composing the tweet message:

    -(IBAction)tweet:(id)sender{
        // check if the person has twitter
        if([[Twitter sharedInstance] session]){
            // first, show a pop up window for someone to customize their tweet message, limited to 140 characters
            UIAlertView *tweetAlert = [[UIAlertView alloc] initWithTitle:@"Compose Tweet"
                                                                 message:nil
                                                                delegate:self
                                                       cancelButtonTitle:@"Cancel"
                                                       otherButtonTitles:nil];
            tweetAlert.tag = TAG_TWEET;
            tweetTextView = [UITextView new];
            [tweetTextView setBackgroundColor:[UIColor clearColor]];
            CGRect frame = tweetTextView.frame;
            frame.size.height = 500;
            tweetTextView.frame = frame;
    
            [tweetTextView setFont:[UIFont systemFontOfSize:15]];
    
            tweetTextView.textContainerInset = UIEdgeInsetsMake(0, 10, 10, 10);
    
            [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(limitTextView:) name:@"UITextViewTextDidChangeNotification" object:tweetTextView];
    
    
            [tweetTextView setText:[NSString stringWithFormat:@"%@ %@", [[NSUserDefaults standardUserDefaults] valueForKey:@"tweetText"], self.setShareURL]];
            [tweetAlert setValue:tweetTextView forKey:@"accessoryView"];
            [tweetAlert addButtonWithTitle:@"Tweet"];
            [tweetAlert show];
        }else{
            UIAlertView *alert = [[UIAlertView alloc] initWithTitle:nil
                                                            message:@"Please log in with your Twitter account to tweet!"
                                                           delegate:nil
                                                  cancelButtonTitle:@"OK"
                                                  otherButtonTitles:nil];
            [alert show];
        }
    
    }
    

    Then detect the UIAlertView Tweet (I add a UIAlertViewDelegate):

    - (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex {
       if(alertView.tag == TAG_TWEET){
            if (buttonIndex == 1) {
    
                UIAlertView *tweetStartAlert = [[UIAlertView alloc] initWithTitle:nil
                                                                message:@"Tweeting..."
                                                               delegate:self
                                                      cancelButtonTitle:nil
                                                      otherButtonTitles:nil];
                [tweetStartAlert show];
    
                // get client
                __block TWTRAPIClient *client = [[Twitter sharedInstance] APIClient];
                __block NSString *mediaID;
    
                NSString *text = [tweetTextView text]; // get tweet text
                NSLog(@"text: %@", text);
                NSData *mediaData;
                NSString *mediaLength;
                NSString *mediaType;
                NSString* url = @"https://upload.twitter.com/1.1/media/upload.json";
    
                // if this is a single spin set, tweet the gif
                if([self.setSpins count] ==1){
                    NSLog(@"tweeting GIF with url %@", self.gifURL);
                    mediaData = [NSData dataWithContentsOfURL:[NSURL URLWithString:self.gifURL]];
                    mediaLength = [NSString stringWithFormat:@"%lu", mediaData.length];
                    mediaType = @"image/gif";
                }else if([self.setSpins count] > 1){
                    // multi-spin set - tweet the video
                    NSLog(@"tweeting video with url %@", self.videoURL);
                    mediaData = [NSData dataWithContentsOfURL:[NSURL URLWithString:self.videoURL]];
                    mediaLength = [NSString stringWithFormat:@"%lu", mediaData.length];
                    mediaType = @"video/mp4";
                }
    
                NSError *error;
                // First call with command INIT
                __block NSDictionary *message =  @{ @"status":text,
                                                    @"command":@"INIT",
                                                    @"media_type":mediaType,
                                                    @"total_bytes":mediaLength};
    
                    NSURLRequest *preparedRequest = [client URLRequestWithMethod:@"POST" URL:url parameters:message error:&error];
                    [client sendTwitterRequest:preparedRequest completion:^(NSURLResponse *urlResponse, NSData *responseData, NSError *error){
    
                        if(!error){
                            NSError *jsonError;
                            NSDictionary *json = [NSJSONSerialization
                                                  JSONObjectWithData:responseData
                                                  options:0
                                                  error:&jsonError];
    
                            mediaID = [json objectForKey:@"media_id_string"];
                            NSError *error;
    
                            NSString *mediaString = [mediaData base64EncodedStringWithOptions:0];
    
                            // Second call with command APPEND
                            message = @{@"command" : @"APPEND",
                                        @"media_id" : mediaID,
                                        @"segment_index" : @"0",
                                        @"media" : mediaString};
    
                            NSURLRequest *preparedRequest = [client URLRequestWithMethod:@"POST" URL:url parameters:message error:&error];
    
                            [client sendTwitterRequest:preparedRequest completion:^(NSURLResponse *urlResponse, NSData *responseData, NSError *error){
    
                                if(!error){
                                    client = [[Twitter sharedInstance] APIClient];
                                    NSError *error;
                                    // Third call with command FINALIZE
                                    message = @{@"command" : @"FINALIZE",
                                                @"media_id" : mediaID};
    
                                    NSURLRequest *preparedRequest = [client URLRequestWithMethod:@"POST" URL:url parameters:message error:&error];
    
                                    [client sendTwitterRequest:preparedRequest completion:^(NSURLResponse *urlResponse, NSData *responseData, NSError *error){
    
                                        if(!error){
                                            client = [[Twitter sharedInstance] APIClient];
                                            NSError *error;
                                            // publish video with status
                                            NSLog(@"publish video!");
                                            NSString *url = @"https://api.twitter.com/1.1/statuses/update.json";
                                            NSMutableDictionary *message = [[NSMutableDictionary alloc] initWithObjectsAndKeys:text,@"status",@"true",@"wrap_links",mediaID, @"media_ids", nil];
                                            NSURLRequest *preparedRequest = [client URLRequestWithMethod:@"POST" URL:url parameters:message error:&error];
    
                                            [client sendTwitterRequest:preparedRequest completion:^(NSURLResponse *urlResponse, NSData *responseData, NSError *error){
                                                if(!error){
                                                    NSError *jsonError;
                                                    NSDictionary *json = [NSJSONSerialization
                                                                          JSONObjectWithData:responseData
                                                                          options:0
                                                                          error:&jsonError];
                                                    NSLog(@"%@", json);
    
                                                    [tweetStartAlert dismissWithClickedButtonIndex:0 animated:YES];
    
                                                    UIAlertView *tweetFinishedAlert = [[UIAlertView alloc] initWithTitle:nil
                                                                                                              message:@"Tweeted!"
                                                                                                             delegate:self
                                                                                                    cancelButtonTitle:nil
                                                                                                    otherButtonTitles:nil];
                                                    [tweetFinishedAlert show];
                                                    double delayInSeconds = 1.5;
                                                    dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC));
                                                    dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
                                                        [tweetFinishedAlert dismissWithClickedButtonIndex:0 animated:YES];
                                                    });
    
                                                    [self logShare:@"twitter"];
    
                                                }else{
                                                    NSLog(@"Error: %@", error);
                                                }
                                            }];
                                        }else{
                                            NSLog(@"Error command FINALIZE: %@", error);
                                        }
                                    }];
    
                                }else{
                                    NSLog(@"Error command APPEND: %@", error);
                                }
                            }];
    
                        }else{
                            NSLog(@"Error command INIT: %@", error);
                        }
    
                    }];
                }
            }
        }
    

    Some extra things: I focus the UITextView when the Compose Tweet Alert appears:

    - (void)didPresentAlertView:(UIAlertView *)alertView {
        if(alertView.tag == TAG_TWEET){
            NSLog(@"tweetAlertView appeared");
            [tweetTextView becomeFirstResponder];
        }
    }
    

    Here's how I check whether the UITextView has less than 140 characters:

    - (void)limitTextView:(NSNotification *)note {
        int limit = 140;
        if ([[tweetTextView text] length] > limit) {
            [tweetTextView setText:[[tweetTextView text] substringToIndex:limit]];
        }
    }
    

    Hope this is useful to others as it took me a long time to piece everything together.