// // SwiftWebVC.swift // // Created by Myles Ringle on 24/06/2015. // Transcribed from code used in SVWebViewController. // Copyright (c) 2015 Myles Ringle & Sam Vermette. All rights reserved. // import WebKit public protocol SwiftWebVCDelegate: class { func didStartLoading() func didReceiveServerRedirectForProvisionalNavigation(url: URL) func didFinishLoading(success: Bool) func didFinishLoading(success: Bool, url: URL) func webDismiss() } public class SwiftWebVC: UIViewController { public weak var delegate: SwiftWebVCDelegate? var storedStatusColor: UIBarStyle? var buttonColor: UIColor? = nil var titleColor: UIColor? = nil var closing: Bool! = false lazy var backBarButtonItem: UIBarButtonItem = { var tempBackBarButtonItem = UIBarButtonItem(image: SwiftWebVC.bundledImage(named: "SwiftWebVCBack"), style: UIBarButtonItem.Style.plain, target: self, action: #selector(SwiftWebVC.goBackTapped(_:))) tempBackBarButtonItem.width = 18.0 tempBackBarButtonItem.tintColor = self.buttonColor return tempBackBarButtonItem }() lazy var forwardBarButtonItem: UIBarButtonItem = { var tempForwardBarButtonItem = UIBarButtonItem(image: SwiftWebVC.bundledImage(named: "SwiftWebVCNext"), style: UIBarButtonItem.Style.plain, target: self, action: #selector(SwiftWebVC.goForwardTapped(_:))) tempForwardBarButtonItem.width = 18.0 tempForwardBarButtonItem.tintColor = self.buttonColor return tempForwardBarButtonItem }() lazy var refreshBarButtonItem: UIBarButtonItem = { var tempRefreshBarButtonItem = UIBarButtonItem(barButtonSystemItem: UIBarButtonItem.SystemItem.refresh, target: self, action: #selector(SwiftWebVC.reloadTapped(_:))) tempRefreshBarButtonItem.tintColor = self.buttonColor return tempRefreshBarButtonItem }() lazy var stopBarButtonItem: UIBarButtonItem = { var tempStopBarButtonItem = UIBarButtonItem(barButtonSystemItem: UIBarButtonItem.SystemItem.stop, target: self, action: #selector(SwiftWebVC.stopTapped(_:))) tempStopBarButtonItem.tintColor = self.buttonColor return tempStopBarButtonItem }() lazy var actionBarButtonItem: UIBarButtonItem = { var tempActionBarButtonItem = UIBarButtonItem(barButtonSystemItem: UIBarButtonItem.SystemItem.action, target: self, action: #selector(SwiftWebVC.actionButtonTapped(_:))) tempActionBarButtonItem.tintColor = self.buttonColor return tempActionBarButtonItem }() lazy var webView: WKWebView = { let config = WKWebViewConfiguration() config.websiteDataStore = WKWebsiteDataStore.nonPersistent() var tempWebView = WKWebView(frame: UIScreen.main.bounds, configuration: config) tempWebView.uiDelegate = self tempWebView.navigationDelegate = self return tempWebView; }() /* lazy var webView: WKCookieWebView = { var tempWebView = WKCookieWebView(frame: UIScreen.main.bounds, configuration: WKWebViewConfiguration(), useRedirectCookieHandling: true) tempWebView.uiDelegate = self tempWebView.navigationDelegate = self return tempWebView; }() */ var request: URLRequest! var navBarTitle: UILabel! var hideToolbar = false //////////////////////////////////////////////// deinit { webView.stopLoading() UIApplication.shared.isNetworkActivityIndicatorVisible = false webView.uiDelegate = nil; webView.navigationDelegate = nil; } public convenience init(urlString: String, hideToolbar: Bool) { self.init(pageURL: URL(string: urlString)!, hideToolbar: hideToolbar) } public convenience init(pageURL: URL, hideToolbar: Bool) { self.init(aRequest: URLRequest(url: pageURL), hideToolbar: hideToolbar) } public convenience init(aRequest: URLRequest, hideToolbar: Bool) { self.init() self.request = aRequest self.hideToolbar = hideToolbar } //////////////////////////////////////////////// // View Lifecycle override public func loadView() { view = webView let language = NSLocale.preferredLanguages[0] as String request.setValue(CCUtility.getUserAgent(), forHTTPHeaderField: "User-Agent") request.addValue("true", forHTTPHeaderField: "OCS-APIRequest") request.addValue(language, forHTTPHeaderField: "Accept-Language") _ = webView.load(request) } override public func viewDidLoad() { super.viewDidLoad() updateToolbarItems() } override public func viewWillAppear(_ animated: Bool) { assert(self.navigationController != nil, "SVWebViewController needs to be contained in a UINavigationController. If you are presenting SVWebViewController modally, use SVModalWebViewController instead.") navBarTitle = UILabel() navBarTitle.backgroundColor = UIColor.clear if presentingViewController == nil { if let titleAttributes = navigationController!.navigationBar.titleTextAttributes { navBarTitle.textColor = titleAttributes[NSAttributedString.Key.foregroundColor] as? UIColor //[titleAttributes:"NSColor"] // ["NSColor"] as! UIColor } } else { navBarTitle.textColor = self.titleColor } navBarTitle.shadowOffset = CGSize(width: 0, height: 1); navBarTitle.font = UIFont(name: "HelveticaNeue-Medium", size: 17.0) navigationItem.titleView = navBarTitle; super.viewWillAppear(true) if (UIDevice.current.userInterfaceIdiom == UIUserInterfaceIdiom.phone) { self.navigationController?.setToolbarHidden(false, animated: false) } else if (UIDevice.current.userInterfaceIdiom == UIUserInterfaceIdiom.pad) { self.navigationController?.setToolbarHidden(true, animated: true) } self.navigationController?.setToolbarHidden(hideToolbar, animated: false) } override public func viewWillDisappear(_ animated: Bool) { super.viewWillDisappear(true) if (UIDevice.current.userInterfaceIdiom == UIUserInterfaceIdiom.phone) { self.navigationController?.setToolbarHidden(true, animated: true) } } override public func viewDidDisappear(_ animated: Bool) { super.viewDidDisappear(true) UIApplication.shared.isNetworkActivityIndicatorVisible = false } override public func dismiss(animated flag: Bool, completion: (() -> Void)? = nil) { super.dismiss(animated: flag, completion: { self.delegate?.webDismiss() }) } //////////////////////////////////////////////// // Toolbar func updateToolbarItems() { backBarButtonItem.isEnabled = webView.canGoBack forwardBarButtonItem.isEnabled = webView.canGoForward let refreshStopBarButtonItem: UIBarButtonItem = webView.isLoading ? stopBarButtonItem : refreshBarButtonItem let fixedSpace: UIBarButtonItem = UIBarButtonItem(barButtonSystemItem: UIBarButtonItem.SystemItem.fixedSpace, target: nil, action: nil) let flexibleSpace: UIBarButtonItem = UIBarButtonItem(barButtonSystemItem: UIBarButtonItem.SystemItem.flexibleSpace, target: nil, action: nil) if (UIDevice.current.userInterfaceIdiom == UIUserInterfaceIdiom.pad) { let toolbarWidth: CGFloat = 250.0 fixedSpace.width = 35.0 let items: NSArray = [fixedSpace, refreshStopBarButtonItem, fixedSpace, backBarButtonItem, fixedSpace, forwardBarButtonItem, fixedSpace, actionBarButtonItem] let toolbar: UIToolbar = UIToolbar(frame: CGRect(x: 0.0, y: 0.0, width: toolbarWidth, height: 44.0)) if !closing { toolbar.items = items as? [UIBarButtonItem] if presentingViewController == nil { toolbar.barTintColor = navigationController?.navigationBar.barTintColor } else { toolbar.barStyle = (navigationController?.navigationBar.barStyle)! } toolbar.tintColor = navigationController?.navigationBar.tintColor } navigationItem.rightBarButtonItems = items.reverseObjectEnumerator().allObjects as? [UIBarButtonItem] } else { let items: NSArray = [fixedSpace, backBarButtonItem, flexibleSpace, forwardBarButtonItem, flexibleSpace, refreshStopBarButtonItem, flexibleSpace, actionBarButtonItem, fixedSpace] if !closing { if presentingViewController == nil { navigationController?.toolbar.barTintColor = navigationController?.navigationBar.barTintColor } else { navigationController?.toolbar.barStyle = (navigationController?.navigationBar.barStyle)! } navigationController?.toolbar.tintColor = navigationController?.navigationBar.tintColor toolbarItems = items as? [UIBarButtonItem] } } } //////////////////////////////////////////////// // Target Actions @objc func goBackTapped(_ sender: UIBarButtonItem) { webView.goBack() } @objc func goForwardTapped(_ sender: UIBarButtonItem) { webView.goForward() } @objc func reloadTapped(_ sender: UIBarButtonItem) { webView.reload() } @objc func stopTapped(_ sender: UIBarButtonItem) { webView.stopLoading() updateToolbarItems() } @objc func actionButtonTapped(_ sender: AnyObject) { if let url: URL = ((webView.url != nil) ? webView.url : request.url) { let activities: NSArray = [SwiftWebVCActivitySafari(), SwiftWebVCActivityChrome()] if url.absoluteString.hasPrefix("file:///") { let dc: UIDocumentInteractionController = UIDocumentInteractionController(url: url) dc.presentOptionsMenu(from: view.bounds, in: view, animated: true) } else { let activityController: UIActivityViewController = UIActivityViewController(activityItems: [url], applicationActivities: activities as? [UIActivity]) if floor(NSFoundationVersionNumber) > NSFoundationVersionNumber_iOS_7_1 && UIDevice.current.userInterfaceIdiom == UIUserInterfaceIdiom.pad { let ctrl: UIPopoverPresentationController = activityController.popoverPresentationController! ctrl.sourceView = view ctrl.barButtonItem = sender as? UIBarButtonItem } present(activityController, animated: true, completion: nil) } } } //////////////////////////////////////////////// @objc func doneButtonTapped() { closing = true UINavigationBar.appearance().barStyle = storedStatusColor! self.dismiss(animated: true, completion: nil) } // MARK: - Class Methods /// Helper function to get image within SwiftWebVCResources bundle /// /// - parameter named: The name of the image in the SwiftWebVCResources bundle class func bundledImage(named: String) -> UIImage? { let image = UIImage(named: named) if image == nil { return UIImage(named: named, in: Bundle(for: SwiftWebVC.classForCoder()), compatibleWith: nil) } // Replace MyBasePodClass with yours return image } } extension SwiftWebVC: WKUIDelegate { // Add any desired WKUIDelegate methods here: https://developer.apple.com/reference/webkit/wkuidelegate } extension SwiftWebVC: WKNavigationDelegate { public func webView(_ webView: WKWebView, didStartProvisionalNavigation navigation: WKNavigation!) { self.delegate?.didStartLoading() UIApplication.shared.isNetworkActivityIndicatorVisible = true updateToolbarItems() } public func webView(_ webView: WKWebView, didReceiveServerRedirectForProvisionalNavigation navigation: WKNavigation!) { self.delegate?.didReceiveServerRedirectForProvisionalNavigation(url: webView.url!) } public func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) { self.delegate?.didFinishLoading(success: true) self.delegate?.didFinishLoading(success: true, url: webView.url!) UIApplication.shared.isNetworkActivityIndicatorVisible = false webView.evaluateJavaScript("document.title") { result, error in guard let title = result as? String else { return } if (error == nil && self.navBarTitle != nil) { self.navBarTitle.text = String(describing: title) self.navBarTitle.sizeToFit() self.updateToolbarItems() } } } public func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) { decisionHandler(.allow) } public func webView(_ webView: WKWebView, didFail navigation: WKNavigation!, withError error: Error) { self.delegate?.didFinishLoading(success: false) self.delegate?.didFinishLoading(success: false, url: webView.url!) UIApplication.shared.isNetworkActivityIndicatorVisible = false updateToolbarItems() } public func webView(_ webView: WKWebView, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) { if let serverTrust = challenge.protectionSpace.serverTrust { completionHandler(Foundation.URLSession.AuthChallengeDisposition.useCredential, URLCredential(trust: serverTrust)) } else { completionHandler(URLSession.AuthChallengeDisposition.useCredential, nil); } } }