TRIBE is an Apple Staff Favorite iPhone Predictions for 2009
Dec 12

Among the most popular posts on this blog have been those about UIWebView. (The fact that it’s the #1 search result on Google for the term UIWebView might help. :)

Here’s I’d like to revisit the problem of displaying local images in a UIWebView. In this post I presented a little hack to embed small images into the HTML. While this may work in some cases, it’s far from an optimal solution. For example it does not address other types of external files you might want to refer to from your HTML.

Using relative paths or file: paths to refer to images does not work with UIWebView. Instead you have to load the HTML into the view with the correct baseURL: 

NSString *path = [[NSBundle mainBundle] bundlePath];
NSURL *baseURL = [NSURL fileURLWithPath:path];
[webView loadHTMLString:htmlString baseURL:baseURL];

You can then refer to your images like this:

<img src="myimage.png">

Or from within CSS like this:

background-image: url(loading.gif)

It’s important to note that images inside your application bundle are at the root of the bundle, even if you place them in an Images directory in your project.

 

written by Nick \\ tags: , ,

42 Responses to “UIWebView – Loading External Images and CSS”

  1. Jon Says:

    If this works the way I think it does, it’s just what I’m looking for. The only question I have is where does the code go? I am a super beginner with Xcode, and I don’t know my way around it too well.

    Where should this be going? In one of the Classes files?

    NSString *path = [[NSBundle mainBundle] bundlePath];
    NSURL *baseURL = [NSURL fileURLWithPath:path];
    [webView loadHTMLString:htmlString baseURL:baseURL];

  2. Nick Says:

    @Jon: I typically place this code in viewWillAppear in the ViewController that has the UIWebView.

  3. Tom Says:

    Thanks that’s working perfect :)

  4. Chuck Smith Says:

    Thanks so much for posting this. I thought I was going to have to do the ugly image data encoding solution instead, but this works much better!

  5. Dan Says:

    Hey, this trick works great; but only one problem, I can’t get webpages to run javascripts that read code from the URL using this method.

    Basically I’m trying to run a script that takes a value from one pages and uses it on the next (both are stored locally). Normally I would just do it with a cookie, but as it stands right now, you can’t uses cookies with the UIWebView….

    and suggestions would be great! Thanks!!

  6. Nick Says:

    @Dan: You can use stringByEvaluatingJavaScriptFromString to read and set JavaScript variables.

  7. Benny Says:

    Hi Nick, just wanted to stop by and say thanks! This is exactly what I was looking for :)

  8. Jimmy Says:

    Hi Nick. I am planning to grab images from a URL (using dataWithContentsOfURL) and and store them to my application Documents directory. Will I be able to access these images from my UIWebView with <img src=”abcd.jpg”> ?

  9. Nick Says:

    @Jimmy: Yes you can. What you need to do is to set baseURL to the Documents directory.

  10. John Says:

    Yup. Exactly what I was searching for. God bless internet and Nick.

  11. walker_dev Says:

    Thanks a ton!

  12. Devguy Says:

    I’ve been working on this for several days, and I’m struggling the whole way.

    What I’m trying to do is load a web page, modify it on the fly (to insert some CSS dynamically), and then display the page with the new code. This is working okay, the problem is that when I type in a user_id and click [submit], it immediately responds that the session has expired. What am I missing?

    Thanks in advance!

    Devguy

  13. Nick Says:

    @Devguy: If you are handling the response from the web server in your own code in order to modify it, and then you just load the modified HTML into the UIWebView, then you lose any HTTP header information, such as cookies. I can’t think of any easy solution to this.

  14. Patrick Bucher Says:

    Thank you! This helps me a lot :-)

  15. hamdouch Says:

    @Devguy : I’m also working on a project similar to yours .
    How did you succeed to load the web page , modify the css and display it with the new code .
    I’m a Xcode beginner so can you help me?

  16. Ezra Epstein Says:

    There are a bunch of ways to do that. Easiest is via JavaScript – you can modify CSS that way – using the UIWebView’s -stringByEvaluatingJavaScriptFromString: method.

    An alternative approach is to have your html reference a .css file and then modify the .css file before loading the html into the UIWebView. For example, in the view’s controller:

    - (void)viewDidLoad {
    [super viewDidLoad];
    NSString *dcssPath = [[NSBundle mainBundle] pathForResource:@”Dynamic” ofType:@”css”];
    [@"body { background-color: #ff0000; color:#ffffff; }" writeToFile:dcssPath atomically:YES encoding:NSUTF8StringEncoding error:NULL];

    NSString *indexHtmlPath = [[NSBundle mainBundle] pathForResource:@”index” ofType:@”html”];
    [frontView loadRequest:[NSURLRequest requestWithURL:[NSURL fileURLWithPath:indexHtmlPath]]];
    }

    Then just include an index.html in your project’s Resources and have it reference the Dynamic.css file…

  17. hamdouch Says:

    Thanks Ezra ,
    Can i do the same thing whith a web page (withou inserting a .html and .css in resources) .I mean to any page that we can open with webview?

  18. hamdouch Says:

    Can i also modify the content of the html and only keep the interesting parts?

  19. Dan Says:

    Is it possible to load remote HTML pages and have them access local images AND remote images? Like, I may have a folder icon that appears all over the place and I just want to load that locally. On the other hand, a user-submitted image on my webpage will of course not be stored locally and must be retrieved from the remote server.

    Any ideas?

  20. Joe Says:

    OK, this is weird. As soon as I use baseURL (as you’ve defined it – thanks!!!), if I use loadHTMLString:baseURL: the web view shows up empty … even though baseURL points directly to the bundle (trying this in the 3.0 simulator too). As soon as I make baseURL point elsewhere (like a web site), it shows up just fine, but it also doesn’t load any local resources – of course. Hmm …

  21. Joe Says:

    Ah-ha! “Issue: UIWebView can’t load local resources in apps built against 3.0.
    When using [UIWebView loadHTMLString:baseURL:], the HTML string should not refer to local resources with the file:// scheme. Instead, pass in NULL or a file:// URL for baseURL:, or include the resources directly in the HTML with and tags.”

    Reference: iPhone SDK Release Notes for iPhone OS 3.0

  22. Joe Says:

    But wait a sec – that IS what I’m doing. baseURL _is_ using a file scheme. Ugh. :(

  23. Nick Says:

    @Dan: You can refer to images on your web page by an absolute URL, and images in your bundle by a relative URL (the image name).

  24. Joe Says:

    @Nick: No can do. Relative URLs do not work per the 3.0 SDK Release Notes (when using loadHTMLString:baseURL:). I even tried the Data variant. No dice. :(

  25. Nick Says:

    @Joe: Interesting, I was not aware of this change. Let me do some more thinking and see what else I can come up with.

  26. Joe Says:

    Just found what appears to be a good workaround for loading CSS!

    http://dblog.com.au/iphone-development/loading-local-files-into-uiwebview/

  27. Joseph Says:

    Thanks! This is exactly what I need!

  28. pramod Says:

    Does UIWebView cache the images loaded using img src tag. if so where do it cache in the iPhone and what is the time it keeps its content into its cache.

  29. Nick Says:

    @pramod: There seems to be a lot of confusion surrounding UIWebView and caching on the iPhone. I have not done any testing myself so unfortunately I cannot add any clarity. But this Stack Overflow entry seems to have the best overview of the situation.

  30. I.Iordanov Says:

    Hi All. If you are still interested in this topic I prepare an example in my blog and pointed the links to the blogs I used to build a page with local resources using UIWebView.
    http://mentormate.com/blog/iphone-uiwebview-class-local-css-javascript-resources/
    I hope this will save your time. I wm will be happy if you share your opinion on my blog.

  31. ashish Says:

    this works very well and fast but it does not load images if I give baseurl instead of nil. It takes few seconds to load.

    NSURL *myUrl = [[NSURL alloc] initFileURLWithPath:self.contentPath];
    //NSLog(@”Content url is %@”,myUrl);

    NSString *string = [[NSString alloc]initWithContentsOfFile:self.contentPath encoding:NSASCIIStringEncoding error:nil];
    [contentDisplay loadHTMLString:string baseURL:nil]; //here nil if replaced by myUrl webView takes time to load. Any help ?
    [string release];
    [myUrl release];

  32. subharb Says:

    Hello,

    Great post, but I get this error: -[NSURL length]: unrecognized selector sent to instance
    After loading the HTML, any ideas?

    Thanks.

  33. Nick Says:

    @subharb: Not sure where that error comes from. I don’t see that method call in the code above.

  34. Display Images in UIWebView | iPhone Development Blog Says:

    [...] See this post for an alternate way to display images: UIWebView – Loading External Images and CSS Categories: Windows & Views Tags: base64, HTML, [...]

  35. Amit Says:

    It was helpfull

  36. rtovars Says:

    Thanks a lot for this tip! It worked fine in my project! =)

  37. Sam Says:

    Hie, I m new going to develop a app for both Iphone & iPad using UlWebView. I m a web developer and thoght to make an intractive app, which I thought of make as offine browsing with contents.
    but I saw some forums that apple no longer accepts webApps. is this ture??
    thankss

  38. Nick Says:

    @Sam: You can always develop and deploy web apps without Apple’s approval. Just put it up on your server and tell the world about it. If you want to create an app for distribution on the App Store then you need Apple’s approval. Apple is not so keen on native apps that are just web apps wrapped inside a UIWebView, and you may get rejected. It depends on the features of the app. If you can show that your app needs to be native because there are some features that cannot be implemented just using Safari, then approval should be easier.

  39. Erik Says:

    For some reason this doesn’t work for me. It just writes the string of the html page in my UIWebView:

    NSString *path = [[NSBundle mainBundle] bundlePath];
    NSURL *baseURL = [NSURL fileURLWithPath:path];
    [webView loadHTMLString:@"tour.html" baseURL:baseURL];

    Did I do that right?

  40. Mouli Says:

    You saved my day… just that one line I was really struggling to get there..

    Thank you

  41. Siva Says:

    Hi

    i have tried all your codes you & others shared with this conversations, but it does not working for me .Can any one provide me the sample code with the external css & image files.

    Thanks

  42. vinod.R Says:

    if have an html file ,have various divisions in that,seperated by division name.i want to load a specific division .How to do it?

Leave a Reply