How can I save a html file with external resources using AFNetworking? - iphone

I would like to save a .html webpage with AFNetworking, but would also like to save the resources (such as .css files, .js files, images etc) within the webpage so that the whole webpage can be viewed offline.
Is this possible with AFNetworking, and how would I do it? Could a short example be posted please?
Thanks!

AFNetworking is not necessary to do this. Instead, what you want to do is use an NSURLCache subclass that supports disk cacheing (such as Peter Steinberger's fork of SDURLCache). With that in place, just load up a URL using a UIWebView (this may not necessarily have to be displayed to a user), and subsequent loads should use that local cache.
At the very least, do not waste your time trying to write something on your own to download assets on a webpage. This process requires a web browser (which UIWebView qualifies as) to determine everything needed to load.

Related

What's the best way to download multiple images and display multiple UIImageView?

I need to download images from a website and display them on(?) multiple UIImageView.
Maybe I'll code a php to "read" the directory and search for images, write a XML file and use it as medium. But I'm not sure if it's the best way.
Let's see the options you have to fetch images from a website:
Fetching HTML and Parsing the HTML to find the images (on the iphone). Then downloading the images.
Writing a script (maybe PHP) that writes all image links to an XML file (or JSON), and then fetch the output of your script with all the links.
If you choose option (1) you'll need NSURLConnection to fetch data asynchronously (without blocking the UI). I would also use TFHpple to parse HTML using xpath queries, see this tutorial for help. Finally to fetch the images using their URLs you can use SDWebImage, SDWebimage also provides caching so your app will not download the same image multiple times.
The bad side of using option (1) is that any change in the Website you're getting the images from will break your app and you'll need to issue an update to the app store in order to fix it.
If you choose option (2), your app will be easier to fix if the website changes, you'll just need to modify your script.
If you go with option (2) you'll probably need NSURLConnection, NSXMLParser (or a third party XML parsing library) and to download the images I would recomend SDWebImage again. I would also advise using JSON (and NSJSONSerialization) instead of XML, just beacuse I find JSON easier to parse.
Yes, it will be very good if you write some php script to get image list (list of image urls).
After getting such urls you can asynchronously download and show them in image views. Look here for such async image view implementation

Presenting a website locally and offline in iOS

I am developing an application for a client where a requirement is that a series of complex (multi-file, JS, CSS, etc), websites must be presented offline, without any web connection required at all.
So I have all of the HTML content folders, and can add them into my XCode project... but now I need to show them.
The UIWebView is fine when you just have one HTML file... but the relative paths for the JS and CSS do not translate over.
What is the best way to do this. I've seen a couple of potential choices. One way is to run a super basic web server locally, dump all the files into /documents (or thereabouts) and serve it from there... the second is to somehow make UIWebView re-interpret the paths so that they point to the right place locally... which I am not sure if it's possible but I've seen it alluded to.
Seems like a lot of people just cover loading a single UIWebView page, and not so much discussing how to deal with CSS/JS dependencies.
Anyone have any bright ideas, links, etc?
Thanks
I think that if you add your HTML/CSS/JS tree to your Xcode project and select "Create folder references for any added folder" (instead of "Recursively create groups for any added folders"), then your bundle will contain the HTML/CSS/JS folder hierarchy (instead of the flattened-out list of all files). This would preserve relative paths.
As to the "reinterpreting" point, you can define
– webView:shouldStartLoadWithRequest:navigationType:
in your UIWebViewDelegate to intercept any attempt at loading any file. There you can change the url on the fly.
Also, have a look at this interesting article by Rob Napier: Drop-in offline caching for UIWebView.

How can I save pdf's to my app resources folder, and access them in run-time?

I have an app I'm designing that will allow for lots of PDF viewing. There are a lot of different languages available, and so if I were to include all of them in the app, it would be like 100+ mb in size which just won't fly.
So I'm thinking that I am going to put the pdf's on my server, and access them with a direct download link like this:
http://mysite.com/pdfs/thepdf.pdf
Which will return the exact pdf I want. So I'm wondering how I can go about accessing these resources as I download them on the fly?
I imagine I need to save the pdf's to the app resources folder? And then when a tableView row for the pdf is selected, I check if the pdf is in the resources folder (how do I do that?), and if not, pull it down off the server, and load it into my view?
I think I have an okay idea of what I need to do, just not very clear on the code to do it. Can anybody post the code for accessing the resources folder (if that's actually what I need to be doing), and maybe the code for how to check if something is in the resources folder?
Thanks!
Have you considered using a UIWebView to view the PDF instead of downloading and loading it yourself? UIWebView should take care of caching, so you won't have to worry about that.
Assuming that a UIWebView won't work, to download PDFs and see if they exist, you need to store it in the Documents folder. The resources folder cannot be altered after you submit your app to Apple, but the Documents folder in your app is completely fine. To access it, I would actually recommend ConciseKit, which can be found on GitHub. It gives you a helper method to access your app's document directory. The helper method is
[$ documentPath];
Then you can get the path for a file by doing
[[$ documentPath] stringByAppendingPathComponent:#"file.pdf"];
So that is how you get a path to a file, to check if it exists, you want to use NSFileManager.
[[NSFileManager defaultManager] fileExistsAtPath:#"path from above"];

UIWebView - remote html loading local images

I'm trying to develop an application using UIWebView. The app is loading remote URL's, so in order to make it quick I want it to use the images included in the application bundle. I was wondering if there is a way to do it without forcing the application to manually replace the address of each image to point into local resources?
I doubt it, unfortunately. Browser security models in general (and this applies to browsers on the desktop as well of course) don't allow file:// scheme URLs to be used in the context of any other scheme (http://) page. If this was allowed, then arbitrary sites you browse to could load local files and possible access private user data, which would be Bad. Local images with the file:// scheme will only work in a page that is itself in the file:// domain.
I'm not sure how to tell you to accomplish this, but perhaps someone else has a clever idea.
You can use this:
Stop Images from loading in UIWebView
...which sounds horrendous, but is actually quite easy to do, and lets you replace requests for the remote URL with a hit to the local URL.
You'll have to convert the URLs manually, of course.

UIWebView and NSURLCache have a troubled relationship

I am trying to solve 2 things in my UIWebView:
Load local assets in place of remote ones, under the right conditions
Load remote assets as normal if there are no local ones or they are outdated
Allow the webview to go "back" without needing to reload it's html form the server
So to handle #1 and #2, I implemented a custom subclass NSURLCache. It gets called when the webview requests assets, and I can send along the local ones instead, aborting the server call for the asset. I even have a little timestamping system that knows if the local version is old or not to figure out which one to use.
But #3 is throwing me for a loop. It seems that regardless of cache-control headers, UIWebView will ALWAYS reload the HTML when going back.
So I tried to force caching of the HTML in my custom NSURLCache class. It seems to work, and returns the instance of NSCachedURLResponse with the HTML I want, but the UIWebView fails to notice and loads it from the server anyway. After some searching I see there is some "inconsistencies" with UIWebView and the url cache, and I guess this is one. Works great for assets, but not so great for the HTML that makes up the page it's trying to display.
So then I decided that since this may not work, do it manually. I created a stack of urls, and their data that I fetch manually and load it with loadData:MIMEType:textEncodingName:baseURL:. Lo and behold it seemed to work great! I could now go back, the web view delegate would intercept the load, and tell it to load my manually fetched data instead, and the server would not be hit.
However, then I noticed that the NSURLCache was no longer being used for my assets. It seems it only asks for cached assets if you load content with loadRequest: and not by loading data or an html string with the baseUrl set properly.
So despite all my efforts I cannot make a web view conditionally load local assets AND navigate back without hitting the server. It seems like I have a few bugs here in the SDK.
UIWebView ignores the servers Cache-Control header for HTML content
UIWebView asks for a NSCachedURLResponse's for the main HTML request but is then ignored and discarded.
UIWebView asks the NSURLCache for assets if you load it up with a request, but when loading with HTML or data it bypasses the cache completely and requests it directly from the remote server.
So first up, anyone see a solution to these things? And second, any reason that I am being stupid and these are not actually SDK bugs?
To tackle your first #3:
While it may seem a little unorthodox, how about persisting the downloaded HTML to an NSUserDefaults object as a flat string, and restoring it (conditionally) later when you need it?
I've abandoned this. There were just too many gotchas. Instead I just load new page in via ajax. And instead of [webview goBack] I have some custom javascript to do cool stuff for me on [webview stringByEvaluatingJavascriptFromString:#"goBack()"]