Clear UIWebView cache when use local image file - ios

I use a UIWebView to load a local html, and there is a PNG file inside the html created by Objc.
After the PNG file has been modified, I reload the html in UIWebView, but the image doesn't change. However, if I quit the app and reopen it, the image file will be changed to the new one.
I have checked the PNG file in Documents with Finder, so I'm sure it has been modified, but the old one is still in UIWebView.
So, as I think that it's a UIWebView cache problem, I've tried:
[[NSURLCache sharedURLCache] removeAllCachedResponses];
[_webView loadRequest:[NSURLRequest requestWithURL:[NSURL fileURLWithPath:url isDirectory:NO ] cachePolicy:NSURLRequestReloadIgnoringLocalAndRemoteCacheData timeoutInterval:1]]; or NSURLRequestReloadIgnoringCacheData
None of them works, and I can't change the filename, because the PNG file is used in a lot of places (other html and objc code).
I've tried this too:
some.png?r=randomNumber
but it can't be showed.
How do I clear the UIWebView cache when using a local image file inside a local html?

Other than renaming every file on each access, I've only seen one thing work for this and that is modifying the HTML with javascript to add a timestamp onto the image url so it tricks the webview into thinking it's a different file. Images (usually) load the same no matter what you put after the ? in their url. I think this would be easier than renaming every file each time you load the web view. Something like this (using jQuery):
<img src="myimg.jpg" />
<script>
$(function() {
$('img').each(function(i, el) {
$(el).attr('src', $(el).attr('src')+'?pizza='+(new Date()).getTime());
});
});
</script>
I guess this is assuming that this javascript loads and runs before the images are loaded, but in theory this should work.
For a little background, I've made a page in a webview that used RequireJS to asynchronously load quite a few files. I had the EXACT same problem that this question is talking about except that I was loading javascript files instead of images. The key to fixing this issue was adding a timestamp to every path of javascript file and thus tricking the webview (ex me.js?ts=236136236 and whatever.js?ts=3153524623). I found this to work great.
One other thing I needed to do was add a timestamp to the path of my HTML file when loading it into the webview like this:
[NSURL URLWithString:[[NSString stringWithFormat:#"%#/index.html?pizza=%f", webDirectoryPath, [[NSDate date] timeIntervalSince1970]]
I now can modify all the local files and each time the webview appears the changes come through.

You can try this, in your AppDelegate.m
+(void)initialize {
[[NSURLCache sharedURLCache] setDiskCapacity:0];
[[NSURLCache sharedURLCache] setMemoryCapacity:0];
}

If your html didn't change and the only change was in image you should use UIWebView's reload message instead of loading request again.
Something like this:
- (void)reloadWebView:(id)sender
{
if (self.loaded) {
[self.webView reload];
} else {
NSString *html = [[NSBundle mainBundle] pathForResource:#"web" ofType:#"html"];
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL fileURLWithPath:html]];
[self.webView loadRequest:request];
self.loaded = YES;
}
}
You don't even need any manipulations with cache.

Related

Loading local images into WKWebView

I'm trying to get WKWebView to display locally downloaded images in a WKWebView. The webview normally displays HTML, which is retrieved remotely. The contents of the HTML can sometimes contain remote links to images. My app parses the HTML and looks for these HTML tags, downloads the file it is referencing and subsequently replaces the remote link with a local one.
Normally speaking, this wouldn't be very difficult but the images aren't being displayed, presumably due to the images and the local HTML files for the webview being in two separate directories (the documents directory and the app bundle directory respectively).
I've seen people suggest moving the download destination of the images to the same directory as where the HTML files are but this isn't an option for me as I don't want to start mixing up files downloaded by the user with local assets.
What would be my best course of action here?
Well, I've found a workaround. Instead of locally storing the images and referencing them in the HTML files, I'm now instead converting the images to Base64 and then adding them to the HTML. It's not ideal but it gets the job done. I'm going to leave this question open in case someone ever manages to find an actual solution.
To display cached HTML referencing cached resources in a WKWebView:
For each of the resources within your HTML content string, cache it into the directory as provided by NSTemporaryDirectory(). So an image tag like:
...<img src='https://www.myimage.com/example_image.png'/>...
should be cached and replaced into something like this:
...<img src='/private/var/mobile/Containers/Data/Application/527CF4FC-9319-4DFF-AB55-9E276890F5DC/tmp/example_image.png'/>...
Now cache the HTML content string with the replaced resource URLs. It must also be cached in the directory provided by NSTemporaryDirectory(). One difference here is that it must be cached (and later referenced) using the file:// protocol as a restriction of caching the string using NSData (see sample code).
For example file:///private/var/mobile/Containers/Data/Application/527CF4FC-9319-4DFF-AB55-9E276890F5DC/tmp/my_html_content_string.html
A few things to point out:
You cannot load the HTML as a raw string (loadHTMLString:baseURL:).
You cannot reference the cached resource within your HTML string using the file:// protocol. That may work in a UIWebView, but will not work in the WKWebView.
Objective-C
// To cache the HTML string:
NSString *HTML = <HTML CONTENT WITH CACHED RESOURCES>;
NSData *data = [HTML dataUsingEncoding: NSUTF8StringEncoding];
[data writeToURL: cachedHTMLURL atomically: YES];
// To load the store HTML file:
[myWKWebView loadRequest: [NSURLRequest requestWithURL: cachedHTMLURL]]; // (file://.../tmp/my_html_content_string.html)
Swift
// To cache the HTML string:
let HTML = <HTML CONTENT WITH CACHED RESOURCES>
let data = HTML.data(using: String.Encoding.utf8)
do {
try data.write(to: cachedHTMLURL, options: .atomic)
} catch {
print(error)
}
// To load the store HTML file:
myWKWebView.load(URLRequest(url: cachedHTMLURL)) // (file://.../tmp/my_html_content_string.html)
I had the same problem with WKWebView as it can not load both html strings and images at the same time for security purposes. I switched to UIWebView, which is deprecated, but I was able to load both html strings and referenced images at the same time.
I developed a definitive solution for the company I work for. But it relies on the html / javascript side. Anywhere inside your html code where you will reference to a local image <img src="..."/> you should set this "src" dynamically, and it will work seamlessly.
function getLocalURL(path) {
let origin = window.location.origin
if (origin == "file://") {
return origin + window.location.pathname.replace("/index.html","") + path
}
return path
}
You should, clearly, rename index.html to whatever is your main .htm(l) filename :)
Usage:
getLocalURL("/local_images/location_icon.png")
Will return a WKWebView working path for the referenced local image path:
"file:///Users/arthurdapaz/Library/Developer/CoreSimulator/Devices/5073AF19-26A0-460E-BC82-E89100B8E1AB/data/Containers/Data/Application/2B099343-0BF5-4849-B1C2-2512377A9772/Documents/distDriver/local_images/location_icon.png"

iOS UIWebview does not load new css

In my app,I download an HTML app and save it in documents directory.I open it using a UIwebview. This works fine. But the problem is,if I make any css change on my server and then download the app again,the changes are reflected in documents directory but when I open the app in UIwebview , the changes are not reflected there. If I open the .html file in safari , the css changes work.
I load my html file using the following code:
appReq = [NSURLRequest requestWithURL:appURL cachePolicy:NSURLRequestReloadIgnoringCacheData timeoutInterval:20.0];
[self.webView loadRequest:appReq];
where appURL = [NSURL fileURLWithPath:"path to downloaded html app in documents directory"];
I tried to clear the caches using following methods:
[[NSURLCache sharedURLCache] removeCachedResponseForRequest:appReq];
and
[[NSURLCache sharedURLCache] removeAllCachedResponses];
but they do not help.
P.S : The changes are only reflected if I reopen my application.
Does anyone has any clue how to solve this?
You should generate a rendom number and append it to your path (to ignore the cache).
Instead of:
appURL = [NSURL fileURLWithPath:"path to downloaded html app in documents directory"];
use:
int randomNumber = rand() % 1012074;
appURL = [NSURL fileURLWithPath:[NSString stringWithFormat:#"%#&ignoreCache=%d",<path to downloaded html app in documents directory>,(int)randomNumber]];
I hope it will help you!
Good luck!

Get html code and edit then load on to web view

I want to load a web site on a UIWebView which is not under my control and edit/add certain UI changes (Some texts, images, etc) to it. Can I do this within my iOS source code? I can't change the hosted html contents since them not under my control.
If this cannot doable within iOS source code, please advice me the correct way to achieve this.
Load the webpage into an NSString, make any modifications and then put the html into the UIWebView.
NSURL *url = [NSURL URLWithString:#"http://example.com/"];
NSString *page = [NSString stringWithContentsOfURL:url usedEncoding:nil error:nil];
/* Make changes to page here */
[self.webView loadHTMLString:page baseURL:nil];
I'd get the dom with JavaScript, manipulate, then inject back with JavaScript.
See stringByEvaluatingJavaScriptFromString:.
You can write your own full featured, minified JavaScript, then pass into using this method.
// Change body color of any HTML content inside a UIWebView.
NSString *javaScript = #"document.getElementByTagName('body').backgroundColor = '#888';";
[webView stringByEvaluatingJavaScriptFromString:javaScript];

reading PDF protected by password using UIWebview

I'm using this code to load my PDF into webView:
NSURL *targetURL = [NSURL URLWithString:#"http://example.com/demo.pdf"];
NSURLRequest *requestObj = [NSURLRequest requestWithURL:targetURL];
[viewWeb loadRequest:requestObj];
and everything works fine, but there's one problem to resolve.
My demo.pdf is protected by password, of course I know this password but don't want to input it everytime when pdf is loaded.
Can I set my password as variable/string and load PDF without type password?
I don't think there's anything as straight forward as telling the webview what the password is, but instead I would download the PDF file manually (NSURLConnection or something), then unlock it using CGPDFDocumentUnlockWithPassword(doc, pass).
You could then generate an unlocked version as NSData in memory and load that into the web view (not password protected at this point)
You can draw it into NSData using the following (skip over the parts about custom drawing a red box on top):
http://b2cloud.com.au/how-to-guides/drawing-over-a-pdf-in-ios-pdf-template
Of course if your PDF is huge or has a ton of images this could take some time...
CGPDFDocument reference:
https://developer.apple.com/library/ios/documentation/graphicsimaging/reference/CGPDFDocument/Reference/reference.html

UIWebView cache in iOS

I'm hosting UIWebView in my app. it looks like UIWebView caches images and data itself.
I want to clear its cache on app startup.
Cleaning up Safari's cache doesn't help. the only way I found to flush UIWebView's cache is to power off my iPhone and turn it again. Closing the app doesn't help either.
Apple documentation says nothing about it...or I'm missing something. Just in case, app is created with monotouch.
If you want to obliterate all cached responses, something like this looks like the way to go:
[[NSURLCache sharedURLCache] removeAllCachedResponses];
There is a view cache that shows a bitmap of the last page used (like we see inside Safari) but that does not looks like what you're seeing (since it requires to reboot the device).
I've not noticed this behaviour before (never looked for it either ;-) but the following answer looks promising.
FWIW this is not something that would be specific to MonoTouch.
Ive tried all the suggestions on stack overflow and none of them work. The only way I got it to work and feel that its a reliable solution is to create new html files on a temp directory (with a different directory name - a Guid works best) every time, and copy all the related images, scripts, css, every time to that temp directory.
Then open it using an NSUrlRequest object
string tempdir = Path.Combine(UIController.Common.DataFolder,System.Guid.NewGuid().ToString ());
Directory.CreateDirectory (tempdir);
//-- create your html on the tempdirectory here
//-- copy all the images, and all the css, and js files
UIWebView wv = new UIWebView(new RectangleF(30,30,480,680));
NSUrlRequest req = new NSUrlRequest(new NSUrl (Path.Combine (tempdir,"default.html"), false),NSUrlRequestCachePolicy.ReloadRevalidatingCacheData,10);
wv.LoadFinished += delegate(object sender1, EventArgs e1)
{
//delete the tempdirectory
Directory.Delete(tempdir);
};

Resources