AWS iOS v2 Video uploading issue - ios

After using AWS SDK for iOS v1 i was using [S3PutObjectRequest stream] property to upload video files to the s3 server.With new version of the AWS SDK for the IOS such property was removed. I found out that new version has few Classes that can handle it such as [AWSKinesis] am i right are this classes are suitable for uploading video to the S3 server?
If yes could someone provide some examples please.

You should use AWSS3TransferManager for uploading movies to your S3 bucket. This sample app demonstrates how to use the transfer manager.

self.s3 = [[AmazonS3Client alloc] initWithAccessKey:ACCESS_KEY_ID withSecretKey:SECRET_KEY];
NSError *error = nil;
NSData *data = [NSData dataWithContentsOfFile:tempPath options:nil error:&error];
S3PutObjectRequest *por = [[S3PutObjectRequest alloc] initWithKey:#"Video Name"
inBucket:#"BucketName"];
//por.contentType = #"image/jpeg";
por.contentType = #"video/quicktime";
por.data = data;
por.delegate = self;
start = [NSDate date];
[self.s3 putObject:por];
Successfully uploaded then below method will call:
-(void)request:(AmazonServiceRequest *)request didCompleteWithResponse: (AmazonServiceResponse *)response
Failed to upload then below method will call:
-(void)request:(AmazonServiceRequest *)request didFailWithError:(NSError *)error

For people that what to use AWSKinesis lib is available nice tutorial.
http://docs.aws.amazon.com/mobile/sdkforios/developerguide/kinesis.html

Related

Minimal iOS code to do an HTTP GET from Amazon S3 with authorization?

The documentation for AWS (Amazon Web Services) is vast, and rather chaotic. I found a git repo for iOS that demonstrates performing various tasks including a couple of projects for getting/putting data to S3.
I already have an existing client application that uses Apples NSURLSession to do HTTPS GET requests for content from S3 when the records are public. However, my client want the data to be secure.
I don't want to invest the time to learn the AWSS3TransferManager framework, and I don't want to include the whole framework in my project, either). I don't want all that baggage. All I need is a call that will let me provide a user ID or access key/secret key, or perhaps a password, and get a query string I can add to my HTTP get requests that authorizes the request for all users of the app.
I don't need upload. I don't need API-based console support. I don't need or want Amazon's session manager/download manager. All I want is the 1 call that will let me provide an access key and secret key and get back something I can add to the get request that authorizes it, so I can submit a request and get back a file. Should be easy, right? I've been pouring through the documentation and sample code for a couple of hours now, and no luck.
Looking at the samples, they use 500 kilos of frameworks I don't need and don't want.
Can somebody point me to a minimal library that lets me generate the key(s) I need to prove that the user has access to this content, given username and an access key Id and secret key, or perhaps a password? This would not be that hard.
Here is simple code for HTTP GET. If you are interested in HTTP PUT - check implementation at http://simpleios.s3-website-us-east-1.amazonaws.com.
#import <CommonCrypto/CommonCrypto.h>
static NSString * const accessKey=#"AKIAIOSFODNN7EXAMPLE";
static NSString * const secretKey=#"wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY";
...
NSString * fileUrl=#"https://s3.amazonaws.com/someBucket/someFile";
NSString * bucket=#"someBucket";
NSString * filePath=#"someFile";
NSURLSession *delegateFreeSession=[NSURLSession sessionWithConfiguration: [NSURLSessionConfiguration defaultSessionConfiguration] delegate: nil delegateQueue: [NSOperationQueue mainQueue]];
[[delegateFreeSession dataTaskWithURL: [NSURL URLWithString:[fileUrl stringByAppendingString:[self buildQuery:bucket forFile:filePath]]] completionHandler:^(NSData *received, NSURLResponse *response, NSError *error) {
if(error!=nil ){
NSLog(#"Error trying to download file - %#", error);
}
else{
//do something
}
}] resume ];
...
- (NSString * ) buildQuery:(NSString *)bucketName forFile:(NSString *)filePath{
NSString *expDate=[self expirationDate];
NSMutableString *base=[NSMutableString new];
[base appendString:#"?AWSAccessKeyId="];
[base appendString:accessKey];
[base appendString:#"&Expires="];
[base appendString:expDate];
[base appendString:#"&Signature="];
NSMutableString *stringToSign=[NSMutableString new];
[stringToSign appendString:#"GET\n\n\n" ];
[stringToSign appendString:expDate];
[stringToSign appendString:#"\n" ];
[stringToSign appendString:#"/"];
[stringToSign appendString:bucketName];
[stringToSign appendString:#"/"];
[stringToSign appendString:filePath];
NSString *signature=[self sign:stringToSign];
signature=[signature stringByReplacingOccurrencesOfString:#"/" withString:#"%2F"];
signature=[signature stringByReplacingOccurrencesOfString:#"+" withString:#"%2B"];
signature=[signature stringByReplacingOccurrencesOfString:#"=" withString:#"%3D"];
[base appendString:signature];
return base;
}
- (NSString *) expirationDate{
int expireInSeconds=300;
double sec=[[NSDate date] timeIntervalSince1970]+expireInSeconds;
static NSNumberFormatter *numberFormatter=nil;
if(numberFormatter==nil){
numberFormatter=[NSNumberFormatter new];
[numberFormatter setMaximumFractionDigits:0];
}
NSString *expDate=[numberFormatter stringFromNumber:[NSNumber numberWithDouble:sec]];
return expDate;
}
- (NSString *)sign:(NSString *)stringToSign {
NSData *data=[stringToSign dataUsingEncoding:NSUTF8StringEncoding];
CCHmacContext context;
const char *keyCString = [secretKey cStringUsingEncoding:NSASCIIStringEncoding];
CCHmacInit(&context, kCCHmacAlgSHA1, keyCString, strlen(keyCString));
CCHmacUpdate(&context, [data bytes], [data length]);
unsigned char digestRaw[CC_SHA1_DIGEST_LENGTH];
NSInteger digestLength = CC_SHA1_DIGEST_LENGTH;
CCHmacFinal(&context, digestRaw);
NSData *digestData = [NSData dataWithBytes:digestRaw length:digestLength];
return [digestData base64EncodedStringWithOptions:kNilOptions];
}
One problem with this is that it sounds like you are trying to embed secret/access keys into the app itself instead of using something more secure like Amazon Cognito https://aws.amazon.com/cognito/, which the iOS SDK provides access to.
The other is that iOS SDK for AWS doesn't allow you to cherry pick which methods to include, though it does allow you to generate a pre-signed URL for S3 gets. For just S3 you only need the S3 & Core frameworks, but it sounds like that is too much as well.
If you really just want the most minimal download size possible you could implement AWS signing yourself by looking at the AWS iOS SDK source code https://github.com/aws/aws-sdk-ios or S3's signing documentation, but signing an AWS request is non-trivial, and you would lose a lot of beneficial logic (retries, ect...).
You also mentioned not wanting to learn the TransferManager. The TransferUtility is the successor of that and would be drastically faster to learn than implementing your own signing. I can't see it taking more than an hour or two to understand it (maybe a little more if you decide to use Cognito for authentication, but that's really tangential to TransferUtility). http://docs.aws.amazon.com/mobile/sdkforios/developerguide/s3transferutility.html
Edit: In order to give credentials for the PreSignedURLBuilder. You can also see adding credentials to all clients created with the SDK at http://docs.aws.amazon.com/mobile/sdkforios/developerguide/setup.html (Getting started with Swift/Objective-c section)
You can use this to provide credentials
AWSCognitoCredentialsProvider *credentialsProvider = [[AWSCognitoCredentialsProvider alloc]
initWithRegionType:AWSRegionUSEast1 identityPoolId:#"IDENTITY_POOL_ID"];
AWSServiceConfiguration *configuration = [[AWSServiceConfiguration alloc]
initWithRegion:AWSRegionUSEast1 credentialsProvider:credentialsProvider];
[AWSS3PreSignedURLBuilder registerS3PreSignedURLBuilderWithConfiguration:configuration
forKey:#"customServiceConfiguration"];
AWSS3PreSignedURLBuilder *customPreSignedURLBuilder = [AWSS3PreSignedURLBuilder S3PreSignedURLBuilderForKey:#"customServiceConfiguration"];

How to download pdf from google drive V3 API in IOS?

Working with the Google Drive V3 API to download files and pdf.
As per Google Doc, Google Drive V3 Api below is the Url to download files(say text file).
NSString *url = [NSString stringWithFormat:#"https://www.googleapis.com/drive/v3/files/%#?alt=media",file.identifier];
However when i simply used this url, it gives me error while downloading files then i tried something like this with Client ID and its working fine.(here i removed alt=media and added client id in the url.Which is perfectly working fine).Below is the modified url.
`NSString *url = [NSStringstringWithFormat:#"https://www.googleapis.com/drive/v3/files/%#?key=%#", file.identifier,kClientID];`
Now for pdf they have mentioned in the Google Doc to use the below url.
NSString *url = [NSString stringWithFormat:#"https://www.googleapis.com/drive/v3/files/%#/export?alt=media&mimeType=application/pdf", file.identifier];
Again i m facing the same problem..the above url for downloading the pdf giving me the error.i have done all the permutation and combination with the url with no success.
***The Sample code provided in the Doc is using google drive V2 Api.
So,How to download pdf with the use of Google Drive V3 Api?Please help.
Today, I success for download file from Google Drive V3 Api.
self.fileSize = [loadFile.quotaBytesUsed unsignedIntegerValue];
////////////////////////////////////////////////////////////////////////////////////////////////////
GTMSessionFetcher *fetcher = [GTMSessionFetcher fetcherWithURLString:loadFile.webContentLink];
if(fetcher==nil)
{
break;
}
fetcher.authorizer = [GTLServiceDrive sharedServiceDrive].authorizer;
fetcher.destinationFileURL = [NSURL fileURLWithPath:self.intoPath];
__block typeof(self) blockSelf = self;
fetcher.downloadProgressBlock = ^(int64_t bytesWritten, int64_t totalBytesWritten, int64_t totalBytesExpectedToWrite) {
//get download progress
};
////////////////////////////////////////////////////////////////////////////////////////////////////
[fetcher beginFetchWithDelegate:self didFinishSelector:#selector(fetcher:finishedWithData:error:)];
-(void)downloadFile:(NSString *)url{
GTMSessionFetcher *fetcher = [GTMSessionFetcher fetcherWithURLString:url];
fetcher.authorizer = [[GTLServiceDrive alloc]init].authorizer;
fetcher.destinationFileURL = [NSURL fileURLWithPath:url];
__block typeof(self) blockSelf = self;
fetcher.downloadProgressBlock = ^(int64_t bytesWritten, int64_t totalBytesWritten, int64_t totalBytesExpectedToWrite) {
//get download progress
NSLog(#"bytesWritten = %d",bytesWritten);
NSLog(#"totalBytesWritten = %d",totalBytesWritten);
NSLog(#"totalBytesExpectedToWrite = %d",totalBytesExpectedToWrite);
};
[fetcher beginFetchWithDelegate:self didFinishSelector:#selector(fetcher:finishedWithData:error:)];
}

Uploading images to Firebase

I'm trying to upload images to Firebase like this:
Firebase *ref = [[Firebase alloc] initWithUrl:#"https://<app-name>.firebaseio.com/posts"];
Firebase *newPost = [ref childByAutoId];
NSDictionary *newPostData = #{
#"image" : [self encodeToBase64String:image]
};
[newPost updateChildValues:newPostData];
I'm using this code to encode the image:
- (NSString *)encodeToBase64String:(UIImage *)image {
return [UIImagePNGRepresentation(image) base64EncodedStringWithOptions:NSDataBase64Encoding64CharacterLineLength];
}
But this does not work as the string exceeds the maximum size:
Terminating app due to uncaught exception 'InvalidFirebaseData', reason: '(updateChildValues:) String exceeds max size of 10485760 utf8 bytes:
What can I do to resolve this problem? I haven't found anything online in regards to iOS development and images when using Firebase.
If the image is too big, you should store a smaller image. Let me quote myself: How do you save a file to a Firebase Hosting folder location for images through android?
The Firebase Database allows you to store JSON data. While binary data is not a type that is supported in JSON, it is possible to encode the binary data in say base64 and thus store the image in a (large) string. [But] while this is possible, it is not recommended for anything but small images or as a curiosity to see that it can be done.
Your best option is typically to store the images on a 3rd party image storage service.
As Frank van Puffelen suggested, my solution was to use Amazon S3 for imagine storage, and use Firebase to store a reference to the image location.
I created a method called uploadImage: and it looks like this:
-(void)uploadImage:(UIImage *)image
{
// Create reference to Firebase
Firebase *ref = [[Firebase alloc] initWithUrl:#"https://<MY-APP>.firebaseio.com"];
Firebase *photosRef = [ref childByAppendingPath:#“photos];
Firebase *newPhotoRef = [photosRef childByAutoId];
// Image information
NSString imageId = [[NSUUID UUID] UUIDString];
// Create dictionary containing information
NSDictionary photoInformation = #{
#“photo_id” : imageId
// Here you can add more information about the photo
};
NSString *imagePath = [NSTemporaryDirectory() stringByAppendingPathComponent:[NSString stringWithFormat:#"%#.png", imageId]];
NSData *imageData = UIImagePNGRepresentation(image);
[imageData writeToFile:imagePath atomically:YES];
NSURL *imageUrl = [[NSURL alloc] initFileURLWithPath:imagePath];
AWSS3TransferManagerUploadRequest *uploadRequest = [AWSS3TransferManagerUploadRequest new];
uploadRequest.bucket = #“<AMAZON S3 STORAGE NAME>“; // create your own by setting up an account on Amazon aws.
uploadRequest.key = imageId;
uploadRequest.contentType = #"image/png";
uploadRequest.body = imageUrl;
AWSS3TransferManager *transferManager = [AWSS3TransferManager defaultS3TransferManager];
[[transferManager upload:uploadRequest] continueWithExecutor:[AWSExecutor mainThreadExecutor] withBlock:^id(AWSTask *task) {
if (!task.error) {
// Update Firebase with reference
[newPhotoRef updateChildValues:currentPHD withCompletionBlock:^(NSError *error, Firebase *ref) {
if (!error) {
[newPhotoRef updateChildValues:photoInformation withCompletionBlock:^(NSError *error, Firebase *ref) {
if (!error) {
// Uploaded image to Amazon S3 and reference to Firebase
}
}];
}
}];
} else {
// Error uploading
}
return nil;
}];
}
Edit
The method should be a block method, something like this:
-(void)uploadImage:(UIImage *)image withBlock:(void (^)(Firebase *ref, NSError *error, AWSTask *task))handler
{
// upload
}

iOS how to insert a local file URL into NSURLConnection response data?

I'm trying to modify a behavior of a webpage within my iOS app and make the in-page media player play a file from the local caches folder instead of fetching it from a web server.
Below is my code that replaces the http:// video path with a local file path. The code does not work, giving me "Resource Temporary not available. Please try again" error message popup. Is it possible to have a web-based media player play file from a local disk using file URL?
I tried substituting these for the instanceURL, but they don't seem to work.
[fileURL path]
[fileURL absolutePath]
I'm intercepting the request for the file and am parsing it to find out that the page is asking for a video file:
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
// An NSURLConnection delegate callback. We pass this on to the client.
{
NSDictionary* decisionDictionary = [[RequestListener sharedInstance] shouldContinue:connection processRequestData:data];
BOOL shouldContinue = [decisionDictionary[#"shouldContinue"] boolValue];
if(shouldContinue == NO)
{
return;
}else
{
NSData* d = data;
//substitute fake data
if(decisionDictionary[#"data"])
{
d = decisionDictionary[#"data"];
}
[[self client] URLProtocol:self didLoadData:d];
}
}
Within my shouldContinue method, I check if the video is present locally and modify the response data to create a path to a local video.
NSString* path = [VideoDownloader localVideoPathForVideoID:videoID];
NSURL* fileURL = [NSURL fileURLWithPath:path];
DLog(#"url:%#",[fileURL absoluteString]);
NSString* replacement = [NSString stringWithFormat:#"\"instanceUrl\":\"%#\"",[[fileURL absoluteURL] absoluteString]];
DLog(#"replacement:%#",replacement);
NSString* forgedResponse = [parts componentsJoinedByString:#","];
NSData* forgedData = [forgedResponse dataUsingEncoding:NSUTF8StringEncoding];
return #{#"shouldContinue":#(YES),#"data":forgedData};
Have a look at NSURLProtocol. You can intercept http requests before they are sent to a host to decide what to do about it: Continue to server, redirect to local cache.
There's a decent tutorial by our beloved Ray Wenderlich.
Apple has a programming guide as well.

AWS iOS SDK v2 Files Upload to S3 issue

I am trying to upload images to the S3, and for files that are less than 2 mb, it is ok, but for more than 2 mb, server return Code=-1001 "The request timed out.". Could someone explain how it is possible to handle this problem?
Code example below:
AWSS3 *s3 = [[AWSS3 alloc] initWithConfiguration:configuration];
AWSS3PutObjectRequest *logFile = [AWSS3PutObjectRequest new];
logFile.bucket = bucket;
logFile.key = path;
logFile.contentType = [self contentTypeForImageData:self.userPicture];
logFile.body = self.userPicture;
logFile.contentLength = [NSNumber numberWithInteger:[self.userPicture length]];
[[s3 putObject:logFile] continueWithBlock:^id(BFTask *task) {
NSLog(#"Amazon error : %#", [task error]);
return nil;
}];
When using initWithConfiguration:, you must manually retain a strong reference to an instance of AWSS3. One way to accomplish this is to make it a property. Using defaultS3 eliminates the need for this since the AWSS3 class retains the strong reference to the default service client for you.
Hope this helps,

Resources