Uiwebview and Local CSS File

Load .CSS file from within app in uiwebview

You are basically on the right track, but you should be able to add the css using the same stringByEvaluatingJavaScriptString method.

- (void)webViewDidFinishLoad:(UIWebView *)webView {

NSString *jsFile = @"storage.js";
NSString *jsFilePath = [[NSBundle mainBundle] pathForResource:jsFile ofType:nil];
NSURL *jsURL = [NSURL fileURLWithPath:jsFilePath];
NSString *javascriptCode = [NSString stringWithContentsOfFile:jsURL.path encoding:NSUTF8StringEncoding error:nil];
[webView stringByEvaluatingJavaScriptFromString:javascriptCode];

// Updated to load css from "styling.css" file.
NSString *cssFile = @"styling.css";
NSString *cssFilePath = [[NSBundle mainBundle] pathForResource:jsFile ofType:nil];
NSURL *cssURL = [NSURL fileURLWithPath:jsFilePath];
NSString *cssString = [NSString stringWithContentsOfFile:jsURL.path encoding:NSUTF8StringEncoding error:nil];

// NSString *cssString = @"body { font-family: Verdana, Geneva, sans-serif; font-size: 50px; color: #F00; }";

NSString *javascriptString = @"var style = document.createElement('style'); style.innerHTML = '%@'; document.head.appendChild(style)";
NSString *javascriptWithCSSString = [NSString stringWithFormat:javascriptString, cssString];
[webView stringByEvaluatingJavaScriptFromString:javascriptWithCSSString];

}

Once you do this, you can verify that the style is applied by using Safari remote debugging to view the source for the page displayed on the device / simulator. It can show you if some existing CSS is overriding yours.

Insert CSS into loaded HTML in UIWebView / WKWebView

You can do it like this:

- (void)webViewDidFinishLoad:(UIWebView *)webView {
NSString *cssString = @"body { font-family: Helvetica; font-size: 50px }"; // 1
NSString *javascriptString = @"var style = document.createElement('style'); style.innerHTML = '%@'; document.head.appendChild(style)"; // 2
NSString *javascriptWithCSSString = [NSString stringWithFormat:javascriptString, cssString]; // 3
[webView stringByEvaluatingJavaScriptFromString:javascriptWithCSSString]; // 4
}

What this code does:

// 1 : Define a string that contains all the CSS declarations

// 2 : Define a javascript string that creates a new <style> HTML DOM element and inserts the CSS declarations into it. Actually the inserting is done in the next step, right now there is only the %@ placeholder. I did this to prevent the line from becoming too long, but step 2 and 3 could be done together.

// 3 : Combine the 2 strings

// 4 : Execute the javascript in the UIWebView

For this to work, your HTML has to have a <head></head> element.

EDIT:

You can also load the css string from a local css file (named "styles.css" in this case). Just replace step //1 with the following:

NSString *path = [[NSBundle mainBundle] pathForResource:@"styles" ofType:@"css"];
NSString *cssString = [NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:nil];

As another option you can just inject a <link> element to the <head> that loads the CSS file:

- (void)webViewDidFinishLoad:(UIWebView *)webView {
NSString *path = [[NSBundle mainBundle] pathForResource:@"styles" ofType:@"css"];
NSString *javascriptString = @"var link = document.createElement('link'); link.href = '%@'; link.rel = 'stylesheet'; document.head.appendChild(link)";
NSString *javascriptWithPathString = [NSString stringWithFormat:javascriptString, path];
[webView stringByEvaluatingJavaScriptFromString:javascriptWithPathString];
}

This solution works best for large CSS files. Unfortunately it does not work with remote HTML files. You can only use this when you want to insert CSS into HTML that you have downloaded to your app.

UPDATE: WKWebView / Swift 3.x

When you are working with a WKWebView injecting a <link> element does not work because of WKWebView's security settings.

You can still inject the css as a string. Either create the CSS string in your code //1 or put it in a local file //2. Just be aware that with WKWebView you have to do the injection in WKNavigationDelegate's webView(_:didFinish:) method:

func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
insertCSSString(into: webView) // 1
// OR
insertContentsOfCSSFile(into: webView) // 2
}

func insertCSSString(into webView: WKWebView) {
let cssString = "body { font-size: 50px; color: #f00 }"
let jsString = "var style = document.createElement('style'); style.innerHTML = '\(cssString)'; document.head.appendChild(style);"
webView.evaluateJavaScript(jsString, completionHandler: nil)
}

