URLSession delegate is not working on swift 4.2 - ios

This code is working fine on Swift version 3, I'm not able to make it work on Swift 4
func rest() {
let path = "https://localhost:8443/someservice"
let request = NSMutableURLRequest(URL: NSURL(string: path)!)
let configuration = NSURLSessionConfiguration.defaultSessionConfiguration()
let session = NSURLSession(configuration: configuration, delegate: self, delegateQueue:NSOperationQueue.mainQueue())
let task = session.dataTaskWithRequest(request, completionHandler: {data, response, error -> Void in
let json:JSON = JSON(data: data!)
if let c = json["content"].string {
print(c)
}
})
task.resume()
}
func URLSession(session: NSURLSession, task: NSURLSessionTask, didReceiveChallenge challenge: NSURLAuthenticationChallenge, completionHandler: (NSURLSessionAuthChallengeDisposition, NSURLCredential?) -> Void) {
completionHandler(NSURLSessionAuthChallengeDisposition.UseCredential, NSURLCredential(forTrust: challenge.protectionSpace.serverTrust!))
}

You may need latest syntax
func urlSession(_ session: URLSession,
task: URLSessionTask,
didReceive challenge: URLAuthenticationChallenge,
completionHandler: #escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void)

Your Delegate method is right for below swift 4.0 version but it's wrong for swift 4.0 and higher.
Here is working code, You need to use like this.
class ViewController: UIViewController,URLSessionDelegate {
func urlSession(_ session: URLSession, didReceive challenge: URLAuthenticationChallenge, completionHandler: #escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
completionHandler(URLSession.AuthChallengeDisposition.useCredential, URLCredential(trust: challenge.protectionSpace.serverTrust!))
}
}

Related

How to implement URLSessionDelegate to allow self signed certificate? (iOS/Swift)

I'm trying to use SocketIO to connect to a server running on my workstation from an iOS/Swift app. The certificate I'm using on the server is self-signed and I'm using the following code to connect:
import UIKit
import SocketIO
class ViewController: UIViewController, URLSessionDelegate {
let socketManager = SocketManager(socketURL: URL(string:"https://my_server_url")!,
config: [SocketIOClientOption.log(true),
SocketIOClientOption.forcePolling(true),
SocketIOClientOption.selfSigned(true),
SocketIOClientOption.sessionDelegate(self)])
func URLSession(_ session: URLSession,
task: URLSessionTask,
didReceive challenge: URLAuthenticationChallenge,
completionHandler: (URLSession.AuthChallengeDisposition, URLCredential?)
-> Void) {
print("didReceive challenge")
completionHandler(.useCredential, URLCredential(trust: challenge.protectionSpace.serverTrust!))
}
Unfortunately I get the following error: Argument type '(ViewController) -> () -> (ViewController)' does not conform to expected type 'URLSessionDelegate' where I set the sessionDelegate to self.
I'm not sure why that is the case since all funcs in URLSessionDelegate are optional and I thought that my implementation of URLSession conformed to the protocol. I apologise if I'm doing something dumb but I'm new to iOS and Swift and I've been looking for an answer for hours with no success!
func urlSession(_ session: URLSession, task: URLSessionTask, didReceive challenge: URLAuthenticationChallenge, completionHandler: #escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
// Pass test server with self signed certificate
if challenge.protectionSpace.host == "self-signed-certificate.server.com" {
completionHandler(.useCredential, URLCredential(trust: challenge.protectionSpace.serverTrust!))
} else {
completionHandler(.performDefaultHandling, nil)
}
}

ios download file with data chunks delegate

I want to download a file from a certain url .
what I need is the data delegate ( the delegate which gives me the downloaded data) .
I implemented the :
func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive data: Data) {
delegate but it doesn't get called .
my code is :
func download(url: URL)
{
let sessionConfig = URLSessionConfiguration.default
let session = URLSession(configuration: sessionConfig, delegate: self, delegateQueue: nil)
let task = session.downloadTask(with: url)
task.resume()
}
func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive data: Data) {
print("apending ")
self.dataaa.append(data)
}
func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive response: URLResponse, completionHandler: #escaping (URLSession.ResponseDisposition) -> Void) {
print("here")
}
the two delegate functions don't get called !
You're using the delegate methods for a data task, but you're creating a download task. Those two task types work differently and use completely different delegate methods.

