How to inject html into a webview? - iphone

Problem: I have a webview that is loading a page from Http://somerandomsite-here
before the page is loaded I would like to add in the <head> block a reference to a .js that is in my bundle.
How do I do that?

Found the answer by myself:
NSString *path = [[NSBundle mainBundle] pathForResource:#"test" ofType:#"js"];
NSString *jsCode = [NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:nil];
[sourceWeb stringByEvaluatingJavaScriptFromString:jsCode];
in test.js place this code in a function that you'll call (see below)
Function setup() { var fileref=document.createElement('script')
fileref.setAttribute("type","text/javascript")
fileref.setAttribute("src", "filename.js");}
when you think it's right do it for you particular case, call this:
NSString *setup = [NSString stringWithFormat:#"Setup()"];
[sourceWeb stringByEvaluatingJavaScriptFromString:setup];

Related

Injecting a local css into UIWebView

I'm trying to "inject" a local css file into downloaded xhtml file.
I found many examples of how to do it, but it just doesn't work for me...
Here is my code:
- (void)webViewDidFinishLoad:(UIWebView *)webView
{
NSString *path = [[NSBundle mainBundle] bundlePath];
NSString *cssPath = [path stringByAppendingPathComponent:#"test.css"];
NSString *js = [NSString stringWithFormat:#"var cssNode = document.createElement('link');"
"cssNode.type = 'text/css';"
"cssNode.rel = 'stylesheet';"
"cssNode.href = '%#';", cssPath];
js = [NSString stringWithFormat:#"%#document.getElementsByTagName('head')[0].appendChild(cssNode);", js];
//m_webview is a member
[m_webView stringByEvaluatingJavaScriptFromString:js];
}
What am I doing wrong here?
Thanks,
I also had trouble doing this.
I was trying to load an HTML file from a server and change the styling using a local CSS file.
At first I used
[webView loadRequest:reqObj];
And when it hit - (void)webViewDidFinishLoad:(UIWebView *)webView i was trying to push the CSS file as a child to 'head':
- (void)webViewDidFinishLoad:(UIWebView *)webView
{
NSString *path = [[NSBundle mainBundle] bundlePath];
NSString *cssPath = [path stringByAppendingPathComponent:#"style.css"];
NSString *js = [NSString stringWithFormat:#"var cssChild = document.createElement('link');"
"cssChild = 'text/css';"
"cssChild = 'stylesheet';"
"cssChild = '%#';", cssPath];
js = [NSString stringWithFormat:#"%# document.getElementsByTagName('head')[0].appendChild(cssChild);", js];
[webView stringByEvaluatingJavaScriptFromString:js];
}
So... it didn't work...
then i tried
NSString *path = [[NSBundle mainBundle] bundlePath];
NSURL *baseURL = [NSURL fileURLWithPath:path];
[webView loadHTMLString:htmlString baseURL:baseURL];
(I copied the HTML string into htmlString) and then, inside - (void)webViewDidFinishLoad:(UIWebView *)webView I injected the CSS as in the code above. And it worked!
But... my HTML file is stored in a remote server and I didn't have the HTML string, so I used
NSString* myFile = [NSString stringWithFormat:#"http://blablabla.com/file.html"];
NSString* myFileURLString = [myFile stringByReplacingPercentEscapesUsingEncoding:NSASCIIStringEncoding];
NSData *myFileData = [[NSData alloc] initWithContentsOfURL:[NSURL URLWithString:myFileURLString]];
NSString* myFileHtml = [[[NSString alloc] initWithData:myFileData encoding:NSASCIIStringEncoding] autorelease];
To get the HTML. Now, I have the raw HTML text inside ' myFileHtml '.
I now use
NSString *path = [[NSBundle mainBundle] bundlePath];
NSURL *baseURL = [NSURL fileURLWithPath:path];
[webView loadHTMLString:myFileHtml baseURL:baseURL];
And catching the response in ' webViewDidFinishLoad ', injecting my CSS file into it and it worked :)
Maybe there's another, more elegant, solution to this problem, but this is what I came up with...
Hope it helped.
cssNode.href = '%#';", cssPath];
The line above fails because it tries to fetch the file from the webserver. Using something like:
cssNode.href = 'file://%#';", cssPath];
accesses the local file system. You can use Safari's developer mode to inspect the iPhone simulator and see whether file is found and loaded.
I eventually ended up implementing inline stylesheets instead of linking to stylesheet. Here's the code that works for me
NSError *error;
NSString *css = [[NSString alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:#"stylesheet" ofType:#"css"] encoding:NSASCIIStringEncoding error:&error];
css = [css stringByReplacingOccurrencesOfString:#"\n" withString:#" "]; // js dom inject doesn't accept line breaks, so remove them
NSString *js = [NSString stringWithFormat:#"var styleNode = document.createElement('style');"
"styleNode.type = 'text/css';"
"styleNode.innerHTML = ' %# ';", css];
js = [NSString stringWithFormat:#"%#document.getElementsByTagName('head')[0].appendChild(styleNode);", js];
[_webView stringByEvaluatingJavaScriptFromString:js];
I ran into this while looking for an answer to the same question. I'm loading an HTML page from a web server into a UIWebView. The HTML already has lots of CSS, appropriate for web viewing. In my case I wanted to display:none a few irrelevant div's.
I didn't want to store the HTML locally then load from the file, so I came up with another solution, conceptually similar to others here but more to my tastes. This is Swift 3. Have this run after the page loads, but before it's displayed:
let css = "#someDiv {display:none;} #otherDiv {display:none;} .someClass {display:none;}"
let js = "var sheet = document.createElement('style');sheet.innerHTML = \"\(css)\";document.body.appendChild(sheet);"
webView.stringByEvaluatingJavaScript(from: js)
maybe this should do the trick? (Not tested in Xcode):
- (void)webViewDidFinishLoad:(UIWebView *)webView
{
NSString *path = [[NSBundle mainBundle] bundlePath];
NSString *cssPath = [path stringByAppendingPathComponent:#"test.css"];
NSString *js = [NSString stringWithFormat:#"var cssNode = document.createElement('link');"
"cssNode.type = 'text/css';"
"cssNode.rel = 'stylesheet';"
"cssNode.href = '%#';", cssPath];
js = [NSString stringWithFormat:#"%#document.getElementsByTagName('head')[0].appendChild(cssNode);", js];
NSString *k = [NSString stringWithFormat:#"var script = %#; %#", cssPath, js];
//m_webview is a member
[m_webView stringByEvaluatingJavaScriptFromString:k];
}
Swift 5:
Before Show WebSite inject css to html
import UIKit
import WebKit
class WebViewController: UIViewController, WKNavigationDelegate {
#IBOutlet weak var webView: WKWebView!
override func viewDidLoad() {
super.viewDidLoad()
config()
}
private func config(){
webView.navigationDelegate = self
guard let url = URL(string: "url") else {
return
}
webView.load(URLRequest(url: url))
}
func webView(_ webView: WKWebView, didCommit navigation: WKNavigation!) {
let css = "Css Code"
let js = "var style = document.createElement('style'); style.innerHTML = '\(css)'; document.head.appendChild(style);"
webView.evaluateJavaScript(js, completionHandler: nil)
}
}

iOS - how to read entire content of an html resource file into an NSString *?

I want to put the content of my html resource file into an NSString object. Is it possible and advisable to do that? How could it be done?
Possible? - yes
Advisable? - unless it is an extremely large file, why not?
How? - There is already a method to do it for you in NSString - stringWithContentsOfFile:encoding:error:.
See the snippet below:
NSError* error = nil;
NSString *path = [[NSBundle mainBundle] pathForResource: #"foo" ofType: #"html"];
NSString *res = [NSString stringWithContentsOfFile: path encoding:NSUTF8StringEncoding error: &error];

"Inject" Objective-C data into a UIWebView that loads a local HTML file?

I am trying to load a UIWebView with local HTML/CSS that is build to look like a nutrition label. The problem is, the data for the food lies inside of my iPhone app. Do I have to put all of my HTML into one enormous NSString object and concatenate my data into it, or is there a way to load the HTML from a local .html file, but somehow "inject" the data that is stored within Objective-C into it?
If the data to be injected is "safe", you could construct your "enormous NSString object" as a format string, sprinkled with %# markers, and use stringWithFormat: to perform the injection in a single move. This is how I construct the pages in the TidBITS News app, using pieces that all come from RSS. It's really quite painless.
You can load basic html using NSData's method dataWithContentsOfFile and then use javascript to modify html in the way you need.
Code would look something like this (using this example):
NSString *path = [[NSBundle mainBundle] pathForResource:#"food" ofType:#"html"];
NSData *data = [NSData dataWithContentsOfFile:path];
if (data) {
[webView loadData:data MIMEType:#"text/html" textEncodingName:#"UTF-8"];
}
[webView stringByEvaluatingJavaScriptFromString:#"var script = document.createElement('script');"
"script.type = 'text/javascript';"
"script.text = \"function myFunction() { "
"var field = document.getElementById('field_3');"
"field.value='Calling function - OK';"
"}\";"
"document.getElementsByTagName('head')[0].appendChild(script);"];
[webView stringByEvaluatingJavaScriptFromString:#"myFunction();"];
I would do a hybrid of both- have an HTML file in the app that you load, then replace certain strings in that before giving it to the UIWebView. So for example, you could have a file like this
<html>
<head>
<title><!--foodName--></title>
</head>
<body>
<h1><!--foodName--></h1>
<p>Calories / 100g: <!--foodCalories--></p>
</body>
</html>
You'd load that into Cocoa, then replace your special placeholder comments with the actual values you want.
NSDictionary *substitutions = [NSDictionary dictionaryWithObjectsAndKeys:
#"Carrots", #"foodName",
[NSNumber numberWithInt:20], #"foodCalories",
// add more as needed
nil];
NSMutableString *html = [NSMutableString stringWithContentsOfFile:[[NSBundle mainBundle] pathForResource:#"foodCard" ofType:#"html"]
encoding:NSUTF8StringEncoding
error:nil];
for(NSString *substitutionKey in substitutions)
{
NSString *substitution = [[substitution objectForKey:substitutionKey] description];
NSString *searchTerm = [NSString stringWithFormat:#"<!--%#-->", substitutionKey];
[html replaceOccurrencesOfString:searchTerm withString:substitution options:0 range:NSMakeRange(0, [html length])];
}
[webView loadHTMLString:html baseURL:[[NSBundle mainBundle] resourceURL]];
Since iOS 2 you can use - (NSString *)stringByEvaluatingJavaScriptFromString:(NSString *)script within a UIWebView subclass to execute JS scripts in your webview. This is the best way to inject data from the "Objective-C part" of your application.
Cf: https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIWebView_Class/#//apple_ref/occ/instm/UIWebView/stringByEvaluatingJavaScriptFromString:

iPhone SDK - how to add a CSS into a UIWebView

I've read many of the existing questions and answers for my problem but none seem to answer it specifically and simply.
I am displaying many HTML files in my app and want to use a CSS to help format them. The CSS file will be held locally together with the HTML files.
I think I want to add the CSS ref inline - presuming that's then right way to do it?
My code is
- (void)viewDidAppear:(BOOL)animated {
[super viewWillAppear:animated];
[adviceContent loadRequest:[NSURLRequest requestWithURL:[NSURL fileURLWithPath:[[NSBundle mainBundle]
pathForResource:[advice objectForKey:#"HTML"] ofType:#"html"]
isDirectory:NO]]];
[super viewDidAppear:animated];
}
And I've inserted my CSS reference in the HTML file thus within the head tags <
link rel="stylesheet" type="text/css" href="photovaluesCSS_2column.css" media="screen"/>
Can someone explain where I'm going wrong?
Thanks
When loading the HTML, you need to specify a base URL for the css file, so your controller will "know" where that CSS file is located.
Here's a code that loads a html string which uses a css file. You can load the entire css from a file, or modify it as you need.
// HTML files are stored in the main bundle
NSBundle *bundle = [NSBundle mainBundle];
NSString *path = [bundle bundlePath];
NSString *filename = #"none";
NSString *fullPath = [NSBundle pathForResource:filename ofType:#"html" inDirectory:path];
// load a HTML from a file
NSString *chapter_filename = [NSString stringWithFormat:#"Section%d", _chapter];
NSString *sectionHTMLPath = [[NSBundle mainBundle] pathForResource:chapter_filename ofType:#"html"];
NSString* htmlContent = [NSString stringWithContentsOfFile:sectionHTMLPath encoding:NSUTF8StringEncoding error:nil];
// add a generic template and the css file directive
NSString* htmlString = #"<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\"> <html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"he\" lang=\"he\"><head><style type=\"text/css\" media=\"all\">#import \"styles.css\";</style><meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\" /></head><body>%#</body></html>";
// load the html into a web view
NSURL *url = [NSURL fileURLWithPath:fullPath];
[_webView loadHTMLString:[NSString stringWithFormat:htmlString, htmlContent] baseURL:url];

iPhone - Using a localized resource

I'm trying to display an html file into a UIWebView :
NSString *htmlPath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:#"error.htm"];
NSError* error;
NSStringEncoding encoding;
NSString *htmlContent = [NSString stringWithContentsOfFile:htmlPath usedEncoding:&encoding error:&error];
NSString* bundlePath = [[NSBundle mainBundle] bundlePath];
[self.webView loadHTMLString:htmlContent baseURL:[NSURL fileURLWithPath:bundlePath]];
error.htm is localized. When using this method, no page is loaded. The htmlContent refers to myApp.app/error.htm. But all my error.htm files are in localized folders.
If I use another non localized HTML file (error2.htm, pure copy of error.htm), it is displayed.
How may I use the localized file ?
You are creating the path to the html file yourself using the root resource path and a string - the iPhone isn't psychic, how would it know that you have localised this file?
Try using
NSString *htmlPath = [[NSBundle mainBundle] pathForResource:#"error" ofType:#"html"];
instead - this should deal with localised resources for you.
Localization shouldn't be the problem - I'm loading localized HTML files perfectly fine using something like this:
NSString *path = [[NSBundle mainBundle] pathForResource:#"error" ofType:#"htm"];
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL fileURLWithPath:path isDirectory:NO]];
// ...
[self.webView loadRequest:request];
The answer is not correct (and also didn't work for me) -
this is the function to use for loading localized resource:
- (NSString *)pathForResource:(NSString *)name ofType:(NSString *)ext inDirectory:(NSString *)subpath forLocalization:(NSString *)localizationName;
the localizationName is the two characters localization language code.
BTW - you can get your default/current one by using:
return [[[NSUserDefaults standardUserDefaults] objectForKey:#"AppleLanguages"] objectAtIndex:0];