Loading Local Files into UIWebView

I thought i would make this a separate post to the Build your very own Web Browser! tutorial as it can be used for many different purposes and it took me a bit to figure it out.

For my example I am going to be trying to use a file in my local bundle in a UIWebView, my file is going to be called “sample.jpg” and it will be in the root folder of my project, this will work for any folder though.

I will show you the code and then I will explain it.


NSString *imagePath = [[NSBundle mainBundle] resourcePath];
imagePath = [imagePath stringByReplacingOccurrencesOfString:@"/" withString:@"//"];
imagePath = [imagePath stringByReplacingOccurrencesOfString:@" " withString:@"%20"];

NSString *HTMLData = @"
<h1>Hello this is a test</h1>
<img src="sample.jpg" alt="" width="100" height="100" />";
[webView loadHTMLString:HTMLData baseURL:[NSURL URLWithString: [NSString stringWithFormat:@"file:/%@//",imagePath]]];

Line 1
This will get the path to the main bundle root folder.

Line 2
We need the slashes to be double slashed to work correctly in the UIWebView, so we are searching for all instances of “/” and replacing it with “//”

Line 3
Same deal as above but we are searching for a space and replacing it with the HTML equivalent of %20

Line 4
This is putting some sample data together for out UIWebView, you will see that we have set the images source to just our “sample.jpg” file as it is sitting in the root folder, if it was in a folder called “images” we would need to set the source to “images//sample.jpg”. Remember the double slashing!

Line 5
This is pretty much the same as my example in the tutorial although we are setting the baseURL to the root of our application bundle, this allows us to reference everything relatively instead of absolute paths.

Well thats about it, if you have done my Build your very own Web Browser! tutorial you will be able to replace the contents of applicationDidFinishLaunching with the above code (don’t forget to leave the makeKeyAndVisible line in there) and you will be loading content from your local device in no time!

0
Share

