How to detect only short taps - ios

In my view controller, I have a WKWebView and I use a UITapGestureRecognizer to detect taps on the webview in order to show/hide the navigation and status bars. I also use the taps+javascript to detect when special parts of the web content are tapped.
WKWebView uses long-presses to allow the user to select text.
Super-long-presses work great. The web content is selected by WKWebView as expected and life is good.
My problem is when the user applies "shorter"-long-presses, because the UITapGestureRecognizer recognizes them as taps. WKWebView selects the text, so it seems like the user pressed long enough, but upon release the UITapGestureRecognizer fires the designated action and my code to show/hide the navigation bar kicks in.
What I want is to only show/hide the navigation bar when the user applies a very short tap. If they touch long enough for WKWebView to select text, I want to let WKWebView handle it.
I was hoping to filter taps by touch duration, but I haven't been able to find a way to determine this information.
Am I missing something? Can I achieve this with a UITapGestureRecognizer or do I need a different approach?
I'm targetting iOS 8 & 9.

If you have access to the gesture recognizer used by the WKWebView that selects the text, then you can setup your short tap recognizer to require that WKWebView recognizer to fail, using requireGestureRecognizerToFail:.
If you don't have access to the gesture recognizer used by the WKWebView, then you can take this hackier approach:
Create a UILongPressGestureRecognizer. This long press recognizer doesn't do anything on its own, but it's needed by step 2.
In your short tap recognizer, use requireGestureRecognizerToFail:, specifying the UILongPressGestureRecognizer from step 1.
Note, this second approach only has a shot of working if WKWebView is using a UILongPressGestureRecognizer under the hood.

For WKWebView the most simple solution will be just to use method from WKNavigationDelegate protocol and inside of it decide whether to handle that url or not.
public func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction,
decisionHandler: #escaping (WKNavigationActionPolicy) -> Void) {
if let url = navigationAction.request.url, url.scheme?.lowercased() == Constants.mailToScheme {
UIApplication.shared.open(url, options: [:])
decisionHandler(.cancel)
} else {
decisionHandler(.allow)
}
}

If #melany code does't work properly then make following changes ...
func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: ((WKNavigationActionPolicy) -> Void)) {
switch navigationAction.navigationType {
case .linkActivated:
UIApplication.shared.openURL(navigationAction.request.url!)
decisionHandler(.cancel)
return
default:
break
}
decisionHandler(.allow)
}

Related

how do I perform tasks before loading a webview url in ios?

so I can't seem to figure out a way to perform some tasks before loading a url in ios webview.
Like in android we can use shouldOverrideUrlLoading.
#Override
public boolean shouldOverrideUrlLoading(final WebView view, String url) {
///sometask
}
but I can't find a function that does something like this in ios.
Say a user clicked on a href tag inside the webview that takes it to different page, how do I know what link that tag takes the user to? before changing the page.
Basically I want to check what url the webpage is about to load and perform extra steps according to that url.
You can use WKNavigationDelegate
set navigationDelegate in viewDidLoad
self.webView?.navigationDelegate = self
Observe URL in below navigationDelegate Method.
func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: (WKNavigationActionPolicy) -> Void) {
DispatchQueue.main.async {
if let urlString = navigationAction.request.url?.absoluteString{
print(urlString)
}
}
decisionHandler(.allow)
}

WKNavigationDelegate occasionally doesn't get called

I use a WKWebView in my app and use a native login page. Whenever the web app redirects to the login page I catch it and show the native view controller. This works perfectly fine most of the time. However, I've found that every once in a while (in production mainly) some users get shown the web app login page. It's very rare and inconsistent. I was able to see this behavior when coming back into the app after it was in the background for a while.
func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: #escaping (WKNavigationActionPolicy) -> Void) {
if let url = navigationAction.request.url {
if (url.absoluteString.contains("/login")) {
decisionHandler(.cancel)
// redirects to native login page
...
return
}
}
decisionHandler(.allow)
}
Also, I do set the delegate BEFORE calling load on the webview.
Any idea what might be going on and how to prevent this from happening?

WKWebview navigation response method isn't getting called upon clicking done button in a webview

