Can't use URLSession with Swift on Watchkit - swift

I have a problem when trying to fetch some data with swift on apple watch. When i try this code in Swift Playground it works well but when I put it in an WatchOS app it shows me this error :
Error Domain=NSURLErrorDomain Code=-1202 "The certificate for this server is invalid. You might be connecting to a server that is pretending to be “kholle.fr” which could put your confidential information at risk." UserInfo={NSErrorClientCertificateStateKey=0, NSLocalizedRecoverySuggestion=Would you like to connect to the server anyway?, _NSURLErrorFailingURLSessionTaskErrorKey=LocalDataPDTask <8B22FE2A-DFA9-4655-82A5-357F5A732CCD>.<1>, NSErrorFailingURLKey=https://kholle.fr/backend_saved, _NSURLErrorRelatedURLSessionTaskErrorKey=(
Here is the code I use in my WatchOS App
class ViewModel: ObservableObject {
#Published var kholles: [Kholle] = []
func fetch(group: String) {
let url = URL(string: "https://kholle.fr/backend_saved")! //Here is my https server link
let task = URLSession.shared.dataTask(with: url) { data, _,
error in
guard let data = data, error == nil else {
return
}
//Convert to JSON
do {
let kholle = try JSONDecoder().decode([String: [Kholle]].self, from: data)
DispatchQueue.main.async {
print(kholle["B 16"])
}
} catch {
print(error)
}
}
task.resume()
}
}
Thanks in advance for your help

I found out the solution by adding to my node server an Intermediate Certificate.

Related

Error Domain=NSURLErrorDomain Code=-1202 "The certificate for this server is invalid

I am trying to call my api in my home network but for some reason, I get the following error message:
finished with error [-1202] Error Domain=NSURLErrorDomain Code=-1202 "The certificate for this server is invalid. You might be connecting to a server that is pretending to be “192.168.179.185” which could put your confidential information at risk."
I tried some solutions but none of them is fitting my code somehow.
import SwiftUI
import EFQRCode
struct ShowQRCodeView: View {
//#Binding var isLoggedIn : Bool
#Binding var deviceId : String
#Binding var apiKey : String
#Binding var userId : String
#Binding var employeeId : Int
#State private var x = UUID().uuidString
#State var users = [User]()
var body: some View {
VStack(){
Form{
Section("QR-Code"){
if let cgImage = EFQRCode.generate(for: deviceId) {
Image(uiImage: UIImage(cgImage: cgImage)).resizable().frame(width: 150, height: 150)
}
Button("Login"){
Task{
await doHTTPUserCall()
}
}
}
}.frame(height: 180)
}.onAppear {
if (deviceId == "") {
deviceId = x // Could change here
}
}
}
func doHTTPUserCall() async {
var url = "https://192.168.179.185:8090/CC0001/BE/admin/api/v1/employee/deviceid/"
url += String(deviceId)
guard let reqUrl = URL(string: url) else {
print("Invalid URL")
return()
}
var req = URLRequest(url: reqUrl)
req.httpMethod = "GET"
let formatter = DateFormatter()
formatter.dateFormat = "yyyy-MM-dd"
formatter.timeZone = TimeZone(abbreviation: "ETC")
let task = URLSession.shared.dataTask(with: req) { data, response, error in
if let data = data {
do{
let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .formatted(formatter)
users = try decoder.decode(Array<User>.self, from: data)
} catch{
print(error)
}
} else if let error = error {
print("HTTP Request Failed \(error)")
}
if let response = response as? HTTPURLResponse {
print("Response HTTP Status code: \(response.statusCode)")
}
}
task.resume()
}
}
I think it has something to do with a self signed ssl certificate.
Would appreciate any help, thanks
You can't use a self-signed certificate without first setting up the device to trust the certificate that did the signing (i.e., the certificate itself, since it signed itself). So you will need to find a way to open that certificate in iOS so that it can be added to the device's trusted certificate store. You could email it to yourself then tap on the attachment, or put it into iCloud Drive and open it from Drive on the phone. Then got to Settings and search for Trusted Certificates and go there to mark this certificate as trusted.
You might find it easier to just get a real cert for your server, such as a free one using certbot.eff.org

Alamofire error sessionDeinitialized ssl certificate

I'm testing Alamofire with ssl certificate.
using swift and swiftUI I wrote this 2 functions to load the ssl from a bundle and make the request using Alamofire.
func getCertificate() -> [SecCertificate] {
let url = Bundle.main.url(forResource: "ssl", withExtension: "cer")
let localCer = try! Data(contentsOf: url!) as CFData
guard let certificate = SecCertificateCreateWithData(nil, localCer) else {
return []
}
return [certificate]
}
func loginUserIcrew(userName: String, password: String){
let evaluators: [String: ServerTrustEvaluating] = [
linkIcrew: PinnedCertificatesTrustEvaluator(certificates:getCertificate())
]
let manager = ServerTrustManager(evaluators: evaluators)
let session = Session(serverTrustManager: manager)
session.request (linkIcrew,method: .get, encoding: URLEncoding.default)
.response { response in
print(response)
}
}
and I using it in a simple button like this
struct SalaryStart: View {
#ObservedObject var ss = SalaryManager()
var body: some View {
Button {
ss.loginUserIcrew(userName: "user", password: "pass")
} label: {
Text("test")
}
}
}
I'm getting the error : Alamofire.AFError.sessionDeinitialized
any help how to solve tis issue? reading online looks like the session need to keep alive, but I don't understand what does it mean??
thanks for the help
sessionDeinitialized means what it says: your Session was deinitialized while the request was in progress and so it was cancelled. You need to keep the Session alive at least long enough to complete the request. Usually you want to use a single Session for all of your requests, so I suggest keeping it as a singleton.

cannot read data from Json hosted on GitHub

when try to read data from a json on my GitHub space, I get an error
nw_protocol_get_quic_image_block_invoke dlopen libquic failed
Invalid response from the server. Please try again.
am I using wrong url or there is an issue in the way I'm parsing data?
my repo url
https://github.com/stark226/stark226.github.io.git
where there is a simple json file at this url
https://github.com/stark226/stark226.github.io/blob/3b2bebb4a3d85524732c7e7ec302b24f8d3e66ae/testjson.json
in my viewDidload
getDataFromJsonOnGithub(completed: { [weak self] result in
guard let self = self else {return}
switch result {
case .success(let expected):
print(expected)
case .failure(let error):
print(error.rawValue)
}
})
my struct
struct RemoteData: Codable, Hashable {
var tokenDuration: Int
}
my func
func getDataFromJsonOnGithub(completed: #escaping (Result<RemoteData, ListOfErrors>) -> Void) {
let endpoint = "https://github.com/stark226/stark226.github.io/stark226/testjson.json"
guard let url = URL(string: endpoint) else {
completed(.failure(.invalidUsername))
return
}
let task = URLSession.shared.dataTask(with: url) { data, response, error in
if let _ = error {
completed(.failure(.unableToComplete))
return
}
guard let response = response as? HTTPURLResponse, response.statusCode == 200 else {
completed(.failure(.invalidResponse))
return
}
guard let data = data else {
completed(.failure(.invalidData))
return
}
do {
let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase
let expectedRrsult = try decoder.decode(RemoteData.self, from: data)
completed(.success(expectedRrsult))
} catch {
completed(.failure(.invalidData))
}
}
task.resume()
}
enum ListOfErrors: String, Error {
case invalidUsername = "This username created an invalid request. Please try again."
case unableToComplete = "Unable to complete your request. Please check your internet connection"
case invalidResponse = "Invalid response from the server. Please try again."
case invalidData = "The data received from the server was invalid. Please try again."
case unableToFavorite = "There was an error favoriting this user. Please try again."
case alreadyInFavorites = "You've already favorited this user. You must REALLY like them!"
}
You have to access the raw file. The URL you are accessing renders an HTML page. Try the following url (click on "Raw" button in GitHub):
https://raw.githubusercontent.com/stark226/stark226.github.io/3b2bebb4a3d85524732c7e7ec302b24f8d3e66ae/testjson.json

Strange error nw_protocol_get_quic_image_block_invoke dlopen libquic failed

I'm new to swift and iOS in general, please keep that in mind.
I get this error when opening the CFReadStream. It does not matter if I open the read or write streams, the app always fails.
var readStream: Unmanaged<CFReadStream>?
var writeStream: Unmanaged<CFWriteStream>?
let host: CFString = NSString(string: hostIP)
let port: UInt32 = UInt32(self.VNCport)
self.password = password
CFStreamCreatePairWithSocketToHost(kCFAllocatorDefault, host, port, &readStream, &writeStream)
inputStream = readStream!.takeRetainedValue()
outputStream = writeStream!.takeRetainedValue()
if readStream == nil {
print("Erro read")
}
if writeStream == nil {
print("Erro write")
}
inputStream!.delegate = self
outputStream!.delegate = self
inputStream!.schedule(in: RunLoop.main, forMode: RunLoop.Mode.default)
outputStream!.schedule(in: RunLoop.main, forMode: RunLoop.Mode.default)
inputStream!.open()
outputStream!.open()
I made a clean project with just this function and a Button, the result is the same. No quic lib is used in the project.
Can someone help?
I faced the same error in a different context, in XCode 12.0.1 too. It might not be related, but I suspect its an issue with accessing the run loop of the main thread. I was just trying out some introductory code I found online, and faced the same issue, so this is a bug, rather than a problem with your code. Here's how you can get a piece of code that has the same issue:
git clone git#github.com:BestKora/CS193P-Fall-2017-Demo-iOS12.git
cd "CS193P-Fall-2017-Demo-iOS12/Cassini L10"
xed . # this opens XCode (CLI tool stands for XCode editor)
Having said that, by rewriting the code, I was able to prevent this issue. Maybe you can find something amongst the code below to fix your specific issue:
Specifically, instead of using the following (DispatchQueue.global)
private func fetchImage() {
if let url = imageURL {
spinner.startAnimating()
DispatchQueue.global(qos: .userInitiated).async { [weak self] in
let urlContents = try? Data(contentsOf: url)
DispatchQueue.main.async {
if let imageData = urlContents, url == self?.imageURL {
self?.image = UIImage(data: imageData)
}
}
}
}
}
I use URLSession.shared.dataTask, and this error no longer happens:
private func fetchImage() {
print("fetching image")
if let url = imageURL {
let task = URLSession.shared.dataTask(with: url) {(data, response, error) in
guard let data = data else {
return
}
// maybe try dispatch to main
DispatchQueue.main.async {
self.imageView.image = UIImage(data: data)
}
}
task.resume()
}
}
I had same issue in an Widget Target, but solved it by adding "public" to the variables.
Fixed struct is shown below.
struct LastCommitEntry: TimelineEntry {
public let date: Date
public let commit: Commit
}
This is just a Simulator message. It won't appear on a real device, and it doesn't affect the behavior of your app, so ignore it.
I was getting this issue in url session.
Thank you
Restarting my simulator did the trick.
For me, it started working when I encoded the data using String(data: safeData, encoding: .utf8) line:
if let safeData = data {
let dataString = String(data: safeData, encoding: .utf8)
print(dataString!)
}
In my case it was a problem with the model. I was working with Codable Model but it wasn't parsing the data properly. When I used the simulator the error was there but when I used my device it disappeared, neverthelesss, the collection view wasn't showing. When I change my model the error was corrected.
You'll need to adopt that specific delegate you're using in your class.
Like in below example:
class ViewController: UIViewController, UITextFieldDelegate
And don't forget to set your current class as the delegate, like below (for my own case):
IBOutlet weak var searchTextField: UITextField!
searchTextField.delegate = self

How to use a JSON file from an Onine server like turbo360?

I am using a do catch scenario to try a JSONDecoder(), the only >problem is that I keep catching the error, but when I review my code I >can't see the error, maybe I need another set of eyes to help me out >of this one!
I placed my JSON file in a storage folder in turbo360, I've also tried gitHub, but neither is working, I believe.
import UIKit
class ViewController: UIViewController {
final let url = URL(string: "https://storage.turbo360.co/portfolio-website-hxoc6m/actors")
override func viewDidLoad() {
super.viewDidLoad()
downloadJson()
}
func downloadJson() {
guard let downloadURL = url else { return }
URLSession.shared.dataTask(with: downloadURL) { data, urlResponse, error in
guard let data = data, error == nil, urlResponse != nil else {
print("something is wrong")
return
}
print("downloaded")
print(downloadURL)
do
{
let decoder = JSONDecoder()
let actors = try decoder.decode(Actors.self, from: data)
print(actors)
} catch {
print("Something wrong after downloaded")
}
}.resume()
}
}
I supposed to get: JSONDonloadingSwift4.Actors
as confirmation that my JSON file has been accessed and decoded
Your JSON is invalid. You are missing an opening " on the last image URL. Fix that and as long as your Actor definition matches you should be good. jsonlint is very useful for checking JSON structure.