【问题标题】:Share videos on Twitter via iOS App通过 iOS 应用在 Twitter 上分享视频
【发布时间】:2015-08-17 04:59:36
【问题描述】:

是否可以使用 SLRequest 共享视频?

我可以使用相同的图片分享图片

SLRequest *postRequest = [SLRequest requestForServiceType:SLServiceTypeTwitter requestMethod:SLRequestMethodPOST URL:requestURL parameters:message];

if (isImage)
{
    NSData *data = UIImagePNGRepresentation(imgSelected);
    [postRequest addMultipartData:data withName:@"media" type:@"image/png" filename:@"TestImage.png"];
}

postRequest.account = account;

[postRequest performRequestWithHandler:^(NSData *responseData, NSHTTPURLResponse *urlResponse, NSError *error)
{
    if (!error)
    {
        NSLog(@"Upload Sucess !");
    }
}];

【问题讨论】:

标签: ios objective-c video twitter social-framework


【解决方案1】:

我一直在阅读 Twitter 视频上传 API 文档,它非常简单。您基本上需要向他们的 API 发出 3 个 POST 请求。您上传的视频大小也限制为 15 MB。

使用此端点上传至少需要 3 次调用,一次调用 初始化请求,返回media_id,一次或多次调用 追加/上传二进制或base64编码数据,最后一次调用 完成上传并使 media_id 可用于其他资源。

所以它是这样工作的:

  • 请求 1:发送带有视频大小(以字节为单位)的初始化请求。这将返回我们必须在请求 2 和 3 中使用的媒体 ID 号。

  • 请求 2:使用请求 1 返回的媒体 ID 号上传视频数据。

  • 请求 3:视频上传完成后,将“FINALIZE”请求发送回 Twitter API。这让 Twitter API 知道视频文件的所有块都已完成上传。

注意 Twitter API 接受以“块”形式上传的视频。因此,如果您的视频文件很大,您可能希望将其拆分为多个文件,因此您将不得不多次重复“请求 2”(不要忘记每次增加“segment_index”数字)。

我已经尝试在下面进行编码。尝试一下并尝试一下。我稍后会更新我的答案以改进它。

