Skip to content

Instantly share code, notes, and snippets.

@fahied
Created January 10, 2017 06:46
Show Gist options
  • Star 21 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save fahied/698e6f3a09d898b0020d1d4775ffef93 to your computer and use it in GitHub Desktop.
Save fahied/698e6f3a09d898b0020d1d4775ffef93 to your computer and use it in GitHub Desktop.
WKWebView controller example with progress bar
//
// MyWKWebVC.Swift
// Example
//
// Created by Fahied on 04/01/2017.
//
import Foundation
import UIKit
import WebKit
var myContext = 0
class MyWKWebVC: UIViewController {
var webView: WKWebView!
var package: NSDictionary!
var progressView: UIProgressView!
//init
override func loadView() {
//add webview
webView = WKWebView()
webView.navigationDelegate = self
view = webView
//add progresbar to navigation bar
progressView = UIProgressView(progressViewStyle: .default)
progressView.autoresizingMask = [.flexibleWidth, .flexibleTopMargin]
progressView.tintColor = #colorLiteral(red: 0.6576176882, green: 0.7789518833, blue: 0.2271372974, alpha: 1)
navigationController?.navigationBar.addSubview(progressView)
let navigationBarBounds = self.navigationController?.navigationBar.bounds
progressView.frame = CGRect(x: 0, y: navigationBarBounds!.size.height - 2, width: navigationBarBounds!.size.width, height: 2)
}
//deinit
deinit {
//remove all observers
webView.removeObserver(self, forKeyPath: "title")
webView.removeObserver(self, forKeyPath: "estimatedProgress")
//remove progress bar from navigation bar
progressView.removeFromSuperview()
}
//viewcontroller
override func viewDidLoad() {
webView.load(myRequest())
webView.allowsBackForwardNavigationGestures = true
// // add observer for key path
webView.addObserver(self, forKeyPath: "title", options: .new, context: &myContext)
webView.addObserver(self, forKeyPath: "estimatedProgress", options: .new, context: &myContext)
}
//actions
func doneTapped() {
//Routing is your class handle view routing in your app
Routing.showAnotherVC(fromVC: self)
}
//observer
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
guard let change = change else { return }
if context != &myContext {
super.observeValue(forKeyPath: keyPath, of: object, change: change, context: context)
return
}
if keyPath == "title" {
if let title = change[NSKeyValueChangeKey.newKey] as? String {
self.navigationItem.title = title
}
return
}
if keyPath == "estimatedProgress" {
if let progress = (change[NSKeyValueChangeKey.newKey] as AnyObject).floatValue {
progressView.progress = progress;
}
return
}
}
//compute your url request
func myRequest() -> URLRequest {
return URLRequest(url: (URL(string: "https://google.com")
}
func addDoneButton() {
let done = UIBarButtonItem(barButtonSystemItem: .done, target: self, action: #selector(doneTapped))
navigationItem.rightBarButtonItems = [done]
}
func hideBackButton() {
navigationItem.setHidesBackButton(true, animated: false)
}
}
extension PaymentVC: WKNavigationDelegate {
//WKNavigationDelegate
func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
if let url = navigationAction.request.url {
if url.absoluteString.contains("/something") {
// if url contains something; take user to native view controller
Routing.showAnotherVC(fromVC: self)
decisionHandler(.cancel)
} else if url.absoluteString.contains("done") {
//in case you want to stop user going back
hideBackButton()
addDoneButton()
decisionHandler(.allow)
} else if url.absoluteString.contains("AuthError") {
//in case of erros, show native allerts
}
else{
decisionHandler(.allow)
}
}
}
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
progressView.isHidden = true
}
func webView(_ webView: WKWebView, didStartProvisionalNavigation navigation: WKNavigation!) {
progressView.isHidden = false
}
}
@tinusg
Copy link

tinusg commented Sep 22, 2017

Looks great, I used parts of it. But I think you have to add the observers before webview.load()?

@gkmrakesh
Copy link

Can you please help solving "Block Based KVO Violation: Prefer the new block based KVO API with keypaths when using Swift 3.2 or later. (block_based_kvo)" warning while using wkwebview progress bar

@jp-dubey07
Copy link

Great! The use of observer solved my problem i.e. webview content is loaded first followed by title for navigation item.

@jp-dubey07
Copy link

However, use of this function throws a warning Block based KVO violation.. Refer screenshot for detail.

screen shot 2018-04-10 at 11 54 51 am

Any fix for this?

@farshadmb
Copy link

farshadmb commented Feb 11, 2024

       var observers: [NSKeyValueObservation] = []
       let obs = webView.observe(\.title, options: .new) {[weak self] webView, _ in
            self?.navBarTitle?.text = webView.title
        }
        observers.append(obs)
        let progressObs = webView.observe(\.estimatedProgress, options: .new) {[weak self] webView, _ in
            self?.progressView.progress = Float(webView.estimatedProgress)
        }
        observers.append(progressObs)
        let isLoadingObs = webView.observe(\.isLoading, options: .new) {[weak self] webView, _ in
            self?.progressView.isHidden = webView.isLoading
        }
        observers.append(isLoadingObs)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment