I am trying to show an image (logo) while the WKWebView is loading.
So, looking at other posts, I would put an image on the screen in ViewDidLoad() and hide the image in the didFinish method. But, for some reason, the didFinish method is not working. It does not print that it finished (although the webview does show up on the screen). For this, I also already looked at other posts. But, these mainly suggest to set the delegate of the WKWebView (which I did). Here is my code:
import UIKit
import Foundation
import WebKit
class ViewController: UIViewController, WKUIDelegate {
var webView: WKWebView!
override func loadView() {
let webConfiguration = WKWebViewConfiguration()
webView = WKWebView(frame: .zero, configuration: webConfiguration)
webView.uiDelegate = self
view = webView
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
let myURL = URL(string:"https://www.mijnmedicijn.nl/")
let myRequest = URLRequest(url: myURL!)
webView.load(myRequest)
}
func webView(_ webView: WKWebView,
didFinish navigation: WKNavigation!){
print("Webview did finish load")
}
func webView(_ webView: WKWebView,
didStart navigation: WKNavigation!){
print("Webview did start laoding")
}
}
What am I doing wrong? Why doesn't the didFinish work? How would I make it work and show an image while loading?
You need to add the delegate of the navigation
webView.navigationDelegate = self
class ViewController: UIViewController , WKUIDelegate , WKNavigationDelegate {
First of all, optional func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) is a method declared in WKNavigationDelegate hence your class must conform to protocol WKNavigationDelegate and your code must look like webView.navigationDelegate = self
Secondly, for your another question in comments "Why does it print the statement seconds after the webview is already loaded on my phone?"
The optional func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) is called when webview mainframe navigation gets completed i.e. WKWebView fully completes loading the entire page.
An ideal implementation for showing/hiding loading image would be,
Conform to WKNavigationDelegate.
Implement optional func webView(_ webView: WKWebView, didStartProvisionalNavigation navigation: WKNavigation!) and write code to show the loading image in this function. As this function gets called as soon as WKWebView starts mainframe navigation.
Implement optional func webView(_ webView: WKWebView, didCommit navigation: WKNavigation!) and write code to hide the loading image in this function. As this function gets called as soon as contents start arriving in WKWebView.
Also implement optional func webView(_ webView: WKWebView, didFail navigation: WKNavigation!, withError error: Error) and write code to hide the loading image in this function. This function should be implemented just-in-case URL loading fails.
Related
I have 2 views on my screen first is the Webview and the second is a static view "errorView" with the error message "set to hidden". I am trying to load the errorView if we have an error loading website to Webview.
#objc private func loadURL() {
guard let url = URL(string: "https://www.hackingwi") else {
self.errroLoadingWebView.isHidden = false
return
}
webView?.load(URLRequest(url: url))
webView?.allowsBackForwardNavigationGestures = true
}
You can use WKNavigationDelegate.
set delegate
webView.uiDelegate = self
webView.navigationDelegate = self
class StaticWebPageVC: WKNavigationDelegate, WKUIDelegate {
func webView(_: WKWebView, didFinish _: WKNavigation!) {
// Web view loaded
}
func webView(_ webView: WKWebView, didFail navigation: WKNavigation!, withError error: Error) {
// Show error view
}
func webView(_ webView: WKWebView, didFailProvisionalNavigation navigation: WKNavigation!, withError error: Error) {
// Show error view
}
}
I am working on an app that mainly consist of a WKWebView.
I monitor it's navigation status using the WKNavigationDelegate protocol.
I create my viewController as a WKNavigationDelegate
class ViewController: UIViewController, WKUIDelegate, WKNavigationDelegate, UIGestureRecognizerDelegate {
...
override func viewDidLoad() {
...
webView.navigationDelegate = self
...
I load the request on the webview like so:
let gotoUrl = ... as? String
if let url = URL(string: gotoUrl) {
let request = URLRequest(url: url)
webView.load(request)
}
And then the delegate methods:
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
print("Successfully loaded")
}
func webView(_ webView: WKWebView, didCommit navigation: WKNavigation!) {
print("Did commit navigation")
}
func webView(_ webView: WKWebView, didStartProvisionalNavigation navigation: WKNavigation!) {
print("Start Provisional navigation")
}
func webViewWebContentProcessDidTerminate(_ webView:WKWebView) {
print("request failed")
}
func webView(_ webView: WKWebView, didFail navigation: WKNavigation!, withError error: Error) {
print("request failed")
}
func webView(_ webView: WKWebView, didFailProvisionalNavigation: WKNavigation!, withError: Error) {
print("request failed")
}
This works fine for my webapps initial url: https://example.com/app/
Then the delegate methods are called.
When the app is opened from a notification I want to direct the webview to a specific part of the webapp.
However when i load an url that load a specific part of the webapp:
https://example.com/app/#/secure/content/alarm-base/alarm-list//alarm-detail/1381122
The delegate methods are not called, although the webview loads the url successfully.
The delegate methods are also called if I load the specific url directly on startup.
The web appication is written in AngularJS.
I would like for the delegate handlers to trigger for every request I load from the code.
Any idea on how to achieve this?
I am not sure what is going on, but it is possible to force it to use the delegate by adding the following code when doing the request:
webView.load(request)
webView.stopLoading()
webView.reload()
It is clunky, but it solves the problem for me.
I want to display progress while the WebView is loading and dismiss it when the WebView finishes loading.
I tried this code:
import UIKit
import WebKit
import SVProgressHUD
class ViewController: UIViewController, UIWebViewDelegate {
#IBOutlet var WebView1: WKWebView!
#IBOutlet var WebView2: WKWebView!
let YouTubeURL = URL (string: "https://www.youtube.com/")
#IBAction func YTButtonAction(_ sender: Any) {
let YTRequest = URLRequest(url: YouTubeURL!)
WebView1.load(YTRequest)
if WebView1.isLoading {
SVProgressHUD.show()
}
func webViewDidFinishLoad(WebView1 : UIWebView) {
SVProgressHUD.dismiss()
}
}
}
But it doesn't work.
The progress continue rotating.
Anybody knows how to solve this problem?
Three fatal issues:
You have to set the delegate
WebView1.delegate = self
The signature of the delegate method is wrong
func webViewDidFinishLoad(_ webView: UIWebView)
The delegate method must be on the top level of the class.
I think there is a fourth fatal issue: I doubt that WKWebView conforms to UIWebViewDelegate at all. I suppose you have to adopt WKNavigationDelegate and implement webView(:didFinish:) instead.
And please conform to the Swift naming convention that variable and function / method names start with a lowercase letter.
The answer :
I changed
UIWebViewDelegate to WKNavigationDelegate
WebView1.delegate = self to WebView1. navigationDelegate = self
The name of the WKWebView property is navigationDelegat
func webViewDidFinishLoad(WebView1 : UIWebView) to
func webView(_ webView: WKWebView,
didFinish navigation: WKNavigation!)
I want to load HTML pages using WkWebView and I want to show the page just after it's finished loading. As long as it's loading I would like to show an activity indicator on an empty View.
I create two view a loadingView and a wkWebView. While the page is loading I add to VC as subview the loadingView and after I want to remove loadingView and add wkWebView. Here is my code:
[self addSubview:_loadingView];
_wkWebView = [[WKWebView alloc] initWithFrame:self.frame];
_wkWebView.frame = CGRectMake(self.frame.origin.x, self.frame.origin.y, self.frame.size.width, self.frame.size.height);
//Send a request to wkUrlconnection
NSURL *wkUrl = [NSURL URLWithString:self.wkUrlString];
NSURLRequest *wkRequest = [NSURLRequest requestWithURL:wkUrl];
//Here I want to check if it's loaded and then remove loadingView and add wkWebView
[_wkWebView loadRequest:wkRequest];
[self.loadingView removeFromSuperview];
[self addSubview:_wkWebView];
Can someone show me how to check while it's loading and if finish refresh the VC? Thank you for your answers.
I think the WKNavigationDelegate's webView:didFinishNavigation: delegate callback is what you're looking for.
Configure and present your activity indicator when you start to load and then stop and remove it from view when the callback is called.
For anyone who is experiencing the issue of a webpage containing multiple frames and therefore doing multiple loads which interrups your load animation, I have implemented the following and it works for me in all the situations I have come across so far:
Swift:
var loadCount: Int = 0
override func viewDidLoad() {
super.viewDidLoad()
startLoading()
webview.navigationDelegate = self
let request = URLRequest(url: url)
webview.load(request)
}
func webView(_ webView: WKWebView, didStartProvisionalNavigation navigation: WKNavigation!) {
loadCount += 1
}
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
loadCount -= 1
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) { [weak self] in
if self?.loadCount == 0 {
self?.stopLoading()
}
}
}
The basic idea is to start your load animation before you request the url, then count each request being made and only stop the load animation when your request count == 0. This is done after a slight delay as I find that some frames queue up requests synchronously so the next load will begin before the 0.1 second delay has completed.
( ͡° ͜ʖ ͡°)
for swift 4.2:
func webView(_ webView: WKWebView,
didFinish navigation: WKNavigation!){
print("loaded")
}
be sure to set delegate for webView in didLoad (or similar)
webView.navigationDelegate = self
class WebViewVC: UIViewController {
// MARK: IBOutlets
#IBOutlet weak var webView: WKWebView!
#IBOutlet weak var activityIndicator: UIActivityIndicatorView!
// MARK: Life cycle
override func viewDidLoad() {
super.viewDidLoad()
webView.navigationDelegate = self
loadWebsite()
}
}
// MARK: WKWebView
extension WebViewVC: WKNavigationDelegate {
func webView(_ webView: WKWebView, didStartProvisionalNavigation navigation: WKNavigation!) {
activityIndicator.startAnimating()
}
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
activityIndicator.stopAnimating()
}
}
// MARK: Private methods
extension WebViewVC {
private func loadWebsite() {
guard let url = URL(string: "google.com") else { return }
let urlRequest = URLRequest(url: url)
webView.load(urlRequest)
}
}
I am very new to Swift and iOS development so thank you so much in advance for helping me!
I have tried every example online and every page on this site and I cannot get my Activity Indicator to stop being displayed once the page completes loading in my WKWebview.
Any assistance would be so appreciated! Thank you!
import UIKit
import WebKit
class FirstViewController: UIViewController, WKUIDelegate, WKNavigationDelegate {
#IBOutlet var webView: WKWebView!
#IBOutlet var activityIndicator: UIActivityIndicatorView!
override func viewDidLoad() {
super.viewDidLoad()
webView.uiDelegate = self
activityIndicator.startAnimating()
activityIndicator.isHidden = true
activityIndicator.hidesWhenStopped = true
let url = Bundle.main.url(forResource: "Web/bulk_material_table", withExtension: "html")!
webView.loadFileURL(url, allowingReadAccessTo: url)
let request = URLRequest(url: url)
self.webView.load(request)
}
func showActivityIndicator(show: Bool) {
if show {
activityIndicator.startAnimating()
} else {
activityIndicator.stopAnimating()
}
}
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
showActivityIndicator(show: false)
}
func webView(_ webView: WKWebView, didStartProvisionalNavigation navigation: WKNavigation!) {
showActivityIndicator(show: true)
}
func webView(_ webView: WKWebView, didFail navigation: WKNavigation!, withError error: Error) {
showActivityIndicator(show: false)
}
}
Just replace
webView.uiDelegate = self
with
webView.navigationDelegate = self
And it will work because
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
showActivityIndicator(show: false)
}
is WKNavigationDelegate's delegate method.