15 Comments

  1. Daniel

    Thanks for the tutorial :)

    Btw, the html-code is encoded in the sample-code, so you can only see the formatted html-code.

    Ive been messing around with this code to try and load a separate html-file instead of the html-string you provide in the example, but cant get it functioning properly.

    Here is my code, perhaps you could easily spot the problem?

    [code]
    // 1) Get: Get string from "outline.plist" in the "DrillDownSave"-codesample.
    savedUrlString = [item objectForKey: @"itemUrl"];

    // 2) Set: The url in string-format, excluding the html-appendix.
    NSString *tempUrlString = savedUrlString;

    // 3) Set: Format a url-string correctly. The html-file is located locally.
    NSString *htmlFile = [[NSBundle mainBundle] pathForResource:tempUrlString ofType:@"html"];

    // 4) Set: Set an "NSData"-object of the url-sting.
    NSData *htmlData = [NSData dataWithContentsOfFile:htmlFile];

    // 5. Gets the path to the main bundle root folder
    NSString *imagePath = [[NSBundle mainBundle] resourcePath];

    // 6. Need to be double-slashes to work correctly with UIWebView, so change all "/" to "//"
    imagePath = [imagePath stringByReplacingOccurrencesOfString:@"/" withString:@"//"];

    // 7. Also need to replace all spaces with "%20"
    imagePath = [imagePath stringByReplacingOccurrencesOfString:@" " withString:@"%20"];

    // 8) Load: Laddar den lokala html-sidan.
    [webView loadData:htmlData MIMEType:@"text/html" textEncodingName:@"UTF-8" baseURL:[NSURL URLWithString:[NSString stringWithFormat:@"file:/%@//",imagePath]]];
    [/code]

    The html-page is a simple one, with this code:
    [code]

    Testing to load an image:

    [/code]

    It loads fine, but only displays the text and no image.

    Can you spot the problem?

  2. Daniel

    It seems the browser only displays formatted html-code, so here it is again, replacing the tags with [ and ] brackets instead:
    [HTML]
    [BODY]
    Testing to load an image:
    [img src="logo.jpg"/]
    [/BODY]
    [/HTML]

  3. Dean

    Sorry about the encoding, I always forget to convert it. Your code didn’t appear either, you can use &lt; and &gt; instad of < and >

    I cannot see your html so I cant really check, have you spat out the [NSString stringWithFormat:@"file:/%@//",imagePath] with a puts or a NSLog? That way you can confirm that the base path is indeed correct.

    -Dean

  4. All I want to do is loading a HTML file , I added css , calendar.html and images into Resources in XCode.

    but I can’t load it in UIWebView. Please help me.

  5. Btw this html file has Js file too

  6. Skip Haughay

    I am trying to figure out the best way to implement some functionality that requires styled text runs within a block of text, presented as part of what stylistically appears as a grouped list view. Whether or not this is the actual implementation remains to be seen by what we end up being able to actually do with the framework. I have been having a heck of a time getting this to work this week, so I may have to try a different approach.

    Here’s what we are trying to implement:

    The screen will contain is a grouped list of four or more items. TWO of the items are blocks of text, ie. a section entitled Overview and a section entitled Description. Inside the rounded rectangle item of the particular section there is but one cell. That cell will contain static text about this item. What we would LIKE to show in this is richly formatted text. This is something that is currently not possible with UILabel items. The secondary requirement is that we want a simple way that a non-programmer (the content expert using this) can edit their own text content for these cells in a layout editor of some sort, and have this information presented in the application at runtime for their customers. To this end, we thought that perhaps a UIWebView would be the ideal solution. We might also be able to have a version in which the application pulls the content from a remote web source, which would allow the trainer to customize the content presentation remotely.

    And now the fun begins.

    So this part of the program is organized as follows:

    There is a protocol that defines an abstract interface for a factory class, whose purpose is to create the four various cell types that are required for this particular screen. There is an instance of a concrete factory created that conforms to this protocol and contains a few required fields. This is passed into the designated initializer of my subclass of UITableViewController. This tableview controller conforms to the UITableViewDelegate protocol, so that it can use its factory object to create the required cells, provide group counts, names, etc, and cell size information.

    I have for my overview cell defined a subclass of the UITableViewCell, which contains a subview that is a UIWebView. I’m creating this from a nib, btw.

    SO through various contortions, I get the UIWebView supplied with the file URL of the HTML content it needs to display. It’s just text…

    So what I then try to do, or rather what I WANT to do, is have the content loaded, with the width of the UIWebView constrained to the dimensions set in the frame in IB. I want the height of the UIWebView to grow to whatever height is required to fully render the block of styled text contained in the file. I setup the HTML with a viewport meta tag that I thought would constrain the width and disable scaling, but am unsure if it actually is working as I wanted it to.

    So anyway, the UIWebView delegate gets called when the content is done loading. What I wanted to do there is constrain the width of the UIWebView, and size the height to that required to show all of the content. I try doing this by invoking sizeToFit. Interesting effect, but not quite what I wanted… I can’t figure out how to constrain it, and the UIWebView, despite being contained in the content superview of the cell, is not being CLIPPED to the view of the container. But that’s another problem.

    What I then wanted to do is cause the containing cell to be redrawn and resized to fit the height of the content in the UIWebView. I tried telling the table view that it needed redisplay, or needed to be layed out again, but neither of these seem to have any effect. So what I get is an unconstrained UIWebView with the content I want, overrunning the view of the parent container view within the cell.

    How to make this work?

    First question, I guess, is how to constrain the UIWebView in one direction and then query its height after it has loaded and sized its content.
    Second question is, how do I get the tableview to redraw itself and ask for the cell heights again?

    I can easily re-architect this so that the UIWebViews are created prior to the table creation, and then when I make the cells in the tableView:cellForRowAtIndexPath, I could size the cell based upon what I know as the size of the UIWebView, and just add it as a subview of the cell’s content view… But then how do I convert the size of the UIWebView cell, which is in pixels, to points, which is what ableView:heightForRowAtIndexPath: returns?

    I could also just NOT do this with a tableview, but rather just lay out my own set of views. But then the problem still remains, how do we constrain UIWebView in one direction, size it in another direction and then query what that new height is so that the containing view can be sized appropriately?

    Furthermore, this view will not always contain just four items. We could have multiple video placards (which invoke video playback in media player) as well as still image views, diagrams, etc. The contents are all data-driven, edited via plist goodness, and a sort of “data bundle” which is a hierarchy of folders containing assets, such as HTML for rich text, images, video assets, etc. In this manner, a non-programmer will be able to customize the content, and not bug me every time they want to modify the product.

    So any ideas? Any idea of a better approach that will meet these requirements? I can, of course, change the design requirements, but I am a stubborn SOB.

  7. Daniel

    Hi again,

    I finally got it working to load an image locally (se first post) :)

    The problem was the html-code, but this works fine:

    <HTML>
    <BODY>
    <img src=”logo.jpg”>
    </BODY>
    </HTML>

    However, I dont have the same luck with loading a sound-file (wav) in the same manner:

    <HTML>
    <BODY>
    <embed src=”test.wav” loop=”false” autoplay=”false” width=”145″ height=”60″></embed>
    </BODY>
    </HTML>

    I thought that the “imagePath” in the code would give you access to other local objects as well, but perhaps I misunderstood?

  8. These tutorials have been very helpful. However, when I add the code from above to the Web Browser tutorial, it throws the following errors. Do you have any idea on how I might correct?

    Thanks.

    /Users/pfavaro/Desktop/WebBrowserTutorial/Classes/WebBrowserTutorialAppDelegate.m:36: error: syntax error before ‘@’ token
    /Users/pfavaro/Desktop/WebBrowserTutorial/Classes/WebBrowserTutorialAppDelegate.m:36: error: syntax error at ‘OTHER’ token
    /Users/pfavaro/Desktop/WebBrowserTutorial/Classes/WebBrowserTutorialAppDelegate.m:38: error: syntax error at ‘OTHER’ token
    /Users/pfavaro/Desktop/WebBrowserTutorial/Classes/WebBrowserTutorialAppDelegate.m:36: warning: unused variable ‘HTMLData’
    Build failed (3 errors, 1 warning)

  9. Tim

    Thanks, this is helpful!
    One things that’s been driving me nuts though. I have images that are 480×320. The bounds of my UIWebView are also those dimensions. But the images shows up much smaller on the iPhone. I think this has something to do with the iPhone shrinking things so that “most” webpages look good on it. But how can I disable this in the context of my UIWebView? I would like to generate content at 480×320 and then load it and have it take the whole screen.
    This has been driving me nuts! Any ideas?

    Either way, thanks to all those who posted replies, and especially to the writer of this tutorial!

  10. This may be a bit more convenient:
    NSURL *baseURL = [NSURL fileURLWithPath:[[NSBundle mainBundle] resourcePath]];

  11. E.C.

    I was able to load a test.html file located locally using UIWebView. However, I would like to hyperlink other local html (L2.html) from test.html. I could not get it to work by using a tag in test.html with HREF=”L2.html” . Can anyone help?
    Thank you.

  12. Add ur html into the .m file itself.

    NSString *HTMLData = @”your html shd go here, delete all the whitespace. “;

  13. Does anyone know how to load images from the Documents directory? I tried this and it doesn’t work for Documents…

  14. Dor

    I have this code:

    NSString *imagePath = [[NSBundle mainBundle] resourcePath];
    imagePath = [imagePath stringByReplacingOccurrencesOfString:@"/" withString:@"//"];
    imagePath = [imagePath stringByReplacingOccurrencesOfString:@" " withString:@"%20"];

    NSString *HTMLData = @””;
    [webView loadHTMLString:HTMLData baseURL:[NSURL URLWithString: [NSString stringWithFormat:@"file:/%@//",imagePath]]];

    and when i test it, it shows me the small cube with a question mark in it, as it doesn’t find the image.
    What am i doing wrong?

    thanks

  15. Jesse

    Hey there, I do believe the solution to the image issue is that all images in your application are bundled and appear at the root directory. In other words, you can have a structure like Resources/html/images/foo.jpg, but when you call that image like so your app won’t find it – the image in the bundle is at the root level, so only will work. This goes for CSS/Javascript etc. I might be wrong about this, but this http://iphoneincubator.com/blog/windows-views/uiwebview-revisited and this post http://iphoneincubator.com/blog/windows-views/display-images-in-uiwebview seem to corroborate that fact. If anyone else knows how to creat sub-folders that work, please let us all know! Cheers

  16. Ashish

    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];

  17. Tommy Herbert

    @Neil Mix: even simpler is
    NSURL *baseURL = [[NSBundle mainBundle] resourceURL];

  18. thgc

    Thanks a bunch man, you saved me a lot of time ;)

Leave a Reply