Remote image doesn't get displayed in html page displayed in UIWebView - ios

The following code
<a href="http://phobos.apple.com/WebObjects/MZStore.woa/wa/viewAlbum?i=156093464&id=156093462&s=143441">
<img height="15" width="61" alt="Randy Newman - Toy Story
- You've Got a Friend In Me" src="http://ax.phobos.apple.com.edgesuite.net/images/
badgeitunes61x15dark.gif"></img>
</a>
Is from apple's documentation
http://developer.apple.com/library/ios/#featuredarticles/iPhoneURLScheme_Reference/Articles/iTunesLinks.html#//apple_ref/doc/uid/TP40007896-SW1
When a html page containing that href is loaded into a browser the image is displayed, however when its loaded into a UIWebView it isn't displayed.
ShouldStartLoadWithRequest: does not get called for the following URL
http://ax.phobos.apple.com.edgesuite.net/images/
badgeitunes61x15dark.gif
Why does it not get called and why does this work in a browser but not in UIWebView?

Well, I just built a prototype with your HTML, and it worked fine for me.
However, a few thoughts:
First, if you implement webView:shouldStartLoadWithRequest:navigationType: in your web view delegate, don't expect a callback for every single item in your HTML page. If I remember correctly, it only calls that for top level requests (e.g. the whole page). So, I would not expect to get a callback just for that one img resource.
Since we already established that implementing webView:shouldStartLoadWithRequest:navigationType: won't do what you want, you might want to remove it altogether. When I first lazily put it in my code, I forgot to return YES; from that method. Since Objective-C is a rather loose language, the app built and ran, but obviously took NO to be the implicit return value from that method. NO stops the request from loading. If the image was the only thing in a sample page you had, you wouldn't see anything (and maybe falsely think it was just because of the img itself).
I can't tell if this is only in the HTML that you posted in your question, or if it's in the real code, too. But, you have whitespace inside your img src URL, after "images/". That would obviously make this break.
In my test, I also started with a web page that didn't scale content to fit. That image is rather small, so if you don't scale your web view to fit, and view it on an iPhone/iPod, you might not have noticed such a small image.
webview.scalesPageToFit = YES;
Anyway, that's all I can think of. Like I said, it works for me. It's not the image itself, or any difference between Mobile Safari, vs. UIWebView.
Double check and report back :)

Related

Can loadHTMLString load image asynchronously?

I have a local template and generate a complete html string by inserting result of a web API call into the template. The html string has some links to external images.
I'm showing the string in a UIWebView by calling its loadHTMLString method as below ...
self.newsBodyWebView.loadHTMLString(unifiedDoc, baseURL: nil)
I'm not quite clear about loadHTMLString's behavior, it appears that it's rendering contents synchronously, like even if I'm sure that the text part has already returned, the UIWebView won't show any content (I'm seeing a blank white view) until the external images are downloaded completely.
Could you please suggest what I can do in this scenario? I'm thinking if I should put different sections of text and images into different UITableViewCell to separate their display, this does not seem like a tidy solution though.

How to avoid a blink when UIWebView loads HTML

I have a native iOS app that contains a tab bar. The view controller for each tab contains a UIWebView. When the user switches between tabs, I load the HTML in the corresponding web view. The HTML is fully cached on a device. Here is how I feed the HTML to UIWebView:
[self.webView loadHTMLString:htmlString baseURL:baseUrl];
baseUrl is a file URL pointing to a directory where all assets are located.
This works great in online and offline modes, however it takes time for the UIWebView to parse and render the HTML. As a result, the user sees a brief blink of a white background when switching between tabs. I'd like to remove it, because the user is able to tell that the UI is not native (native UI renders instantly).
I was thinking about taking a screenshot of the UIWebView once it's done rendering the HTML and caching it in memory. The next time the user navigates to that web view, the app displays the screenshot while the UIWebView is rendering the HTML in the background. Finally, the app swaps the screen shot with the actual UIWebView and takes a new screenshot. This is similar to how Google Chrome app works.
Does anyone know a better solution to this problem?
Depends on how you present that web view. I'm not really sure from your description how you do it, but since you're talking about a blink of white background, I'm going to assume there is a situation where you have a web view with a loaded html and then you switch it to another html. The solution for that case would be:
create a second web view,
load the new html to this new web view,
when that web view finishes loading html (you can find out if you use UIWebViewDelegate) you can then quickly switch it with your old web view (meaning you finally add the new web view to the view hierarchy at THIS point, not when you created it).
This way you'll have an instant switch between old and new html, however user will be left waiting and it is your decision what to do with it. You could use UIActivityIndicatorView for example.
When webViewDidFinishLoad: gets called you can do any number of things, make the webview visible, remove something that you had on top of the webview etc...

