Use wkwebview back reload - ios

I am using WKWebview,I want that when I click the back button, it refresh the page rather than reading the page cache.
if (self.webView.canGoBack) {
[self.webView goBack];
[self.webView reload];
}
But, when you return to certain pages these are loaded twice and can't return to the first page.
Do not know to have people meet the same requirements and how to solve? The premise is not use UIWebview.

I was also facing the same issue. After removing the reload method, it was working correctly.
if ([self.wkWebView canGoBack]) {
[self.wkWebView goBack];
}

var backNavigation: WKNavigation?
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
if backNavigation?.isEqual(navigation) ?? false {
webView.reload()
backNavigation = nil
}
}

in my page's js file, I add this and it worked.
var solveLoadingProblem = function () {
window.addEventListener("popstate", function (e) {
location.reload(true);
});
};
solveLoadingProble();

Related

How to run Code after asynchronus code is finished, Swift

I have a asynchronus Funktion, loadHTMLString, that I call to load the Text out of an HTML File. The loading Process needs time, almost a second. The Problem is: I want to go on with my Code, if the File is loaded, but I dont know when the loading is finished. Is there a way to do that?
func generateAndLoadPDF() {
// Thats my HTML File
let html = HTML.get(from: "Vorlage.html")
// I load this HTML File in my WebView, that takes almost a second
wkWebView.loadHTMLString(html, baseURL: Bundle.main.bundleURL)
// I delayed the Following Code, so the HTML-String has time to load
// Actually I dont want to delay the Code, I want that the following Code runs after .loadHTMLString is finished.
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
// I generate the PDF
let wkPDFData = PDF.generate(using: self.wkWebViewPrintFormatter())
self.loadIntoWKWebView(wkPDFData)
}
}
Thanks,
Boothosh
Conform to WKNavigationDelegate
webView.navigationDelegate = self
extension ViewController: WKNavigationDelegate {
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
debugPrint("didFinish")
}
}

How can i display only the content of a website?

I need to display only a part of the website, basically the CONTENT part of the website.
I can display the website with uiwebkit but, i dont want to display the entire website but only the CONTENT part of the webpage. I have no idea how to do this , as i have never done this and i did some google search but could not find anything on ios / swift.
How can i do this? Thanks.
you can use WKNavigationDelegate which allow you to implement did finish the function of webview in this function you can hide specific content of website.
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
let removeelementid = "javascript:(function() { " + "document.getElementsByClassName('td-header-menu-wrap-full td-container-wrap')[0].style.display=\"none\"; " + "})()"
webView.evaluateJavaScript(removeelementid) { (res, error) in
if error != nil
{
print("Error")
}
else
{
//do any thing
}
}
}
func webView(_ webView: WKWebView, didFail navigation: WKNavigation!, withError error: Error) {
print(error.localizedDescription)
}
as you can see i am removing specific content of web by its class name td-header-menu-wrap-full td-container-wrap
Go to that web site right click -> click inspect. pick class names of content and call in this function . hope this will help you.

How to set localStorage item in webView before loading a URLRequest?

I have to access a web page that has token on its localStorage
let javascript = "localStorage.setItem('token', 'abc')"
let url = URL(string: "https://test.com/abc")
webView.evaluateJavaScript(javascript) { (_, err) in
print(err?.localizedDescription)
// This will return 'A JavaScript exception occurred'
}
let request = URLRequest(url: url!)
webView.load(request)
I dont think this is possible. You get this error:
Error Domain=WKErrorDomain Code=4
"A JavaScript exception occurred" UserInfo={WKJavaScriptExceptionLineNumber=0,
WKJavaScriptExceptionMessage=SecurityError: The operation is
insecure., WKJavaScriptExceptionColumnNumber=0,
NSLocalizedDescription=A JavaScript exception occurred}
And there nothing you can do about for the WKWebView.
i solve it but i think it's a bad practice and the right way was to be able to send token in request's header
the main problem was that you can't run javascript script that add localStorage item before the web view load so i had to wait utile that page is loaded then then run javascript script that add needed token then reload that page Here is my code but again it's bad practice i think and i believe that front end team should allow me to end that token in request header
fist there was that method with reload the web view only one time
var loaded = false
func load() {
if !loaded {
webView.reload()
}
loaded = true
}
then i had to confirm to WKNavigationDelegate delegate to reload that page when it's loaded and here is my code
extension ViewController: WKNavigationDelegate {
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
webView.evaluateJavaScript(javascript) { (_, err) in
self.load()
}
}
}

Keyboard "done" button pressed event for UIWebView and WKWebView