func insertContentsOfCSSFile(into webView: WKWebView) {
guard let path = Bundle.main.path(forResource: "styles", ofType: "css") else { return }
let cssString = try! String(contentsOfFile: path).trimmingCharacters(in: .whitespacesAndNewlines)
let jsString = "var style = document.createElement('style'); style.innerHTML = '\(cssString)'; document.head.appendChild(style);"
webView.evaluateJavaScript(jsString, completionHandler: nil)
}

Swift - Apply local css to web view

Add delegate method of UIWebView like this

func webViewDidFinishLoad(webView: UIWebView) {    
if let path = Bundle.main.path(forResource: "styles", ofType: "css") {
let javaScriptStr = "var link = document.createElement('link'); link.href = '%@'; link.rel = 'stylesheet'; document.head.appendChild(link)"
let javaScripthPath = String(format: javaScriptStr, path)
self.articleView.stringByEvaluatingJavaScript(from: javaScripthPath)
}

//Second way
do {
let cssContent = try NSString(contentsOfFile: path, encoding: NSUTF8StringEncoding as NSStringEncoding);
let javaScrStr = "var style = document.createElement('style'); style.innerHTML = '%@'; document.head.appendChild(style)"
let JavaScrWithCSS = NSString(format: javaScrStr, cssContent)
self.articleView.stringByEvaluatingJavaScriptFromString(JavaScrWithCSS as String)
} catch let error as NSError {
print(error);
}
}

Hope this will help you.

load a local css file into a webview

The reason is CSS and JS files not available at runtime for render in HTML.

You need to take care of some points:

  1. All CSS/JS/HTML files must be added to Project Properties >> Build Phases >> Copy Bundle Resources.

Check that all files are added if not then manually add those files.

Sample Image


  1. All files are should be placed in the same folder, so that reference file path will be available at run time.

  2. Instead of using directly file names, I will prefer you to use marker. Use symbols as a marker to replace with actual path of CSS and JS files.

For example:

NSString *HTML_HEADER=@"<HTML><HEAD><link rel='stylesheet' href='#FILE1#' type='text/css'></HEAD><BODY>";
NSString *HTML_FOOTER=@"</BODY></HTML>";

NSString *cssFilePath = [[NSBundle mainBundle] pathForResource:@"style" ofType:@"css"];
NSString *html_header_with_files = [HTML_HEADER stringByReplacingOccurrencesOfString:@"#FILE1#" withString:cssFilePath];

NSString *htmlString = [NSString stringWithFormat:@"%@%@%@",html_header_with_files,notif.html,HTML_FOOTER];

NSLog(@"htmlString %@", htmlString);
[self.webView loadHTMLString:htmlString baseURL:nil];

In above example I have replace style.css string from html part and add marker #FILE1#.

This marker is relative url to file style.css and it will be replace before html load in webView.

So whenever you would like to load html to webView, load all resource files from their relatives urls.

Here HTML_HEADER will be replace with actual path for all resources files.

Load UIWebView with a CSS local file

This stackoverflow question appears to have one or two answers that may help you.

You need to load the local CSS (using a method not unlike @Shrey uses, but looking for your CSS file), and somehow inject it into the page, and the only way appears to be to use:

[webview stringByEvaluatingJavaScriptFromString:someJavascriptToInjectCSS];

and some clever Javascript to modify the page to add the CSS in.

Hope this helps point you in the right direction. I have used this method to inject stuff into pages, so it does work, but I don't know Javascript well enough to write the code to inject your CSS into the page.

SWIFT - Loading local CSS file

Your HTML file is loaded from a string, so it's loaded into a web view that can't access files on the file system (probably due to the Same Origin Policy that browsers implement). It can only access resources similarly injected in via loadHTMLString.

If you want to use local CSS, load your HTML from a file instead of a string. This will give the web view access to the CSS if it's in the same directory.

Here is a demo, first, the HTML is now a file.

Sample Image

Then, your code can look like this:

class ViewController: UIViewController, UIWebViewDelegate {

@IBOutlet weak var webview: UIWebView!
override func viewDidLoad() {
super.viewDidLoad()
webview.delegate = self

let path = Bundle.main.path(forResource: "app", ofType: "html")!
let url = URL(fileURLWithPath: path)
let request = URLRequest(url: url)

webview.loadRequest(request)
}

func webViewDidFinishLoad(_ webView: UIWebView){
let path = Bundle.main.path(forResource: "styles", ofType: "css")!

let javaScriptStr = "var link = document.createElement('link'); link.href = '\(path)'; link.rel = 'stylesheet'; document.head.appendChild(link)"
webview.stringByEvaluatingJavaScript(from: javaScriptStr)
}
}


Related Topics



Leave a reply



Submit