将 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]];
}
}
希望这对其他人有用,因为我花了很长时间才将所有内容拼凑在一起。
在我的 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]];
}
}
希望这对其他人有用,因为我花了很长时间才将所有内容拼凑在一起。