I'm using WKWebview for my Swift app. For some reason, WKWebview navigation response delegate method isn't getting called when the user clicks the done button in a WKWebView. When I try the same action on the web, it redirects to the correct url.
So far I have tried clearing WKWebview cache before configuring WKWebView in viewDidLoad or if I get a memory warning. Also, ensured my info.plist allows arbitrary loads and NSExceptionAllowsInsecureHTTPLoads for testing purposes. Despite trying these things to debug, the navigation response delegate method still didn't get called.
func webView(_ webView: WKWebView, decidePolicyFor navigationResponse: WKNavigationResponse, decisionHandler: #escaping (WKNavigationResponsePolicy) -> Void) {
if let webviewUrl = webView.url {
let urlString = webviewUrl.absoluteString
if urlString.contains("\(myUrlComponents)") {
self.navigationController?.popViewController(animated: true)
decisionHandler(.cancel)
return
}
}
decisionHandler(.allow)
}
I want to be able to detect a specific WKWebview url when the navigation response method gets called and go back to the previous screen.
I think you'll find that it will be called if you use the delegate function that looks identical to the one you're using except that the "decisionHandler" is a function taking WKNavigationActionPolicy as its argument.

How to open social link by clicking on button inside WKWebView

There is a social link button inside WKWebView. When I click on the button nothing happens.
Could you please tell me how to open the link by clicking on the button?
Thanks in advance.
what link u want to open change "facebook","twitter" and you can add more links also
func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: #escaping (WKNavigationActionPolicy) -> Void) {
if navigationAction.navigationType == .linkActivated {
if let url = navigationAction.request.url ,UIApplication.shared.canOpenURL(url) {
// let urlString = try! String(contentsOf: url)
if (url.absoluteString.range(of: "facebook.com") != nil || url.absoluteString.range(of: "twitter.com") != nil){
//UIApplication.shared.open(url)
print("Redirected to browser. No need to open it locally")
decisionHandler(.cancel)
}else{
print("Open it locally")
decisionHandler(.allow)
}
}
You need a on click listener.
You can use WKWebView to display interactive web content in your app. Ideal for displaying HTML markup, styled text content, or complete web pages. After that, you need to handle the Social button you're calling and the data submitted if any...
Responding To WKWebView Events With WKNavigationDelegate
A WKWebView web view has two main delegate protocols and properties:
navigationDelegate of type WKNavigationDelegate, which responds to
navigation events
uiDelegate of type WKUIDelegate, which responds to user
interaction events
Of these two delegate protocols, the WKNavigationDelegate is probably used most frequently. So, let’s hook into some page navigation events! We’ll do so with these delegate functions:
webView(_:didStartProvisionalNavigation:)
webView(_:didCommit:)
webView(_:didFinish:)
webView(_:didFail:withError:)
webView(_:didFailProvisionalNavigation:withError:)
First, let’s adopt the protocol and set the webView delegate. Here’s how:
Add the WKNavigationDelegate protocol to your view controller’s class declaration, like: class WebViewController: UIViewController, WKNavigationDelegate
Set the navigationDelegate property of webView to self, before loading the web request, like: webView?.navigationDelegate = self
Next, implement the five delegate functions described earlier. Set their function bodies to print(#function), so we can see the order in which the functions are called.
Like this:
func webView(_ webView: WKWebView, didStartProvisionalNavigation navigation: WKNavigation!)
{
print(#function)
}

swift force viewController change from within webkit function

I have a viewController showing a webkit view.
If the user browses to a certain type of link, then I want to move from that viewController to a new one, which can parse that specific type of url and display results (rather than moving to a new page)
However, as I understand it, in order to check the url links to see it's of the right kind then I need to use the function
func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: #escaping (WKNavigationActionPolicy) -> Void) {
but this only gives me the ability to write a bit of code to look at the URL link, and return a decision on whether to proceed to it or not, rather than what I want to do which is look at the URL link and then effectively segue to a completely new viewController to parse it.
Any ideas on how I should construct please?
public func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: #escaping (WKNavigationActionPolicy) -> Swift.Void)
{
if(navigationAction.navigationType == .other)
{
if navigationAction.request.url != nil
{
// Put your condition check on url.
// Create your view controller instance from storyboard. Pass the url to it and navigate.
}
decisionHandler(.cancel)
return
}
decisionHandler(.allow)
}

Resources