I am using WKWebView to open a url but before that it authenticates the user. It is working fine when we input the correct credentials but in case of wrong credentials, I am unable to find any delegate or function that can detect the failure.
Code:
func webView(_ webView: WKWebView, didReceive challenge:
URLAuthenticationChallenge, completionHandler: #escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
let user = "user"
let password = "password"
let credential = URLCredential(user: user, password: password, persistence: URLCredential.Persistence.forSession)
completionHandler(URLSession.AuthChallengeDisposition.useCredential, credential)
}
I can detect the previousFailureCount from URLAuthenticationChallenge, in case of failed response failureResponse always gives status code: 401. Any better way to detect the failure or success for URLAuthenticationChallenge?
You can get status code from the response. Implement the delegate method
func webView(_ webView: WKWebView, decidePolicyFor navigationResponse: WKNavigationResponse,
decisionHandler: #escaping (WKNavigationResponsePolicy) -> Void) {
if let response = navigationResponse.response as? HTTPURLResponse {
if response.statusCode == 401 {
decisionHandler(.cancel)
} else {
decisionHandler(.allow)
}
}
}
Related
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
I want to open authorised url in WKWebview my application. I have tried all possible solution from stackoverflow and google but none of them working for me.
if let url = myURL {
var request = URLRequest(url: url)
request.addValue("3d66fc991e82415398a8e92d8856da3e", forHTTPHeaderField: "Authorization")
webView.load(request)
}
I have also added this delegate.
public func webView(_ webView: WKWebView, didReceive challenge: URLAuthenticationChallenge, completionHandler: #escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
let creds = URLCredential(user:"user1", password:"1234", persistence: URLCredential.Persistence.permanent)
completionHandler(URLSession.AuthChallengeDisposition.useCredential, creds)
}
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)
}
}
I have created a WKWebView. It loads the url of MSB ie. My school bucks. It loads almost all url for payment. But at one url didFinishLoad is not getting called. I have added all the delegates for the web view.but certainly it is not working. The whole process works fine in the web browser of iPhone.
Below is the code I have added below code for that
let preferences = WKPreferences()
preferences.javaScriptEnabled = true
let configuration = WKWebViewConfiguration()
configuration.preferences = preferences
self.webView = WKWebView(frame: frame, configuration: configuration)
self.view.addSubview(webView)
self.webView.navigationDelegate = self
self.webView.uiDelegate = self
Delegates Methods for the navigation
// MARK: - WKWebView Delegation
extension PaymentWebViewController:WKNavigationDelegate {
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
DILog.print(items: "didFinish")
self.hideLoader()
if let strUrl = webView.url?.absoluteString {
self.readRedirectUrl(stringUrl: strUrl)
}
}
func webView(_ webView: WKWebView, didFail navigation: WKNavigation!, withError error: Error) {
DILog.print(items: "faluere")
self.hideLoader()
}
func webView(_ webView: WKWebView, didStartProvisionalNavigation navigation: WKNavigation!) {
DILog.print(items: "didStatrt")
self.showLoader()
if let strUrl = webView.url?.absoluteString {
DILog.print(items: "URL IS \(strUrl)")
}
}
func webView(_ webView: WKWebView,
didReceive challenge: URLAuthenticationChallenge,
completionHandler: #escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void)
{
if(challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodServerTrust)
{ DILog.print(items: "Auth Channlenge1")
let cred = URLCredential(trust: challenge.protectionSpace.serverTrust!)
completionHandler(.useCredential, cred)
}
else
{ DILog.print(items: "Auth Channlenge2")
completionHandler(.performDefaultHandling, nil)
}
}
func webViewWebContentProcessDidTerminate(_ webView: WKWebView) {
DILog.print(items: "webViewWebContentProcessDidTerminate")
}
func webView(_ webView: WKWebView, didCommit navigation: WKNavigation!) {
DILog.print(items: "didCommit")
}
func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: #escaping (WKNavigationActionPolicy) -> Void) {
DILog.print(items: "decidePolicyFor Action")
decisionHandler(WKNavigationActionPolicy.allow)
}
func webView(_ webView: WKWebView, decidePolicyFor navigationResponse: WKNavigationResponse, decisionHandler: #escaping (WKNavigationResponsePolicy) -> Void) {
DILog.print(items: "decidePolicyFor response ")
decisionHandler(.allow)
}
}
You need to add exception (SecTrustSetExceptions) for that particular url. As there is some conflict with its signing identity and your WKWebView.
I was also facing same issue in my app and successfully solved by using below snippet.
try this:
extension PaymentWebViewController: WKNavigationDelegate {
func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: #escaping (WKNavigationActionPolicy) -> Void) {
decisionHandler(.allow)
}
func webView(_ webView: WKWebView, decidePolicyFor navigationResponse: WKNavigationResponse, decisionHandler: #escaping (WKNavigationResponsePolicy) -> Void) {
decisionHandler(.allow)
}
func webView(_ webView: WKWebView, didReceive challenge: URLAuthenticationChallenge, completionHandler: #escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
let serverTrust = challenge.protectionSpace.serverTrust
let exceptions = SecTrustCopyExceptions(serverTrust!)
SecTrustSetExceptions(serverTrust!, exceptions)
completionHandler(.useCredential, URLCredential(trust: serverTrust!))
}
}
Hope you've already setup this in your info.plist:
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoadsInWebContent</key>
<true/>
</dict>
this question is identical to the following: WKWebView catch HTTP error codes; unfortunately the methods in Obj-C are not applicable to Swift 4, thus the cited WKNavigationResponse.response is no longer of type NSHTTPURLResponse so it doesn't have the http status code.
But the issue is still the same: I need to get the http status code of the answer to detect if the expected page is loaded or not.
Please note that webView(_ webView: WKWebView, didFailProvisionalNavigation navigation: WKNavigation!, withError error: Error) delegate is not called in case of 404 but only in case of network issue (i.e. server offline); the func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) is called instead.
Thanks a lot for your answers.
Using a WKNavigationDelegate on the WKWebView you can get the status code from the response each time one is received.
func webView(_ webView: WKWebView, decidePolicyFor navigationResponse: WKNavigationResponse,
decisionHandler: #escaping (WKNavigationResponsePolicy) -> Void) {
if let response = navigationResponse.response as? HTTPURLResponse {
if response.statusCode == 401 {
// ...
}
}
decisionHandler(.allow)
}
HTTPURLResponse is a subclass of URLResponse. The Swift way of “conditional downcasting” is the conditional cast as?, this can be combined with conditional binding if let:
func webView(_ webView: WKWebView, decidePolicyFor navigationResponse: WKNavigationResponse,
decisionHandler: #escaping (WKNavigationResponsePolicy) -> Void) {
if let response = navigationResponse.response as? HTTPURLResponse {
if response.statusCode == 401 {
// ...
}
}
decisionHandler(.allow)
}