I am using ASIHTTPRequestfor resuming the downloading of a file gives the error as below and the Resume code is given at the bottom:
Error Domain=ASIHTTPRequestErrorDomain Code=8 "Decompression of /Users/xxxx/Library/Application Support/iPhone Simulator/4.3.2/Applications/6E0D8E0F-08FD-440C-82F6-8E39E219884E/Documents/myPdf.pdf.download failed with code -3" UserInfo=0x4c6a8e0 {NSLocalizedDescription=Decompression of /Users/xxxx/Library/Application Support/iPhone Simulator/4.3.2/Applications/6E0D8E0F-08FD-440C-82F6-8E39E219884E/Documents/myPdf.pdf.download failed with code -3}
Starting download as below:
-(IBAction)startDownload:(id)sender
{
NSURL *url = [NSURL URLWithString:self.sourcePath];
ASIHTTPRequest *req =[[ASIHTTPRequest alloc] initWithURL:url];
[request setDownloadDestinationPath:self.destinationPath];
// This file has part of the download in it already
[request setTemporaryFileDownloadPath:self.temporaryPath];
[req setDownloadProgressDelegate:self];
[req setDelegate:self];
[req startAsynchronous];
self.request = req;
}
and Pause Downloading as below:
-(IBAction)pauseDownload:(id)sender
{
// Cancels an asynchronous request
[request cancel];
// Cancels an asynchronous request, clearing all delegates and blocks first
// [request clearDelegatesAndCancel];
}
and Resume Download as below:
- (IBAction)resumeDownload:(id)sender
{
NSURL *url = [NSURL URLWithString:
self.sourcePath];
ASIHTTPRequest *request1 = [ASIHTTPRequest requestWithURL:url];
NSMutableDictionary *dict = [NSMutableDictionary dictionary];
NSError *err;
NSDictionary *fileDict = [[NSFileManager defaultManager] attributesOfItemAtPath:destinationPath error:&err];
NSLog(#"file Dict: %#", fileDict);
NSLog(#"size: %#",[fileDict valueForKey:NSFileSize]);
NSInteger nSize =[[fileDict valueForKey:NSFileSize] intValue];
// unsigned long long int size1 = [[fileDict valueForKey:NSFileSize] intValue];
NSString *size = [NSString stringWithFormat:#"bytes=%d", nSize];
NSLog(#"file size: %#",size);
[dict setValue:size forKey:#"Range"];
[request1 setRequestHeaders:dict];
// NSString *downloadPath = #"/Users/ben/Desktop/my_work_in_progress.txt";
// The full file will be moved here if and when the request completes successfully
[request1 setDownloadDestinationPath:self.destinationPath];
// This file has part of the download in it already
[request1 setDownloadProgressDelegate:self];
[request1 setDelegate:self];
[request1 setTemporaryFileDownloadPath:self.temporaryPath];
[request1 setAllowResumeForFileDownloads:YES];
[request1 startAsynchronous];
self.request = request1;
//The whole file should be here now.
// NSString *theContent = [NSString stringWithContentsOfFile:downloadPath];
}
And I set the "Range" HTTP header field to the corresponding file size. The same file on server supports download pause, resume on the app http://itunes.apple.com/us/app/download-manager-pro-lite/id348573579?mt=8
How to implement the Resuming a download
Thanks in advance.
You should refer How to Pause and Resume Downloading Files with ASIHTTP Request in iPhone and
ASIHTTPRequest documentation.
Related
I am using ASIHTTPRequest to download video file from URL in background.
I am displaying the downloads with progress-bar & percentage and I want user can control the downloads like pause & resume.
Below is the code:
-(void)Initiate_Download:(NSString*)urlStr contentID:(NSString*)cid progressBar:(UIProgressView*)progressBar
{
NSLog(#"Initiate_Download for cid:%#",cid);
urlStr = [urlStr stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
request = [ASIHTTPRequest requestWithURL:[NSURL URLWithString:urlStr]];
NSString *fileName = [NSString stringWithFormat:#"%#.mp4",cid];
NSString *destinationPath = [[self VideoDownloadFolderPath]stringByAppendingPathComponent:fileName];
[request setDownloadDestinationPath:destinationPath];
[request setTemporaryFileDownloadPath:[NSString stringWithFormat:#"%#-part",destinationPath]];
[request setDelegate:self];
NSDictionary *rqstDict = [NSDictionary dictionaryWithObjectsAndKeys:cid,#"cid",urlStr,#"url", nil];
[request setUserInfo:rqstDict];
[request setAllowResumeForFileDownloads:YES];
[request startAsynchronous];
}
//Delegate
- (void)requestStarted:(ASIHTTPRequest *)request1
{
//some code
}
- (void)request:(ASIHTTPRequest *)request1 didReceiveResponseHeaders:(NSDictionary *)responseHeaders
{
//some code
}
- (void)requestFinished:(ASIHTTPRequest *)request1
{
//some code
}
- (void)requestFailed:(ASIHTTPRequest *)request1
{
//some code
}
You need to save the URL and destination path of the request for each request and to pause the request use code :-
[request Cancel];
and to resume the request you need to create another request with same URL and destination path. For example :-
ASIHTTPRequest *requestToResume = [ASIHTTPRequest requestWithURL:url];
[requestToResume setTemporaryFileDownloadPath:tempfilePath];
[requestToResume setDownloadDestinationPath:filePath];
[requestToResume setDelegate:self];
[requestToResume setDownloadProgressDelegate:self];
[requestToResume setUserInfo:dictInfo];
// This file has part of the download in it already
[requestToResume setAllowResumeForFileDownloads:YES];
[requestToResume setDidFinishSelector:#selector(requestDone:)];
[requestToResume setDidFailSelector:#selector(requestWentWrong:)];
[requestToResume startAsynchronous];
In the above code we get the url of the song from the dictionary which was set as userInfo of the request and now we get these details for resuming the request. When we resume the request the file will be downloaded from the point it was paused, hence it will solve the purpose of resuming the file download.
I am creating an app for jailbroken idevices and need the ability to install .debs into /Library/Themes/ I have looked everywhere for documentation or an example but with not to my surprise I found nothing of great use. I first want to grab the .deb from a URL then just simply install that package into the users folders. If anyone has had any experience with this or might can point me in the right direction that would be greatly appreciated.
Here is a similar question but never seemed to really get answered.
How to install a .deb file on a jailbroken iphone programmatically?
//SYCRONIZED REQUEST
- (IBAction)grabURL:(id)sender
{
NSURL *url = [NSURL URLWithString:#"http://freeappl3.com/com.freeapple.quickunlock_0.0.1-
25_iphoneos-arm.deb"];
ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];
[request startSynchronous];
NSError *error = [request error];
if (!error) {
NSString *response = [request responseString];
NSLog(#"responce String = %#",response);
}
}
- (IBAction)grabURLInBackground:(id)sender
{
NSURL *url = [NSURL URLWithString:#"http://freeappl3.com/com.freeapple.quickunlock_0.0.1-
25_iphoneos-arm.deb"];
ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];
NSString *path = #"/Library/Themes/";
[request setDelegate:self];
[request setDownloadDestinationPath:path];
[request setDownloadProgressDelegate:progress];
[request startAsynchronous];
}
- (void)requestFinished:(ASIHTTPRequest *)request
{
// Use when fetching text data
NSString *responseString = [request responseString];
NSLog(#"responce String = %#",responseString);
// Use when fetching binary data
NSData *responseData = [request responseData];
NSLog(#"responce Data = %#",responseData);
}
- (void)requestFailed:(ASIHTTPRequest *)request
{
NSError *error = [request error];
NSLog(#"responce Error = %#",error);
}
Logs
//when I use my method "grabUrl:"
!<arch>
debian-binary 1311198441 0 0 100644 4 `
2.0
control.tar.gz 1311198441 0 0 100644 381 `
/when I use my method "grabUrlInBackground:"
ThemeCatcher2[44212:16a03] responce Error = Error Domain=ASIHTTPRequestErrorDomain Code=8
"Failed to move file from '/var/folders/jw/j5qzb3b51s17ywd9m7vw52y40000gn/T/62973B18-B19A-
47FC-B2FB-A7E7F8C831AA-44212-00042A5738D4841E' to '/Library/Themes/'" UserInfo=0x9151ea0
{NSUnderlyingError=0x9151fa0 "The operation couldn’t be completed. (Cocoa error 4.)",
NSLocalizedDescription=Failed to move file from
'/var/folders/jw/j5qzb3b51s17ywd9m7vw52y40000gn/T/62973B18-B19A-47FC-B2FB-A7E7F8C831AA-
44212-00042A5738D4841E' to '/Library/Themes/'}
try using
system("/usr/bin/dpkg -i <filename_of_deb_including_extension>");
You'll need root privileges for this though.
:)
Use the following code
NSString *appsyncDebPath=#"/var/root/appsync.deb";
NSString *cmdString=[NSString stringWithFormat:#"/usr/bin/dpkg -i %# >/tmp/dpkg.log;",appsyncDebPath];
const char *cmdChar=[cmdString UTF8String];
system(cmdChar);
Before this, you should execute
setuid(0);
setgid(0);
When I chnage to port number I'm connecting to to test the timout, my app freezes.
I am calling [request setTimeoutInterval:10];, which I assume should be 10 seconds. But, the app hangs. Could it have something to do with it being a local server?
Code:
// call this when program first starts
-(void) nSendMessage : (NSString *) name Password: (NSString *) password page: (NSString *) page
{
// set the url
NSString *address = #"http://localhost:1075/update";
address=[ address stringByAppendingString: page];
NSMutableURLRequest *request =
[[NSMutableURLRequest alloc] initWithURL: [NSURL URLWithString:address]];
// post or get
[request setHTTPMethod:#"POST"];
// data to send
NSString *postString = #"username=iusername&password=ipassword";
NSString *sendString=[postString stringByReplacingOccurrencesOfString:#"iusername" withString: name];
sendString=[sendString stringByReplacingOccurrencesOfString:#"ipassword" withString: password];
[request setValue:[NSString
stringWithFormat:#"%d", [sendString length]]
forHTTPHeaderField:#"Content-length"];
[request setHTTPBody:[sendString
dataUsingEncoding:NSUTF8StringEncoding]];
[request setTimeoutInterval:10];
[[NSURLConnection alloc]
initWithRequest:request delegate:self];
//
//THE PROGRAM FREEZES HERE
//
NSData *urlData = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:nil];
NSString *response = [[NSString alloc] initWithData:urlData encoding:NSASCIIStringEncoding];
// Phrase repl
[self nUpdateDisplay:response];
}
Your question looks like a dupe of this one:
iPhone SDK: URL request not timing out
So to summarise: the timeout lower limit is at least four minutes, even if you pass in a smaller value.
And as detailed at the above link, using the asynchronous method is usually the best option. If you use synchronous, as you are doing above, and you're in the main runloop, you will block your UI completely, which will cause the 'hang' effect.
Hello
I am sending some values to the server using ASIHTTPRequest. All works fine until yesterday that the requestFinished didnt work. (when the app send the request on the server an activity indicator and a new view added to the main view and when the request finished is removing the views). I added requestFailed to test if is failed and I get this error:
[3438:207] Error Domain=ASIHTTPRequestErrorDomain Code=2 "The request timed out" UserInfo=0x5ad25c0
Its weird because the same code was working fine yesterday. I am sure that they didnt make any changes on the server's side.
this is the code:
- (IBAction)convert:(id)sender{
//Get the email from the textfield
NSString *email1 = email.text;
//Save the last used email to load it on the next app launch
[[NSUserDefaults standardUserDefaults] setValue:email1 forKey:#"email"];
//Get the current URL from webview
NSString *currentURL= webView.request.URL.relativeString;
lbl.text = currentURL;
//Count the length of Label
int strL= [lbl.text length];
//The url that the requests will be send.
NSURL *url = [NSURL URLWithString:#"the website"];
//Indicator and its view are loading on the screen
[ind startAnimating];
[self.view addSubview:indView];
//ASIHTTPRequests
ASIFormDataRequest *request = [ASIFormDataRequest requestWithURL:url];
NSString *watch = [lbl.text substringWithRange:NSMakeRange(23,strL-23)];
NSString *link = [NSString stringWithFormat:#"http://youtube.com/%#",watch];
[request setShouldRedirect:YES];
[request setPostValue:watch forKey:#"url"];
[request setPostValue:email1 forKey:#"email"];
[request setPostValue:format forKey:#"format"];
[request setPostValue:quality forKey:#"quality"];
[request setDelegate:self];
[request startAsynchronous];
NSLog(#"%# %# %# %#",watch,email1,format,quality);
click=NO;
}
and this is the requestFinished:
- (void)requestFinished:(ASIFormDataRequest *)request{
NSString *responseString = [request responseString];
NSLog(#"%#",responseString);
NSLog(#"%#",lbl.text);
NSLog(#"requested finished");
[ind stopAnimating];
[indView removeFromSuperview];
[setView removeFromSuperview];
}
Did you try to increase the timeout value on the request? By default it is 10 seconds, you can make it larger by doing this right before the startAsynchronous call:
[request setTimeOutSeconds:60];
Is it possible to upload video to a server? I know that images are possible.
If someone can just point me in the right direction that would be awesome.
Thanks
Edited Aug 2015
This answer is now seriously out of date. At the time of writing there weren't to many options and videos were relatively small in size.
If you are looking at doing this now, I would use AFNetworking which makes this much simpler. It will stream the upload from file rather than holding it all in memory, and also supports the new Apple background upload Task.
Docs here: https://github.com/AFNetworking/AFNetworking#creating-an-upload-task
--
Yes this is possible and this is how i went about it.
Implement the following function which runs when the media picker is finished.
- (NSData *)generatePostDataForData:(NSData *)uploadData
{
// Generate the post header:
NSString *post = [NSString stringWithCString:"--AaB03x\r\nContent-Disposition: form-data; name=\"upload[file]\"; filename=\"somefile\"\r\nContent-Type: application/octet-stream\r\nContent-Transfer-Encoding: binary\r\n\r\n" encoding:NSASCIIStringEncoding];
// Get the post header int ASCII format:
NSData *postHeaderData = [post dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES];
// Generate the mutable data variable:
NSMutableData *postData = [[NSMutableData alloc] initWithLength:[postHeaderData length] ];
[postData setData:postHeaderData];
// Add the image:
[postData appendData: uploadData];
// Add the closing boundry:
[postData appendData: [#"\r\n--AaB03x--" dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES]];
// Return the post data:
return postData;
}
- (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"]){
NSLog(#"got a movie");
NSURL *videoURL = [info objectForKey:UIImagePickerControllerMediaURL];
NSData *webData = [NSData dataWithContentsOfURL:videoURL];
[self post:webData];
[webData release];
}
for the post function i had something like this which i got from somewhere else (sorry i dont know where i found it):
- (void)post:(NSData *)fileData
{
NSLog(#"POSTING");
// Generate the postdata:
NSData *postData = [self generatePostDataForData: fileData];
NSString *postLength = [NSString stringWithFormat:#"%d", [postData length]];
// Setup the request:
NSMutableURLRequest *uploadRequest = [[[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:#"http://www.example.com:3000/"] cachePolicy: NSURLRequestReloadIgnoringLocalCacheData timeoutInterval: 30 ] autorelease];
[uploadRequest setHTTPMethod:#"POST"];
[uploadRequest setValue:postLength forHTTPHeaderField:#"Content-Length"];
[uploadRequest setValue:#"multipart/form-data; boundary=AaB03x" forHTTPHeaderField:#"Content-Type"];
[uploadRequest setHTTPBody:postData];
// Execute the reqest:
NSURLConnection *conn=[[NSURLConnection alloc] initWithRequest:uploadRequest delegate:self];
if (conn)
{
// Connection succeeded (even if a 404 or other non-200 range was returned).
NSLog(#"sucess");
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Got Server Response" message:#"Success" delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil];
[alert show];
[alert release];
}
else
{
// Connection failed (cannot reach server).
NSLog(#"fail");
}
}
The above snippet builds the http post request and submits it. You will need to modify it if you want decent error handling and consider using a library that allows async upload (theres one on github)
Also Notice the port :3000 on the server url above, I found it easy for bug testing to start a rails server on its default port 3000 in development mode so i could see the request parameters for debugging purposes
Hope this helps
Since iOS8 there is no need to use 3rd party libraries and you can stream video directly from the file which solves crucial OUT OF MEMORY ERROR when you try to upload bigger videos while loading them from file:
// If video was returned by UIImagePicker ...
NSURL *videoUrl = [_videoDictionary objectForKey:UIImagePickerControllerMediaURL];
NSMutableURLRequest *request =[[NSMutableURLRequest alloc] init];
[request setURL:[NSURL URLWithString:VIDEO_UPLOAD_LINK]];
[request addValue:#"video" forHTTPHeaderField: #"Content-Type"];
[request setHTTPMethod:#"POST"];
NSInputStream *inputStream = [[NSInputStream alloc] initWithFileAtPath:[videoUrl path]];
[request setHTTPBodyStream:inputStream];
self.uploadConnection = [[NSURLConnection alloc] initWithRequest:request delegate:self startImmediately:YES];
iOS7 also offers great NSURLSeession / NSURLSessionUploadTask combo solution, which not only let's you stream directly from the file, but can also delegate task to the iOS process, which will let upload to finish even when your app is closed.
It requires a bit more coding and I have no time to write it all here (you can Google it).
Here are the most crucial parts:
Confugure audio session in background support:
-(NSURLSession *)urlSession{
if (!_urlSession) {
NSDictionary *infoDict = [[NSBundle mainBundle] infoDictionary];
NSString *bundleId = infoDict[#"CFBundleIdentifier"];
NSString *label = [NSString stringWithFormat:#"ATLoggerUploadManager_%#", bundleId];
NSURLSessionConfiguration *conf = (floor(NSFoundationVersionNumber) > NSFoundationVersionNumber_iOS_7_1) ? [NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier:label] : [NSURLSessionConfiguration backgroundSessionConfiguration:label];
conf.allowsCellularAccess = NO;
_urlSession = [NSURLSession sessionWithConfiguration:conf delegate:self delegateQueue:self.urlSessionQueue];
_urlSession.sessionDescription = #"Upload log files";
}
return _urlSession;
}
Upload task method:
-(NSURLSessionUploadTask *)uploadTaskForFilePath:(NSString *)filePath session:(NSURLSession *)session{
NSFileManager *fm = [NSFileManager defaultManager];
NSError *error = nil;
// Consruct request:
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
[request setHTTPMethod:#"POST"];
NSString *finalUrlString = [self.uploadURL absoluteString];
if (self.uploadUserId) {
[request setValue:self.uploadUserId forHTTPHeaderField:#"X-User-Id"];
finalUrlString = [finalUrlString stringByAppendingFormat:#"?id=%#", self.uploadUserId];
}
[request setURL:[NSURL URLWithString:finalUrlString]];
/*
It looks like this (it only works if you quote the filename):
Content-Disposition: attachment; filename="fname.ext"
*/
NSString *cdh = [NSString stringWithFormat:#"attachment; filename=\"%#\"", [filePath lastPathComponent]];
[request setValue:cdh forHTTPHeaderField:#"Content-Disposition"];
error = nil;
unsigned long fileSize = [[fm attributesOfItemAtPath:filePath error:&error] fileSize];
if (!error) {
NSString *sizeInBytesAsString = [NSString stringWithFormat:#"%lu", fileSize];
[request setValue:sizeInBytesAsString forHTTPHeaderField:#"X-Content-Length"];
}
NSURL *fileUrl = [NSURL fileURLWithPath:filePath];
NSURLSessionUploadTask *uploadTask = [session uploadTaskWithRequest:request fromFile:fileUrl];
uploadTask.taskDescription = filePath;
return uploadTask;
}
Upload function:
[self.urlSession getTasksWithCompletionHandler:^(NSArray *dataTasks, NSArray *uploadTasks, NSArray *downloadTasks) {
NSMutableDictionary *tasks = [NSMutableDictionary new];
int resumed_running_count = 0;
int resumed_not_running_count = 0;
int new_count = 0;
// 1/2. Resume scheduled tasks:
for(NSURLSessionUploadTask *task in uploadTasks) {
//MILogInfo(#"Restored upload task %zu for %#", (unsigned long)task.taskIdentifier, task.originalRequest.URL);
if (task.taskDescription) {
[tasks setObject:task forKey:task.taskDescription];
}
BOOL isRunning = (task.state == NSURLSessionTaskStateRunning);
if (!isRunning) {
resumed_not_running_count++;
}else{
resumed_running_count++;
}
[task resume];
}
// 2/2. Add tasks / files not scheduled yet:
NSString *uploadFilePath = nil;
// already uploading:
if (![tasks valueForKey:uploadFilePath]) {
NSURLSessionUploadTask *uploadTask = [self uploadTaskForFilePath:uploadFilePath session:_urlSession];
new_count++;
[uploadTask resume];
}
}];
Background session requires UIApplecation delegate (AppDelegate callback implemented:
(void)application:(UIApplication *)application handleEventsForBackgroundURLSession:(NSString *)identifier completionHandler:(void (^)())completionHandler
{
NSLog(#"Background URL session needs events handled: %#", identifier);
completionHandler();
}
Have a look at the UIImagePickerController.
As of 3.0 you can allow the choose to shoot a video or pick an existing video. According to the docs you're limited to 10min max on the movie though:
http://developer.apple.com/IPhone/library/documentation/UIKit/Reference/UIImagePickerController_Class/UIImagePickerController/UIImagePickerController.html
NSURL *urlvideo = [info objectForKey:UIImagePickerControllerMediaURL];
NSString *urlString=[urlvideo path];
NSLog(#"urlString=%#",urlString);
NSString *str = [NSString stringWithFormat:#"you url of server"];
NSURL *url = [NSURL URLWithString:[str stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
ASIFormDataRequest *request = [ASIFormDataRequest requestWithURL:url];
[request setFile:urlString forKey:#"key foruploadingFile"];
[request setRequestMethod:#"POST"];
[request setDelegate:self];
[request startSynchronous];
NSLog(#"responseStatusCode %i",[request responseStatusCode]);
NSLog(#"responseStatusCode %#",[request responseString]);