URLSession in Swift 3 - URLAuthenticationChallenge

Below is the snippet for making request.
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.setValue("application/json", forHTTPHeaderField: "Accept")
let configurationId = String(format: "NetworkManager%d", UInt16(arc4random_uniform(UInt32(UINT16_MAX))))
let configuration = URLSessionConfiguration.background(withIdentifier: configurationId)
let session = Foundation.URLSession(configuration: configuration, delegate: self, delegateQueue: OperationQueue.current)
let task = session.downloadTask(with: request)
task.resume()
While making this request, the authentication challenge methods as described below are not getting called.
#nonobjc func urlSession(_ session: Foundation.URLSession, didReceive challenge: URLAuthenticationChallenge, completionHandler: (Foundation.URLSession.AuthChallengeDisposition, URLCredential?) -> Swift.Void)
#nonobjc func urlSession(_ session: Foundation.URLSession, task: URLSessionTask, didReceive challenge: URLAuthenticationChallenge, completionHandler: (Foundation.URLSession.AuthChallengeDisposition, URLCredential?) -> Swift.Void)
Try using the following header slightly different from the ones you listed in your question.
open func urlSession(_ session: URLSession, task: URLSessionTask, didReceive challenge: URLAuthenticationChallenge, completionHandler: #escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
//handle challenge here.
}

Swift 3 URLSession with URLCredential not working

I am doing a URLSession, but the URL requires credentials.
I have this whole method here that is trying to do a URLSession with URLCredentials:
func loginUser(_ username: String, password: String, completion: #escaping (_ result: Bool) -> Void)
{
//Create request URL as String
let requestString = String(format:"%#", webservice) as String
//Covert URL request string to URL
guard let url = URL(string: requestString) else {
print("Error: cannot create URL")
return
}
//Convert URL to URLRequest
let urlRequest = URLRequest(url: url)
print(urlRequest)
//Add the username and password to URLCredential
credential = URLCredential(user:username, password:password, persistence: .forSession)
//Setup the URLSessionConfiguration
let config = URLSessionConfiguration.default
//Setup the URLSession
let session = URLSession(configuration: config, delegate: self, delegateQueue: nil)
//Prepare the task to get data.
let task = session.dataTask(with: urlRequest, completionHandler: { (data, response, error) in
DispatchQueue.main.async(execute: {
if(error == nil)
{
completion(true)
}
else
{
completion(false)
}
})
})
//Run the task to get data.
task.resume()
}
and here are my URLSessionDelegate Methods:
func urlSession(_ session: URLSession, didReceive challenge: URLAuthenticationChallenge, completionHandler: #escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
if challenge.previousFailureCount > 0
{
completionHandler(Foundation.URLSession.AuthChallengeDisposition.cancelAuthenticationChallenge, nil)
}
else
{
completionHandler(Foundation.URLSession.AuthChallengeDisposition.useCredential, URLCredential(trust:challenge.protectionSpace.serverTrust!))
}
}
/**
Requests credentials from the delegate in response to an authentication request from the remote server.
*/
func urlSession(_ session: URLSession, task: URLSessionTask, didReceive challenge: URLAuthenticationChallenge, completionHandler: #escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
completionHandler(Foundation.URLSession.AuthChallengeDisposition.useCredential,credential)
}
I notice when I debug this in this delegate method:
func urlSession(_ session: URLSession, didReceive challenge: URLAuthenticationChallenge, completionHandler: #escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
if challenge.previousFailureCount > 0
{
completionHandler(Foundation.URLSession.AuthChallengeDisposition.cancelAuthenticationChallenge, nil)
}
else
{
completionHandler(Foundation.URLSession.AuthChallengeDisposition.useCredential, URLCredential(trust:challenge.protectionSpace.serverTrust!))
}
}
That this method gets called twice and when it hits this line for the second time:
completionHandler(Foundation.URLSession.AuthChallengeDisposition.useCredential, URLCredential(trust:challenge.protectionSpace.serverTrust!))
I get this error:
fatal error: unexpectedly found nil while unwrapping an Optional value
and then my app crashes! How do I fix this error?
the crash is due to challenge.protectionSpace.serverTrust being nil when you attempt to force unwrap it.
you should unwrap serverTrust and handle it being nil. my guess is that when serverTrust is nil challenge.error has a value.
func urlSession(_ session: URLSession, 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
}
}
Here is syntax as per swift 3.
Just verify firstly in which part of the delegate method it entered
open func urlSession(_ session: URLSession, didReceive challenge: URLAuthenticationChallenge, completionHandler: #escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Swift.Void){
var disposition: URLSession.AuthChallengeDisposition = URLSession.AuthChallengeDisposition.performDefaultHandling
var credential:URLCredential?
if challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodServerTrust {
credential = URLCredential(trust: challenge.protectionSpace.serverTrust!)
if (credential != nil) {
disposition = URLSession.AuthChallengeDisposition.useCredential
}
else{
disposition = URLSession.AuthChallengeDisposition.performDefaultHandling
}
}
else{
disposition = URLSession.AuthChallengeDisposition.cancelAuthenticationChallenge
}
if (completionHandler != nil) {
completionHandler(disposition, credential);
}
}
Here is a slightly refactored from the above answers, a delegate class checks the number of failures, uses default unless the challenge is of type server trust it then calls the completion with trust credential:
class AuthSessionDelegate: NSObject, URLSessionDelegate {
func urlSession(_ session: URLSession,
didReceive challenge: URLAuthenticationChallenge,
completionHandler: #escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
let authMethod = challenge.protectionSpace.authenticationMethod
guard challenge.previousFailureCount < 1, authMethod == NSURLAuthenticationMethodServerTrust,
let trust = challenge.protectionSpace.serverTrust else {
completionHandler(.performDefaultHandling, nil)
return
}
completionHandler(.useCredential, URLCredential(trust: trust))
}
}

