how to cache html5 File(UIWebView) - ios

I use the UIWebView to load the URL which is a HTML5 application.
What I want to do is cache the HTML file,when there is no net connection,it load the cache.
when the connection can be use,it load the URL again to see if there has new data

you can try something like this:
#define APP_PATH_HTML_PAGES_CACHE [[NSHomeDirectory() stringByAppendingPathComponent:#"Library/Caches"] stringByAppendingPathComponent:#"html_pages_cache"]
- (void)setUrlString:(NSString *)urlString{
if (![_urlString isEqualToString:urlString]) {
NSURL *url = nil;
_urlString = urlString;
NSString *fileName = [self fileNameFromUrl:_urlString];
if(isInternetConnected){//load page and store on file system
url = [NSURL URLWithString:_urlString];
[self downloadPageWithName:fileName andUrl:url];//download to cache
}else{
//network is not available, check for cached file
if ([self isFileExistInCacheDirectory:fileName]) {
url = [NSURL fileURLWithPath:[APP_PATH_HTML_PAGES_CACHE stringByAppendingPathComponent:fileName]];
}
else {
//TODO: show offline/error alert
}
}
//load local or remote page
// here url can point to local file or web page
NSURLRequest* request = [[NSURLRequest alloc]initWithURL:url];
//to be sure that view components did initialized.
if ([self view]) {
[self.webView loadRequest:request];
}
}
- (void)downloadPageWithName:(NSString*)fileName andUrl:(NSURL*)url
{
`dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[self checkIsCacheDirectoryExistOrCreate];`
NSString *filePath = [APP_PATH_HTML_PAGES_CACHE stringByAppendingPathComponent:fileName];
NSData *data = [NSData dataWithContentsOfURL:url];
[data writeToFile:filePath atomically:YES];
NSLog(#"Download: %# -> %#", url.absoluteString, filePath);
});
}

Related

how to load a local html file if there is no internet connection

