I have a requirement to open the URL in WKWebView and login to the portal. As user logged in successfully after that I have to perform download operation from WKWebView, Everything is working fine but it's opening in external safari browser but as per requirement it should open in WKWebView
Outlet for WKWebView
#IBOutlet var webView: WKWebView!
Function to call URL in WKWebVIew
func loadURLInWebView() {
let url = URL(string: "https://www-qa.yyy.com/content/dash/en/public/login.html")
let urlRequest = URLRequest(url: url!)
if let webView = webView {
webView.load(urlRequest)
}
}
after adding decidePolicyFor delegate it's opening url in safari but it should open in WKWebView. I am not able to find the issue.
public func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: #escaping (WKNavigationActionPolicy) -> Void) {
let url = navigationAction.request.url
guard url != nil else {
print(url!)
decisionHandler(.allow)
return
}
if url!.description.lowercased().starts(with: "http://") ||
url!.description.lowercased().starts(with: "https://") {
decisionHandler(.cancel)
UIApplication.shared.open(url!, options: [:], completionHandler: nil)
} else {
decisionHandler(.allow)
}
}
you are handling guard statement in the wrong way. In guard else, the condition will be called when the URL is nil.
If you do print(URL!) in else your app will crash. moreover when URL is nill, you should call cancel Handler.
public func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: #escaping (WKNavigationActionPolicy) -> Void) {
guard let url = navigationAction.request.url else { // else will be called when url is nil
decisionHandler(.cancel)
return
}
if url.description.lowercased().starts(with: "http://") ||
url.description.lowercased().starts(with: "https://") {
decisionHandler(.allow)
} else {
decisionHandler(.cancel)
UIApplication.shared.open(url, options: [:], completionHandler: nil)
}
}
Related
I have an iOS app that contains a WebView that has a button that opens WhatsApp. The button is not working. What I should do to let WebView open WhatsApp?
If I open website in browser, it opens WhatsApp.
Here is my solution I found after research:
func webView(_ webView: WKWebView,
decidePolicyFor navigationAction: WKNavigationAction,
decisionHandler: #escaping (WKNavigationActionPolicy) -> Void)
{
if let requestURL = navigationAction.request.url?.absoluteString,
!requestURL.contains("https") && !requestURL.contains("http") {
if requestURL == "whatsapp://send",
let urlString = requestURL.addingPercentEncoding(withAllowedCharacters: NSCharacterSet.urlQueryAllowed) {
if let whatsappURL = NSURL(string: urlString) {
if UIApplication.shared.canOpenURL(whatsappURL as URL) {
UIApplication.shared.open(whatsappURL as URL, options: [:], completionHandler: { (Bool) in
})
} else {
// Handle a problem
}
}
}
decisionHandler(.cancel)
} else {
decisionHandler(.allow)
}
}
I have been struggling for a while now. My Webview doesn't download files, doesn't matter what kind of file and I don't get anything in the console.
Here is my code to handle the download
var filePathDestination: URL?
weak var downloadDelegate: WebDownloadable?
func generateTempFile(with suggestedFileName: String?) -> URL {
let temporaryDirectoryFolder = URL(fileURLWithPath: NSTemporaryDirectory(), isDirectory: true)
return temporaryDirectoryFolder.appendingPathComponent(suggestedFileName ?? ProcessInfo().globallyUniqueString)
}
func downloadFileOldWay(fileURL: URL, optionSessionCookies: [HTTPCookie]?) {
// Your classic URL Session Data Task
}
func cleanUp() {
filePathDestination = nil
}
func downloadDidFinish(_ download: WKDownload) {
guard let filePathDestination = filePathDestination else {
return
}
downloadDelegate?.downloadDidFinish(fileResultPath: filePathDestination)
cleanUp()
}
func download(_ download: WKDownload,
didFailWithError error: Error,
resumeData: Data?) {
downloadDelegate?.downloadDidFail(error: error, resumeData: resumeData)
}
func download(_ download: WKDownload, decideDestinationUsing
response: URLResponse, suggestedFilename: String,
completionHandler: #escaping (URL?) -> Void) {
filePathDestination = generateTempFile(with: suggestedFilename)
if(filePathDestination != nil){
print(filePathDestination!)
}
completionHandler(filePathDestination)
}
func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, preferences: WKWebpagePreferences, decisionHandler: #escaping (WKNavigationActionPolicy, WKWebpagePreferences) -> Void) {
if navigationAction.shouldPerformDownload {
decisionHandler(.download, preferences)
} else {
decisionHandler(.allow, preferences)
}
}
func webView(_ webView: WKWebView, decidePolicyFor navigationResponse: WKNavigationResponse, decisionHandler: #escaping (WKNavigationResponsePolicy) -> Void) {
if navigationResponse.canShowMIMEType {
decisionHandler(.allow)
} else {
decisionHandler(.download)
}
}
func webView(_ webView: WKWebView, navigationAction: WKNavigationAction, didBecome download: WKDownload) {
download.delegate = downloadDelegate
}
func webView(_ webView: WKWebView, navigationResponse: WKNavigationResponse, didBecome download: WKDownload) {
download.delegate = downloadDelegate
}
When I print out navigationAction.request.url I get the right URL, but no download. Any help would be appreciated
This is my situation:
I have a view controller within a WKWebView. This webview starts with a page "A". In this page there are some links (href) and I want that for some of these links must open in the external browser.
For this reason I set the WKWebView delegate:
func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: #escaping (WKNavigationActionPolicy) -> Void) {
if let url = webView.url?.absoluteString
{
if(self.isExternalURL(url))
{
let urlT = URL(string: url)!
decisionHandler(.cancel)
UIApplication.shared.open(urlT, options: [:], completionHandler: nil)
}
else
{
decisionHandler(.allow)
}
}
else
{
decisionHandler(.allow)
}
}
private func isExternalURL(url:String) -> Bool
{
//......check link
}
My problem is that if I select an external link the external browser opens, but the webview does not remain on page A, but it also loads the external link while I would like it to remain on page A.
I dont know why
You should use navigationAction.request.url instead of webView.url
webView.url - Already loaded url
navigationAction.request.url - New url to load
Change
func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: #escaping (WKNavigationActionPolicy) -> Void) {
if let url = navigationAction.request.url?.absoluteString
{
if self.isExternalURL(url)
{
decisionHandler(.cancel)
UIApplication.shared.open(navigationAction.request.url, options: [:], completionHandler: nil)
}
else
{
decisionHandler(.allow)
}
}
else
{
decisionHandler(.allow)
}
}
You can try to use webView(webView: WKWebView, didStartProvisionalNavigation navigation: WKNavigation!)
func webView(webView: WKWebView, didStartProvisionalNavigation navigation: WKNavigation!) {
if let url = navigationAction.request.url?.absoluteString
{
if self.isExternalURL(url)
{
webView.stopLoading()
UIApplication.shared.open(navigationAction.request.url, options: [:], completionHandler: nil)
}
}
}
I am trying to add http header to URLRequest, which I am loading in WKWebView.
I tried this code:
var urlRequest = URLRequest(url: URL(string: "url")!)
urlRequest.addValue("value", forHTTPHeaderField: "key")
self.viewerWebKit.load(urlRequest)
and also this:
var urlRequest = URLRequest(url: URL(string: "url")!)
urlRequest.setValue("value", forHTTPHeaderField: "key")
self.viewerWebKit.load(urlRequest)
But when I am printing http headers with this code:
func webView(_ webView: WKWebView, decidePolicyFor navigationResponse: WKNavigationResponse, decisionHandler: #escaping (WKNavigationResponsePolicy) -> Void) {
let headers = (navigationResponse.response as! HTTPURLResponse).allHeaderFields
for (key,value) in headers {
print("key \(key) value \(value)")
}
decisionHandler(.allow)
}
nothing is added or set. What am I doing wrong?
optional func webView(_ webView: WKWebView,
decidePolicyFor navigationAction: WKNavigationAction,
decisionHandler: #escaping (WKNavigationActionPolicy) -> Void)
Use this delegate function. You can find headers of request in navigationAction.request.
URLRequest immutable so if you want to add header in that request you need to make it mutable.use this extension to add header.
extension URLRequest {
internal mutating func addHeaders() {
let mutableRequest = ((self as NSURLRequest).mutableCopy() as? NSMutableURLRequest)!
mutableRequest.setValue("your header", forHTTPHeaderField: "key")
self = mutableRequest as URLRequest
}
}
}
Use where you want to set Header:
request.addHeaders()
Having some trouble redirecting a user to a link from a WKWebView.
User is essentially meant to be authenticating on a website using WKWebView, the website checks the authentication which in turn redirects the user back to our app.
My initial thought is that there is some sort of restriction to allow the user to exit the app during the redirecting process. Which is why I implemented WKNavigationDelegate and saw that when we try authenticating the code below didReceive challenge runs through the second if case - which I only assume that its a good thing. Though the app does not get redirected.
Below is the code I have.
import UIKit
import WebKit
class WebViewViewController: UIViewController, WKUIDelegate, WKNavigationDelegate {
var webView: WKWebView!
override func viewDidLoad() {
super.viewDidLoad()
navigationController?.navigationBar.isHidden = false
tabBarController?.tabBar.isHidden = true
webView.navigationDelegate = self
if let url = URL(string: "SomeUrl") {
let request = URLRequest(url: url)
webView.load(request)
}
}
override func loadView() {
let webConfiguration = WKWebViewConfiguration()
webView = WKWebView(frame: .zero, configuration: webConfiguration)
webView.uiDelegate = self
view = webView
}
override func viewWillAppear(_ animated: Bool) {
self.navigationController?.navigationBar.isHidden = false
}
override func viewWillDisappear(_ animated: Bool) {
self.tabBarController?.tabBar.isHidden = false
}
func webViewDidFinishLoad(_ webView: UIWebView) {
if let URL = webView.request?.url {
OAuthHelper.oAuthManager.processOAuthStep1Response(url: URL)
}
}
func webView(_ webView: WKWebView, didStartProvisionalNavigation navigation: WKNavigation!) {
}
func webView(_ webView: WKWebView, didReceiveServerRedirectForProvisionalNavigation navigation: WKNavigation!) {
}
func webView(_ webView: WKWebView, didReceive challenge: URLAuthenticationChallenge, completionHandler: #escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
if challenge.previousFailureCount > 0 {
completionHandler(Foundation.URLSession.AuthChallengeDisposition.cancelAuthenticationChallenge, nil)
} else if let serverTrust = challenge.protectionSpace.serverTrust {
completionHandler(Foundation.URLSession.AuthChallengeDisposition.useCredential, URLCredential(trust: serverTrust))
} else {
print("unknown state. error: \(challenge.error)")
// do something w/ completionHandler here
}
}
func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: #escaping (WKNavigationActionPolicy) -> Void) {
if (navigationAction.navigationType == .linkActivated){
decisionHandler(.cancel)
} else {
decisionHandler(.allow)
}
}
}
I did not fully understand the problem. If the question is that if you want the user to redirect from Webview to Native App, then you do have different options. I will be providing the options. Let me know if this is you are looking at.
Use WKURLSchemeHandler to handle the custom URLs. Read my article about this. https://medium.com/#kumarreddy_b/custom-scheme-handling-in-uiwebview-wkwebview-bbeb2f3f6cc1. https://github.com/BKRApps/KRWebView
you will be getting the urls in func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: #escaping (WKNavigationActionPolicy) -> Void), here you can intercept the URL and then use your URL scheme to get into the native app. Use OpenUrl to do this. But this is deprecated.