2015-05-21 109 views
0

我已经搜索了几天的上传IOS资产的方式,但没有在临时目录中创建该文件的副本,但没有运气。我得到的代码使用临时副本,但复制可能在10MB到4GB之间的视频文件是不现实的。
最接近我以阅读只读模式阅读资产的代码如下。每苹果文档,这应该工作 - 请访问以下链接:NSURLSession - 在AWS IOS SDK中使用uploadTaskWithStreamedRequest

https://developer.apple.com/library/ios/documentation/Miscellaneous/Reference/EntitlementKeyReference/Chapters/EnablingAppSandbox.html

我已经启用这些键:

<key>com.apple.security.assets.movies.read-write</key> 
<string>YES</string> 
<key>com.apple.security.assets.music.read-write</key> 
<string>YES</string> 
<key>com.apple.security.assets.pictures.read-write</key> 
<string>YES</string> 
<key>com.apple.security.files.downloads.read-write</key> 
<string>YES</string> 

下面是代码:

// QueueController.h 
#import <AVFoundation/AVFoundation.h> 
#import <AWSS3.h> 
#import <Foundation/Foundation.h> 
#import <MobileCoreServices/MobileCoreServices.h> 
#import "Reachability1.h" 
#import "TransferType.h" 
#import "TransferModel.h" 
#import "Util.h" 

@interface QueueController : NSObject<NSURLSessionDelegate> 

@property(atomic, strong) NSURLSession* session; 
@property(atomic, strong) NSNumber* sessionCount; 
@property(atomic, strong) NSURLSessionConfiguration* configuration; 

+ (QueueController*)sharedInstance; 
- (void)transferMediaViaQueue:(MediaItem*)mediaItem 
      withTransferType:(TransferType)transferType; 
@end 

@implementation QueueController { 
    NSOperationQueue* copyQueue; 
    NSOperationQueue* transferQueue; 
    NSMutableArray* inProcessTransferArray; 
    NSMutableArray* pendingTransferArray; 
    bool isTransferring; 
} 

static QueueController* sharedInstance = nil; 

// Get the shared instance and create it if necessary. 
+ (QueueController*)sharedInstance { 
    @synchronized(self) { 
    if (sharedInstance == nil) { 
     sharedInstance = [[QueueController alloc] init]; 
    } 
    } 
    return sharedInstance; 
} 

- (id)init { 
    if (self = [super init]) { 
    appDelegate = 
     (RootViewControllerAppDelegate*)[UIApplication sharedApplication] 
      .delegate; 
    copyQueue = [[NSOperationQueue alloc] init]; 
    transferQueue = [[NSOperationQueue alloc] init]; 
    transferQueue.maxConcurrentOperationCount = MAX_CONCURRENT_TRANSFERS; 
    inProcessTransferArray = [[NSMutableArray alloc] init]; 
    pendingTransferArray = [[NSMutableArray alloc] init]; 
    isTransferring = false; 
    if (self.session == nil) { 
     self.configuration = [NSURLSessionConfiguration 
      backgroundSessionConfigurationWithIdentifier:@"transferQueue"]; 
     self.session = [NSURLSession sessionWithConfiguration:self.configuration 
                delegate:self 
               delegateQueue:transferQueue]; 
    } 
    } 
    return self; 
} 

- (void)transferMediaViaQueue:(MediaItem*)mediaItem 
      withTransferType:(TransferType)transferType { 
    // Create a transfer model 
    NSUserDefaults* defaultUser = [NSUserDefaults standardUserDefaults]; 
    NSString* user_id = [defaultUser valueForKey:@"UserId"]; 
    TransferModel* transferModel = [[TransferModel alloc] init]; 
    transferModel.mediaItem = mediaItem; 
    transferModel.transferType = transferType; 
    transferModel.s3Path = user_id; 
    transferModel.s3file_name = mediaItem.mediaName; 
    transferModel.assetURL = 
     [[mediaItem.mediaLocalAsset defaultRepresentation] url]; 

    ALAssetRepresentation* mediaRep = 
     [mediaItem.mediaLocalAsset defaultRepresentation]; 
    transferModel.content_type = 
     (__bridge_transfer NSString*)UTTypeCopyPreferredTagWithClass(
      (__bridge CFStringRef)[mediaRep UTI], kUTTagClassMIMEType); 

    @synchronized(pendingTransferArray) { 
    if ((!isTransferring) && 
     (transferQueue.operationCount < MAX_CONCURRENT_TRANSFERS)) { 
     isTransferring = true; 
     if (transferModel.transferType == UPLOAD) { 
     /** 
     * Read ALAsset from NSURLRequestStream 
     */ 
     NSInvocationOperation* uploadOP = [[NSInvocationOperation alloc] 
      initWithTarget:self 
        selector:@selector(uploadMediaViaLocalPath:) 
        object:transferModel]; 
     [transferQueue addOperation:uploadOP]; 
     [inProcessTransferArray addObject:transferModel]; 
     } 

    } else { 
     // Add to pending 
     [pendingTransferArray addObject:transferModel]; 
    } 
    } 
} 

