How to get steps from Fitbit
First of all setup Fitbit account in https://dev.fitbit.com/
Get Client id & Client Secret from Fitbit dashboard
set Identifier and URL Scheme
-> identifier = your bundle id
-> URL Schemes : your web url
Create model for Fitbit credential
class FitbitAPI {
static let sharedInstance: FitbitAPI = FitbitAPI()
static let baseAPIURL = URL(string:"https://api.fitbit.com/1")
func authorize(with token: String) {
let sessionConfiguration = URLSessionConfiguration.default
var headers = sessionConfiguration.httpAdditionalHeaders ?? [:]
headers["Authorization"] = "Bearer \(token)"
sessionConfiguration.httpAdditionalHeaders = headers
session = URLSession(configuration: sessionConfiguration)
}
var session: URLSession?
}
class ViewController: UIViewController,AuthenticationProtocol {
var authenticationController: AuthenticationController?
override func viewDidLoad() {
super.viewDidLoad()
authenticationController = AuthenticationController(delegate: self)
}
private func retrivedataFromFitbit() {
if let authToken = UserDefaults.standard.string(forKey: "authToken") {
FitbitAPI.sharedInstance.authorize(with: authToken)
fetchFitbitActivity.fetchFitbitActivity(date: Date()) { (steps) in
print(steps ?? 0)
}
}
}
}
Fetch Fitbit activity model
import Foundation
import SafariServices
import AuthenticationServices
typealias AuthHandlerCompletion = (URL?, Error?) -> Void
class AuthContextProvider: NSObject {
private weak var anchor: ASPresentationAnchor!
init(_ anchor: ASPresentationAnchor) {
self.anchor = anchor
}
}
extension AuthContextProvider: ASWebAuthenticationPresentationContextProviding {
@available(iOS 12.0, *)
func presentationAnchor(for session: ASWebAuthenticationSession) -> ASPresentationAnchor {
return anchor
}
}
protocol AuthHandlerType: class {
var session: NSObject? { get set }
var contextProvider: AuthContextProvider? { get set }
func auth(url: URL, callbackScheme: String, completion: @escaping AuthHandlerCompletion)
}
extension AuthHandlerType {
func auth(url: URL, callbackScheme: String, completion: @escaping AuthHandlerCompletion) {
if #available(iOS 12, *) {
let session = ASWebAuthenticationSession(url: url, callbackURLScheme: callbackScheme) {
url, error in
completion(url, error)
}
if #available(iOS 13.0, *) {
session.presentationContextProvider = contextProvider
} else {
// Fallback on earlier versions
}
session.start()
self.session = session
} else {
let session = SFAuthenticationSession(url: url, callbackURLScheme: callbackScheme) {
url, error in
completion(url, error)
}
session.start()
self.session = session
}
}
}
struct Constants {
static let authUrl = URL(string: "https://www.fitbit.com/oauth2/authorize")
static let responseType = "code"
static let clientId = "your client id"
static let redirectScheme = "your web url://m"
static let redirectUrl = "\(redirectScheme)fitbit/auth"
static let scope = ["activity", "heartrate", "location", "nutrition", "profile", "settings", "sleep", "social", "weight"]
static let expires = "604800"
private init() {}
}
class Model: AuthHandlerType {
var session: NSObject? = nil
var contextProvider: AuthContextProvider?
func auth(_ completion: @escaping ((String?, Error?) -> Void)) {
guard let authUrl = Constants.authUrl else {
completion(nil, nil)
return
}
var urlComponents = URLComponents(url: authUrl, resolvingAgainstBaseURL: false)
urlComponents?.queryItems = [
URLQueryItem(name: "response_type", value: Constants.responseType),
URLQueryItem(name: "client_id", value: Constants.clientId),
URLQueryItem(name: "redirect_url", value: Constants.redirectUrl),
URLQueryItem(name: "scope", value: Constants.scope.joined(separator: " ")),
URLQueryItem(name: "expires_in", value: String(Constants.expires))
]
guard let url = urlComponents?.url else {
completion(nil, nil)
return
}
auth(url: url, callbackScheme: Constants.redirectScheme) {
url, error in
if error != nil {
completion(nil, error)
} else if let `url` = url {
guard let components = URLComponents(url: url, resolvingAgainstBaseURL: false),
let item = components.queryItems?.first(where: { $0.name == "code" }),
let code = item.value else {
completion(nil, nil)
return
}
completion(code, nil)
}
}
}
}
class fetchFitbitActivity {
static func fetchFitbitActivity(date : Date , callback: @escaping (Int)->()){
//static func fetchFitbitActivity(arg: Bool, completion: (Bool) -> ()) {
let dateformatter = DateFormatter()
dateformatter.dateFormat = "yyyy-MM-dd"
dateformatter.timeZone = TimeZone(identifier: "UTC")
dateformatter.locale = NSLocale(localeIdentifier: "en_US_POSIX") as Locale?
var datePath = dateformatter.string(from: date)
datePath = datePath + ".json"
print(datePath)
guard let session = FitbitAPI.sharedInstance.session,
let stepURL = URL(string: "https://api.fitbit.com/1/user/-/activities/date/\(datePath)") else {
callback(0)
return
}
let dataTask = session.dataTask(with: stepURL) { (data, response, error) in
guard let response = response as? HTTPURLResponse, response.statusCode < 300 else {
callback(0)
return
}
do {
let jsonDecoder = JSONDecoder()
guard let data = data,
let dictionary = (try jsonDecoder.decode(Json4Swift_Base_Fitbit_Exercise.self, from: data)) as? Json4Swift_Base_Fitbit_Exercise else {
callback(0)
return
}
//let Activities = dictionary.activities ?? []
let TotalStepCount = dictionary.summary?.steps ?? 0
print(TotalStepCount)
callback(TotalStepCount)
}catch{
print(error.localizedDescription)
}
}
dataTask.resume()
}
}
Fitbit data Model
import Foundation
struct Json4Swift_Base_Fitbit_Exercise : Codable {
let activities : [Activities]?
let goals : Goals?
let summary : Summary?
enum CodingKeys: String, CodingKey {
case activities = "activities"
case goals = "goals"
case summary = "summary"
}
init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)
activities = try values.decodeIfPresent([Activities].self, forKey: .activities)
goals = try values.decodeIfPresent(Goals.self, forKey: .goals)
summary = try values.decodeIfPresent(Summary.self, forKey: .summary)
}
}