I have a number of uiwebview in my app that display html files hosted on a server. I would also like to have local copies of the html files that will display if there is no internet connection, but I don't understand how to do that. The .m files I have are similar to below.
Currently the uiwebview will display the remotely hosted page (in the example below "contact.html". Is anyone able to explain how I can load a local copy of the file if there is no internet available?
#import "ContactMeViewController.h"
#interface ContactMeViewController ()
#end
#implementation ContactMeViewController
- (void)viewDidLoad
{
NSString *urlAddress = #"http://www.domain.co.nz/apppages/contact.html";
//Create a URL object.
NSURL *url = [NSURL URLWithString:urlAddress];
//URL Request Object
NSURLRequest *requestObj = [NSURLRequest requestWithURL:url];
//Load the request in the UIWebView.
[webview loadRequest:requestObj];
webview.scalesPageToFit = YES;
}
- (void)viewDidUnload
{
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
#end
I have updated the .m file as follows, but get a blank screen with no internet connection instead of the local file loading:
#import "ContactMeViewController.h"
#interface ContactMeViewController (UIWebViewDelegate)
#end
#implementation ContactMeViewController
- (void)viewDidLoad
{
NSString *urlAddress = #"http://www.kuranimarsters.co.nz/apppages/contact.html";
//Create a URL object.
NSURL *url = [NSURL URLWithString:urlAddress];
//URL Request Object
NSURLRequest *requestObj = [NSURLRequest requestWithURL:url];
//Load the request in the UIWebView.
[webview loadRequest:requestObj];
webview.scalesPageToFit = YES;
}
-(void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error {
if (-1009 == kCFURLErrorNotConnectedToInternet) {
// if we can identify the error i.e, no internet connection
[self loadHtmlFile];
}
}
-(void)loadHtmlFile
{
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *filePath = [documentsDirectory stringByAppendingPathComponent:#"contact.html"];
NSString *content = [NSString stringWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:NULL];
NSString* htmlString = [NSString stringWithContentsOfFile:content encoding:NSUTF8StringEncoding error:nil];
[webview loadHTMLString:htmlString baseURL:nil];
}
- (void)viewDidUnload
{
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
#end
Apply delegates for UIWebView and in -(void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error load local html file.
By default, if internet is there -(void)webViewDidFinishLoad:(UIWebView *)webView, will get executed and you will see page as per URL.
you can store data of html file to document directory of app as.html file & load webview with this file on next time such as
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *filePath = [NSString stringWithFormat:#"%#/%#", [paths objectAtIndex:0],#"index.html"];
// Download and write to file
NSURL *url = [NSURL URLWithString:#"http://www.domain.co.nz/apppages/contact.html"];
NSData *urlData = [NSData dataWithContentsOfURL:url];
[urlData writeToFile:filePath atomically:YES];
// Load file in UIWebView
[web loadRequest:[NSURLRequest requestWithURL:[NSURL fileURLWithPath:filePath]]];
Use delegate methods of webView and implement it in ContactMeViewController.m
In didFailLoadWithError method you can identify error code using [error code]. You can use kCFURLErrorNotConnectedToInternet = -1009.
-(void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error {
if ([error code] == kCFURLErrorNotConnectedToInternet) {
// if we can identify the error i.e, no internet connection
[self loadHtmlFile];
}
}
-(void)loadHtmlFile
{
NSString *htmlFile = [[NSBundle mainBundle] pathForResource:#"contact" ofType:#"html"];
NSString* htmlString = [NSString stringWithContentsOfFile:htmlFile encoding:NSUTF8StringEncoding error:nil];
[webview loadHTMLString:htmlString baseURL:nil];
}

NSURL download file, indicators shows too late

Hi I got the following code and want do show an ActivityIndicator while downloading. But the indicator shows only when the download has finished?
_fanDownloadIndicator.hidden = NO;
NSLog(#"batzn");
NSString *documentPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)objectAtIndex:0];
NSString *file = [documentPath stringByAppendingPathComponent:#"fan_new.mp3"];
BOOL fileExists = [[NSFileManager defaultManager]fileExistsAtPath:file];
if(fileExists == NO) {
NSURL *downurl = [NSURL URLWithString:url];
NSData *data = [NSData dataWithContentsOfURL:downurl];
if ([data writeToFile:file atomically:YES]) {
NSLog(#"downloaded fan");
Issue
You are doing the download task on main thread, and you wait until the thread ends before you show your loading view.
Solution
You need to start downloading task on background thread by using dispatch_async. Check out the code below
_fanDownloadIndicator.hidden = NO;
NSLog(#"batzn");
NSString *documentPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)objectAtIndex:0];
NSString *file = [documentPath stringByAppendingPathComponent:#"fan_new.mp3"];
BOOL fileExists = [[NSFileManager defaultManager]fileExistsAtPath:file];
if(fileExists == NO) {
//Show your loading view here
dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
//Do your downloading here on background thread
NSURL *downurl = [NSURL URLWithString:url];
NSData *data = [NSData dataWithContentsOfURL:downurl];
dispatch_async(dispatch_get_main_queue(), ^{
if ([data writeToFile:file atomically:YES]) {
//Hide your loading view
NSLog(#"downloaded fan");
}
});
});
}
Also I'll provide a suggestion for your loading view which is MBProgressHUD. Here is what you can do with it
//Show loading form here
[MBProgressHUD showHUDAddedTo:self.view animated:YES];
dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_LOW, 0), ^{
// Do something...
dispatch_async(dispatch_get_main_queue(), ^{
[MBProgressHUD hideHUDForView:self.view animated:YES];
});
});
Update
If you are dealing with downloading images, i should recommend this library:
SDWebImage
It also offers a third party to show activity indicator.

Failed to download and open a PDF file with error failed to find PDF header in ios

I am having an app in which I am opening a PDF file from a url.
I am successfully able to open it in a webView.
Now I want to download that PDF file and save it in my documents folder and want to send that PDF file in my mail.
I searched a lot and found the best solution below.
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask, YES);
NSString *documentsPath = [paths objectAtIndex:0];
NSString *filePath = [documentsPath stringByAppendingPathComponent:#"myfile.pdf"];
if(![[NSFileManager defaultManager] fileExistsAtPath:filePath]){
NSData *pdfData = [[NSData alloc] initWithContentsOfURL:[NSURL URLWithString:#"http://developer.apple.com/iphone/library/documentation/UIKit/Reference/UIWebView_Class/UIWebView_Class.pdf"]];
//Store the downloaded file in documents directory as a NSData format
[pdfData writeToFile:filePath atomically:YES];
}
NSURL *url = [NSURL fileURLWithPath:filePath];
NSURLRequest *requestObj = [NSURLRequest requestWithURL:url];
[webView setUserInteractionEnabled:YES];
[webView setDelegate:self];
webView.scalesPageToFit = YES;
[webView loadRequest:requestObj];
But when i try this code, it gives me error saying failed to find PDF header: `%PDF' not found
I am even not able to open my PDF also.
I know same questions are asked before but I am not able to solve this error right now.
I don't know what I am doing wrong over here.
Sorry for the inconvenience.
Please help me with this.
try this code for downloading & saving your pdf file
UIActivityIndicatorView *indicator=[[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
[indicator startAnimating];
NSLog(#"Downloading Started");
NSString *urlToDownload = #"http://gradcollege.okstate.edu/sites/default/files/PDF_linking.pdf";
NSURL *url = [NSURL URLWithString:urlToDownload];
NSURLRequest *request=[[NSURLRequest alloc] initWithURL:url cachePolicy:NSURLCacheStorageAllowed timeoutInterval:120.0f];
[NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
[indicator stopAnimating];
if (!connectionError) {
if ( data )
{
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *filePath = [NSString stringWithFormat:#"%#/%#", documentsDirectory,#"myfile.pdf"];
//saving is done on main thread
dispatch_async(dispatch_get_main_queue(), ^{
[data
writeToFile:filePath atomically:YES];
NSLog(#"File Saved !");
NSURL *url = [NSURL fileURLWithPath:filePath];
NSURLRequest *requestObj = [NSURLRequest requestWithURL:url];
[_rssWebView setUserInteractionEnabled:YES];
//[_rssWebView setDelegate:self];
[_rssWebView loadRequest:requestObj];
});
}
}
}];
If convert to string server response, that you got in NSData *pdfData, you will see next:
<!DOCTYPE html>
<html>
<head>
<title>iOS Developer Library</title>
<meta charset="utf-8">
<script>
var content_page = "navigation";
var href = window.location.href;
if (window.location.href.match('#')) {
var newhref = href.replace('#', '');
newhref = newhref.replace('%23', '#');
window.location.href = newhref;
}
else {
console.log(content_page);
console.log(content_page.match("content_page"));
if(content_page.match("content_page")) {
window.location.href = './navigation';
}
else {
window.location.href = "./" + content_page;
}
}
</script>
</head>
<body>
</body>
<script type="text/javascript" src="/library/webstats/pagetracker.js"></script>
<script type="text/javascript">
if(typeof PageTracker !== 'undefined') {
if(window.addEventListener) {
window.addEventListener("load", function(){PageTracker.logPageLoad()},false);
} else if(window.attachEvent) {
window.attachEvent("onload",function(){PageTracker.logPageLoad()});
}
}
</script>
</html>
This only web page, which, as I can assume, will forward you to document with another URI:
https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIWebView_Class/UIWebView_Class.pdf. So you must use this url if you want to download .pdf file
Also, pay attention on #pawan's answer, and use his approach to avoid download files in main thread

How can I have UIDocumentInteractionController show Calendar as an option for opening a .ics file?

I am intercepting a type of URL in the webview I use in my app in order to download the file that it links to instead of just trying to open it in the webview. The link is to a .ics file. So I download that file into the temporary directory and then bring up the file in a UIDocumentInteractionController instance, but Calendar is not shown as one of the apps to open that .ics file in, just Mail, DropBox and "Copy".
As you can see in the commented out line in the code below I've tried making the link open with webcal:// at the front instead of http://, and also manually setting the UIDocumentInteractionController's UTI to no avail. Is there some reason my local .ics file would not show Calendar as an option for opening it?
//Test for link to an ics file
if ([urlToLoad rangeOfString:#"GetSingleEventCalendarFile" options:NSCaseInsensitiveSearch].location != NSNotFound)
{
//urlToLoad = [urlToLoad stringByReplacingOccurrencesOfString:#"http" withString:#"webcal"];
//NSData *contact = [NSData dataWithContentsOfURL:[NSURL URLWithString:webCalProtocol]];
//return NO;
NSURLRequest *req = [[NSURLRequest alloc] initWithURL:[NSURL URLWithString:urlToLoad]];
[NSURLConnection sendAsynchronousRequest:req queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *resp, NSData *respData, NSError *error){
NSString *urlString = [req.URL absoluteString];
NSString *actIdAndRest = [urlString substringFromIndex:[urlString rangeOfString:#"="].location + 1];
NSString *actId = [actIdAndRest substringToIndex:[actIdAndRest rangeOfString:#"&"].location];
NSString *fileName = [[#"activity" stringByAppendingString:actId] stringByAppendingString:#".ics"];
NSString * path = [NSTemporaryDirectory() stringByAppendingPathComponent:fileName];
NSError *errorC = nil;
BOOL success = [respData writeToFile:path
options:NSDataWritingFileProtectionComplete
error:&errorC];
if (success) {
NSBundle * bundleContaining = [NSBundle bundleWithPath:NSTemporaryDirectory()];
NSLog(#"%#", bundleContaining);
NSURL *fileURL = [bundleContaining URLForResource:fileName withExtension:#"ics"];
documentController = [UIDocumentInteractionController interactionControllerWithURL:fileURL];
//documentController.UTI = #"ics";
[documentController presentOptionsMenuFromRect:CGRectZero inView:self.view animated:YES];
} else {
NSLog(#"fail: %#", errorC.description);
}
}];
}

How to retrieve the set of images from server and store it in documents directory in iOS?

I want to retrieve a folder containing 10 images from server, then store that folder in my document directory. I did some code, but when I run it, I am getting the image urls, not the images themselves. Can anyone help me out?
My code:
-(void)viewWillAppear:(BOOL)animated
{
NSMutableData *receivingData = [[NSMutableData alloc] init];
NSURL *url = [NSURL URLWithString:#"http://Someurl.filesCount.php"];
NSURLRequest *req = [NSURLRequest requestWithURL:url];
NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:req delegate:self startImmediately:YES];
}
-(void) connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
[receivingData appendData:data];
}
-(void) connectionDidFinishLoading:(NSURLConnection *)connection
{
NSError *error = nil;
{
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *path = [paths objectAtIndex:0];
printf("\n the path is :%s",[path UTF8String]);
NSString *zipPath = [path stringByAppendingPathComponent:#"filesCount.php"];
[receivingData writeToFile:zipPath options:0 error:&error];
NSString *documentsDirectoryPath = [[NSHomeDirectory() stringByAppendingPathComponent:#"Documents"] stringByAppendingPathComponent:#"filesCount"];
NSLog(#"the path %#",documentsDirectoryPath);
}
I made this function in my previous project. You need to pass your imageView and serverUrl, then its automatically show image in your imageView and save image to temp directory, when you want again to fetch same image, then next time it take image from disk.
+(void)downloadingServerImageFromUrl:(UIImageView*)imgView AndUrl:(NSString*)strUrl{
NSFileManager *fileManager =[NSFileManager defaultManager];
NSString* theFileName = [NSString stringWithFormat:#"%#.png",[[strUrl lastPathComponent] stringByDeletingPathExtension]];
NSString *fileName = [NSHomeDirectory() stringByAppendingPathComponent:[NSString stringWithFormat:#"tmp/%#",theFileName]];
imgView.backgroundColor = [UIColor darkGrayColor];
UIActivityIndicatorView *actView = [[UIActivityIndicatorView alloc]initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhite];
[imgView addSubview:actView];
[actView startAnimating];
CGSize boundsSize = imgView.bounds.size;
CGRect frameToCenter = actView.frame;
// center horizontally
if (frameToCenter.size.width < boundsSize.width)
frameToCenter.origin.x = (boundsSize.width - frameToCenter.size.width) / 2;
else
frameToCenter.origin.x = 0;
// center vertically
if (frameToCenter.size.height < boundsSize.height)
frameToCenter.origin.y = (boundsSize.height - frameToCenter.size.height) / 2;
else
frameToCenter.origin.y = 0;
actView.frame = frameToCenter;
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(queue, ^{
NSData *dataFromFile = nil;
NSData *dataFromUrl = nil;
dataFromFile = [fileManager contentsAtPath:fileName];
if(dataFromFile==nil){
dataFromUrl=[[[NSData alloc] initWithContentsOfURL:[NSURL URLWithString:strUrl]] autorelease];
}
dispatch_sync(dispatch_get_main_queue(), ^{
if(dataFromFile!=nil){
imgView.image = [UIImage imageWithData:dataFromFile];
}else if(dataFromUrl!=nil){
imgView.image = [UIImage imageWithData:dataFromUrl];
// NSString *fileName = [NSHomeDirectory() stringByAppendingPathComponent:[NSString stringWithFormat:#"tmp/%#",theFileName]];
BOOL filecreationSuccess = [fileManager createFileAtPath:fileName contents:dataFromUrl attributes:nil];
if(filecreationSuccess == NO){
NSLog(#"Failed to create the html file");
}
}else{
imgView.image = [UIImage imageNamed:#"NO_Image.png"];
imgView.tag = 105;
}
[actView removeFromSuperview];
[actView release];
});
});
}
Try using this code.
NSURL* url = [NSURL URLWithString:#"http://imageAddress.com"];
NSURLRequest* request = [NSURLRequest requestWithURL:url];
[NSURLConnection sendAsynchronousRequest:request
queue:[NSOperationQueue mainQueue]
completionHandler:^(NSURLResponse * response,
NSData * data,
NSError * error) {
if (!error){
// do whatever you want with directory or store images.
NSImage* image = [[NSImage alloc] initWithData:data];
}
}];
Use this code to download the image using URL and store in document directory. Iterate the logic for set of images to download and store.
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *imageURL = #"http://sampleUrl";
NSString *documentsDirectory = [paths objectAtIndex:0]; // Get documents folder
UIImage *image = [[UIImage alloc] initWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:imageURL]]];
NSString *imagePath = [documentsDirectory stringByAppendingPathComponent:[NSString stringWithFormat:#"Image1.png"]];
if(image != NULL)
{
//Store the image in Document
NSData *imageData = UIImagePNGRepresentation(image);
[imageData writeToFile: imagePath atomically:YES];
}
If you'll showing the images loaded from server on UI, then
try SDWebImageView, can be used with UIButton or UIImageView, very easy and efficient.
example,
[yourImageView setImageWithURL:[NSURL URLWithString:#"http://www.domain.com/path/to/image.jpg"]
placeholderImage:[UIImage imageNamed:#"placeholder.png"]];
Read how to use it?
Okay, now for multiple images, you may need to run a loop, if you've a common base url for all your pictures (on server) something like http://yoururl/server/pictures/1.png will be replace by 2.png 3.png ... n.png, or you get different urls for pictures need to pass that url, you can load it into imageview objects, and later save them into document directory (remember, SDWebImageView by default doing this work for you). You can turn this off too.
P.S. It will load images once and stored into local (in cache) it self, next time when you pass the same image url, it won't load from server and directly load the image from local.

Resources