Swift: NSURL Session not working with watchOS - ios

I'am using a NSURL Session to get the HTML code of a specific website. The following code works perfectly fine with iOS (in ViewController.swift) but it always fails in watchOS (in InterfaceController.swift). The code always print the else statement: print("apple watch: error with loading nsurlsession").
Could anybody explain me (why it fails and) how I could change this? I'm grateful for every response!
(I'm using swift 4.0 with iOS 11 and watchOS 4.0 - tested in simulator and on iPhone 7 with paired Apple Watch series 2)
Code:
func authorizeBase() {
let loginString = NSString(format: "%#:%#", username, password)
let loginData: NSData = loginString.data(using: String.Encoding.utf8.rawValue)! as NSData
let base64LoginString = loginData.base64EncodedString(options: [])
let url: NSURL = NSURL(string: urlPath)!
let request: NSMutableURLRequest = NSMutableURLRequest(url: url as URL)
request.setValue("Basic \(base64LoginString)", forHTTPHeaderField: "Authorization")
request.httpMethod = "GET"
let config = URLSessionConfiguration.default
config.requestCachePolicy = .reloadIgnoringLocalCacheData //deactivate cache
config.urlCache = nil
let authString = "Basic \(base64LoginString)"
config.httpAdditionalHeaders = ["Authorization" : authString]
let session = URLSession(configuration: config)
session.dataTask(with: url as URL) {
( data, response, error) in
if (response as? HTTPURLResponse) != nil {
_ = NSString(data: data!, encoding: String.Encoding.utf8.rawValue)
let contents = String(data: data!, encoding: .ascii)
print("apple watch: Content:", contents!)
self.parseHTMLOverview(content: contents!)
self.updateTable() //!!!
}
else {
print("apple watch: error with loading nsurlsession")
}
}.resume()
}

Thank's a lot for your hint Srstka!
After hours of thinking I figured it out. I just forgot to add "Allow Arbitrary Loads" to the Info.plist in the WatchKit Extension.

Related

Spotify API Authorization Error (Swift)

I've made a little App in Swift where a user can search the Spotify database for songs. I am using the Web API Console > Search for an Item. My problem is the new OAuth system where you have to sign-in and all that stuff. My authorization is ok, but when I'm trying to get an access token with the following code, it's returning me the following error: {"error":"server_error","error_description":"Unexpected status: 400"}. My code is:
let keys = "<MY_APPLICATION_KEYS>"
let url = NSURL(string: "https://accounts.spotify.com/api/token")
let session = URLSession.shared
let request = NSMutableURLRequest(url: url! as URL)
request.httpMethod = "POST"
request.setValue("Basic \(keys)", forHTTPHeaderField: "Authorization")
request.setValue("client_credentials", forHTTPHeaderField: "grant_type")
let task = session.dataTask(with: request as URLRequest) { (data, response, error) in
guard let _: Data = data, let _: URLResponse = response, error == nil else {
print(error!)
return
}
let dataString = NSString(data: data!, encoding: String.Encoding.utf8.rawValue)
print("Data: \(dataString!)")
self.parseData(JSONData: data!)
}
task.resume()
}
var accessToken = ""
func parseData(JSONData : Data) {
do {
var readableJSON = try JSONSerialization.jsonObject(with: JSONData, options: .mutableContainers) as! JSONStandard
if let token = readableJSON["access_token"] as? String {
accessToken = token
}
print("Access Token: \(accessToken)")
updateTokenInFirebase()
}
catch{
print(error)
}
Any help would be very appreciated, thank you very much in advance!
Documentation of the Web API: Web API Link
I am using on the Client Credentials Flow the first method.
I know it's been ~1 year since you posted this but I had the same issue and after a few tries was able to get it. You can test this in Playground.
import Foundation
import PlaygroundSupport
PlaygroundPage.current.needsIndefiniteExecution = true
if let url = URL(string: "https://accounts.spotify.com/api/token") {
var postRequest = URLRequest(url: url)
postRequest.httpMethod = "POST"
let bodyParams = "grant_type=client_credentials"
postRequest.httpBody = bodyParams.data(using: String.Encoding.ascii, allowLossyConversion: true)
let id = "your client id"
let secret = "your secret"
let combined = "\(id):\(secret)"
let combo = "\(id):\(secret)".toBase64()
postRequest.addValue("Basic \(combo)", forHTTPHeaderField: "Authorization")
let task = URLSession.shared.dataTask(with: postRequest) { (data, response, error) in
guard let data = data else {
return
}
print(String(data: data, encoding: String.Encoding.utf8)!)
}
task.resume()
}
extension String {
func fromBase64() -> String? {
guard let data = Data(base64Encoded: self) else {
return nil
}
return String(data: data, encoding: .utf8)
}
func toBase64() -> String {
return Data(self.utf8).base64EncodedString()
}
}
I know this is really late, but the issue is with this line:
request.setValue("client_credentials", forHTTPHeaderField: "grant_type")
According to the authorization guide, this should be in the body of the request, not the headers.

How to stop task or section from NSURLSession

I am Using NSURLSession for call an post API, but when i turn of the wifi and then hit the web service and again turn on the wifi NSURLSession is calling that previously call web service, i want to stop this process. i read on some of documents that NSURLSession store the section of every service call when connection break in any situation , and again hit that service when connection established again. So now i am not getting any solution to stop that service call after connection reconnect to my device.
Any one please help me. Thanks in advance.
Below is my code i used.
let token: NSString!
let urlPath: NSURL!
if provider .isEqualToString("No"){
urlPath = NSURL(string: kAPI_SERVERBASEURL + (url as String))
}
else{
urlPath = NSURL(string: kAPI_SERVERBASEURLSEARCHPROVIDER + (url as String))
}
var postJsonData = NSData()
var jsonString = NSString()
do {
postJsonData = try NSJSONSerialization.dataWithJSONObject(dictRequest, options:[])
jsonString = NSString(data: postJsonData, encoding: NSUTF8StringEncoding)!
NSLog("request - %#", jsonString);
// do other stuff on success
} catch {
print("JSON serialization failed: \(error)")
}
let request = NSMutableURLRequest(URL: urlPath);
request.cachePolicy = NSURLRequestCachePolicy.ReloadIgnoringLocalCacheData
request.HTTPShouldHandleCookies = false
request.timeoutInterval = 120 ;
request.HTTPMethod = "POST";
if NSUserDefaults.standardUserDefaults().valueForKey(kAccessToken) != nil{
token = NSUserDefaults.standardUserDefaults().valueForKey(kAccessToken) as! NSString
//token = "tk_1vNoEoZRxJwY"
request.setValue("\(token)", forHTTPHeaderField: "access_token")
}
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
request.HTTPBody = postJsonData
let session = NSURLSession.sharedSession()
let task = session.dataTaskWithRequest(request) { (data:NSData?, response:NSURLResponse?, error:NSError?) -> Void in
`
It may help you.
1.Declare one variable about the NSURLSessionTask like
var task: NSURLSessionTask? = nil
2.When ever you need to call dataTaskWithRequest assign the object to declared object like
task = NSURLSession.sharedSession().dataTaskWithURL(NSURL(fileURLWithPath: ""))
3.when you want to cancel the request just do the below.
if nil != task {
task!.cancel()
task = nil
}
Suppose you want cancel the request before calling another one combine both 2 and 3 steps like
if nil != task {
task!.cancel()
task = nil
}
task = NSURLSession.sharedSession().dataTaskWithURL(NSURL(fileURLWithPath: ""))

Where do I specify ReloadIgnoringLocalCacheData for NSURLSession in Swift 2

I have an app that makes an API call every 5 seconds using NSURLSession and p2-oauth2. I'm running into an issue of it returning cached data instead of the updated information from the API. I read this post by Matt Thompson where he describes the different cache policies, the one I think I need to use is ReloadIgnoringLocalCacheData. I think it's suppose to be put in the AppDelegate DidFinishLaunchingWithOptions functions. But, the problem I'm having is I don't know where or how to specify it. I haven't found any Swift solutions. Can anyone tell me what my function should say?
If it's helpful, here is my API request:
let urlPath = "https://sandbox-api.uber.com/v1/requests/\(uberRequestId)"
let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
guard let endpoint = NSURL(string: urlPath) else { print("Error creating endpoint");return }
let request = appDelegate.oauth.request(forURL: NSURL(string:urlPath)!)
request.setValue("application/json; charset=utf-8", forHTTPHeaderField: "Content-Type")
request.HTTPMethod = "GET"
//get response from Uber and iterate through to find Uber Product ID.
NSURLSession.sharedSession().dataTaskWithRequest(request) { (data, response, error) -> Void in
do {
guard let dat = data else { throw JSONError.NoData }
let result = try NSJSONSerialization.JSONObjectWithData(dat, options: NSJSONReadingOptions.MutableContainers)
print(result)
//set status
status = result["status"] as! String
print("found status...returning it back -> \(status)")
completion(status: "\(status)")
} catch let error as JSONError {
print(error.rawValue)
print("ERROR NEEDS TO BE HANDLED.")
} catch {
print(error)
print("ERROR NEEDS TO BE HANDLED.")
}
}.resume()
Here is the final request that properly sets the cache policy. I added one line with ReloadIgnoringLocalCacheData.
let urlPath = "https://sandbox-api.uber.com/v1/requests/\(uberRequestId)"
let url:NSURL = NSURL(string: urlPath)!
let session = NSURLSession.sharedSession()
let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
let request = appDelegate.oauth.request(forURL: NSURL(string:urlPath)!)
request.HTTPMethod = "GET"
//added this line to set cache policy
request.cachePolicy = NSURLRequestCachePolicy.ReloadIgnoringLocalCacheData
request.setValue("application/json; charset=utf-8", forHTTPHeaderField: "Content-Type")
let task = session.dataTaskWithRequest(request) {
(
let data, let response, let error) in
guard let _:NSData = data, let _:NSURLResponse = response where error == nil else {
print("error")
return
}
let dataString = NSString(data: data!, encoding: NSUTF8StringEncoding)
print(dataString)
}
task.resume()
Assuming the OAuth API returns a mutable request, you can set its cachePolicy property to NSURLRequestCachePolicy.ReloadIgnoringCacheData.

How to upload and associate an Image with a User in Parse.com (REST API), using Swift 2.0

I am trying to associate an image or a file with an object in Parse.com using the REST API. The Parse.com REST API Doc is quite vague, it talks about first how to upload which is fine, and then how to associate. The only issue is that it doesn't show how to associate with a User table, only an Object table, so when I tried to associate with a user, it asked for a username and password, and the response is as if it tries to create a new user. When I tried to associate with a regular table Company, it create a new entry. Any help would welcome, this is the code I have so far.
This is the code to upload a file to Parse.com with REST
let baseURL = NSURL(string: self.baseURL)
let url = NSURL(string: "/1/files/pic.jpg", relativeToURL: baseURL)
let request = NSMutableURLRequest()
request.HTTPMethod = "\(HTTPMethod.POST)"
request.addValue(appID, forHTTPHeaderField: "X-Parse-Application-Id")
request.addValue(apiKey, forHTTPHeaderField: "X-Parse-REST-API-Key")
request.addValue("image/jpeg", forHTTPHeaderField: "Content-Type")
let image = UIImage(named: "empAvatar")
let imageData = UIImageJPEGRepresentation(image!, 0.9)
let base64String = imageData!.base64EncodedStringWithOptions(NSDataBase64EncodingOptions(rawValue: 0))
let param = ["userProfile":base64String]
do{
request.HTTPBody = try NSJSONSerialization.dataWithJSONObject(param, options: .PrettyPrinted)
} catch {
print("ERROR: HTTP Body JSON")
}
request.URL = url
let session = NSURLSession.sharedSession()
let task = session.dataTaskWithRequest(request) {
data, response, error in
do {
let imageDic = try NSJSONSerialization.JSONObjectWithData(data!, options: []) as! [String:AnyObject]
print("DATA: \(imageDic)")
} catch {
}
}
task.resume()
This is the code to associate a file with a user/object
let baseURL = NSURL(string: self.baseURL)
let url = NSURL(string: "/1/users/", relativeToURL: baseURL)
let request = NSMutableURLRequest()
request.HTTPMethod = "\(HTTPMethod.POST)"
request.addValue(appID, forHTTPHeaderField: "X-Parse-Application-Id")
request.addValue(apiKey, forHTTPHeaderField: "X-Parse-REST-API-Key")
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
let param = ["name":"John", "picture":["name":"tfss-127e50c4-be6e-4228-b1a3-3f253358ac-pic.jpg","__type":"File"]]
do{
request.HTTPBody = try NSJSONSerialization.dataWithJSONObject(param, options: .PrettyPrinted)
} catch {
print("ERROR: HTTP Body JSON")
}
request.URL = url
let session = NSURLSession.sharedSession()
let task = session.dataTaskWithRequest(request) {
data, response, error in
do {
let imageDic = try NSJSONSerialization.JSONObjectWithData(data!, options: []) as! [String:AnyObject]
print("DATA: \(imageDic)")
} catch {
}
}
task.resume()
With the URL, I also tried:
let url = NSURL(string: "/1/class/Company/", relativeToURL: baseURL)
And it just created a new entry.
Thanks you!
POST request will create new entry try using PUT method instead.

Swift to php on local server doesn't work on my device?

I am having an issue with the following code, it works on the iphone 5s simulator. But when i attach my iphone5s device it doesn't work. With the simulator i get this (as expected) back from swiftupload.php
Button pressed <- swift
responseString = Optional({"message":"some variable"}Success) <- from php
Email has ben sent <- swift
And with my device attached i get
Button pressed
responseString = Optional()
The php file looks like:
$postdata = json_decode(file_get_contents("php://input"), TRUE);
$message = $postdata["data"];
// Store values in an array
$returnValue = array("message" => $message);
// Send back request in JSON format
echo json_encode($returnValue);
And this is the function in swift
func postToServerFunction(){
// json php
let request = NSMutableURLRequest(URL: NSURL(string: "http://localhost/mydomain.com/swiftupload.php")!)
let session = NSURLSession.sharedSession()
request.HTTPMethod = "POST"
let params = ["data":"some variable"] as Dictionary<String, String>
request.HTTPBody = try! NSJSONSerialization.dataWithJSONObject(params, options: [])
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
request.addValue("application/json", forHTTPHeaderField: "Accept")
let task = session.dataTaskWithRequest(request, completionHandler: {data, response, error -> Void in
//Response print
let responseString = NSString(data: data!, encoding: NSUTF8StringEncoding)
print("responseString = \(responseString)")
if let HTTPResponse = response as? NSHTTPURLResponse {
let statusCode = HTTPResponse.statusCode
if statusCode == 200{
print("Email has ben sent")
}
}
})
task.resume()
print("Button pressed")
}
On the iPhone the localhost is IP of the iPhone.
Replace "localhost" with IP of your MAC/PC and check App Transport Security exceptions https://stackoverflow.com/a/30732693/4755417

Resources