It Is Posible to Load Customise HTML View into Webview in Swift

Load local html into UIWebView using swift

To retrieve URLs for application resources, you should use URLForResource method of NSBundle class.

Swift 2

let url = NSBundle.mainBundle().URLForResource("privacy", withExtension:"html") 

Swift 3

let url = Bundle.main.url(forResource: "privacy", withExtension: "html")

How can I load HTML Code to WebView on Swift

In UIWebView:-

let webView = UIWebView()
webView.loadHTMLString("<!DOCTYPE html><html><head>Loading HTML</head><body><p>Hello!`</p></body></html>", baseURL: nil)`

As now from April 2020 no app will be allowed with UIWebView. So, we need to use WKWebView for that.

And now here's the code for WKWebView:

let webView = WKWebView()
webView.loadHTMLString("<!DOCTYPE html><html><head>Loading HTML</head><body><p>Hello!`</p></body></html>", baseURL: nil)`

Load local web files & resources in WKWebView

Updated for Swift 4, Xcode 9.3


This methods allows WKWebView to properly read your hierarchy of directories and sub-directories for linked CSS, JS and most other files. You do NOT need to change your HTML, CSS or JS code.

Solution (Quick)

  1. Add the web folder to your project (File > Add Files to Project)

    • Copy items if needed
    • Create folder references *
    • Add to targets (that are applicable)
  2. Add the following code to the viewDidLoad and personalize it to your needs:

    let url = Bundle.main.url(forResource: "index", withExtension: "html", subdirectory: "website")!
    webView.loadFileURL(url, allowingReadAccessTo: url)
    let request = URLRequest(url: url)
    webView.load(request)

Solution (In-Depth)

Step 1

Import the folder of local web files anywhere into your project. Make sure that you:

Xcode > File > Add Files to "Project"

☑️ Copy items if needed

☑️ Create folder references (not "Create groups")

☑️ Add to targets

Step 2

Go to the View Controller with the WKWebView and add the following code to the viewDidLoad method:

let url = Bundle.main.url(forResource: "index", withExtension: "html", subdirectory: "website")!
webView.loadFileURL(url, allowingReadAccessTo: url)
let request = URLRequest(url: url)
webView.load(request)
  • index – the name of the file to load (without the .html extension)
  • website – the name of your web folder (index.html should be at the root of this directory)

Conclusion

The overall code should look something like this:

import UIKit
import WebKit

class ViewController: UIViewController, WKUIDelegate, WKNavigationDelegate {

@IBOutlet weak var webView: WKWebView!

override func viewDidLoad() {
super.viewDidLoad()

webView.uiDelegate = self
webView.navigationDelegate = self

let url = Bundle.main.url(forResource: "index", withExtension: "html", subdirectory: "Website")!
webView.loadFileURL(url, allowingReadAccessTo: url)
let request = URLRequest(url: url)
webView.load(request)
}

}

If any of you have further questions about this method or the code, I'll do my best to answer!

How to load local html file into UIWebView

probably it is better to use NSString and load html document as follows:

Objective-C

NSString *htmlFile = [[NSBundle mainBundle] pathForResource:@"sample" ofType:@"html"];
NSString* htmlString = [NSString stringWithContentsOfFile:htmlFile encoding:NSUTF8StringEncoding error:nil];
[webView loadHTMLString:htmlString baseURL: [[NSBundle mainBundle] bundleURL]];

Swift

let htmlFile = NSBundle.mainBundle().pathForResource("fileName", ofType: "html")
let html = try? String(contentsOfFile: htmlFile!, encoding: NSUTF8StringEncoding)
webView.loadHTMLString(html!, baseURL: nil)

Swift 3 has few changes:

let htmlFile = Bundle.main.path(forResource: "intro", ofType: "html")
let html = try? String(contentsOfFile: htmlFile!, encoding: String.Encoding.utf8)
webView.loadHTMLString(html!, baseURL: nil)

Did you try?

Also check that the resource was found by pathForResource:ofType:inDirectory call.

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)
}

Load html text in WKWebView

Here is a modified version of your ViewController class:

import UIKit
import WebKit

