I'm working on an iOS application that displays locally-stored content (HTML files) in a UIWebView.
The problem is that some of the assets referenced from the HTMLs (for example fonts and images) take quite a while when loaded for the first time. I assume that the solution to the problem is to somehow cache these assets with NSURLCache before they're used in a UIWebView, but this seems to cause some trouble.
What I have tried so far:
Subclassing NSURLCache and overriding cachedResponseForRequest so that it returns a response with the asset preloaded in an NSData object. Preloading is done in the init method. The overridden cachedResponseForRequest seems to get called but for some reason the UIWebView still loads the asset from the file system.
Using storeCachedResponse:forRequest: to cache NSCachedURLResponse objects containing the assets before they're used in a UIWebView.
Neither of these seems to help. Any advice for where to look for the problem?
Related
I have a WKWebView in my iOS 11+ app where I need to load custom HTML from local in-memory HTML. I can accomplish this by using webView.loadHTMLString or webview.load(data), which is working fine.
This HTML references some required .js/.css/.png files. For normal web URL requests, WKWebView will just do this on the fly, loading missing files. But in this case, I need to intercept these requests, and provide the file contents, as some of it needs to be dynamically generated. So the .css files etc. I need to serve are not physically present as local files.
I thought this would be just a matter of implementing the decidePolicyFor methods of the WKNavigationDelegate protocol, but for some reason this is not triggered for local subrequests, so how can I accomplish this?
I also tried saving the HTML as a local temporary file and loading it using webView.load(URLRequest), but that does not trigger the delegate either. If it was a web URL, it triggers fine.
Let's say you render fullIosAppPath/page.html which has text like <img src="folder/1.png">.
In such case you need to have a file fullIosAppPath/folder/1.png in your app's folder. The WKWebView will load 1.png without any interception - it will just render the image.
So you can parse the HTML file before rendering it, and generate/load the requires resources like 1.png.
You can parse an HTML file with frameworks like Kanna, or write some simple parser by yourself.
Its is well documented that UIImage imageNamed caches the images. And the trend with the newer version of iOS is to use Asset Files to simplify all the #2x and #3x images for all devices.
But to avoid caching the images and to make best use of memory with images, so far I would use methods like imageWithData. But these methods don't work with Asset files that has been my understanding so far. Cause I could not find methods like pathForResource on the bundle working properly for Asset images. Is this a drawback on iOS or is there a nice workaround or is it just plain n00b ness on my behalf?
On one of my projects I have noticed a large memory consumption only because some image used on some startup screen or so still being cached courtesy imageNamed:
How can one work around this i.e continue using the simplicity and ease of Asset set Images and yet avoid caching using imageNamed:
Thanks
Although UIImage's imageNamed caches the images, and some of the old forums continue to dole out that information. In earlier OS version, imageNamed had a memoryLeak, which has long been fixed.
When app receives memory warning, cache is cleared. So you can continue to use it.
I want to make a hybrid app , because some files(like images) have been cached in my app's bundle already. If I use a webView to load a web page in server. and this webPage is use these images , can the webView to visit the app's bundle file system?
You could use some custom links to refer your bundle and change it on the fly from your app.
Let's say you use bundle://image.png then in your code you replace all "bundle://image.png" strings with someting like
[[NSBundle mainBundle] pathForResource:#"image" ofType:#"pnf" inDirectory:#"html_files"];
Anyway this approach creates a strong interdependence into the server and the app wich is not good I think.
I will use a more conventional approach caching images with something like: https://github.com/path/FastImageCache
Well, i searched everywhere but i didn't have any luck with my situation.
I am loading my webpage with UIWebView with the following code:
NSString *fullURL;
fullURL=#"http://domain.com";
NSURL *url=[NSURL URLWithString:fullURL];
NSURLRequest *requestObj=[NSURLRequest requestWithURL:url];
[_webView loadRequest:requestObj];
I want to load the remote HTML file but load the images from the bundle resourses.
The HTML file looks like this:
<img src="http://domain.com/images/image.png" width="20px" height="20px"/>
Can this be done? The majority of the posts over the internet(and here) are for loading local HTML with local images/resources which is different in my case.
Any help with my code?
Thanks
It would probably be better to use some more "loosely coupled" solution - not to edit the HTML code itself in some hacky way (regexp, not regexp... changing the HTML code manually is still pretty hacky).
As a matter of fact, I believe it can be done. The iOS just needs to be somehow informed that some of the assets are available offline, from the bundle.
Basically, when UIWebView is loading a page, first thing that happens behind the scene is downloading the main *.html page. Then all the graphics/css'es/js'es etc are being downloaded.
You can let the html file be downloaded "as is", but intercept those requests that are going to download graphics (+ other assets) and provide them from local bundle. Please refer to this post:
http://robnapier.net/blog/offline-uiwebview-nsurlprotocol-588
and apply appropriate changes. The big win here is that from the webview's (and code that loads / maintain via JavaScript calls it's content) perspective - nothing has changed at all. Only the custom NSURLProtocol itself knows that some data was loaded from local storage.
Had the exact same problem. Subclassing NSURLCache to redirect the cache to cache images from local storage worked like a charm.
Here is the writeup that I followed:
http://www.cocoawithlove.com/2010/09/substituting-local-data-for-remote.html
TL;DR Complicated, avoid if you can, but possible.
If you still want to do it: don't do a UIWebView :loadRequest on the URL itself since it will trigger the start of downloading images very rapidly so modifying the images sources using Javascript will likely happen too late.
What you instead have would have to do is to download the contents of the URL on the native side and iterate the image tags there replacing the sources (quite complicated, don't use Regular Expressions to parse HTML btw, there are libraries for that), then injecting the modified HTML using UIWebView loadHTMLString:baseURL:.
I am using appfile:/. The path is correct; if I put it on screen and copy-paste it in the explorer it links to the image.
Is there anything else I need to do?
UPDATED I have updated the library, now is more easy to use. Can you test it?
I am the author of the StageWebViewBridge class. There is a known problem if you are using Android. Anyway, I have a working solution I will update the next week.
If the problem is not in Android, then send me some code.
I am also confused on how to access locally packaged assets. I put them in the HTML folder as requested and when I send a signal to the StageWebViewBridge to set the .src attribute of a video I'm not sure how to do it.
Without StageWebViewBridge and entirely in a website I can just reference the file for a video object via JavaScript directly e.g. swvRef.src = 'file.mp4';. This works perfectly fine. When I try to tell flash to send a call via StageWebViewBridge it does receive the call to the StageWebView (I have JavaScript reporting it). However when I try to set the .src of a video object I can't figure out the correct path.
The documentation says to put all things in a 'html' folder. I did so. No reference to a .src of 'html/a.mp4' or 'a.mp4' or 'htmlCache/a.mp4' ever makes the new javascript html5 video class work.
Bridge otherwise is working perfectly sending AS->JS and JS->AS. I'm just looking for info on how to reference packaged files. I want to play a video I put in the /html folder and so far, I just can't do it.
Got the same issue and fixed it with "appfile:/"
Why do you require "appfile:/ for a local html file ?
If the treated html/js/css is local and asset is relative (aka ../ or no http://) you should treat them as "appfile:/" ?
If the treated file is distant you do not have to handle assets ?
Is there a best practice to work with "appfile:/" ?
Actually I debug my html/js/css game in the browser but if I use appfile:/ it will no longer works. I will have to handle 2 behaviors.