iPhone dev: load a file from resource folder - iphone

I'm writing an iPhone app with a UIWebView which should display various html files I have in the app resource folder. In xcode my project overview, these html files are displayed like this:
dirA
|---> index.html
|---> a1.html
|---> a2.html
|---> my.css
|---> dirB
|---> b1.html
|---> b2.html
|---> dirC
|---> c1.html
|---> c2.html
These resources where added to the project as such:
Checked "Copy items into destination groups folder (if needed)".
Reference type: Default.
Text encoding: Unicode (utf-8).
Recursively create groups for any added folders.
The links in my html are relative, meaning they look like this:
a1
a2
b2
c1
In order to display the index.html when the app starts up, I use the following code:
NSString *path = [[NSBundle mainBundle] pathForResource:#"index" ofType:#"html"];
NSURL *url = [NSURL fileURLWithPath:path];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
[webView loadRequest:request];
This works fine. Following links from the index file also works fine, as long as the html files requested are directly under dirA. If the link followed points to a file in a sub-directory, then didFailLoadWithError will catch the situation and report that the requested file does not exist.
Also,
[webView loadHtmlString:myHtml];
cannot be part of the solution, as I need back and forward buttons to work in my web view.
So the question is: How can I follow a relative link to an html file in a sub directory within my resources?
I've been all over stackoverflow and the rest of the tubes for the past few days trying to figure this one out, but nowhere have I come across the solution to this exact problem. Any insight at all would be very, very much appreciated!
EDIT: Yoohoo! I figured it out! What joy! Here is what I did:
Imported my resources anew, choosing "Create folder references for any added folders" instead of "Recursively create groups for any added folders."
Specified the root directory for resource, like so: NSString *path = [[NSBundle mainBundle] pathForResource:#"index" ofType:#"html" inDirectory:#"dirA"];

To create folders in the app bundle drag the folder to Xcode and select the radio button: "Create Folder References for any added folders".

The subdirectories you use in XCode are groups not actual folders. all of the resources are likely being flattened out to the output folder. If you create actual folders outside of XCode that might work. Try creating the folder and file heirarchy and drag/dropping into XCode. Also check your build folder using Finder to see exactly how XCode is deploying your files.

I managed to use HTML files containing resources and links using relative paths by using the +fileURLWithPath: initializer instead of +URLWithString: when loading an HTML string and passing a baseURL in the web view.
NSString* path = [[NSBundle mainBundle] pathForResource:#"index" ofType:#"html" inDirectory:#"HTMLContent"];
NSString* htmlString = [NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:&error];
[self.webView loadHTMLString:htmlString baseURL:[NSURL fileURLWithPath:path]];
"HTMLContent" is my equivalent for your "dirA". No other changes were required.

Related

Loading a UIWebview with a local HTML file from a nested folder structure

Specifically, I have a folder structure that looks like the below:
about (main folder)
css (this sub-folder contains the css files)
img (this sub-folder contains the img files)
js (this sub-folder contains the js files)
page (this subfolder contains the index.html file)
If I click on the index.html file from a normal computer browser, everything works as expected.
However, I am trying to load this index.html into a UIWebView.
So far, what I've done is I dragged the "about" folder to XCode and copied it there as I would any other file. Then I tried the following code:
NSString *htmlFile = [[NSBundle mainBundle] pathForResource:#"index" ofType:#"html"];
NSData *htmlData = [NSData dataWithContentsOfFile:htmlFile];
NSURL *baseURL = [NSURL fileURLWithPath:[[NSBundle mainBundle] resourcePath]];
[webView loadData:htmlData MIMEType:#"text/html" textEncodingName:#"UTF-8" baseURL:baseURL];
The webview loads the index.html, however it doesnt load the images/css/js, as I presume it can't find them within the folder structure.
Any help would be appreciated! Thank you!
oops, I actually found the answer here: Load resources from relative path using local html in uiwebview
I was able to use the actual folder structure as is with the following code:
NSURL *url = [NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:#"index" ofType:#"html" inDirectory:#"/about/page"]];
[webView loadRequest:[NSURLRequest requestWithURL:url]];
Instead of using images/css/js use only sample.js.

Loading offline resources into UIWebView or alternative solution

After looking up information regarding loading offline resources into UIWebView, it looks like I'm out of luck for any easy solution.
I can load my main html file very easily by doing the following
[webView loadRequest:[NSURLRequest requestWithURL:[NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:#"tour" ofType:#"html"]isDirectory:NO]]];
The problem is that all the images/etc inside that are inside folders in my resources do not load. If it is in the top level like tour.html is, then it does load.
The paths simply do not behave like paths as if it was on a server.
When you drag a folder of resources to XCode, select "Create folder references for any added folders" rather than the default "Create groups for any added folders".
Your folder icon will appear as blue - not yellow, which means it is a reference to the actual physical folder on disk.
It will then preserve its structure when added into the bundle.

Use a local CSS file in UIWebView

I have searched the web and tried this a couple ways now but I have a CSS file within my XCode project and a UIWebView which has the html written in it's controller.
I need to get the WebView to recognize the CSS file and use it when the view is shown to the user. I cannot depend on the application having access to internet so I have tried every method I have seen which does not depend on it. The following is what I have so far and it does not work:
style.css is located in supporting files
NSString *html = #"<html><head><link rel=\"stylesheet\" type=\"text/css\"
href=\"style.css\" ><title>Words</title><link rel=\"stylesheet\" type=\"text/css\"
href=\"style.css\" /></head><body><table cellpadding=\"0\" cellspacing=\"0\"
border=\"0\"
width=\"100%\" class=\"resource-table\"><tr><th width=\"20%\">Reference/Performance
Level</th><th width=\"20%\">Words</th><th width=\"20%\">Words</th><th
width=\"20%\">Words</th><th width=\"20%\">Highly Effective</th></tr><tr><td><p
class=\"bold\">Words</p><p>Words</p></td><td><ul class=\"normal\"><li>Words</li></ul>
</td><td><ul class=\"normal\"><li>Words</li></ul></td><td><ul class=\"normal\">
<li>Words</li></ul></td><td><ul class=\"normal\"><li>Words</li></ul></td></tr><tr><td>
<p class=\"bold\">Domain 4f P. 107</p><p>4-Decision Making</p></td><td><ul
class=\"normal\"><li>Words</li></ul></td><td><ul class=\"normal\"><li>Words</li></ul>
</td><td><ul class=\"normal\"><li>Words</li></ul></td><t<ul class=\"normal\">
<li>Words</li></ul></td></tr><tr><td><p class=\"bold\">Words</p></td><td></td><td>
</td><td></td><td><ul class=\"normal\"><liWords</li><li>Words</li></ul></td></tr>
</table></body></style></html>";
NSString *path = [[NSBundle mainBundle] bundlePath];
NSURL *baseURL = [NSURL fileURLWithPath:path];
[webView loadHTMLString:html baseURL:baseURL];
Must Include Relative Path for Files in Folder References
Is your css file located at the root of the app? If so, I don't know why your code is not working. My guess is that your css file exists inside a "folder reference" (blue folder) in which case you must also include the folder path in the baseURL (or change html to href=\"someFolder/style.css\").
Note that resources (images, etc...) inside of folder groups will get flattened into the same folder when you compile your app, but folder references maintain their folder heirarchy.
Double Check File Location
Find your app (MyCoolProj.app file). You can do this from XCode by expanding "Products". Under this should be your .app file. If you bring up a context menu for this file, you should be able to "Show in Finder".
Now that you found your .app file in finder, select it and again bring up the context menu. Now select "Show Package Contents".
You should now see all files inside your app. Find where your css file is. If it is inside a folder, then it is definitely in a folder reference in your project and to reference it you MUST include the relative folder path you traversed to get to it.
Side Note: You should also notice that all images and other resources that were in folder groups (not folder references) all exist inside the same folder at the root of your .app file. They no longer have no folder hierarchy. This is why you can find images with only their name using [UIImage imageNamed:] like: [UIImage imageNamed:#"someImageName.png"]. If they existed in a folder reference, again you would have to include that path.
You can implement the style directly into the HTML code, with an style tag, instead of a separated file.
I hope it helps you!!
Also you can create the html file and load it in the UIWebview inside the app, something like this:
NSString *resources = [[NSBundle mainBundle] resourcePath];
NSString *filePath = [resources stringByAppendingPathComponent:#"infotext.html"];
NSError *error = nil;
NSString * resourceFileContent = [NSString stringWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:&error];
if (error != nil) {
#throw [NSException exceptionWithName:[error domain] reason:[error localizedDescription] userInfo:[error userInfo]];
}
NSURL *baseURL = [NSURL fileURLWithPath:resources];
[self.mWebView loadHTMLString:resourceFileContent baseURL:baseURL];

Localizing HTML files in XCode

I have a localized iOS application in which I wish to include some localized HTML files. I can't work out how to do it.
Currently, my folder structure looks like this:
/myapp
/en.lrproj
/Localizable.strings
/fr.lrproj
/Localizable.strings
/webviews
/view1
/index.html
/pic1.png
/view2
/index.html
/pic2.png
As you can see, I currently have the views organized into their own folders with the associated images.
In XCode, when I selected the Localizable.strings files I can add new localizations. When searching for the solution to this problem I see that other people have done the same for the HTML files, however when I select the HTML files there are no options displayed for localizations, so I'm wondering if the folder structure is the problem.
On the other hand, I don't know how to structure the HTML into language code folders whilst not replicating the graphics that have to be along side.
Clearly I'm not understanding something - what do I need to do to get this working?
Thanks,
Tim
Arrange your index.html right next to the Localized.strings, keep the pics in the web views directory:
/myapp
/en.lrproj
/Localizable.strings
/view1/index.html
/view2/index.html
/fr.lrproj
/Localizable.strings
/view1/index.html
/view2/index.html
/webviews
/view1
/pic1.png
/view2
/index.html
/pic2.png
The build a file path:
NSArray* availableLocalizations = [[NSBundle mainBundle] localizations];
NSArray* userPrefered = [NSBundle preferredLocalizationsFromArray:availableLocalizations forPreferences:[NSLocale preferredLanguages]];
NSString *filePath = [[NSBundle mainBundle] pathForResource:#"index" ofType:#"html" inDirectory:#"view" forLocalization:[userPrefered objectAtIndex:0]];
The picture in the html tree are now similar to
/myapp/en.lrproj/view1/index.html
/myapp/webviews/view1/pic1.png
Inside your index.html make the <img> tags point to ../../../webview/pic1.png
(Not sure about the number of ../'s that you need. You might want to open a terminal, navigate to /myapp/en.lrproj/view1/ and test with ls ../../../webview/pic1.png. )
I assume "webviews/view1/index.html" is English, and "webviews/view2/index.html" is French.
NSString *dir = NSLocalizedString("webviews/view1", #"webdir");
NSString *path = [[NSBundle mainBundle]pathForResource:#"index" ofType:#"html" inDirectory:dir];
in Localizable.strings of French
/* webdir */
"webviews/view1" = "webviews/view2";
I tested above code using below in a ViewController.
[self.webView loadRequest:[NSURLRequest requestWithURL:[NSURL fileURLWithPath:path]]];
"webviews" directory should be a "folder reference" in Xcode, not a group.
(Blue directory icon, not yellow one)
Also, be careful not to add a slash after the directory name, like "webviews/view2/".
I found that this could be a problem when I run that on iOS 5.x(I tested it on 5.0.1 and 5.1.1). But no problem on iOS 6.1.2.

UIWebView display locally stored website (HTML, images, Javascript)

I've looked EVERYWHERE for this, can't find anything. I basically need to store an entire website inside of my iPhone for some interesting reasons. Regardless I can't figure out how to display it correctly in my UIWebView.
EDIT: I should clarify, I can load the original HTML file, and I have chagned all of the pathing to be local, except nothing gets linked in.
Here is the code
self.dataDetectorTypes = UIDataDetectorTypeLink;
NSString *path = [[NSBundle mainBundle] pathForResource:#"index" ofType:#"html"];
NSURL *url = [NSURL fileURLWithPath:path];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
[self loadRequest:request];
index.html has a bunch of <script type="text/javascript" src="somescript.js">
None of the JS code gets executed
Looks like you're loading the HTML from inside your bundle. This means that all the additional files (.js, .css, and any media files) also need to be present in your bundle. So the first thing to check is to look inside the contents of your executable and make sure the js, etc. files are included.
If that looks fine the next thing to check is if the html, js, or css files reference content via relative or absolute URLs. If there's an absolute path reference in the web content then UIWebView is going to try to download that content each time so it'll only work when you have a net connection. If the path is relative then it's going to look in the bundle to see if such a file exists.
When you included the html and content into the XCode project file you probably dragged the file(s) over to the project side-bar and were asked whether to "Recursively create groups for any added folders" or to "Create Folder References for any added folders."
The default is the first one which means XCode creates a yellow folder in your project, but it'll ignore the directory hierarchy on disk when time comes to generate the output bundle. If you choose the second option then the folder is blue and if you look in your output bundle you'll see that the whole folder hierarchy has been replicated.
The first works for simple web pages where everything is at the same folder level and you can use the method you list above to load it. The second case works better if your web page is complex and references content in sub-folders in which case you need to load the web pages from a relative path (say, the 'webpages' folder):
NSString *path = [[NSBundle mainBundle]
pathForResource:#"index" ofType:#"html"
inDirectory:#"webpages"];
The last thing to check for is if there are any BASE tags in the html file. This is a way to specify a default address or target for all links on a page, but it can muck up webview links.
The problem is that this call:
NSURL *url = [NSURL fileURLWithPath:path];
doesn't setup a baseURL and so relative paths in the .html file for things like javascript, css, images etc don't work.
Instead use this:
url = [NSURL URLWithString: [path lastPathComponent]
relativeToURL: [NSURL fileURLWithPath: [path stringByDeletingLastPathComponent]
isDirectory: YES]];
and then things like "styles.css" in the index.html file will be found IFF they are copied into the bundle next to the .html file.
You need to set this:
myWebView.dataDetectorTypes = UIDataDetectorTypeLink
Make sure that the .js files are in your copy to resource bundle section and not in the compile section. Xcode places them in the compile group by default.
When adding pathFor resource in Dictionary , it displays a nil string error.
My attempt was to run an entire web page out of the Xcode project file. To do that you must:
When importing the file select "Create folder references for any added folders".
Set up the web view, but make sure you set the relative path as previously mentioned.
NSString *path = [[NSBundle mainBundle] pathForResource:#"filename"
ofType:#"html"
inDirectory:#"Directory"];
NSURL *url = [NSURL URLWithString:[path lastPathComponent] relativeToURL:
[NSURL fileURLWithPath: [path stringByDeletingLastPathComponent]
isDirectory:YES]];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
[self.currentWebView loadRequest:request];