class ViewController: UIViewController, UIScrollViewDelegate, WKNavigationDelegate {

@IBOutlet weak var webView: WKWebView!
@IBOutlet weak var pagesLabel: UILabel!

var readBookNumber = 0
let headerString = "<meta name=\"viewport\" content=\"initial-scale=1.0\" />"
var textSize = 3

var contentSize: CGSize = .zero

override func viewDidLoad() {
super.viewDidLoad()

// Web View Delegate

webView.scrollView.delegate = self
webView.navigationDelegate = self

webView.scrollView.isPagingEnabled = true
webView.scrollView.alwaysBounceVertical = false
webView.scrollView.showsHorizontalScrollIndicator = true
webView.scrollView.showsVerticalScrollIndicator = false
webView.scrollView.panGestureRecognizer.isEnabled = false
webView.scrollView.pinchGestureRecognizer?.isEnabled = false
webView.scrollView.bouncesZoom = false

self.webView.isOpaque = false;
self.webView.backgroundColor = .clear

// Load File

do {
guard let filePath = Bundle.main.path(forResource: "0", ofType: "html")
else {
print ("File reading error")
return
}
var content = try String(contentsOfFile: filePath, encoding: .utf8)
let baseUrl = URL(fileURLWithPath: filePath)

content.changeHtmlStyle(font: "Iowan-Old-Style", fontSize: 4, fontColor: "black")
webView.loadHTMLString(headerString+content, baseURL: baseUrl)

// add content size Observer
webView.scrollView.addObserver(self, forKeyPath: #keyPath(UIScrollView.contentSize), options: .new, context: nil)

}
catch {
print ("File HTML error")
}
}

override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
if (keyPath == #keyPath(UIScrollView.contentSize)) {
let contentSize = webView.scrollView.contentSize
if contentSize != self.contentSize {
self.contentSize = contentSize
DispatchQueue.main.async {
self.webView.scrollView.contentOffset.x = CGFloat(UserDefaults.standard.integer(forKey: "pageToLoad"))
}
}
}
}

// MARK: - webView Scroll View

func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
self.stoppedScrolling()
}

func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) {
if !decelerate {
self.stoppedScrolling()
}
}

func scrollViewDidScroll(_ scrollView: UIScrollView) {
var currentPage = Int((webView.scrollView.contentOffset.x / webView.scrollView.frame.size.width) + 1)
let pageCount = Int(webView.scrollView.contentSize.width / webView.scrollView.frame.size.width)

if currentPage == 0 {
currentPage = 1
} else {

}

if !webView.isHidden {
pagesLabel.text = "\( currentPage ) из \( pageCount )"
} else {
pagesLabel.text = ""
}
}

func scrollViewWillBeginZooming(_ scrollView: UIScrollView, with view: UIView?) {
webView.scrollView.pinchGestureRecognizer?.isEnabled = false
}

func stoppedScrolling() {
let pageToLoad = Int((webView.scrollView.contentOffset.x))
UserDefaults.standard.set(pageToLoad, forKey: "pageToLoad")
}

// MARK: - loading webView

func webView(_ webView: WKWebView, didStartProvisionalNavigation navigation: WKNavigation!) {
}

func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {

// Маленькая задержка, которую мне хотелось бы использовать

/*DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
self.webView.scrollView.contentOffset.x = CGFloat(UserDefaults.standard.integer(forKey: "pageToLoad"))
}*/

// Большая задержка, которую мне приходится использовать

// don't do this here... we'll do the "auto-scroll" inside the change contentSize Observer
//DispatchQueue.main.asyncAfter(deadline: .now() + 2.0) {
// self.webView.scrollView.contentOffset.x = CGFloat(UserDefaults.standard.integer(forKey: "pageToLoad"))
//}
}

func webView(_ webView: WKWebView, didFail navigation: WKNavigation!, withError error: Error) {
}

}

extension String {
mutating func changeHtmlStyle(font: String, fontSize: Int, fontColor: String) {
let style = "<font face='\(font)' size='\(fontSize)' color= '\(fontColor)'>%@"
self = String(format: style, self)
}
}

It uses an Observer to watch the contentSize change in the web view's scroll view.

Note that it is called multiple times - with different values - during the load and layout process, but it may do the job for you.

Also note, though, that you'll need to account for changes in the web view size - for example, if the user rotates the device. So... more to do, but this may get you going.

Load local html into UIWebView using swift

To retrieve URLs for application resources, you should use URLForResource method of NSBundle class.

Swift 2

let url = NSBundle.mainBundle().URLForResource("privacy", withExtension:"html") 

Swift 3

let url = Bundle.main.url(forResource: "privacy", withExtension: "html")

Using HTML and Local Images Within UIWebView

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">

(from uiwebview revisited)

How to insert HTML into a UIWebView

This should do the trick:

NSString *myHTML = @"<html><body><h1>Hello, world!</h1></body></html>";
[myUIWebView loadHTMLString:myHTML baseURL:nil];


Related Topics



Leave a reply



Submit