How to get JSON from google calendar API in swift? - ios

What I want to do is sync the data from google calendar to my app.
I can login my app with google+ account now, then how can I get the private JSON data from calendar with my account ID and password?
Thanks in advance.

I was able to retrieve JSON data via HTTP requests using Google Calendar API. As an example, here is a code snippet to make a request to retrieve my calendar metadata:
let url = NSURL(string: "https://www.googleapis.com/calendar/v3/calendars/calendarId")
let task = NSURLSession.sharedSession().dataTaskWithURL(url!) {(data, response, error) in
let dataAsNSString = NSString(data: data, encoding: NSUTF8StringEncoding)
// implement your app logic
}
task.resume()
As far as syncing data between your app and Google Calendar, you can implement callbacks to make PUT requests to update via Google Calendar API. As an example, here is a code snippet for a callback function to make a PUT request to sync w/ your Google Calendar:
func updateUserDataToGoogleCalendar(calendarId: String) {
let url = NSURL(string:"https://www.googleapis.com/calendar/v3/calendars/calendarId")
let dataAsString = "sync data"
var data: NSData? = dataAsString.dataUsingEncoding(NSUTF8StringEncoding)
var headers = Dictionary<String, String>() // specify any headers
Http().put(url!, headers: headers, data:data!) { (result) in
if result.success {
if let json: AnyObject = result.jsonObject {
// implement your app logic
}
}
}
There are numerous Swift HTTP wrapper libraries available. In my example, I am using Swift HTTP.

Related

How to implement basic web authentication in SwiftUI App for a specific web service that does not provide an API?

I will get straight to the point. Please excuse my english
So there is a website (we can call it X) which offers a service to query and fetch documents etc after logging in with your username / password
I am trying to figure out a way to, basically, provide the same service except natively through the app. The user of the app will still have to enter their username and password and then I make a request to the website and "log" in and then provide the same interface the website does after logging in but the app will be able to save the login information and be able to have some other features that would be beneficial wrt to the documents that it then fetches.
The website does not offer an api (atleast that I know of) I am struggling to figure out how to send the URL request with the username and password.
First I read about using ASAuthenticationServices but that led me to reading that you need the callback url which did not work for me (1. because I can't setup the callback url through the API and 2. because my custom app callback url did not fire)
Then I tried to use a WKWebView to embed a browser and a try to catch the details after the user logged in but still no success.
I have also read that JWT might be the solution considering that it is only a single server authentication needed
This is my code so far, I have stripped it down to basically just show the request I'm making
If anyone could shed some light as to how to perform a simple web login (to basically embed the web service and be able to use it as an app) I would really appreciate it.
Thanks
So this is where I'm at now. I'm trying to form a URLRequest and just checking whether the signin response works, should I be trying to implement a callback in a custom WKWebView ? I'm more kind of asking as to what method I should be using. Should I be researching more into JWT ? or should I be looking at using custom WKWebViews and trying to catch the callback and save the credentials etc through that or do I need to just deconstruct and send custom URLRequests in order to authenticate? thank you
import Combine
import Foundation
final class SignInDummy: ObservableObject {
#Published var username = ""
#Published var password = ""
#Published var hasError = false
#Published var isSigningIn = false
var canSignIn: Bool {
!username.isEmpty && !password.isEmpty
}
func signIn() {
guard !username.isEmpty && !password.isEmpty else {
return
}
let url = URL(string: "https:// URL to website (copy and pasted url of the login page)")!
var request = URLRequest(url: url)
request.httpMethod = "POST"
let authData = (username + ":" + password).data(using: .utf8)!.base64EncodedString()
request.addValue("Basic \(authData)", forHTTPHeaderField: "Authorization")
isSigningIn = true
URLSession.shared.dataTask(with: request) { [weak self] data, response, error in
DispatchQueue.main.async {
if error != nil || (response as! HTTPURLResponse).statusCode != 200 {
self?.hasError = true
} else if let data = data {
do {
let signInResponse = try JSONDecoder().decode(SignInResponse.self, from: data)
print(signInResponse)
// TODO: Cache Access Token in Keychain
} catch {
print("Unable to Decode Response \(error)")
print("\(response?.mimeType)")
print("\(response.debugDescription)")
}
}
self?.isSigningIn = false
}
}.resume()
}
fileprivate struct SignInResponse: Decodable {
// MARK: - Properties
let accessToken: String
}
}

login user with GET request swift

I have created a screen with a text field called customer_number text field and another screen with a text field called password text field. I want to integrate my app with an existing API made by the backend developers. I am new to IOS Development and I don't know how to go about it. How do I make a get request and pass the login credentials for the user to login?
I want to get the customer number from the API and pass it to the app and enable the customer to log in.
I think this question is too big and complex to be replied exhaustively. You didn't tell us about the API. What kind of input does it take? What kind of response?
Supposing the simplest case. You API expects JSON objects as input and respond with another JSON object containing the information you request.
I usually do tasks like this using the NSURLRequest.
let js = ["Username":username, "Password":password]
let session = URLSession.init(configuration: .default)
let url = URL(...)
var req = URLRequest.init(url: url, cachePolicy: .reloadIgnoringLocalAndRemoteCacheData, timeoutInterval: 10)
req.httpMethod = "POST"
// Add some header key-value pairs
req.addValue(..., forHTTPHeaderField: ...)
...
let task = session.dataTask(with: request) { (data, response, error) in
guard error == nil else { return }
guard let responseData = data else { return }
let code = (response as! HTTPURLResponse).statusCode
// Checking for code == 200 states for authorised user. Generally log-in APIs should return some 4xx code if not allowed or non-authorised user.
if code == 200 {
// Now we try to convert returned data as a JSON object
do {
let json = try JSONSerialization.jsonObject(with: responseData, options: [])
// use your json object here, for example checking if contains the user number...
} catch {
// handle errors
}
}
}
task.resume()
I coded this very quickly, please check the correctness of al mechanism!

iOS/Swift & Coinbase Pro API - Subscribe to Websocket Feed

I am attempting to subscribe to a websocket feed using Swift. Per the new Coinbase Pro API documentation for their websocket feed:
To begin receiving feed messages, you must first send a subscribe message to the server indicating which channels and products to receive. This message is mandatory — you will be disconnected if no subscribe has been received within 5 seconds.
The first thing I did was add Starscream to the project to make connecting to websockets easier to implement. I followed the steps on the README and added the delegate methods appropriately.
Next, I successfully sent an HTTP GET request (I get a 200 code in response) by creating a URLSession object and calling dataTask(with: ) after setting up a request, like so:
let session = URLSession.shared
guard let url = URL(string: "https://api.pro.coinbase.com/users/self/verify") else {
print("Could not create URL.")
return
}
var request = URLRequest(url: url)
request.httpMethod = "GET"
let body: [String: Any] = ["type": "subscribe",
"channels": [["name": "heartbeat"],
["product_ids": ["BTC-USD"]]]]
let data = try! JSONSerialization.data(withJSONObject: body,
options: JSONSerialization.WritingOptions.sortedKeys)
request.httpBody = data
let task = session.dataTask(with: request) { (data, response, error) in
// Check for errors, clean up data, etc.
}
task.resume
Everything appears to be linked up correctly, but I am still not receiving the "subscription" messages from the websocket feed. What am I missing?

How to get user time line in JSON format using Twitter Kit in iOS SDK

I am trying to implement Twitter kit in my App. I have added SDK in my app & able to login. Now I have to get user time line data in JSON format (because I have to perform some manipulation & sorting over data). I found this link on Twitter to get time line for a user but in my case I need data in JSONformat not as DataSource object.
Can anyone suggest how to retrieve the time line data in JSON format using Twitter Kit?
TWTRAPIClient has several methods for making request and getting data. Use given code snippet to get user timelines.For parameters, kindly refer this page
let parameters = ["screen_name": "stevenhepting", "count": "3"]
var error : NSError?
let req = TWTRAPIClient().urlRequest(withMethod: "GET", url: "https://api.twitter.com/1.1/statuses/user_timeline.json", parameters: parameters, error: &error)
TWTRAPIClient().sendTwitterRequest(req, completion: { (response, data, error) in
do {
let response = try JSONSerialization.jsonObject(with: data!, options: .allowFragments) as? [[String : Any]]
if response != nil {
print((response! as NSArray).debugDescription)
}
}
catch {
print(error.localizedDescription)
}
})
To get other timelines, please refer
Twitter Developer Documentation

How can I process multiple links of JSON data?

The code works perfectly. The problem is that, after trying for a while, I cannot figure out how to make my program process a second link of different JSON data.
Here is my viewDidLoad where everything goes on:
override func viewDidLoad() {
super.viewDidLoad()
var err: NSError?
let urlPath: String = "https://na.api.pvp.net/api/lol/na/v1.4/summoner/by-name/" + searchFieldDataPassed + "?api_key=(removed my private api key for obvious reasons"
var url: NSURL = NSURL(string: urlPath)!
let session = NSURLSession.sharedSession()
let task = session.dataTaskWithURL(url) { data, response, error in
// cast response as NSHTTPURLResponse and switch on statusCode if you like
if let httpResponse = response as? NSHTTPURLResponse { switch httpResponse.statusCode { case 200..<300: println("OK") default: println("Not OK") } }
// parse JSON using NSJSONSerialization if you've got data
if let jsonResult = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers, error: &err) as? NSDictionary,
let include = jsonResult.objectForKey(self.searchFieldDataPassed) as? NSDictionary {
if let summLevel = include[ "summonerLevel" ] as? NSNumber {
dispatch_async(dispatch_get_main_queue()) {
self.summonerLevel.text = "\(summLevel.integerValue)"
println("summoner level: \(summLevel.integerValue)")
}
}
if let profIconId = include[ "profileIconId" ] as? NSNumber {
dispatch_async(dispatch_get_main_queue()) {
self.profileIconId.text = "\(profIconId.integerValue)"
println("profile icon id: \(profIconId.integerValue)")
}
}
if let idNum = include [ "id" ] as? NSNumber {
dispatch_async(dispatch_get_main_queue()) {
self.idNumber = idNum
println("id number: \(self.idNumber)")
}
}
}
// spawn off another network call here if you like
}
task.resume()
}
That is from my secondViewController where all the processing goes on for JSON and then is displayed.
Here is the JSON data that I'm processing (for the first JSON parsing):
{"soon2challenger":{"id":43993167,"name":"soon2challenger","profileIconId":844,"summonerLevel":30,"revisionDate":1435549418000}}
All of that works fine, now, I want to process this JSON data which actually takes the id from the first parsed JSON data and uses it in the link to process more data, which I would like to output, part of it, to the screen.
Second JSON data:
{"summonerId":43993167,"playerStatSummaries":[{"playerStatSummaryType":"AramUnranked5x5","wins":25,"modifyDate":1423007927000,"aggregatedStats":{"totalChampionKills":676,"totalTurretsKilled":20,"totalAssists":991}},{"playerStatSummaryType":"CAP5x5","wins":15,"modifyDate":1429065922000,"aggregatedStats":{"totalChampionKills":312,"totalMinionKills":4885,"totalTurretsKilled":31,"totalNeutralMinionsKilled":511,"totalAssists":216}},{"playerStatSummaryType":"CoopVsAI","wins":28,"modifyDate":1421882181000,"aggregatedStats":{"totalChampionKills":266,"totalMinionKills":2802,"totalTurretsKilled":50,"totalNeutralMinionsKilled":385,"totalAssists":164,"maxChampionsKilled":0,"averageNodeCapture":0,"averageNodeNeutralize":0,"averageTeamObjective":0,"averageTotalPlayerScore":49,"averageCombatPlayerScore":0,"averageObjectivePlayerScore":49,"averageNodeCaptureAssist":0,"averageNodeNeutralizeAssist":0,"maxNodeCapture":0,"maxNodeNeutralize":0,"maxTeamObjective":0,"maxTotalPlayerScore":49,"maxCombatPlayerScore":0,"maxObjectivePlayerScore":49,"maxNodeCaptureAssist":0,"maxNodeNeutralizeAssist":0,"totalNodeNeutralize":0,"totalNodeCapture":0,"averageChampionsKilled":0,"averageNumDeaths":0,"averageAssists":0,"maxAssists":0}},{"playerStatSummaryType":"CoopVsAI3x3","wins":15,"modifyDate":1421882181000,"aggregatedStats":{"totalChampionKills":140,"totalMinionKills":1114,"totalTurretsKilled":9,"totalNeutralMinionsKilled":449,"totalAssists":91}},{"playerStatSummaryType":"OdinUnranked","wins":1,"modifyDate":1421882181000,"aggregatedStats":{"totalChampionKills":31,"totalAssists":45,"maxChampionsKilled":10,"averageNodeCapture":4,"averageNodeNeutralize":4,"averageTeamObjective":0,"averageTotalPlayerScore":843,"averageCombatPlayerScore":268,"averageObjectivePlayerScore":575,"averageNodeCaptureAssist":3,"averageNodeNeutralizeAssist":1,"maxNodeCapture":6,"maxNodeNeutralize":7,"maxTeamObjective":2,"maxTotalPlayerScore":1468,"maxCombatPlayerScore":529,"maxObjectivePlayerScore":939,"maxNodeCaptureAssist":5,"maxNodeNeutralizeAssist":2,"totalNodeNeutralize":22,"totalNodeCapture":25,"averageChampionsKilled":5,"averageNumDeaths":5,"averageAssists":8,"maxAssists":19}},{"playerStatSummaryType":"RankedSolo5x5","wins":116,"losses":120,"modifyDate":1433630047000,"aggregatedStats":{"totalChampionKills":1699,"totalMinionKills":33431,"totalTurretsKilled":219,"totalNeutralMinionsKilled":6501,"totalAssists":1969}},{"playerStatSummaryType":"RankedTeam3x3","wins":0,"losses":0,"modifyDate":1377726216000,"aggregatedStats":{}},{"playerStatSummaryType":"RankedTeam5x5","wins":3,"losses":0,"modifyDate":1383784473000,"aggregatedStats":{"totalChampionKills":28,"totalMinionKills":636,"totalTurretsKilled":6,"totalNeutralMinionsKilled":101,"totalAssists":41}},{"playerStatSummaryType":"Unranked3x3","wins":9,"modifyDate":1421882181000,"aggregatedStats":{"totalChampionKills":90,"totalMinionKills":1427,"totalTurretsKilled":11,"totalNeutralMinionsKilled":428,"totalAssists":105}},{"playerStatSummaryType":"URF","wins":4,"modifyDate":1435024847000,"aggregatedStats":{"totalChampionKills":68,"totalMinionKills":642,"totalTurretsKilled":14,"totalNeutralMinionsKilled":182,"totalAssists":55}},{"playerStatSummaryType":"Unranked","wins":566,"modifyDate":1435549418000,"aggregatedStats":{"totalChampionKills":8419,"totalMinionKills":128213,"totalTurretsKilled":960,"totalNeutralMinionsKilled":26117,"totalAssists":7812}}]}
Heres the link of the second JSON data I want to parse (just adding it, could be useful, but not sure):
https://na.api.pvp.net/api/lol/na/v1.3/stats/by-summoner/43993167/summary?season=SEASON2015&api_key=(took-out-my-private-api-key-for-obvious-reasons)
The link doesn't work because I have to keep my api key private to myself, but the JSON data that it displays is right above the link, which is the what it would result if you were to use the link with the api key.
Just to restate, I would like to process the second part (above of this) of JSON data, but I do not understand how to process multiple links of JSON. I have the first JSON data parsed, but am unable to parse the second JSON data.
I believe Apple is deprecating NSURLConnection. Take a look at NSURLSession. Using it, you can pass in a completion block that takes three arguments: NSData?, NSURLResponse?, and NSError?. The data object contains the JSON you can pass into the JSON serializer. After that, if you need to make another network call, just call it from inside the completion block with another NSURLSession data task. Alamofire is a great framework, but sometimes you don't need everything it provides, and it adds complexity into your app that if something goes wrong or doesn't behave the way you intend/understand, you may not fully understand why. If you want to keep it simple and under your control, use NSURLSession.
let session = NSURLSession.sharedSession()
let task = session.dataTaskWithURL(url) { data, response, error in
// cast response as NSHTTPURLResponse and switch on statusCode if you like
// parse JSON using NSJSONSerialization if you've got data
// spawn off another network call here if you like
}
task.resume() // or in Swift 2, task?.resume()
First, i would totally prefer using some common frameworks for http requests - expecially if youre new in swift. For example here with alamofire.
https://github.com/Alamofire/Alamofire
There is also a version with integrated SwiftyJSON, so you are able to parse JSON Responses very easily.
https://github.com/SwiftyJSON/Alamofire-SwiftyJSON
So if you want to make a request, use this:
Alamofire.request(.GET, "http://httpbin.org/get")
.responseJSON { (_, _, json, _) in
var json = JSON(json)
// get the id out (depends on your structure of JSON):
let id = json["id"].int
}
Now you are able to perform a second Request (with the same Code) - Read the Documentation, how to make different Requests (like with POST) and add Parameters.
If you want to use Segues, so you want to load more data from the ID in another ViewController, you can use Segues to push the data to a second ViewController, and Load the new Content from JSON when the new ViewController is initialised.
Check out this how to send data through segues:
Sending data with Segue with Swift

Resources