File downloader Using NSURLSessionTask downloadTask - ios

I want to create File download manager to download multiple files with download percent with play pause delete functionality .
I try below code to download multiple file successfully ...but unable to add progress bar please help
for (int i = 0; i < [arr_bookChapter count]; i++) {
NSURLSessionTask * downloadTask = [session downloadTaskWithURL: downloadfileUrl completionHandler: ^ (NSURL * location, NSURLResponse * response, NSError * error) {
if (error == nil) {
NSHTTPURLResponse * httpResponse = (NSHTTPURLResponse * ) response;
if ([httpResponse statusCode] == 200) {
//download file save here
dispatch_queue_t backgroundQueue = dispatch_queue_create("dispatch_queue_#1", 0);
dispatch_async(backgroundQueue, ^ {
dispatch_async(dispatch_get_main_queue(), ^ {
// NSError *error;
//download complete here
});
});
}
} else {
//faile
}
}];
[downloadTask resume];
}
Here i got swift code:
Can someone create or or provide solution for objective-C

You can easily do this, you just need to implement these delegates in your ViewContorller.
<NSURLSessionDataDelegate, NSURLSessionDelegate, NSURLSessionTaskDelegate>
And than you need to follow this code:
#property (nonatomic, retain) NSMutableData *dataToDownload;
#property (nonatomic) float downloadSize;
- (void)viewDidLoad {
[super viewDidLoad];
NSURLSessionConfiguration *defaultConfigObject = [NSURLSessionConfiguration defaultSessionConfiguration];
NSURLSession *defaultSession = [NSURLSession sessionWithConfiguration: defaultConfigObject delegate: self delegateQueue: [NSOperationQueue mainQueue]];
NSURL *url = [NSURL URLWithString: #"your url"];
NSURLSessionDataTask *dataTask = [defaultSession dataTaskWithURL: url];
[dataTask resume];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveResponse:(NSURLResponse *)response completionHandler:(void (^)(NSURLSessionResponseDisposition disposition))completionHandler {
completionHandler(NSURLSessionResponseAllow);
progressBar.progress=0.0f;
_downloadSize=[response expectedContentLength];
_dataToDownload=[[NSMutableData alloc]init];
}
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data {
[_dataToDownload appendData:data];
progressBar.progress=[ _dataToDownload length ]/_downloadSize;
}

Related

NSURLSession: can't get resume data after calling cancelByProducingResumeData

I want to resume downloading after user cancels downloading or something wrong happens. But when I call cancelByProducingResumeData method, the resumeData is nil. So, I can't resume downloading. I'm sure the download link can be resumed, because our PC client can resume downloading of this link.
Here is my code. Here is the full project.
#import "ViewController.h"
#interface ViewController ()
{
NSURLSession *_session;
}
#property (weak, nonatomic) IBOutlet UIProgressView *progressView;
#property NSURLSessionDownloadTask *netTask;
#property NSData *resumeData;
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
if (_session == nil) {
NSURLSessionConfiguration *confi = [NSURLSessionConfiguration defaultSessionConfiguration];
_session = [NSURLSession sessionWithConfiguration:confi delegate:self delegateQueue:[NSOperationQueue mainQueue]];
}
}
- (IBAction)startAction:(id)sender {
[self start];
}
- (IBAction)stopActon:(id)sender {
[self stop];
}
- (void)stop {
__weak typeof(self) vc = self;
[self.netTask cancelByProducingResumeData:^(NSData * _Nullable resumeData) {
vc.resumeData = resumeData;
vc.netTask = nil;
}];
}
- (void)start {
if (self.resumeData != nil) {
self.netTask = [_session downloadTaskWithResumeData:self.resumeData];
} else {
NSURL *downlaodURL = [NSURL URLWithString:#"http://sdl24.yunpan.cn/share.php?method=Share.download&cqid=37ef0df7c8155bacf55c237bd433ddd8&dt=24.02b6cbb4148de503fe35ddab08dac35b&e=1459317290&fhash=41181b28ff97806ef8469842b4a5eabc330a0c60&fname=feistudy%2B%2B%25E8%25AF%25AD%25E8%25A8%2580%25E5%25AD%25A6%25E4%25B9%25A0%25E6%2596%25B9%25E6%25B3%2595%25E8%25AE%25BA%25E8%25BF%25B0&fsize=87624815&nid=14471440239484082&st=e08142ab7c935cdd15ecc8851c82e819&xqid=22309244"];
self.netTask = [_session downloadTaskWithURL:downlaodURL];
}
[self.netTask resume];
}
- (NSString*)filePath
{
NSString *doc = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
NSString *path = [doc stringByAppendingPathComponent:#"p.rmvb"];
return path;
}
#pragma mark - NSURLSessionDownloadDelegate
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask
didFinishDownloadingToURL:(NSURL *)location
{
dispatch_async(dispatch_get_main_queue(), ^{
NSFileManager *manager = [NSFileManager defaultManager];
[manager moveItemAtPath:location.path toPath:[self filePath] error:nil];
NSLog(#"locaton.path:%#", location.path);
NSLog(#"filePaht:%#",[self filePath]);
});
}
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask
didWriteData:(int64_t)bytesWritten
totalBytesWritten:(int64_t)totalBytesWritten
totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite
{
dispatch_async(dispatch_get_main_queue(), ^{
double progress = totalBytesWritten/(double)totalBytesExpectedToWrite;
NSLog(#"progress:%f",progress);
self.progressView.progress = progress;
});
}
#pragma mark - NSURLSessionTaskDelegate
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task
didCompleteWithError:(nullable NSError *)error
{
if (error) {
NSData *resumeData = error.userInfo[NSURLSessionDownloadTaskResumeData];
self.resumeData = resumeData;
}
}
#end
There's a long list of requirements for when resume data can be obtained. Among other things:
The response must contain an ETag or Last-Modified header.
I think the response must also contain an Accept-Ranges: bytes header
The temporary file must still exist (not low on disk space).
It must be an HTTP or HTTPS request.
The Last-Modified or ETag header must indicate that the file hasn't changed since it was last requested.
There might be other requirements that I'm forgetting, e.g. HTTP/1.1.

Using NSURLSession inside NSURLProtocol

I'm trying to create a transparent NSURLProtocol for http:// and https:// connections using NSURLSession. However at the moment, even though the completion handler is being run, URL requests with the app (UIWebView) are coming back blank. Does anybody have any ideas? Code is below:
#import "MyURLProtocol.h"
// AppDelegate
#import "AppDelegate.h"
static NSString * const MyURLProtocolHandledKey = #"MyURLProtocolHandledKey";
#interface MyURLProtocol () <NSURLConnectionDelegate,NSURLSessionDelegate>
#property (nonatomic, strong) NSURLConnection *connection;
#property (nonatomic, strong) NSMutableData *mutableData;
#property (nonatomic, strong) NSURLResponse *response;
#end
#implementation MyURLProtocol
+(BOOL)canInitWithRequest:(NSURLRequest*)request
{
if ([NSURLProtocol propertyForKey:MyURLProtocolHandledKey inRequest:request])
return NO;
NSString *scheme = request.URL.scheme.lowercaseString;
return [scheme isEqualToString:#"http"] || [scheme isEqualToString:#"https"];
}
+ (NSURLRequest *) canonicalRequestForRequest:(NSURLRequest *)request {
return request;
}
-(void)startLoading
{
NSMutableURLRequest *newRequest = [self.request mutableCopy];
[NSURLProtocol setProperty:#YES forKey:#"MyURLProtocolHandledKey" inRequest:newRequest];
NSURLRequest *request = newRequest;
NSURLSession *session = [NSURLSession sharedSession];
NSURLSessionDataTask *task = [session dataTaskWithRequest:request
completionHandler:
^(NSData *data, NSURLResponse *response, NSError *error) {
if (error != nil) {
NSLog(#"There was an error");
}
NSLog(#"Completiio handler ran");
self.mutableData = [NSMutableData dataWithData:data];
self.response = response;
}];
[task resume];
}
- (void) stopLoading {
[self.connection cancel];
self.mutableData = nil;
}
// Delegate stuff
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
[self.client URLProtocol:self didReceiveResponse:response cacheStoragePolicy:NSURLCacheStorageNotAllowed];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
[self.client URLProtocol:self didLoadData:data];
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
[self.client URLProtocolDidFinishLoading:self];
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
[self.client URLProtocol:self didFailWithError:error];
}
#end
Your code is using NSURLConnection delegates to pass data back to the caller, e.g. connectionDidFinishLoading:.
To fix this:
Replace these with NSURLSession delegate methods.
Create and retain a custom session whose delegate is your protocol class instance; the shared session doesn't have a delegate, so it won't call your class's delegate methods.
Remove the callback block so that the delegate method for request completion will be called correctly.

NSURLSession delegate implementation returns only <head> of html

Let's go straight into code.
First in appDelegate, I register my connection protocol:
[NSURLProtocol registerClass:[MyURLConnection class]];
Here's what my connection class looks like:
+(BOOL)canInitWithRequest:(NSURLRequest *)request {
return YES;
}
-(void)startLoading {
if (self.cachedResponse) {
NSLog(#"there is a cached response %#", self.cachedResponse);
}
MyNetworkSession *task = [MyNetworkSession new];
task.request = self.request;
task.urlClient = self.client;
task.isDataTask = YES;
task.isBackgroundSession = YES;
[task start];
}
-(void)stopLoading {
// nothing here
}
Now, MyNetworkSession is the delegate for NSURLSession tasks, like so:
// ----------- MyNetworkSession.h
#interface MyNetworkSession : NSObject
<NSURLSessionDelegate,
NSURLSessionTaskDelegate,
NSURLSessionDataDelegate>
-(void) start;
#end
//------------ MyNetworkSession.m
#implementation MyNetworkSession {
NSURLSessionDataTask *_dataTask;
NSURLSessionDownloadTask *_downloadTask;
}
// create session
-(NSURLSession*) session {
static NSURLSession *session = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
NSURLSessionConfiguration *backgroundConfiguration = [
NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier:
BACKGROUND_SESSION_IDENTIFIER];
backgroundConfiguration.requestCachePolicy = NSURLRequestUseProtocolCachePolicy;
session = [NSURLSession
sessionWithConfiguration:backgroundConfiguration
delegate:self
delegateQueue:nil];
});
return session;
}
// start download/data task
-(void)start {
if (self.isDataTask){
_dataTask = [self.session dataTaskWithRequest:self.request];
[_dataTask resume];
}
}
#pragma mark- delegate methods
-(void)URLSession:(NSURLSession *)session
task:(NSURLSessionTask *)task
didCompleteWithError:(NSError *)error {
if (error) {
NSLog(#"Error in connection %# for task %#", error, task.response.URL);
}
NSLog(#"completed response %#", task.response.URL.absoluteString);
_dataTask = nil;
_downloadTask = nil;
[self.urlClient URLProtocolDidFinishLoading:self.urlClient];
}
-(void)URLSession:(NSURLSession *)session
dataTask:(NSURLSessionDataTask *)dataTask
didReceiveResponse:(NSURLResponse *)response
completionHandler:(void (^)(NSURLSessionResponseDisposition))completionHandler {
NSLog(#"received response %#", response.URL.absoluteString);
[self.urlClient URLProtocol:self.urlClient
didReceiveResponse:responsecacheStoragePolicy:NSURLCacheStorageAllowedInMemoryOnly];
completionHandler(NSURLSessionResponseAllow);
}
-(void)URLSession:(NSURLSession *)session
dataTask:(NSURLSessionDataTask *)dataTask
didReceiveData:(NSData *)data {
NSLog(#"received data %#", dataTask.response.URL.absoluteString);
if (!self.data) {
self.data = [data mutableCopy];
} else {
[self.data appendData:data];
}
[self.urlClient URLProtocol:self.urlClient didLoadData:self.data];
}
//... some more methods
#end
That's all the relevant code I guess.
The problem is that when I see the response in a webview, I only get the <head> tag of the document.
I am not getting the rest of the html. And also, the js/css files listed in the <head> tag are not downloaded. Do you see any flaw in the implementation?

NSURLSession methods don't call

I want to download a file from the server by using the NSURLSession instead of NSURLConnection. But when I use it, some of delegate method is not calling and I don't know why.
#import "ViewController.h"
#interface ViewController ()<NSURLSessionDelegate,NSURLSessionDataDelegate,NSURLSessionDownloadDelegate>
#property (strong,nonatomic) NSURLSessionDownloadTask *downloadTask;
#property (strong,nonatomic) NSURLSession *session;
#end
#implementation ViewController
-(void)viewWillAppear:(BOOL)animated{
[super viewWillAppear:animated];
NSURLSessionConfiguration *backgroundConfiguration = [NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier:#"com.webcash.TestingNSURLSession"];
self.session = [NSURLSession sessionWithConfiguration:backgroundConfiguration delegate:self delegateQueue:nil];
}
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (IBAction)startDownload:(id)sender {
NSURL *downloadRUL = [NSURL URLWithString:#"http://laguboard.com/music/down/33867378/2794942/NTU0NktpZE56eERWZGxVeC9zTS9LVUd1TEhkZTE0cFZuaW1QS1pFMHVhOUNkM2ZoZEE=/(http://mp3xload.wapka.me).mp3"];
self.downloadTask = [self.session downloadTaskWithURL:downloadRUL];
[self.downloadTask resume];
}
- (IBAction)stopDownload:(id)sender {
}
// ====== THIS METHOD IS NOT CALLING
-(void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didWriteData:(int64_t)bytesWritten totalBytesWritten:(int64_t)totalBytesWritten totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite{
if (totalBytesExpectedToWrite == NSURLSessionTransferSizeUnknown) {
return;
} else {
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
double progress = (double)totalBytesWritten / (double)totalBytesExpectedToWrite;
NSLog(#"Downloading progress : %f",progress);
}];
}
}
// ==============
-(void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error {
if (error != nil) {
NSLog(#"Error : %#",[error localizedDescription]);
} else {
NSLog(#"Download finished");
}
}
-(void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)location{
NSError *error;
NSFileManager *fileManager = [NSFileManager defaultManager];
NSArray *urls = [fileManager URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask];
NSURL *documentsDirectory = [urls objectAtIndex:0];
NSURL *originalURL = [[downloadTask originalRequest] URL];
NSURL *destinationURL = [documentsDirectory URLByAppendingPathComponent:[originalURL lastPathComponent]];
[fileManager removeItemAtURL:destinationURL error:NULL];
BOOL success = [fileManager copyItemAtURL:location toURL:destinationURL error:&error];
if (success) {
NSLog(#"Download finished");
} else {
NSLog(#"Error : %#",error.description);
}
}
#end
I follow up with many tutorial but it's still not working. please help me to fix this out. thank you.!
#import "ViewController.h"
#interface ViewController ()<NSURLSessionDelegate, NSURLSessionTaskDelegate>
#property (nonatomic, strong) NSMutableData *activeDownload;
#property (nonatomic, strong) NSURLSessionTask *downloadTask;
#property (nonatomic, assign) NSInteger downloadSize;
#property (nonatomic, assign) NSInteger downloadedSize;
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (IBAction)startDownload:(id)sender {
self.downloadedSize = 0;
NSURL *nsurl = [NSURL URLWithString:#"http://laguboard.com/music/down/33867378/2794942/NTU0NktpZE56eERWZGxVeC9zTS9LVUd1TEhkZTE0cFZuaW1QS1pFMHVhOUNkM2ZoZEE=/(http://mp3xload.wapka.me).mp3"];
NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration];
NSURLSession *downloadSession = [NSURLSession sessionWithConfiguration:config delegate:self delegateQueue:nil];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:nsurl];
self.downloadTask = [downloadSession dataTaskWithRequest:request];
[self.downloadTask resume];
[downloadSession finishTasksAndInvalidate];
}
- (IBAction)stopDownload:(id)sender {
[self.downloadTask cancel];
self.downloadTask = nil;
self.activeDownload = nil;
}
#pragma mark - NSURLSessionDataDelegate methods
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveResponse:(NSURLResponse *)response completionHandler:(void (^)(NSURLSessionResponseDisposition))completionHandler
{
completionHandler(NSURLSessionResponseAllow);
self.activeDownload = [[NSMutableData alloc] init];
NSString *contentLength = [[(NSHTTPURLResponse *)response allHeaderFields] valueForKey:#"Content-Length"];
self.downloadSize = contentLength.integerValue;
}
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data
{
[self.activeDownload appendData:data];
self.downloadedSize += [data length];
float downloadProgress = ((float) self.downloadedSize / (float) self.downloadSize) * 100;
//percentage of downloading progress
}
#pragma mark - NSURLSessionTaskDelegate methods
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error
{
if (error != nil) {
NSLog(#"Error : %#",[error localizedDescription]);
} else {
NSLog(#"Download finished");
//the data is in self.activeDownload
}
self.activeDownload = nil;
self.downloadTask = nil;
}
#end

IOS 7 how to print the url response data

I am trying to call a web service. I tried this
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:#"http://192.168.75.1:8082/projectname/public/tests"]];
NSURLSessionConfiguration *configuration = [ NSURLSessionConfiguration ephemeralSessionConfiguration];
NSURLSession *session = [NSURLSession sessionWithConfiguration:configuration];
NSURLSessionDownloadTask *task = [session downloadTaskWithRequest:request completionHandler:^(NSURL *localFile, NSURLResponse *response, NSError *error) {
if(!error){
NSLog(#"no error");
}else{
NSLog(#"error");
}
}];
[task resume];
}
as you see there are two nslog statements. I got the no error one.
when I call that web service from my safari, I got a simple string which is index printed in the browser, how can I see that string in my xcode please?
Thanks
you can implement the delegate method
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)location;
EDIT
Try This
NSHTTPURLResponse *response = nil;
NSError *error = nil;
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:YOUR URL]];
NSData *respData = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
NSLog(#"~~~~~ Status code: %d", [response statusCode]);
//Print your recived data here..
NSString *str = [[NSString alloc] initWithData:respData encoding:NSUTF8StringEncoding];
NSLog(#"str: %#", str);
You can use the delegate methods. When a NSURLSessionDownlaodTask is completed, it's delegates will be called if your class confirmed to it.
-(void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)location
you can get your response by parsing the data in that delegate method. It will tell you the location that the URLSession stores the downloaded result.
what I would do If I were you is:
NOTE: it is based on you said you receive a simple string only from your back-end. if that is not a simple string, you may need to revise the –connectionDidFinishLoading: method's body.
.h
#interface UIRandomViewController : UIViewController {
NSURLConnection *_urlConnection;
NSMutableData *_receivedData;
// ...
}
// ...
#end
.m
#implementation UIRandomViewController {
// ...
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
NSURLRequest *_request = [NSURLRequest requestWithURL:[NSURL URLWithString:#"http://192.168.75.1:8082/projectname/public/tests"]];
_urlConnection = [[NSURLConnection alloc] initWithRequest:_request delegate:self startImmediately:TRUE];
// ...
}
// ...
#pragma mark - <NSURLConnectionDelegate>
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
_receivedData = nil;
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
if (_receivedData == nil) _receivedData = [NSMutableData dataWithData:data];
else [_receivedData appendData:data];
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
NSString *_receivedString = [[NSString alloc] initWithData:_receivedData encoding:NSUTF8StringEncoding];
// hello beautiful...
NSLog(#"received data : %#", _receivedString);
}
}
#end

Resources