There are resources for this when using UITextView. How do I register for the Done key button press event? The keyboard shows up when the user focuses a form inside the webview.
The main idea is to use Javascript injection to achieve what you want.
You can try catching the DOM event called onfocusout (Refer to http://www.w3schools.com/jsref/event_onfocusout.asp for more details).
Following is the example of how you could do it for UIWebView. WKWebView can be handled in a similar way.
Call this to inject some Javascript code after the first time your webview loaded
[webView stringByEvaluatingJavaScriptFromString:#"document.getElementById('youTextFieldID').addEventListener('onfocusout', function () {"
#"var frame = document.createElement('iframe');"
#"frame.src = 'doneEditing://';"
#"document.body.appendChild(frame);"
#"setTimeout(function () { document.body.removeChild(frame); }, 0);"
#"}, false);"];
Write your UIWebView delegate method like this
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType {
if ([request.URL.scheme isEqualToString:#"doneEditing"]) {
// Call you event handler here
[self doneButtonTouchEventHandler]
return NO;
}
return YES;
}
Good luck
The key is to add event listeners when the web page loads. I assume that you want to know about the blur event of a text field.
Here is a basic working example:
<html>
<head>
<script>
function initPage() {
document.addEventListener('focusin', handleFocusIn);
document.addEventListener('focusout', handleFocusOut);
}
function handleFocusIn(e) {
alert('In');
}
function handleFocusOut(e) {
alert('Out');
}
</script>
</head>
<body onload="initPage()">
<form>
<input type="text" name="username">
</form>
</body>
</html>
I hope that helps, please let me know otherwise!
Good luck!
#Ducky
answers is for UIWebView
here is a solution for WkWebview
extend ViewController as WKNavigationDelegate
webView.navigationDelegate = self
implement and override function
get your button id and write on document.getElementById
this method called on page load finish
func webView(_ webView: WKWebView,didFinish navigation: WKNavigation!) {
print("loaded")
let doneJS = """
document.getElementById('m_ara_input').addEventListener('focusout', function () {
var frame = document.createElement('iframe');
frame.src = 'doneEditing://';
document.body.appendChild(frame);
setTimeout(function () { document.body.removeChild(frame); }, 0);
}, false);
"""
webView.evaluateJavaScript(doneJS, completionHandler: nil)
}
override below method
func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: #escaping (WKNavigationActionPolicy) -> Void) {
guard let url = navigationAction.request.url else {return}
if (url.scheme == "doneediting") {
executeSubmit()
}
decisionHandler(.allow)
}
write this function
func executeSubmit(){
let js = """
var a = document.getElementsByClassName("btn btn-default pull-left");
a.ara_buton.click();
"""
webView.evaluateJavaScript(js, completionHandler: nil)
}
in javascript ara_buton is the attribute of "name" of button

UIWebViewDelegate: webViewDidFinishLoad not called during in-page navigation

I have an app where users can navigate a pile of locally stored HTML files. I have a UIWebView, configured up correctly with a UIWebViewDelegate. Usually, when the user follows a link, shouldStartLoadWithRequest is called, followed by webViewDidFinishLoad a bit later.
But, if the link is pointing to an anchor on the same page as the one which is currently displayed, only shouldStartLoadWithRequest is called. webViewDidFinishLoad does not fire.
In a sense, I see that this might be expected behaviour, because in-page navigation should not require a page reload. However, I really need a place to hook into the call stack after in-page navigation is complete. The optimal solution would let me know when any sort of navigation has ended, both from another page, in-page and forward/backward actions.
My best hackaround so far has been to call performSelector: withObject: afterDelay: at the end of my shouldStartLoadWithRequest method, but I'm not happy with this.
Does anyone know how I can solve this correctly? Any insight appreciated!
You can try to use NSURLConnectionDataDelegate, it allows you to handle incoming data. Maybe you can determine if the page is loaded manually by adding a sign to your html files.
NSURLConnectionDataDelegate Reference
Edit: gist.github.com/buranmert/7304047 I wrote a piece of code and it worked, that may not be the way you wanted it to work but maybe it helps. Every time user clicks a URL with anchor, it creates another connection and as connection finishes loading web view loads the data, that marks the point where web view finished loading the page. As you use only local html files, I do not think creating connections will create problems
What you are describing is intended behavior. Just as AJAX or resource requests are never passed to the delegate, only root page changes will ever hit webViewDidFinishLoad:. But I have good news, and it doesn't involve saving a bunch of money on car insurance.
Loads performed within an iFrame DO trigger the full delegate methods and this gives you a solution. You can use this mechanism to post a notification to the native code, just as is often done for console.log() as described in this post. Alternatively, Native Bridge would work well to call into your Objective C code from JavaScript.
Just check weather u got the delegate function DidStartLoading if it is called no doubt that DidFinish also should get called
Are you sure your shouldStartLoadWithRequest always returns an YES???
I always add
return YES;
at the end of shouldStartLoadWithRequest implementation.And that works for me.
By returning YES, it denotes that the webview has loaded and would call the webViewDidFinishLoad
if([webView isLoading]==1)
{
//your webview is loading
}
else
{
//your webview has loaded
}
Here is a Swift Implementation of Mert Buran's code incase anybody is looking for it. (Although NSURLConnection is deprecated as of iOS 9)
But it does not solve my problem. When i click on a jquery link that popups a video, it does not fire the webViewDidFinishLoad.
class WebViewController: UIViewController, UIWebViewDelegate, NSURLConnectionDelegate {
var menuURL: String?
var response: NSURLResponse?
var data = NSData()
// MARK: Properties
#IBOutlet weak var webView: UIWebView!
override func viewDidLoad() {
super.viewDidLoad()
webView.delegate = self
// From Web
let url = NSURL (string: menuURL!)
let urlRequest = NSURLRequest(URL: url!)
let connection = NSURLConnection(request: urlRequest, delegate: self)
self.data = NSData()
connection!.start()
// if this is false, page will be 'zoomed in' to normal size
webView.scalesPageToFit = false
}
func webView(webView: UIWebView, shouldStartLoadWithRequest request: NSURLRequest, navigationType: UIWebViewNavigationType) -> Bool {
if navigationType == .LinkClicked && request.URL!.fragment != nil {
let connection = NSURLConnection(request: request, delegate: self)
connection!.start()
return false
}
return true
}
func connection(connection: NSURLConnection, didReceiveResponse response: NSURLResponse) {
self.response = response
}
func connection(connection: NSURLConnection, didReceiveData data: NSData) {
let oldData = NSMutableData(data: self.data)
oldData.appendData(data)
self.data = oldData
}
func connectionDidFinishLoading(connection: NSURLConnection) {
self.webView.loadData(self.data, MIMEType: self.response!.MIMEType!, textEncodingName: "utf-8", baseURL: self.response!.URL!)
self.data = NSData()
}
}

Resources