Strange UIWebView Bug/Behavior

We have a UIWebView in our app, displaying HTML data loaded from memory (not a file). We are experiencing some very strange bug/behavior. Some pages take very long time to render (1-2 minutes). We looked at the source of the pages, and it is indeed very busy with badly written CSS and HTML (not in our control). However, we noticed that if we set a webview to load a page, and then press the power button to shut the iPhone's screen, then immediately press the power button again, and go back to our app, the webview renders the page instantly.
Has anyone experienced this? Any ideas what's going on?
So, uhm, forgot to answer this. It ended up that some of our HTML data had images that were linking to internal organization URLs, which were not accessible outside. And since the web view did not ask the delegate whether it should load, we didn't know about those resources. Pressing the power button caused the connections to drop, which made it render the page.

UIWebView loading but not displaying content

UIWebView successfully loaded content, but is not displaying it. UIWebView is just white screen. BUT, if you click on this UIWebView it will process your click. For example, if you click at place where the link should be (but in fact the white space), the click processed and next page loaded and displayed OK.
The bug is unstable. I got it only with local HTML file (our homepage, it generated locally), web content loads OK. It happens in 20% cases. But in the same time, it is very sticky. Once got white screen, you can reload this page many times and see white screen (but if you click on invisible link, another page displayed successfully). Sometimes it occasionally appears without any reason. Your can "scroll" this blank screen up and down and it occasionally loaded. This local HTML has a lot of stuff, embedded images, javascripts, etc, and it could be javascript problem, but I can't explain how it can be, that content invisible, but still clickable.
It happens in iPod real device and iPhone simulator 4.3, but can't reproduce it on iPad or iPad simulator.
I spent a whole day trying resolve this. Any ideas?
I solved this!
This really weird behaviour of UIWebView was caused by javascript code. The javascript was like (simplified):
<script>
function onLoad() {
location.href='xxx://pageLoaded';
}
</script>
<body onload='onLoad();'>
The idea of this code was to inform app about the fact that page was loaded. In the app I catch request to xxx://pageLoaded and cancel it (in shouldStartLoadWithRequest). Because request cancellation, I didn't expect any problems here. Espesially, I didn't expect that content will become invisible, but still clicable. I added timer (setTimeout) between onload fires and location.href change. It solves the problem.
NOTE: I know about webViewDidFinishLoad event in UIWebView. This is very simplified example just to explain the problem and the solution. Real javascript is more sophisticated and what it is doing can't be reached by simple use webViewDidFinishLoad.

In a UIWebView is it possible to determine when the user has clicked somewhere that isn't a link?

I'm displaying HTML content using a UIWebView and would like some action to occur whenever the user clicks anywhere that isn't a link.
I added a UITapGestureRecognizer, however at the point handleTapGesture is called I do not yet know if the user has clicked on a linked or non linked part of the screen.
To work around this within handleTapGesture I added performSelector:#selector(performAction) withObject:self afterDelay:n]
Then if shouldStartLoadWithRequest is subsequently called I set a flag that performAction checks to see if it actually should perform the action or not.
This works perfectly - but only if the time delay n is sufficiently long enough (about 0.3 to 0.4 seconds) which is too long from a users perspective as its a noticable delay. Also I guess the value of n would likely need to vary on different devices with different processor speeds and so its a fragile solution.
Is there an elegant solution?
Do you have control over the HTML? If so, you can add a global click detection, e.g. <body ontouchdown='detectTouch()'> and then use a custom message to your ObjC app, e.g. location.href="touch://whatever". Watch for the link/location change messages in your UIWebView (shouldStartLoadWithRequest) and parse the scheme and data passed. Don't propagate on link clicks. Should work good.
If you don't have control over the HTML, you can always inject your touch handler, but it's trickier as you'll need to figure out the order of events during a link click, and ignore the ones that aren't links.

Resources