-(void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info { 

    // Assign the mediatype to a string 
    NSString *mediaType = [info objectForKey:UIImagePickerControllerMediaType];

    // Check the media type string so we can determine if its a video
    if ([mediaType isEqualToString:@"public.movie"]) {

        NSURL *videoURL = [info objectForKey:UIImagePickerControllerMediaURL];
        NSData *webData = [NSData dataWithContentsOfURL:videoURL];

        // Get the size of the file in bytes.
        NSString *yourPath = [NSString stringWithFormat:@"%", videoURL];
        NSFileManager *man = [NSFileManager defaultManager];
        NSDictionary *attrs = [man attributesOfItemAtPath:yourPath error: NULL];
        UInt32 result = [attrs fileSize];

        //[self tweetVideoStage1:webData :result];
        [self tweetVideo:webData :result :1 :@"n/a"];
    }
}

-(void)tweetVideo:(NSData *)videoData :(int)videoSize :(int)mode :(NSString *)mediaID {

    NSURL *twitterVideo = [NSURL URLWithString:@"https://upload.twitter.com/1.1/media/upload.json"];

    // Set the parameters for the first twitter video request.
     NSDictionary *postDict;

    if (mode == 1) {

        postDict = @{@"command": @"INIT",
                     @"total_bytes" : videoSize,
                     @"media_type" : @"video/mp4"};
    }

    else if (mode == 2) {

        postDict = @{@"command": @"APPEND",
                     @"media_id" : mediaID,
                     @"segment_index" : @"0",
                     @"media" : videoData };
    }

    else if (mode == 3) {

        postDict = @{@"command": @"FINALIZE",
                     @"media_id" : mediaID };
    }

    SLRequest *postRequest = [SLRequest requestForServiceType:SLServiceTypeTwitter requestMethod:SLRequestMethodPOST URL:requestURL:twitterVideo parameters:postDict];

    // Set the account and begin the request.
    postRequest.account = account;
    [postRequest performRequestWithHandler:^(NSData *responseData, NSHTTPURLResponse *urlResponse, NSError *error) {

        if (!error) {

            if (mode == 1) {

                // Parse the returned data for the JSON string
                // which contains the media upload ID.
                NSMutableDictionary *returnedData = [NSJSONSerialization JSONObjectWithData:responseData options:NSJSONReadingMutableContainers error:&error]
                NSString *tweetID = [NSString stringWithFormat:@"%@", [returnedData valueForKey:@"media_id_string"]];
                [self tweetVideo:videoData :result :2 :tweetID];
            }

            else if (mode == 2) {
                [self tweetVideo:videoData :result :3 :mediaID];
            }
        }

        else {
            NSLog(@"Error stage %d - %", mode, error);
        }
    }];
}

更新 - Twitter API 错误 - https://dev.twitter.com/overview/api/response-codes

在回答您的第一条评论时,错误 503 表示 Twitter 服务器已超载,目前无法处理您的请求。

503 Service Unavailable Twitter 服务器已启动,但已超载 与请求。请稍后再试。

【讨论】:

  • 我从tweetVideoStage3 得到状态码503
  • @VNJ 这基本上意味着 Twitter 服务器现在无法处理您的请求。您将需要再次尝试该请求。 - dev.twitter.com/overview/api/response-codes
  • @VNJ 在发出请求时,您可能还需要传递 API 密钥。我现在无法访问我的笔记本电脑,所以我还不能检查代码。我将在今天晚些时候测试此代码并尽可能修复它。
  • tweetVideoStage2 中,我将以下作为字典NSMutableDictionary *postDictionary = [[NSMutableDictionary alloc] init]; NSString *data = [videoData base64EncodedString]; [postDictionary setValue:@"APPEND" forKey:@"command"]; [postDictionary setValue:mediaID forKey:@"media_id"]; [postDictionary setValue:@"0" forKey:@"segment_index"]; [postDictionary setValue:data forKey:@"media_data"]; 传递。我没有收到任何回复
  • @VNJ 您必须收到一些响应,即使是“200 OK”这样简单的响应。您需要解析存储在请求中传回的“responseData”中的响应数据。查看 tweetVideoStage1 以了解如何解析返回的数据的示例。
【解决方案2】:

我知道如何使用新 API 将视频上传到 Twitter。而且我试过了,效果很好。

请检查:https://github.com/liu044100/SocialVideoHelper

你只需要调用这个类方法。

+(void)uploadTwitterVideo:(NSData*)videoData account:(ACAccount*)account withCompletion:(dispatch_block_t)completion;

希望它能解决你的问题。

最好的问候。

【讨论】:

  • 你好,这个库看起来很有用。如何插入用户推文并将其与视频一起发送?看起来这只是分享视频而已。
  • Lizza,在 tweetVideoStage4 函数中,有 statusContent 变量。这是 Tweet 文本。您必须将 tweettext 发送到uploadTwitterVideo,然后发送到 tweetVideoStage2,然后...发送到带有文本的 tweetVideoStage4。换句话说,创建了一个更多的 func 参数。
  • @Vitalya 感谢您指出这一点!一切看起来都应该正常工作,但我一直走到最后,第 4 阶段的响应是 {"code":324,"message":"The validation of media ids failed."} 。我可以验证我使用的 mediaID 都是相同的,并且它们来自 Twitter,它只是不会拍摄视频。你以前见过这个吗?
  • @Lizza,老实说没有得到这个错误。可能是媒体文件的问题。尝试使用 NSString *filePath = [[NSBundle mainBundle] pathForResource:@"vvideo" ofType:@"mp4"]; NSData *data = [NSData dataWithContentsOfFile:filePath options:nil error:&error];如果帐户没问题应该可以工作。
  • @Lizza {"code":324,"message":"媒体ID验证失败。"}可能是媒体ID不对,请重新检查。
【解决方案3】:

一直在寻找具有以下功能的在 Twitter 上分享视频的解决方案:

  • 支持分块上传
  • 内置支持用户凭据检索

由于找不到符合我需要的,所以我决定写一个。

https://github.com/mtrung/TwitterVideoUpload

我已经测试了一段时间,它对我来说效果很好。

希望对你有帮助,

问候。

【讨论】:

    【解决方案4】:

    根据@Dan 的答案试试这个。它没有经过测试,但我认为它可以工作。

    使用 Cocoa-podspod 'TwitterKit'

    如果您不使用 Pod,请尝试使用 fabric

    //for Extern call
    //Mode is 1
    //MediaId is 0
    - (void)uploadTwitterVideo:(NSData*)videoData videoTitle:(NSString *)title desc:(NSString *)desc withMode:(int)mode  mediaID:(NSString *)mediaID withCompletion:(dispatch_block_t)completion
    {
        NSString *twitterPostURL = @"https://upload.twitter.com/1.1/media/upload.json";
    
        NSDictionary *postParams;
        if (mode == 1) {
            postParams = @{@"command": @"INIT",
                           @"total_bytes" : [NSNumber numberWithInteger: videoData.length].stringValue,
                           @"media_type" : @"video/mp4"};
        } else if (mode == 2) {
            postParams = @{@"command": @"APPEND",
                           @"media_id" : mediaID,
                           @"segment_index" : @"0"};
        } else if (mode == 3) {
            postParams = @{@"command": @"FINALIZE",
                           @"media_id" : mediaID };
        } else if (mode == 4) {
            postParams = @{@"status": desc,
                           @"media_ids" : @[mediaID]};
        }
    
        TWTRAPIClient *twitterInstance = [[Twitter sharedInstance] APIClient];
        NSError *error;
        NSURLRequest *requestTw = [twitterInstance URLRequestWithMethod:@"POST" URL:twitterPostURL parameters:postParams error:&error];
    
        [twitterInstance sendTwitterRequest:requestTw completion:^(NSURLResponse * _Nullable response, NSData * _Nullable data, NSError * _Nullable connectionError) {
            NSLog(@"HTTP Response: %li, responseData: %@", (long)response, [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]);
            if (error) {
                NSLog(@"There was an error:%@", [error localizedDescription]);
            } else {
    
                if (mode == 1) {
                    NSMutableDictionary *returnedData = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:&connectionError];
                    NSString *mediaIDResponse = [NSString stringWithFormat:@"%@", [returnedData valueForKey:@"media_id_string"]];
                    NSLog(@"stage one success, mediaID -> %@", mediaID);
                    [self uploadTwitterVideo:videoData videoTitle:title desc:desc withMode:2 mediaID:mediaIDResponse withCompletion:completion];
                } else if (mode == 2) {
                    [self uploadTwitterVideo:videoData videoTitle:title desc:desc withMode:3 mediaID:mediaID withCompletion:completion];
                } else if (mode == 3) {
                    [self uploadTwitterVideo:videoData videoTitle:title desc:desc withMode:4 mediaID:mediaID withCompletion:completion];
                } else if (mode == 4) {
                    DispatchMainThread(^(){completion();});
                }
            }
        }];
    }
    

    此 API 的工作原理如下。

    - 安装应用程序 (twitter) 时登录和未安装时登录

    - 优先从设置中获取凭证

    检查这个case

    【讨论】:

    • 我必须在“mode”和“mediaid”参数中传递什么?
    【解决方案5】:

    斯威夫特

    它非常简单。 首先,您需要登录您的 Twitter 帐户。转到电话设置,然后单击 Twitter 应用程序并登录。 现在只需在任何地方调用这个videoUpload func

    视频或分块上传方法 Reference

    在该代码上替换您的视频类型/扩展名 并仔细阅读所有推特requirements

    var twitterAccount = ACAccount()
    
            func videoUpload{
                    let path = Bundle.main.path(forResource: "file-Name", ofType:"mp4")
    
                    let filePath = path
                    var fileSize = UInt64()
    
                    do {
                        //return [FileAttributeKey : Any]
                        let attr = try FileManager.default.attributesOfItem(atPath: filePath!)
                        fileSize = attr[FileAttributeKey.size] as! UInt64
    
                        //if you convert to NSDictionary, you can get file size old way as well.
                        let dict = attr as NSDictionary
                        fileSize = dict.fileSize()
                    } catch {
                        print("Error: \(error)")
                    }
    
                    let accountStore = ACAccountStore()
                    let twitterAccountType = accountStore.accountType(withAccountTypeIdentifier: ACAccountTypeIdentifierTwitter)
                    accountStore.requestAccessToAccounts(with: twitterAccountType, options: nil) { (granted, error) in
    
                        if granted {
                            let accounts = accountStore.accounts(with: twitterAccountType)
                            if (accounts?.count)! > 0 {
                                self.twitterAccount = accounts?.last as! ACAccount
                            }}}
    
    
                    twitterAccount = Twitter.sharedInstance().sessionStore.session() as! ACAccount
            uploadVideoToTwitter(videoURL: URL(string : path!)! as NSURL, fileSize: UInt32(fileSize))
            }
    
        func uploadVideoToTwitter(videoURL:NSURL,fileSize: UInt32) {
    
                if let videoData = NSData(contentsOfFile: videoURL.path!){
                    self.tweetVideoInit(videoData: videoData, videoSize: Int(fileSize))
                }
            }
    
            func tweetVideoInit(videoData:NSData,videoSize:Int) {
    
                let uploadURL = NSURL(string:"https://upload.twitter.com/1.1/media/upload.json")
    
                var params = [String:String]()
    
                params["command"] = "INIT"
                params["total_bytes"]  = String(videoData.length)
                params["media_type"]  = "video/mp4"
    
                let postRequest = SLRequest(forServiceType: SLServiceTypeTwitter,
                                            requestMethod: SLRequestMethod.POST,
                                            url: uploadURL as URL!,
                                            parameters: params)
    
                postRequest?.account = self.twitterAccount;
    
                postRequest?.perform(handler: { ( responseData, urlREsponse,error) in
                    if let err = error {
                        print(error as Any)
                    }else{
                        do {
                            let object = try JSONSerialization.jsonObject(with: responseData! as Data, options: .allowFragments)
                            if let dictionary = object as? [String: AnyObject] {
    
                                if let tweetID = dictionary["media_id_string"] as? String{
                                    self.tweetVideoApped(videoData: videoData, videoSize: videoSize, mediaId: tweetID, chunk: 0)
                                }
                            }
                        }
                        catch {
                            print(error)
                        }
                    }
                })
            }
    
            func tweetVideoApped(videoData:NSData,videoSize:Int ,mediaId:String,chunk:NSInteger) {
    
                let uploadURL = NSURL(string:"https://upload.twitter.com/1.1/media/upload.json")
    
                var params = [String:String]()
    
                params["command"] = "APPEND"
                params["media_id"]  = mediaId
                params["segment_index"]  = String(chunk)
    
                let postRequest = SLRequest(forServiceType: SLServiceTypeTwitter,
                                            requestMethod: SLRequestMethod.POST,
                                            url: uploadURL as URL!,
                                            parameters: params)
    
                postRequest?.account = self.twitterAccount
                postRequest?.addMultipartData(videoData as Data!, withName: "media", type: "video/mov", filename:"mediaFile")
    
                postRequest?.perform(handler: { ( responseData, urlREsponse,error) in
                    if let err = error {
                        print(err)
    
                    }else{
                        self.tweetVideoFinalize(mediaId: mediaId)
                    }
                })
            }
    
            func tweetVideoFinalize(mediaId:String) {
                let uploadURL = NSURL(string:"https://upload.twitter.com/1.1/media/upload.json")
    
                var params = [String:String]()
                params["command"] = "FINALIZE"
                params["media_id"]  = mediaId
    
                let postRequest = SLRequest(forServiceType: SLServiceTypeTwitter,
                                            requestMethod: SLRequestMethod.POST,
                                            url: uploadURL as URL!,
                                            parameters: params)
    
                postRequest?.account = self.twitterAccount;
                postRequest?.perform(handler: { ( responseData, urlREsponse,error) in
                    if let err = error {
                        print(err)
                    }else{
                        do {
                            let object = try JSONSerialization.jsonObject(with: responseData! as Data, options: .allowFragments)
                            if let dictionary = object as? [String: AnyObject] {
                                self.postStatus(mediaId: mediaId)
                            }
                        }
                        catch {
                            print(error)
                        }
                    }
                })
            }
    
            func postStatus(mediaId:String) {
    
                let uploadURL = NSURL(string:"https://api.twitter.com/1.1/statuses/update.json")
    
                var params = [String:String]()
                params["status"] = "my first Video Upload"
                params["media_ids"]  = mediaId
    
                let postRequest = SLRequest(forServiceType: SLServiceTypeTwitter,
                                            requestMethod: SLRequestMethod.POST,
                                            url: uploadURL as URL!,
                                            parameters: params)
    
                postRequest?.account = self.twitterAccount;
    
                postRequest?.perform(handler: { ( responseData, urlREsponse,error) in
                    if let err = error {
                        print(err)
                    }else{
                        do {
                            let object = try JSONSerialization.jsonObject(with: responseData! as Data, options: .allowFragments)
                            if let dictionary = object as? [String: AnyObject] {
                                print("video uploaded")
                            }
                        }
                        catch {
                            print(error)
                        }
                    }
                })
            }
    

    【讨论】:

      【解决方案6】:

      我能够成功地将视频上传到推特! 以下是 twitter 文档中提到的步骤:

      1. 申请推特账号

        accountStore.requestAccessToAccounts(with: twitterAccountType,options:nil){(granted, error) in
        
      2. POST 媒体/上传 (INIT)

        params["command"] = "INIT"
        params["total_bytes"]  = String(videoData.length)
        params["media_type"]  = "video/mov"
        
      3. 发布媒体/上传(附加)

        params["command"] = "APPEND"
        params["media_id"]  = mediaId
        params["segment_index"]  = String(chunk)
        
      4. 发布媒体/上传(定稿)

        params["command"] = "FINALIZE"
        params["media_id"]  = mediaId
        
      5. 发布媒体/上传

        params["status"] = twitterDescription
        params["media_ids"]  = mediaId
        

      这是推特文档链接https://dev.twitter.com/rest/media/uploading-media.html

      请在此处详细说明使用 SLRequest 将视频上传到 Twitter 的详细解决方案。

      http://swiftoverflow.blogspot.in/2017/04/upload-video-to-twitter-using-slrequest.html

      【讨论】:

      猜你喜欢
      • 2013-02-05
      • 2015-09-24
      • 1970-01-01
      • 2012-12-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多