So I'm trying to get URLSession URLError.code .notConnectedToInternet but all I'm getting is Code(rawValue: -1020) when using URLSession when disconnecting from the internet.
URLSession.shared.dataTask(with: url) { data, _, error in
if let error = error {
print("error.code \((error as! URLError).code)")
//prints - error.code Code(rawValue: -1020)
if (error as! URLError).code == .notConnectedToInternet {
print("no internet")
//doesn't print
return
}
}
error code -1020 means dataNotAllowed. It means the connection failed because data use isn’t currently allowed on the device.
What you are trying to catch notConnectedToInternet error code -1009 means connection failed because the device isn’t connected to the internet.
So notConnectedToInternet is not same as dataNotAllowed. In this case check your device settings.
Related
I'm trying to start the vpn provider from a container application
After I successfully activated the extension, and started the process by sending xpc request to the network extension, I've tried to load the provider and start getting notifications about handleNewFlow
I use the following callback to signal process has started, in order to start the configuration phase.
extension NetworkExtensionManager: OSSystemExtensionRequestDelegate {
...
func request(_ request: OSSystemExtensionRequest,
didFinishWithResult result: OSSystemExtensionRequest.Result) {
...
After loadAllPreferences, I've set the manager from which I'd like to load the provider:
NEAppProxyProviderManager.loadAllFromPreferences { [self] (managers, error) in
assert(Thread.isMainThread)
if let error = error {
print(error.localizedDescription)
} else {
let manager = managers?.first ?? NEAppProxyProviderManager()
let proto = (manager.protocolConfiguration as? NETunnelProviderProtocol) ?? NETunnelProviderProtocol()
proto.serverAddress = "myHost"
proto.providerBundleIdentifier = "myExtensionBundle"
proto.providerConfiguration = ["key": "val"]
manager.localizedDescription = "myApp"
manager.protocolConfiguration = proto
manager.isEnabled = true
Then I extract the connection out of the manager and use it to start the tunnel provider (hopefully this operation will create a new item under System Preferences --> Network)
let session = manager.connection as! NETunnelProviderSession
do {
os_log(" manager.connection status: \(session.status.rawValue)")
try session.startVPNTunnel(options: nil)
}
catch {
os_log("failed to initProviderManager app proxy provider, \(error.localizedDescription)")
print(error)
}
However, I've got the following error message from the exception thrown out of this line session.startVPNTunnel :
failed to initProviderManager app proxy provider, The operation couldn’t be completed. (NEVPNErrorDomain error 1.)
Looking for the error name I found this NEVPNErrorConfigurationInvalid
Perhaps you can help me figure out where I go wrong in my attempt to start the tunnel provider ?
Thanks !
I would like to implement a way to check if the network is weak or disconnected during network calls I perform using Alamofire 4.9 - the following is what I am currently attempting to do, but I have noticed that if the network it off it never jumps to this line:
URLError.Code.notConnectedToInternet
why does this occur, is there a better way of attempting this?
//Fetch new data
guard let url = URL(string: "test.com")
else { return }
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.httpBody = "value1=test1&value2=test2".data(using: .utf8)
URLSession.shared.dataTask(with: request) { [self] data, _, error in
guard let data = data else { return }
do {
let decoder = JSONDecoder()
let res = try decoder.decode([Structure].self, from: data)
}
}
catch {
if let err = error as? URLError, err.code == URLError.Code.notConnectedToInternet {
// No internet
} else {
print(error)
}
}
}.resume()
There are a variety of errors that can be produced by poor or entirely broken connectivity. .notConnectedToInternet is simply one of them. There is no single, exhaustive list provided by Apple of which errors may be returned when there are connectivity issues, so you'll want to experiment and see what you can produce. Additionally, there are a variety of errors which you can probably throw into a "network connectivity" bucket, such as .dnsLookupFailed or .cannotConnectToHost. Ultimately it may not be worth it to differentiate different types of URLErrors.
By the way, you should use Alamofire 5 if you can, as Alamofire 4 is no longer supported.
I'm currently working on an iOS-App and i need to connect to another device. The NWConnection is successfully established using TCP and I can receive one (and only one) message from the remote device and get an error immediately. The connection gets cancelled (caused by the error I guess).
The console log shows:
Hello World.
[connection] nw_flow_add_read_request [C1 <ip and port of remote device> ready channel-flow (satisfied (Path is satisfied), viable, interface: en0, ipv4, ipv6, dns)] already delivered final read, cannot accept read requests
[connection] nw_read_request_report [C1] Receive failed with error "No message available on STREAM"
error
My code looks like this:
private func setupReceive() {
NWCon!.receive(minimumIncompleteLength: 1, maximumLength: 65536) { (data, _, isComplete, error) in
if let data = data, !data.isEmpty {
let message = String(data: data, encoding: .utf8)
if(message!.contains("Hello World")) {
print("Hello World.")
} else if(message == "Closing connection!") {
//...
}
}
if error != nil { print("error: \(error)") }
else { self.setupReceive() }
}
}
The remote device only sends one package and to receive further packages, the method gets called again.
EDIT: I printed the error message and got
error: Optional(POSIXErrorCode: No message available on STREAM)
which seems to refer to POSIXError ENODATA.
Im tring to make a network call and instead of using callback I try to use delegate instead.using Result type where .Sucsess is T: Decodable and .failure is Error. passing my model in the .Sucsess is working but when trying to pass an error I get a compile error "Generic parameter 'T' could not be inferred" what am I missing ?
protocol NetworkServiceDelegate: class {
func decodableResponce<T: Decodable>(_ result: Result<T, NetworkError>)
}
let dataTask:URLSessionTask = session.dataTask(with: url) { (dataOrNil, responceOrNil, errOrNil) in
if let error = errOrNil {
switch error {
case URLError.networkConnectionLost,URLError.notConnectedToInternet:
print("no network connection")
self.delegate?.decodableResponce(Result.failure(.networkConnectionLost))
case URLError.cannotFindHost, URLError.notConnectedToInternet:
print("cant find the host, could be to busy, try again in a little while")
case URLError.cancelled:
// if cancelled with the cancelled method the complition is still called
print("dont bother the user, we're doing what they want")
default:
print("error = \(error.localizedDescription)")
}
return
}
guard let httpResponce:HTTPURLResponse = responceOrNil as? HTTPURLResponse
else{
print("not an http responce")
return
}
guard let dataResponse = dataOrNil,
errOrNil == nil else {
print(errOrNil?.localizedDescription ?? "Response Error")
return }
do{
//here dataResponse received from a network request
let decoder = JSONDecoder()
let modelArray = try decoder.decode([Movie].self, from:
dataResponse) //Decode JSON Response Data
DispatchQueue.main.async {
self.delegate?.decodableResponce(Result.success(modelArray))
}
} catch let parsingError {
print("Error", parsingError)
}
print("http status = \(httpResponce.statusCode)")
print("completed")
}
this line generates the error, it dosnt metter if I pass my enum that cumfirms to Error or trying to pass the error from the dataTask
self.delegate?.decodableResponce(Result.failure(.networkConnectionLost))
Well, you have two problems, having to do with the question "what type is this?" Swift is very strict about types, so you need to get clear about that.
.networkConnectionLost is not an Error. It is an error code. You need to pass an Error object to a Result when you want to package up the error. For example, URLError(URLError.networkConnectionLost) is an Error.
The phrase Result<T, NetworkError> makes no sense. Result is already a generic. Your job is to resolve the generic that it already is. You do that by specifying the type.
So for example, you might declare:
func decodableResponce(_ result: Result<Decodable, Error>)
It is then possible to say (as tests):
decodableResponce(.failure(URLError(URLError.networkConnectionLost)))
or (assuming Movie is Decodable):
decodableResponce(.success([Movie()]))
That proves we have our types right, and you can proceed to build up your actual code around that example code.
I'm working on a subscription IAP. I set all purchases up, their details come back well, I can do the purchases in sandbox and get all the messages alright. The problem I have now is checking the receipt. I always get a URL returned alright, but when I try to read it I keep getting error that the file does not exist. So I try and refresh with SKReceiptRefreshRequest. Try again, still same.
I have uninstalled app on simulator and two real devices, try again from new install and same problem. One thing I realised, one of the real devices displays the password prompt request with [Sandbox] mention. However after two prompts (including accepting password), instead of purchase completed I get a "user/password don't match" message. On simulator when prompted for itunes account and password it all goes through but the actual purchase confirmation never comes (I waited 4 minutes, stable internet connection).
This is the validation process (I have changed it quite a few times, from different tutorials and other people's problems)
let receiptURL = Bundle.main.appStoreReceiptURL
func receiptValidation() {
print("1")
print("2", receiptURL)
do {
print("3")
let receiptData = try Data(contentsOf: receiptURL!, options: .alwaysMapped)
print(receiptData)
let receiptString = receiptData.base64EncodedString(options: [])
let dict = ["receipt-data" : receiptString, "password" : "\(password)"] as [String : Any]
do {
print("4")
let jsonData = try JSONSerialization.data(withJSONObject: dict, options: .prettyPrinted)
if let sandboxURL = Foundation.URL(string:"https://sandbox.itunes.apple.com/verifyReceipt") {
print("5")
var request = URLRequest(url: sandboxURL)
request.httpMethod = "POST"
request.httpBody = jsonData
let session = URLSession(configuration: URLSessionConfiguration.default)
let task = session.dataTask(with: request) { data, response, error in
print("6")
if let receivedData = data,
let httpResponse = response as? HTTPURLResponse,
error == nil,
httpResponse.statusCode == 200 {
print("7")
do {
print("8")
if let jsonResponse = try JSONSerialization.jsonObject(with: receivedData, options: JSONSerialization.ReadingOptions.mutableContainers) as? Dictionary<String, AnyObject> {
print(jsonResponse, jsonResponse.count)
// parse and verify the required informatin in the jsonResponse
} else { print("Failed to cast serialized JSON to Dictionary<String, AnyObject>") }
}
catch { print("Couldn't serialize JSON with error: " + error.localizedDescription) }
}
}
print("51")
task.resume()
} else { print("Couldn't convert string into URL. Check for special characters.") }
}
catch { print("Couldn't create JSON with error: " + error.localizedDescription) }
}
catch {
let appReceiptRefreshRequest = SKReceiptRefreshRequest(receiptProperties: nil)
appReceiptRefreshRequest.delegate = self
appReceiptRefreshRequest.start()
print("Couldn't read receipt data with error: " + error.localizedDescription) }
}
func requestDidFinish(_ request: SKRequest) {
print("???")
do {
let receipt = try Data(contentsOf: receiptURL!) //force unwrap is safe here, control can't land here if receiptURL is nil
print(receipt)
} catch {
print("WTF NO RECEIPT")
// still no receipt, possible but unlikely to occur since this is the "success" delegate method
}
}
And this is the Debugging output from running the app. receiptURL varies between simulator/real device, but other then that everything remains the same.
1
2 Optional(file:///Users/apple/Library/Developer/CoreSimulator/Devices/47EA3293-9B13-4808-BD0B-13D884D14BFE/data/Containers/Data/Application/2F1B7E4E-C523-4270-BF46-6D77F7A2220C/StoreKit/receipt)
3
Couldn't read receipt data with error: The file “receipt” couldn’t be opened because there is no such file.
???
WTF NO RECEIPT
???
WTF NO RECEIPT
Why can't I get the receipt created, or found? Is it a device problem, a bug or am I oblivious to something?
The whole IAP process works asynchronously due to which you will not receive the receipt data unless the whole process has been completed successfully. I can't see the whole code based on what you have pasted in your question above but if you are trying to access the receipt data immediately on the action of a button or something similar, you will not get it.
The correct way to access receipt data is to try accessing the receipt based on success completion handler callback of your IAP request. Once you submit the IAP request there is a server side process which takes care of processing the IAP and then a callback handler from IAP SKPaymentTransactionObserver class is triggered. Using the notification handler from this class you can send the update to your ViewController to check for receipt data.
While further researching, I have found the following article, which solved the problem
article
Important: If you mistakenly use a sandbox tester account to log in to a production environment on your test device instead of your test environment, the sandbox account becomes invalid and can’t be used again. If this happens, create a new sandbox tester account with a new email address.