Error with URLsession delegate function

I am trying to make a ssl connection with URLSession delegate and this is the error message I get:
Objective-C method 'URLSession:didReceiveChallenge:completionHandler:' provided by method 'URLSession(:didReceiveChallenge:completionHandler:)' conflicts with optional requirement method 'URLSession(:didReceiveChallenge:completionHandler:)' in protocol 'NSURLSessionDelegate'
func URLSession(session: NSURLSession,
didReceiveChallenge challenge:
NSURLAuthenticationChallenge,
completionHandler:
(NSURLSessionAuthChallengeDisposition,
NSURLCredential!) -> Void) {
let serverTrust: SecTrustRef = challenge.protectionSpace.serverTrust!
let serverCert: SecCertificateRef = SecTrustGetCertificateAtIndex(serverTrust, 0).takeUnretainedValue()
let serverKey: NSData = SecCertificateCopyData(serverCert).takeRetainedValue()
let bundle: NSBundle = NSBundle.mainBundle()
let mainbun = bundle.pathForResource("ca", ofType: "der")
let key: NSData = NSData(contentsOfFile: mainbun!)!
// let turntocert: SecCertificateRef =
// SecCertificateCreateWithData(kCFAllocatorDefault, key).takeRetainedValue()
if serverKey == key {
let credential = NSURLCredential(forTrust: challenge.protectionSpace.serverTrust!)
challenge.sender!.useCredential(credential, forAuthenticationChallenge: challenge)
completionHandler(NSURLSessionAuthChallengeDisposition.UseCredential,credential)
}
else{
challenge.sender!.cancelAuthenticationChallenge(challenge)
completionHandler(NSURLSessionAuthChallengeDisposition.CancelAuthenticationChallenge, nil)
}
}
func URLSession(session: NSURLSession, task: NSURLSessionTask, willPerformHTTPRedirection response: NSHTTPURLResponse, newRequest request: NSURLRequest, completionHandler: (NSURLRequest!) -> Void) {
var newRequest : NSURLRequest? = request
print(newRequest?.description);
completionHandler(newRequest)
}
Do you use Swift 2 now? I started getting this error when updating to Swift 2.
I could solve this by changing it to:
func URLSession(session: NSURLSession,
task: NSURLSessionTask,
didReceiveChallenge challenge: NSURLAuthenticationChallenge,
completionHandler: (NSURLSessionAuthChallengeDisposition, NSURLCredential?)
-> Void) {
// your code
}
The correct method signature is:
func URLSession(session: NSURLSession,
didReceiveChallenge challenge: NSURLAuthenticationChallenge,
completionHandler: (NSURLSessionAuthChallengeDisposition,
NSURLCredential?) -> Void)
where the NSURLCredential parameter MUST be optional (with the question mark (?) after the optional value).
See apple documentation.

Resources