- (void)uploadMediaViaLocalPath:(TransferModel*)transferModel { 
    @try { 
    /** 
    * Fetch readable asset 
    */ 
    NSURL* assetURL = 
     [[transferModel.mediaItem.mediaLocalAsset defaultRepresentation] url]; 
    NSData* fileToUpload = [[NSData alloc] initWithContentsOfURL:assetURL]; 
    NSURLRequest* assetAsRequest = 
     [NSURLRequest requestWithURL:assetURL 
         cachePolicy:NSURLRequestUseProtocolCachePolicy 
         timeoutInterval:60.0]; 
    /** 
    * Fetch signed URL 
    */ 
    AWSS3GetPreSignedURLRequest* getPreSignedURLRequest = 
     [AWSS3GetPreSignedURLRequest new]; 
    getPreSignedURLRequest.bucket = BUCKET_NAME; 
    NSString* s3Key = [NSString stringWithFormat:@"%@/%@", transferModel.s3Path, transferModel.s3file_name]; 
    getPreSignedURLRequest.key = s3Key; 
    getPreSignedURLRequest.HTTPMethod = AWSHTTPMethodPUT; 
    getPreSignedURLRequest.expires = [NSDate dateWithTimeIntervalSinceNow:3600]; 

    // Important: must set contentType for PUT request 
    // getPreSignedURLRequest.contentType = transferModel.mediaItem.mimeType; 
    getPreSignedURLRequest.contentType = transferModel.content_type; 
    NSLog(@"mimeType: %@", transferModel.content_type); 

    /** 
    * Upload the file 
    */ 
    [[[AWSS3PreSignedURLBuilder defaultS3PreSignedURLBuilder] 
     getPreSignedURL:getPreSignedURLRequest] 
     continueWithBlock:^id(BFTask* task) { 
      NSURLSessionUploadTask* uploadTask; 
      transferModel.sessionTask = uploadTask; 
      if (task.error) { 
      NSLog(@"Error: %@", task.error); 
      } else { 
      NSURL* presignedURL = task.result; 
      NSLog(@"upload presignedURL is: \n%@", presignedURL); 

      NSMutableURLRequest* request = 
       [NSMutableURLRequest requestWithURL:presignedURL]; 
      request.cachePolicy = NSURLRequestReloadIgnoringLocalCacheData; 
      [request setHTTPMethod:@"PUT"]; 
      [request setValue:transferModel.content_type 
       forHTTPHeaderField:@"Content-Type"]; 

      uploadTask = 
       [self.session uploadTaskWithStreamedRequest:assetAsRequest]; 
      [uploadTask resume]; 
      } 
      return nil; 
     }]; 
    } @catch (NSException* exception) { 
    NSLog(@"exception: %@", exception); 
    } @finally { 
    } 
} 

- (void)URLSession:(NSURLSession*)session 
         task:(NSURLSessionTask*)task 
      didSendBodyData:(int64_t)bytesSent 
       totalBytesSent:(int64_t)totalBytesSent 
    totalBytesExpectedToSend:(int64_t)totalBytesExpectedToSend { 
    // Calculate progress 
    double progress = (double)totalBytesSent/(double)totalBytesExpectedToSend; 
    NSLog(@"UploadTask progress: %lf", progress); 
} 

- (void)URLSession:(NSURLSession*)session 
        task:(NSURLSessionTask*)task 
    didCompleteWithError:(NSError*)error { 
    NSLog(@"(void)URLSession:session task:(NSURLSessionTask*)task " 
     @"didCompleteWithError:error called...%@", 
     error); 
} 

- (void)URLSessionDidFinishEventsForBackgroundURLSession: 
    (NSURLSession*)session { 
    NSLog(@"URLSessionDidFinishEventsForBackgroundURLSession called..."); 
} 

// NSURLSessionDataDelegate 
- (void)URLSession:(NSURLSession*)session 
      dataTask:(NSURLSessionDataTask*)dataTask 
didReceiveResponse:(NSURLResponse*)response 
completionHandler: 
    (void (^)(NSURLSessionResponseDisposition disposition))completionHandler { 
    //completionHandler(NSURLSessionResponseAllow); 
} 

