Reading .xlsx file iOS Objective C - ios

I am trying to download .xlsx file from server using AFNetworking. But it gives me error saying:
Error Domain=com.alamofire.error.serialization.response Code=-1016 "Request failed: unacceptable content-type: application/zip" UserInfo={NSLocalizedDescription=Request failed: unacceptable content-type: application/zip
It shows whole response inside the NSError.
I don't want to use any third party library as I am integrating this in my SDK itself.

To Download .xlsx file in AFNetworking2.x. You can't use this code. This code is for Json Serialization.
Reason:
/*
In AFURLResponseSerialization.m this line will convert downloaded data to json, which make invalid serialization error
*/
responseObject = [NSJSONSerialization JSONObjectWithData:data options:self.readingOptions error:&serializationError];
NOT Working Code :
// This code will not work for XLSX File
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
manager.responseSerializer.acceptableContentTypes = [NSSet setWithObjects:#"application/json", #"text/json", #"text/javascript", #"text/html", nil];
[manager GET:#"Link to xlsx File" parameters:nil success:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(#"JSON: %#", responseObject);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Error: %#", error);
}];
Use this :
https://github.com/AFNetworking/AFNetworking/tree/2.x#creating-a-download-task
NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
AFURLSessionManager *manager = [[AFURLSessionManager alloc] initWithSessionConfiguration:configuration];
NSURL *URL = [NSURL URLWithString:#"Link to xlsx File"];
NSURLRequest *request = [NSURLRequest requestWithURL:URL];
NSURLSessionDownloadTask *downloadTask = [manager downloadTaskWithRequest:request progress:nil destination:^NSURL *(NSURL *targetPath, NSURLResponse *response) {
NSURL *documentsDirectoryURL = [[NSFileManager defaultManager] URLForDirectory:NSDocumentDirectory inDomain:NSUserDomainMask appropriateForURL:nil create:NO error:nil];
return [documentsDirectoryURL URLByAppendingPathComponent:[response suggestedFilename]];
} completionHandler:^(NSURLResponse *response, NSURL *filePath, NSError *error) {
NSLog(#"File downloaded to: %#", filePath);
}];
[downloadTask resume];

Related

Migrating from AFNetworking 2.5.4 to 3.1

I'm trying to migrate this code over to AFNetworking 3.1 but I'm having some issues with the HTTPRequestOperationWithRequest function. From what I can tell it's been deprecated but I don't know what to use instead.
Here is the code:
- (AFHTTPRequestOperation *)GET:(NSString *)URLString
parameters:(NSDictionary *)parameters
timeoutInterval:(NSTimeInterval)timeoutInterval
success:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success
failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure
{
NSMutableURLRequest *request = [self.requestSerializer requestWithMethod:#"GET" URLString:[[NSURL URLWithString:URLString relativeToURL:self.baseURL] absoluteString] parameters:parameters error:nil];
[request setTimeoutInterval:timeoutInterval];
AFHTTPRequestOperation *operation = [self HTTPRequestOperationWithRequest:request success:success failure:failure];
[self.operationQueue addOperation:operation];
return operation;
}
As you can see in the README AFNetworking has switched to NSURLSession. This means that to create a request you do something like this:
NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
AFURLSessionManager *manager = [[AFURLSessionManager alloc] initWithSessionConfiguration:configuration];
NSURL *URL = [NSURL URLWithString:#"http://example.com/download.zip"];
NSURLRequest *request = [NSURLRequest requestWithURL:URL];
NSURLSessionDownloadTask *downloadTask = [manager downloadTaskWithRequest:request progress:nil destination:^NSURL *(NSURL *targetPath, NSURLResponse *response) {
NSURL *documentsDirectoryURL = [[NSFileManager defaultManager] URLForDirectory:NSDocumentDirectory inDomain:NSUserDomainMask appropriateForURL:nil create:NO error:nil];
return [documentsDirectoryURL URLByAppendingPathComponent:[response suggestedFilename]];
} completionHandler:^(NSURLResponse *response, NSURL *filePath, NSError *error) {
NSLog(#"File downloaded to: %#", filePath);
}];
[downloadTask resume];
Your exact function can't be replicated but you can probably work your way back to the caller of that function and replace it with something similar.

AFNetworking multi-part mp4 upload Error

I am trying to upload mp4 video using AFNetworking. It's giving me error
file = (
"The file must be a file of type: mp3, jpeg, bmp, png, mp4, wmv, avi."
);
Here is the code I am using to upload:
NSMutableURLRequest *request = [[AFJSONRequestSerializer serializer] multipartFormRequestWithMethod:#"POST" URLString:webURL parameters:params constructingBodyWithBlock:^(id<AFMultipartFormData> formData) {
BOOL isAppended = [formData appendPartWithFileURL:[NSURL fileURLWithPath:filePathStr] name:#"file" fileName:#"report.mp4" mimeType:#"video/mp4" error:nil];
if (isAppended) {
NSLog(#"appended successfully!");
}
} error:nil];
AFURLSessionManager *manager = [[AFURLSessionManager alloc] initWithSessionConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]];
NSProgress *progress = nil;
NSURLSessionUploadTask *uploadTask = [manager uploadTaskWithStreamedRequest:request progress:&progress completionHandler:^(NSURLResponse *response, id responseObject, NSError *error) {
if (error) {
NSLog(#"Error: %#", error);
} else {
NSLog(#"%# %#", response, responseObject);
}
multiPartCallBack(response,responseObject,error);
}];
[uploadTask resume];

Variables and file URL is not getting posted to server

I am trying to create a Http request using AFNetworking that send some variables and file to server using AFNetworking. but it is not sending files and Variables too.
The request get hit to server but it does not take any parameter or file with it, i double checked it file url and parameters dic is not empty
NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier:[NSString stringWithFormat:#"com.app316.MWPl.backgroundconfiguration"] ];
configuration.sharedContainerIdentifier=kGroupNameToShareData;
AFURLSessionManager *manager = [[AFURLSessionManager alloc] initWithSessionConfiguration:configuration];
AFHTTPRequestSerializer *serializer = [AFHTTPRequestSerializer serializer];
//parameters is NSDictionary With values in it
NSMutableURLRequest *requesting=[serializer requestWithMethod:#"POST" URLString:urlString parameters:parameters error:&error99];
NSURLSessionUploadTask *uploadTask4 =[manager uploadTaskWithRequest:requesting fromFile:storeURL progress:nil completionHandler:^(NSURLResponse *response, id responseObject, NSError *error)
{
if (error)
{
NSLog(#"Error: %#", error);
NSLog(#"Responce== %#", response);
NSLog(#"Success: =%#", responseObject);
}
else
{
NSLog(#"Success: %# %#", response, responseObject);
}
}];
[uploadTask4 resume];

Error Domain=AFNetworkingErrorDomain Code=-1016 "Request failed: unacceptable content-type: video/mp4"

I have video in server url then i'm downloading from url using AFNetworking for later playing the video. But while downloading i got below error
Error Domain=AFNetworkingErrorDomain Code=-1016 "Request failed: unacceptable content-type: video/mp4" UserInfo=0x1e8b6d30 {NSErrorFailingURLKey=http://center.net/projects/AR/Medica/focusvideo.mp4, AFNetworkingOperationFailingURLResponseErrorKey=<NSHTTPURLResponse: 0x1d55c260>, NSLocalizedDescription=Request failed: unacceptable content-type: video/mp4}
code for download the video:
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0]; // Get documents folder
NSString *dataPath = [documentsDirectory stringByAppendingPathComponent:#"images"];
if (![[NSFileManager defaultManager] fileExistsAtPath:dataPath])
[[NSFileManager defaultManager] createDirectoryAtPath:dataPath withIntermediateDirectories:NO attributes:nil error:&error];
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
[manager.requestSerializer setValue:#"application/x-www-form-urlencoded"
forHTTPHeaderField:#"Content-Type"];
[manager setResponseSerializer:[AFJSONResponseSerializer serializer]];
manager.responseSerializer.acceptableContentTypes = [NSSet setWithObjects:#"video/mpeg", nil];
[manager GET:#"http://center.net/projects/AR/Medica/focusvideo.mp4"
parameters:nil
success:^(AFHTTPRequestOperation *operation, id responseObject) {
[operation.responseData writeToFile:[dataPath stringByAppendingPathComponent:#"focusvideo.mp4"] atomically:YES];
NSLog(#"Successfully downloaded file to %#", [NSURL fileURLWithPath:dataPath]);
NSLog(#"THE RESPONSE: %#", responseObject);
}
failure:^(AFHTTPRequestOperation *operation, NSError *error1) {
NSLog(#"%#", error1);
}];
In AFURLResponseSerialization.m file Just add video/mpeg
in acceptable contact type.
Instead of :
self.acceptableContentTypes = [NSSet setWithObjects:#"application/json", #"text/json", #"text/javascript",#"text/html", nil];
Use this :
self.acceptableContentTypes = [NSSet setWithObjects:#"application/json", #"text/json", #"text/javascript",#"text/html",#"video/mpeg", nil];
If using AFNetworking 2.0, you can use the POST method, which simplifies this a bit:
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
manager.requestSerializer = [AFJSONRequestSerializer serializer];
NSDictionary *parameters = #{#"username":username, #"password":password};
[manager POST:#"https://mycompany.atlassian.net/rest/auth/latest/session/" parameters:parameters success:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(#"JSON: %#", responseObject);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Error: %#", error);
}];
This does the creation of the request, setting its Content-Type according to the requestSerializer setting, and encodes the JSON for you. One of the advantages of AFNetworking is that you can get out of the weeds of constructing and configuring NSURLRequest objects manually.

How to download a file and save it to the documents directory with AFNetworking?

I am using the AFNetworking library. I can't figure out how to download a file and save it to the documents directory.
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:#"..."]];
AFHTTPRequestOperation *operation = [[[AFHTTPRequestOperation alloc] initWithRequest:request] autorelease];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *path = [[paths objectAtIndex:0] stringByAppendingPathComponent:#"filename"];
operation.outputStream = [NSOutputStream outputStreamToFileAtPath:path append:NO];
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(#"Successfully downloaded file to %#", path);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Error: %#", error);
}];
[operation start];
I'm gonna bounce off #mattt's answer and post a version for AFNetworking 2.0 using AFHTTPRequestOperationManager.
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *path = [[paths objectAtIndex:0] stringByAppendingPathComponent:#"filename"];
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
AFHTTPRequestOperation *op = [manager GET:#"http://example.com/file/to/download"
parameters:nil
success:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(#"successful download to %#", path);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Error: %#", error);
}];
op.outputStream = [NSOutputStream outputStreamToFileAtPath:path append:NO];
I'm talking about AFNetworking 2.0
[AFHTTPRequestOperationManager manager] creates manager object with default AFJSONResponseSerializer, and it performs content types restriction. Take a look at this
- (BOOL)validateResponse:(NSHTTPURLResponse *)response
data:(NSData *)data
error:(NSError * __autoreleasing *)error
So we need to create a none response serializer and use AFHTTPRequestOperationManager as normal.
Here is the AFNoneResponseSerializer
#interface AFNoneResponseSerializer : AFHTTPResponseSerializer
+ (instancetype)serializer;
#end
#implementation AFNoneResponseSerializer
#pragma mark - Initialization
+ (instancetype)serializer
{
return [[self alloc] init];
}
- (instancetype)init
{
self = [super init];
return self;
}
#pragma mark - AFURLResponseSerializer
- (id)responseObjectForResponse:(NSURLResponse *)response
data:(NSData *)data
error:(NSError *__autoreleasing *)error
{
return data;
}
#end
Usage
self.manager = [AFHTTPRequestOperationManager manager];
self.manager.responseSerializer = [AFNoneResponseSerializer serializer];
[self.manager GET:#"https://sites.google.com/site/iphonesdktutorials/xml/Books.xml"
parameters:parameters
success:^(AFHTTPRequestOperation *operation, id responseObject)
{
if (success) {
success(responseObject);
}
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
if (failure) {
failure(error);
}
}];
so that we can get the whole file without any serialization
Documentation page has example with section 'Creating a Download Task':
NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
AFURLSessionManager *manager = [[AFURLSessionManager alloc] initWithSessionConfiguration:configuration];
NSURL *URL = [NSURL URLWithString:#"http://example.com/download.zip"];
NSURLRequest *request = [NSURLRequest requestWithURL:URL];
NSURLSessionDownloadTask *downloadTask = [manager downloadTaskWithRequest:request progress:nil destination:^NSURL *(NSURL *targetPath, NSURLResponse *response) {
NSURL *documentsDirectoryURL = [[NSFileManager defaultManager] URLForDirectory:NSDocumentDirectory inDomain:NSUserDomainMask appropriateForURL:nil create:NO error:nil];
return [documentsDirectoryURL URLByAppendingPathComponent:[response suggestedFilename]];
} completionHandler:^(NSURLResponse *response, NSURL *filePath, NSError *error) {
NSLog(#"File downloaded to: %#", filePath);
}];
[downloadTask resume];
NB! Code work with iOS 7+ (tested with AFNetworking 2.5.1)
From AFNetworking docs.
Save to loaded file to your documents.
AFNetworking 3.0
NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
AFURLSessionManager *manager = [[AFURLSessionManager alloc] initWithSessionConfiguration:configuration];
NSURL *URL = [NSURL URLWithString:#"http://example.com/download.zip"];
NSURLRequest *request = [NSURLRequest requestWithURL:URL];
NSURLSessionDownloadTask *downloadTask = [manager downloadTaskWithRequest:request progress:nil destination:^NSURL *(NSURL *targetPath, NSURLResponse *response) {
NSURL *documentsDirectoryURL = [[NSFileManager defaultManager] URLForDirectory:NSDocumentDirectory inDomain:NSUserDomainMask appropriateForURL:nil create:NO error:nil];
return [documentsDirectoryURL URLByAppendingPathComponent:[response suggestedFilename]];
} completionHandler:^(NSURLResponse *response, NSURL *filePath, NSError *error) {
NSLog(#"File downloaded to: %#", filePath);
}];
[downloadTask resume];
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
manager.responseSerializer = [AFCompoundResponseSerializer serializer];
manager.responseSerializer.acceptableContentTypes = [NSSet setWithObject:#"application/octet-stream"];
AFHTTPRequestOperation *operation = [manager GET:url parameters:nil success:^(AFHTTPRequestOperation *operation, id responseObject) {
if (responseObject) {
// your code here
} else {
// your code here
}
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
}];
[operation start];
// manager.responseSerializer.acceptableContentTypes = [NSSet setWithObject: #"application/octet-stream"]; can vary depending on what you expect
Yes, it is better to use AFNetworking 2.0 way with AFHTTPRequestOperationManager. With old way my file did download but for some reason didn't update in file system.
Appending to swilliam's answer, to show download progress, in AFNetworking 2.0 you do similarly - just set download progress block after setting output stream.
__weak SettingsTableViewController *weakSelf = self;
operation.outputStream = [NSOutputStream outputStreamToFileAtPath:newFilePath append:NO];
[operation setDownloadProgressBlock:^(NSUInteger bytesWritten, long long totalBytesWritten, long long totalBytesExpectedToRead) {
float progress = totalBytesWritten / (float)totalBytesExpectedToRead;
NSString *progressMessage = [NSString stringWithFormat:#"%# \n %.2f %% \n %# / %#", #"Downloading ...", progress * 100, [weakSelf fileSizeStringWithSize:totalBytesWritten], [weakSelf fileSizeStringWithSize:totalBytesExpectedToRead]];
[SVProgressHUD showProgress:progress status:progressMessage];
}];
This is my method to create bytes string:
- (NSString *)fileSizeStringWithSize:(long long)size
{
NSString *sizeString;
CGFloat f;
if (size < 1024) {
sizeString = [NSString stringWithFormat:#"%d %#", (int)size, #"bytes"];
}
else if ((size >= 1024)&&(size < (1024*1024))) {
f = size / 1024.0f;
sizeString = [NSString stringWithFormat:#"%.0f %#", f, #"Kb"];
}
else if (size >= (1024*1024)) {
f = size / (1024.0f*1024.0f);
sizeString = [NSString stringWithFormat:#"%.0f %#", f, #"Mb"];
}
return sizeString;
}
In addition to the previous answers, with AFNetworking 2.5.0 and iOS7/8 I have found that that the extra step of opening the output stream is also needed to prevent the app from hanging (and eventually crashing from lack of memory).
operation.outputStream = [NSOutputStream outputStreamToFileAtPath:dest
append:NO];
[operation.outputStream open];
[operation start];

Resources