How to download pdf from google drive V3 API in IOS? - 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:)];
}

Related

How to download public-shared file from Google Drive (without Drive API) using Objective C

I currently upload some files on my Google Drive, then create shared links for these files. These shared links has forms
https://drive.google.com/uc?export=download&confirm=wAFv&id=[may_be_file_id]
I create an app that can download these files. I use ASIHTTPRequest open source library to download those files
ASIHTTPRequest* req = [ASIHTTPRequest requestWithURL:[NSURL URLWithString:<downloadURL>]];
req.shouldContinueWhenAppEntersBackground = YES;
req.timeOutSeconds = 60;
req.delegate = self;
req.tag = filename;
[req setDownloadDestinationPath:<a_video_path_on_Document_directory>];
ASINetworkQueue* networkQueue = [[ASINetworkQueue alloc] init];
[networkQueue addOperation:req];
[networkQueue setRequestDidFinishSelector:#selector(finishCallback:)];
[networkQueue setRequestDidFailSelector:#selector(failCallback:)];
[networkQueue setDelegate:self];
[networkQueue go];
The argument 'downloadURL' is shared url of each I mentioned above. But after the 'go' method of networkQueue invoke, the finishCallback is called immediately although the file size is about 2Gb. I tried with another downloader third party opensource but get the same result.
Is the problem on URL or Google Drive has done something to prevent download, but when I paste these URL on Safari on my Macbook, it downloads files OK.
What the problem here?
I just use Google Drive API to download its files.
GTLRDriveService* service = [[GTLRDriveService alloc] init];
GTMSessionFetcher *fetcher = [service.fetcherService fetcherWithURLString:downloadURL]; //GTLServiceDrive *service;
[fetcher beginFetchWithCompletionHandler:^(NSData *data, NSError *error) {
if (error == nil) {
NSLog(#"Retrieved file content");
// File Downloaded!
} else {
NSLog(#"An error occurred: %#", error);
}
}];
And it runs into completion block immediately and print 'Retrieved file content'.
How can it be?

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
}

Aws iOS sdk Pre-singed url giving "SignatureDoesNotMatch" error

Have problem accessing file using presigned url generated by aws sdk, given all necessary permission for the bucket.
I have downloaded the sample code from there github and changed the below
Awscredential provider as per my requirement.
The changes are below
AWSStaticCredentialsProvider *credentialsProvider =[[AWSStaticCredentialsProvider alloc] initWithAccessKey:S3AccessKey secretKey:S3secretKey];
AWSServiceConfiguration *configuration = [[AWSServiceConfiguration alloc] initWithRegion:AWSRegionUSEast1 credentialsProvider:credentialsProvider];
AWSServiceManager.defaultServiceManager.defaultServiceConfiguration = configuration;
Even though i upload the file sucessfully to aws I am not able to access them using the presigned url which i get from the aws sdk while uploading.
Can anyone point out the things i am missing in order to access the files using presigned url.
when url is loaded in browser SignatureDoesNotMatch error is shown
The most possible reason for "SignatureDoesNotMatch" is the contents in header-field are different from the one provided while generating the presigned url.
Here is a code snippet to demonstrate how to generate and download a file by using presigned url:
AWSS3GetPreSignedURLRequest *getPreSignedURLRequest = [AWSS3GetPreSignedURLRequest new];
getPreSignedURLRequest.bucket = #"bucketname";
getPreSignedURLRequest.key = #"keyname";
getPreSignedURLRequest.HTTPMethod = AWSHTTPMethodGET;
getPreSignedURLRequest.expires = [NSDate dateWithTimeIntervalSinceNow:3600];
AWSS3PreSignedURLBuilder *preSignedURLBuilder = [AWSS3PreSignedURLBuilder defaultS3PreSignedURLBuilder];
[[[preSignedURLBuilder getPreSignedURL:getPreSignedURLRequest] continueWithBlock:^id(BFTask *task) {
if (task.error) {
XCTAssertNil(task.error);
return nil;
}
NSURL *presignedURL = task.result;
//NSLog(#"(GET)presigned URL is: %#",presignedURL.absoluteString);
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:presignedURL];
request.cachePolicy = NSURLRequestReloadIgnoringLocalCacheData;
NSError *returnError = nil;
NSHTTPURLResponse *returnResponse = nil;
NSData *responseData = [NSURLConnection sendSynchronousRequest:request returningResponse:&returnResponse error:&returnError];
return nil;
}] waitUntilFinished];
The problem is with presigned url encoding. In iOS and android sdks (not in windows) you need to encode the query string in the Presigned url again.
NEWURL=baseurl +(encoded query String);
NEWURL is the correct url you can access.
it worked for me.
Try with this, you need to register PreSignedURL builder.
AWSStaticCredentialsProvider *credentialsProvider =[[AWSStaticCredentialsProvider alloc] initWithAccessKey:S3AccessKey secretKey:S3secretKey];
AWSServiceConfiguration *configuration = [[AWSServiceConfiguration alloc] initWithRegion:AWSRegionUSEast1 credentialsProvider:credentialsProvider];
AWSServiceManager.defaultServiceManager.defaultServiceConfiguration = configuration;
// Register S3 PreSignedURL Builder
[AWSS3PreSignedURLBuilder registerS3PreSignedURLBuilderWithConfiguration:configuration forKey:#"configuration_name"];
AWSS3PreSignedURLBuilder * urlBuilder = [AWSS3PreSignedURLBuilder S3PreSignedURLBuilderForKey:#"configuration_name"];

AWS iOS v2 Video uploading issue

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

Using NSURLCredentialPersistenceForSession while request and then clearing the credentials on logout still persist the cerdentials

I am using NSURLCredentialPersistenceForSession within didReceiveAuthenticationChallenge of NSURLConnection delegate method while login.
Now when I logout and use this code for clearing the storage..
NSURLCredentialStorage *credentialStorage = [NSURLCredentialStorage sharedCredentialStorage];
NSDictionary *credentialsDicationary = [credentialStorage allCredentials];
NSLog(#"credentialsDicationary..%#",[credentialsDicationary description]);
for (NSURLProtectionSpace *space in [credentialsDicationary allKeys]) {
NSDictionary *spaceDictionary = [credentialsDicationary objectForKey:space];
NSLog(#"spaceDictionary..%#",[spaceDictionary description]);
for (id userName in [spaceDictionary allKeys]) {
NSURLCredential *credential = [spaceDictionary objectForKey:userName];
[credentialStorage removeCredential:credential forProtectionSpace:space];
}
}
But when I suddenly login again exactly after logout the login happens with wrong credentials. Please let mw know how to clear the cache. It works if I relogin after some 5 secs of time.
Thanks in advance..
AJ
If you're using NSURLSession, invalidate the session and create a new one, e.g.:
[self.session invalidateAndCancel];
self.session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:self delegateQueue:nil];
This will clear session-scoped credentials.
If you use NSURLCredentialPersistenceForSession to create the credential then the app stores the credential for the entire session until the app is closed.
You can work around this by either:
changing the url (like appending '#' to the end of the url)
Use NSURLCredentialPersistenceNone and provide the credentials with each nsurlrequest
Append auth info to the url (http://username:password#mywebsite.com), instead of using creds
Append auth info to the request header, instead of using creds
//Pseudo code for appending to header:
NSString *authString = [NSString stringWithFormat:#"%#:%#", self.loginCreds.username, self.loginCreds.password];
NSData *stringData = [authString dataUsingEncoding:NSUTF8StringEncoding];
authString = [NSString stringWithFormat:#"Basic %#", [stringData base64EncodedString]];
[[self requestHeader] setValue:authString forHTTPHeaderField:#"Authorization"];
It's possible to remove the credential but it can take minutes before it is actually removed. However, I don't remember how its done.. It's either done the way you mentioned in the question or through the keychain.
I had the same issue and I tried clear the credential storage, cookies associated with url and even trying to reset the session but nothing seemed to work, finally I just resorted to adding a a random query string value to the end of the url and that did the trick for me
// Random number calculated.
NSInteger randomNumber = arc4random() % 16;
NSURL* apiURL = [NSURL URLWithString:#"https://localhost/api/"];
[[RKObjectManager sharedManager] getObjectsAtPath:[NSString stringWithFormat:#"%#getUser?randomNumber=%d",apiURL,randomNumber]
parameters:nil
success:successBlock
failure:failureBlock];
So instead of trying to remove current cached credentials (which seemed impossible) just use a "fresh" url so there aren't any cached objects associated with it.
I was facing the same problem, now it works.
Using NSURLConnection this issue can be fixed easily by adding a random number to the end of the URL:
So, search for your URLRequest and append the random number to URLRequest
NSInteger randomNumber = arc4random() % 999;
NSString *requestURL = [NSString stringWithFormat:#"%#?cache=%ld",yourURL,(long)randomNumber];
NSURL *URLRequest = [NSURL URLWithString:requestURL];
And make sure you have a random number at the end of all URLs you are calling.

Resources