14

How can I create a "download manager" which would detect when a link you tap (in a UIWebView) has the file ending ".pdf", ".png", ".jpeg", ".tiff", ".gif", ".doc", ".docx", ".ppt", ".pptx", ".xls" and ".xlsx" and then would open a UIActionSheet asking you if you would like to download or open. If you select download, it will then download that file to the device.

Another section of the app would have a list of downloaded files in a UITableView and when you tap on them, they will show in a UIWebView, but of course offline because they would load locally as they would have been downloaded.

See http://itunes.apple.com/gb/app/downloads-lite-downloader/id349275540?mt=8 for a better understanding of what I am trying to do.

What is the best way of doing this?

Jack
  • 13,571
  • 6
  • 76
  • 98
pixelbitlabs
  • 1,934
  • 6
  • 36
  • 65

1 Answers1

31

Use the method - (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType in your UiWebView's delegate to determine when it wants to load resource.

When the method get's called, you just need to parse the URL from the parameter (NSURLRequest *)request, and return NO if it's one of your desired type and continue with your logic (UIActionSheet) or return YES if the user just clicked a simple link to a HTML file.

Makes sense?

Edit_: For better understanding a quick code example

- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType {
     if(navigationType == UIWebViewNavigationTypeLinkClicked) {
          NSURL *requestedURL = [request URL];
          // ...Check if the URL points to a file you're looking for...
          // Then load the file
          NSData *fileData = [[NSData alloc] initWithContentsOfURL:requestedURL;
          // Get the path to the App's Documents directory
          NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); 
          NSString *documentsDirectory = [paths objectAtIndex:0]; // Get documents folder
          [fileData writeToFile:[NSString stringWithFormat:@"%@/%@", documentsDirectory, [requestedURL lastPathComponent]] atomically:YES];
     } 
}

Edit2_: I've updated the code sample after our dicussion about your issues in the chat:

- (IBAction)saveFile:(id)sender {
    // Get the URL of the loaded ressource
    NSURL *theRessourcesURL = [[webView request] URL];
    NSString *fileExtension = [theRessourcesURL pathExtension];

    if ([fileExtension isEqualToString:@"png"] || [fileExtension isEqualToString:@"jpg"]) {
        // Get the filename of the loaded ressource form the UIWebView's request URL
        NSString *filename = [theRessourcesURL lastPathComponent];
        NSLog(@"Filename: %@", filename);
        // Get the path to the App's Documents directory
        NSString *docPath = [self documentsDirectoryPath];
        // Combine the filename and the path to the documents dir into the full path
        NSString *pathToDownloadTo = [NSString stringWithFormat:@"%@/%@", docPath, filename];


        // Load the file from the remote server
        NSData *tmp = [NSData dataWithContentsOfURL:theRessourcesURL];
        // Save the loaded data if loaded successfully
        if (tmp != nil) {
            NSError *error = nil;
            // Write the contents of our tmp object into a file
            [tmp writeToFile:pathToDownloadTo options:NSDataWritingAtomic error:&error];
            if (error != nil) {
                NSLog(@"Failed to save the file: %@", [error description]);
            } else {
                // Display an UIAlertView that shows the users we saved the file :)
                UIAlertView *filenameAlert = [[UIAlertView alloc] initWithTitle:@"File saved" message:[NSString stringWithFormat:@"The file %@ has been saved.", filename] delegate:self cancelButtonTitle:@"OK" otherButtonTitles:nil];
                [filenameAlert show];
                [filenameAlert release];
            }
        } else {
            // File could notbe loaded -> handle errors
        }
    } else {
        // File type not supported
    }
}

/**
    Just a small helper function
    that returns the path to our 
    Documents directory
**/
- (NSString *)documentsDirectoryPath {
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *documentsDirectoryPath = [paths objectAtIndex:0];
    return documentsDirectoryPath;
}
handet87
  • 549
  • 5
  • 22
Björn Kaiser
  • 9,882
  • 4
  • 37
  • 57
  • When you habe the ressources URL just use a NSURLRequest to download that file and Save it locally. Search here on SO or Google, there are plenty of Tutorials :) – Björn Kaiser Sep 11 '11 at 10:26
  • I've searched loads but can't find anything saying how to download files from the UIWebView locally :( – pixelbitlabs Sep 11 '11 at 10:28
  • 1
    Because you don't download a file from a UIWebView, you download a file from an URL. You can get the URL from the request parameter of the method I mentioned in my answer. – Björn Kaiser Sep 11 '11 at 10:49
  • Ok, so how would I "use a NSURLConnection to download the file"? :-) – pixelbitlabs Sep 11 '11 at 11:11
  • The documentation is your friend ;-) http://developer.apple.com/library/ios/#documentation/Cocoa/Conceptual/URLLoadingSystem/Tasks/UsingNSURLConnection.html. In the "- (void)connectionDidFinishLoading:(NSURLConnection *)connection" method you can use NSData's "writeToFile" method, to write save the loaded data into a file in your App's Documents directory. Let me know if you need further assistance – Björn Kaiser Sep 11 '11 at 11:29
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/3340/discussion-between-bjorn-kaiser-and-james-anderson) – Björn Kaiser Sep 11 '11 at 11:30
  • I needed the same code and this code was very helpful..Thanks Bjorn – Cathy Nov 16 '11 at 05:56
  • Please correct me if i am wrong, but this doesn't stop you from having to re-download the resourceURL again for saving, in addition to the initial downloading when you presented the webview. Is there a way to load a webview, and then GRAB the resource in that webview without having to download it again? – zonabi Jul 21 '14 at 19:36
  • Please help me, i am stuck in this logic. If a file is viewable in webview i am showing preview. and if a url having example video which is not viewable in webview i want to download. is it possible to do? – Dory Oct 12 '16 at 09:37