将 GIF 附加到 TWTRComposer?

Attach GIF to TWTRComposer?

在我的 iOS 应用程序中,我想让用户能够发送 GIF 推文。

我有一个工作的 TWTRComposer 并尝试使用 SetImage 方法附加一个 GIF:

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

图像随后出现在作曲家视图中,但当图像发布到 Twitter 时,它是静态图像而不是 GIF。

是否可以将 GIF 附加到使用 TWTRComposer 创建的推文?

编辑

我尝试集成这个库来创建动画 UIImage:

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

更新我的代码,我有以下内容:

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

但这仍然会导致 Twitter 上出现静态图像。

编辑 #2

另一个观察 - 如果我将 GIF 保存到我的 phone 并尝试直接从照片库(打开看起来像 TWTRComposer window 的东西)在 Twitter 上分享它,它发布为图像,而不是 GIF。这让我想到您可能无法将 GIF 附加到 TWTRComposer...

我认为 TWTRComposer 目前不支持动画 GIF 或视频附件。我认为您必须将 media/upload REST API 端点直接调用到 post 附件,然后使用 statuses/update 方法将它们附加到推文。

我刚刚构建了一个具有 GIF 功能并且需要能够 post 到 Twitter 的应用程序。不幸的是,他们的作曲家不能使用 GIF(我 99.9999% 确定,如果你以某种方式让它工作,请告诉我)。

我的解决方案实际上是,如果用户选择在 Twitter 上分享,则将 GIF 转换为 10 秒的视频,只是重复播放 GIF(我的 GIF 的持续时间始终为 2 秒)。

我设法使用 AVAssetWriterInput 和 AVAssetWriterInputPixelBufferAdaptor 做到了。它还为我提供了一个简单的方法 post 到其他社交媒体渠道,因为其中许多不支持通过作曲家(Messenger?)的 GIF。

以下是在任何可共享平台上共享 video/GIF/any 其他媒体类型的方法。

确保您的视图控制器响应 UIActivityItemSource 协议:

@interface MyCustomViewController () <UIActivityItemSource>

那么,我假设你在分享时调用了一些方法:

- (void)methodCalledToShare {
    //Create an activity view controller
    UIActivityViewController *activityController = [[UIActivityViewController alloc] initWithActivityItems:@[self] applicationActivities:nil];
    //decide what happens after it closes (optional)
    [activityController setCompletionWithItemsHandler:^(NSString *activityType, BOOL completed, NSArray *returnedItems, NSError *activityError) {
    }];
    //present the activity view controller
    [self presentViewController:activityController animated:YES completion:^{

    }];
}

那么你需要有这个方法与我们之前遵守的协议有关:

//This is an example for if you want to have different data sent based on which app they choose.
//I have an NSURL pointing to a local video in "videoUrl"
//And I have NSData of a GIF in "gifData"
- (id)activityViewController:(UIActivityViewController *)activityViewController itemForActivityType:(NSString *)activityType {
    id item;
    //If it's Facebook, send a video
    if ([activityType isEqualToString:UIActivityTypePostToFacebook])
        item = self.videoUrl;
    //if its Twitter, send a GIF
    else if ([activityType isEqualToString:UIActivityTypePostToTwitter])
        item = self.gifData;
    //if its mail, send a GIF
    else if ([activityType isEqualToString:UIActivityTypeMail])
        item = self.gifData;
    //If it's text, send a GIF
    else if ([activityType isEqualToString:UIActivityTypeMessage])
        item = self.gifData;
    //If it's Facebook Messenger, send a video
    else if ([activityType isEqualToString:@"com.facebook.Messenger.ShareExtension"])
        item = self.videoUrl;
    //Just default to a video
    else
        item = self.videoUrl;
    return item;
}

我 post 不久前回答了这个问题,但终于开始实施这个功能。

TWTRComposer 仍然不支持添加图像以外的任何内容,因此我按照建议使用了 media/upload REST API。我可以同时发布 GIF 和视频。在发布任何一种媒体之前,我创建了一个自定义的 UIAlertView,它允许某人编写一条推文:

然后当他们点击推文按钮时,如果 GIF 足够小,就会在推文中发布;否则,将在推特上发布视频。

生成的 GIF 推文:https://twitter.com/spinturntable/status/730609962817294336

生成的视频推文:https://twitter.com/spinturntable/status/730609829128081408

以下是我实现此功能的方式(此 post 提供了很多帮助)。

创建用于撰写推文消息的初始 UIAlertView:

-(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];
    }

}

然后检测UIAlertView推文(我加了一个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);
                    }

                }];
            }
        }
    }

一些额外的事情:当 Compose Tweet Alert 出现时,我关注 UITextView:

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

检查 UITextView 是否少于 140 个字符的方法如下:

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

希望这对其他人有用,因为我花了很长时间才将所有内容拼凑在一起。