@end 

但我m收到此错误:

(void)URLSession:session task:(NSURLSessionTask*)task didCompleteWithError:error called...Error Domain=NSURLErrorDomain Code=-999 "cancelled" UserInfo=0x17166f840 {NSErrorFailingURLStringKey=assets-library://asset/asset.MOV?id=94F90EEB-BB6A-4E9D-B77E-CDD60173B60C&ext=MOV, NSLocalizedDescription=cancelled, NSErrorFailingURLKey=assets-library://asset/asset.MOV?id=94F90EEB-BB6A-4E9D-B77E-CDD60173B60C&ext=MOV} 
userInfo: { 
    NSErrorFailingURLKey = "assets-library://asset/asset.MOV?id=94F90EEB-BB6A-4E9D-B77E-CDD60173B60C&ext=MOV"; 
    NSErrorFailingURLStringKey = "assets-library://asset/asset.MOV?id=94F90EEB-BB6A-4E9D-B77E-CDD60173B60C&ext=MOV"; 
    NSLocalizedDescription = cancelled; 
} 

在此先感谢您的帮助。

问候, -J

+0

我上面再次检查的权利网址: https://developer.apple.com/library/ios/documentation/Miscellaneous/Reference/EntitlementKeyReference/Chapters/EnablingAppSandbox.html#//apple_ref/doc/uid/TP40011195-CH4-SW7 似乎这些权利是Mac特有的,并且在IOS中不可用: 注:本章介绍特定于App Sandbox的OS X实现的属性列表键。它们不适用于iOS。 –

回答

0

一对夫妇使用NSURLSessionUploadTask有关评论:

  1. 如果实现didReceiveResponse,你必须电话completionHandler

  2. 如果你调用uploadTaskWithStreamedRequest,为request参数文件警告我们:

    The body stream and body data in this request object are ignored, and NSURLSession calls its delegate’s URLSession:task:needNewBodyStream: method to provide the body data.

    所以你必须,如果实施NSInputStream根据要求落实needNewBodyStream

  3. 被预先警告,但是使用这样的基于流的请求将创建一个请求,其中包含"chunked" transfer encoding,并不是所有服务器都可以处理该请求。

  4. 在代码中的某一点,您似乎尝试将资产的内容加载到NSData。如果您的资产很大,则无法将其合理加载到NSData对象中。此外,这与使用uploadTaskWithStreamedRequest不一致。

    您需要创建NSInputStream或从文件上载它。

  5. 您似乎在使用NSURLRequest的资产URL。该URL应该是您的Web服务的URL。

  6. 使用图像选择器时,您可以访问两个URL键:媒体URL(电影的file:// URL,但不是图片)和资产库参考URL(assets-library:// URL)。如果您使用媒体网址,则可以使用该网址上传影片。但是,您无法使用资产库参考网址进行上传。您只能与ALAssetsLibrary一起使用。

+0

谢谢,因为您发现这是正在进行中的工作。如何在没有图像选择器的情况下访问您在6中提到的媒体网址?我掌握了ALAsset,并通过ALAssetsLibrary收集了所有照片和视频。 -J –

+0

这是你所指的库:AVURLAsset? https://developer.apple.com/library/prerelease/ios/documentation/AVFoundation/Reference/AVURLAsset_Class/index.html#//apple_ref/occ/cl/AVURLAsset -J –

+0

是的,你可以抓住它那样。 – Rob

0

ALAssetPropertyURL是资产的纯粹URL标识符,即识别资产和资产组,我不认为您可以直接使用它来上传到服务。

如果其他方法很费时,可以使用AVAssetExportSession将资产导出到临时URL。 即

[AVAssetExportSession exportSessionWithAsset:[AVURLAsset URLAssetWithURL:assetURL options:nil] presetName:AVAssetExportPresetPassthrough]; 
+0

嗨, 是的,我有AVAssetExport的代码工作,但仍然导致延迟10秒或更多,我只是想输出视频(例如我可能必须输出mp4或mov,所以我将不得不检查扩展名,但我最终可能会这样做 -J –

+0

是的,不幸的是,这可能是唯一的方法btw如果你正在处理多个文件,你可以按照你不需要等待的工作流程所有要复制的文件开始上传,即你可以复制+上传,复制+上传等。 – Xcoder

+0

是的,我使用两个NSOperationQueues,一个用于复制,一个用于上传。因为iOS沙箱会让我陷入循环,我认为另一种选择可能是使用自定义UIImagePicker作为我的自定义库,但我不是当然,如果这可以让我直接访问文件。 –