WKWebView didn't finish loading, when didFinishNavigation is called - Bug in WKWebView?
WKWebView doesn't use delegation to let you know when content loading is complete (that's why you can't find any delegate method that suits your purpose). The way to know whether a WKWebView is still loading is to use KVO (key-value observing) to watch its loading
property. In this way, you receive a notification when loading
changes from true
to false
.
Here's a looping animated gif showing what happens when I test this. I load a web view and respond to its loading
property through KVO to take a snapshot. The upper view is the web view; the lower (squashed) view is the snapshot. As you can see, the snapshot does capture the loaded content:
[NSTimer scheduledTimerWithTimeInterval:1.0 repeats:YES block:^(NSTimer * _Nonnull timer) {
if (self->_webKitView.isLoading == true) {
NSLog(@"Still loading...");
}else {
NSLog(@"Finished loading...");
[timer invalidate];
dispatch_async(dispatch_get_main_queue(), ^{
[self->_activityIndicator stopAnimating];
});
}
}];
WKWebView Content loaded function never get called
You are not setting the navigationDelegate. Set it and it should be fine.
class ViewController: UIViewController, WKNavigationDelegate {
override func viewDidLoad() {
super.viewDidLoad()
let noLayoutFormatOptions = NSLayoutFormatOptions(rawValue: 0)
let webView = WKWebView(frame: CGRectZero, configuration: WKWebViewConfiguration())
webView.setTranslatesAutoresizingMaskIntoConstraints(false)
webView.navigationDelegate = self
view.addSubview(webView)
view.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("V:|[webView]|", options: noLayoutFormatOptions, metrics: nil, views: ["webView": webView]))
view.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("H:|[webView]|", options: noLayoutFormatOptions, metrics: nil, views: ["webView": webView]))
let url = NSURL(string: "http://google.com")
let request = NSURLRequest(URL: url)
webView.loadRequest(request)
}
func webView(webView: WKWebView!, didFinishNavigation navigation: WKNavigation!) {
print("Finished navigating to url \(webView.url)");
}
}
And here is a bit better version with Swift 3.
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let configuration = WKWebViewConfiguration()
let webView = WKWebView(frame: .zero, configuration: configuration)
webView.translatesAutoresizingMaskIntoConstraints = false
webView.navigationDelegate = self
view.addSubview(webView)
[webView.topAnchor.constraint(equalTo: view.topAnchor),
webView.bottomAnchor.constraint(equalTo: view.bottomAnchor),
webView.leftAnchor.constraint(equalTo: view.leftAnchor),
webView.rightAnchor.constraint(equalTo: view.rightAnchor)].forEach { anchor in
anchor.isActive = true
}
if let url = URL(string: "https://google.com/search?q=westworld") {
webView.load(URLRequest(url: url))
}
}
}
extension ViewController: WKNavigationDelegate {
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
print("Finished navigating to url \(webView.url)")
}
}
Hiding view when WKWebView has finished loading swiftUI
Your View
won't know to reload unless it is triggered with something like a @State
property or an ObservableObject
. You haven't really provided enough code from your SwiftUiWebView
to show everything, but here's the gist of what needs to happen:
struct ContentView: View {
@State var webViewFinishedLoading = false
var body: some View {
SwiftUiWebView(url: URL(string: "myUrl"), finishedLoading: $webViewFinishedLoading)
ZStack {
if (!webViewFinishedLoading) {
....
}
}
}
}
struct SwiftUiWebView : UIViewRepresentable {
var url: URL
var finishedLoading: Binding<Bool>
//...
}
Then, you will need to pass that finishedLoading
Binding to your web view delegate and set its .wrappedValue
to true
when you're done loading:
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
if (webView.isLoading) {
return
}
print("Done Loading")
finishedLoading.wrappedValue = true
}
Because it's tied to a @State
variable, your view will know to refresh.
WKWebView Navigation Delegate Not Called
You need to move let test = TestWebview ()
to class level, otherwise this object is going to be evicted when viewDidLoad
completes: the navigationDelegate
is defined as weak
, so it's not going to prevent it either.
How to check if wkwebview finished loading in UItest
I had some problems trying to figure out how to make it too, so I decide to use this work around. In the wkwebview didfinishload if you have any variable there, you can check if it exists or its value. If you do not have any variable there, you must create it in global scope, right? For example if we have this code when wkwebview ends loading:
func webView(_ webView: WKWebView,didFinish navigation: WKNavigation!) {
myTopLabel.text = "Content Loaded"
print("loaded")
}
'myTopLabel' is a UILabel that I use to show the status of my web, so what I had to do is execute this command in UITest:
let nextGameLabel = self.app.staticTexts["Content Loaded"]
app.buttons["Reload Web"].tap()
XCTAssert(nextGameLabel.waitForExistence(timeout: 5))
So When I press the app button, the UITest waits for 5 seconds to see if the web is loaded or not. Hope it helps dude.
WKWebView not working
// Add plist file
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
<key>NSExceptionDomains</key>
<dict>
<key>google.com</key>
<dict>
<key>NSExceptionAllowsInsecureHTTPLoads</key>
<true/>
<key>NSIncludesSubdomains</key>
<true/>
</dict>
</dict>
if WKWebView don't not support then declare .m file below code:
#import <WebKit/WebKit.h>
@interface WebScannerViewController()
{
WKWebView *webView;
}
@end
@implementation WebScannerViewController
- (void)viewDidLoad
{
[super viewDidLoad];
webView.hidden=YES;
webView.UIDelegate = self;
webView.navigationDelegate = self;
self.loadingSign.hidden = NO;
webView.frame=CGRectMake(0, 94, Width, Height-128);
}
Setting loading call backs to WKWebView
You could do this in navigationDelegate
of WKWebView
.
// your ViewController should adopt WKNavigationDelegate protocol
self.wkwebView.navigationDelegate = self
func webView(_ webView: WKWebView, didFinishNavigation navigation: WKNavigation!) {
// similar to webViewDidFinishLoad:
}
Related Topics
Swift - How to Get Last Taken 3 Photos from Photo Library
Move a View When Scrolling in Uitableview
This Certificate Was Signed by an Unknown Authority
Making Video from Uiimage Array with Different Transition Animations
How to Set an Title of the Currently Playing Audio in iPhone Lock Screen
Perform Push Segue After an Unwind Segue
Uitextfield Should Accept Number Only Values
Limit Uitextfield Input to Numbers in Swift
Can't Find Pods.Modulemap - Looking in Wrong Directory
Stretch Background Image for Uibutton
Uicollectionview Sticky Header in Swift
Uirefreshcontrol - Pull to Refresh in iOS 7
iPhone Collecting Coremotion Data in the Background. (Longer Than 10 Mins)
Error: Module File's Minimum Deployment Target Is iOS8.3 V8.3
Can't Install Watchkit App on Apple Watch
Unified Uiviewcontroller "Became Frontmost" Detection
Swift 2.0 Minimum System Version Requirement (Deployment Target)