How to integrate an app with a fitness tracker

Today, almost all countries around the world pay special attention to physical activity of the ordinary people.

In the modern world not everyone can afford to attend the gym, but thanks to the fitness applications, you can do sport anytime and anywhere.

The interest to fitness apps has greatly changed.

Fitness bracelet has become one of the very useful gadgets, without which it is really difficult to manage in a modern life.

According to the functions and abilities fitness apps are divided into categories. The most popular types of fitness apps are – diet and nutrition apps, activity tracking apps,  workout or exercise apps etc.

These days we can observe that the demand of fitness apps is increasing, so it would be a good idea to create a unique fitness application. The first step is to decide what type of app you would like to have and identify features that should be included in it.

 

 

Below you can see some examples how we develop fitness applications and how it works:

import UIKit

import CoreBluetooth

let bandServiceCBUUID = CBUUID(string: “55ff”)

let writeCharacteristicCBUUID = CBUUID(string: “33f1”)

class SMViewController: UIViewController

{

@IBOutlet weak var batteryLevelLabel: UILabel!

 var cbManager: CBCentralManager!

 var cbPeripheral: CBPeripheral!

override func viewDidLoad()

{

super.viewDidLoad()

cbManager = CBCentralManager(delegate: self, queue: nil)

}

fileprivate var setOfSentValues: [Int8] – charging level command

{

return [-94]

}

fileprivate var sentData: Data the formation of a command to read the level of charge

{

let dataArray: [UInt8] = setOfSentValues.compactMap( { UInt8(bitPattern: $0) } )

return Data(bytes: dataArray, count: setOfSentValues.count)

}

func batteryLevelReceived(_ batteryLevel: Int) renovation of ui

{

batteryLevelLabel.text = String(batteryLevel)

print(“Battery level: \(batteryLevel)”)

}

}

extension SMViewController: CBCentralManagerDelegate

{

 func centralManagerDidUpdateState(_ central: CBCentralManager)

{

   switch central.state

{

case .unknown:

print(“State is unknown”)

case .resetting:

print(“State is resetting”)

case .unsupported:

print(“State is unsupported”)

case .unauthorized:

print(“State is unauthorized”)

case .poweredOff:

print(“State is poweredOff”)

case .poweredOn:

print(“State is poweredOn”)

//when state is powered on we can scan for available peripherals

cbManager.scanForPeripherals(withServices: [bandServiceCBUUID])

   }

 }

func centralManager(_ central: CBCentralManager, didDisconnectPeripheral peripheral: CBPeripheral, error: Error?)

{

//do smth after peripheral disconnects

}

 

 func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral,

                     advertisementData: [String : Any], rssi RSSI: NSNumber)

{

   cbPeripheral = peripheral

   cbPeripheral.delegate = self

   cbManager.stopScan()

   cbManager.connect(cbPeripheral)

 }

 

 func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral)

{

   cbPeripheral.discoverServices([bandServiceCBUUID])

 }

}

extension SMViewController: CBPeripheralDelegate

{

 func peripheral(_ peripheral: CBPeripheral, didDiscoverServices error: Error?)

{

   guard let services = peripheral.services else { return }

   for service in services

{

     peripheral.discoverCharacteristics(nil, for: service)

   }

 }

 func peripheral(_ peripheral: CBPeripheral, didDiscoverCharacteristicsFor service: CBService, error: Error?)

{

   guard let characteristics = service.characteristics else { return }

  for characteristic in characteristics

{

if characteristic.uuid == writeCharacteristicCBUUID

{

peripheral.writeValue(sentData, for: characteristic, type: .withResponse)

}

if characteristic.properties.contains(.notify)

{

peripheral.setNotifyValue(true, for: characteristic)

}

   }

 }

 func peripheral(_ peripheral: CBPeripheral, didUpdateValueFor characteristic: CBCharacteristic, error: Error?) получение данных

{

var buff = [UInt8](repeating: 0, count: 1)

if let value = characteristic.value as NSData?

{

value.getBytes(&buff, range: NSRange(location: 1, length: 1))

batteryLevelReceived(buff)

}

 }

}

Now have a look at the scheme of the operation of a bluetooth and other device:

import UIKit

import CoreBluetooth     //1 framework connection

let heartRateServiceCBUUID = CBUUID(string: “0x180D”) //6 service CBUUID announcement

let heartRateCharacteristicCBUUID = CBUUID(string: “2A37”) //9 ad CBUUID features

class SMViewController: UIViewController

{

 @IBOutlet weak var lbHeartRate: UILabel!

 var cbManager: CBCentralManager! //3 variable declaration cbCentralManager (this is about it https://developer.apple.com/documentation/corebluetooth/cbcentralmanager?language=objc)

Here you can find the description of classes : https://developer.apple.com/documentation/corebluetooth?language=objc

 var hrPeripheral: CBPeripheral! //10 variable declaration hrPeripheral

override func viewDidLoad()

{

   super.viewDidLoad()

  cbManager = CBCentralManager(delegate: self, queue: nil) //4 manager initialization

 }

fileprivate func heartRateReceived(_ heartRate: Int) //19 update of UI with new data received from the device

{

   lbHeartRate.text = String(heartRate)

 }

}

extension SMViewController: CBCentralManagerDelegate //2 creation of extension in which protocol methods are implemented CBCentralManagerDelegate

{

 func centralManagerDidUpdateState(_ central: CBCentralManager) //5 redefining the manager status update method

{

   switch central.state

{

case .unknown:

print(“State is unknown”)

case .resetting:

print(“State is resetting”)

case .unsupported:

print(“State is unsupported”)

case .unauthorized:

print(“State is unauthorized”)

case .poweredOff:

print(“State is poweredOff”)

case .poweredOn:

print(“State is poweredOn”)

//when state is powered on we can scan for available peripherals

cbManager.scanForPeripherals(withServices: [heartRateServiceCBUUID]) //7 when a manager has status poweredOn , we can start scanning of available Bluetooth devices with our service heartRateServiceCBUUID

   }

 }

func centralManager(_ central: CBCentralManager, didDisconnectPeripheral peripheral: CBPeripheral, error: Error?)

{

//do smth after peripheral disconnects

}

func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral,

                     advertisementData: [String : Any], rssi RSSI: NSNumber) //8  redefining the method when a device is found

{

   hrPeripheral = peripheral

   hrPeripheral.delegate = self

   cbManager.stopScan()

   cbManager.connect(hrPeripheral) //11 connection to the device

 }

 func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) //12 the device is connected

{

   hrPeripheral.discoverServices([heartRateServiceCBUUID]) //13 we are looking for services

 }

}

extension SMViewController: CBPeripheralDelegate

{

 func peripheral(_ peripheral: CBPeripheral, didDiscoverServices error: Error?) //14 сервисы найдены

{

   guard let services = peripheral.services else { return }

   for service in services

{

     peripheral.discoverCharacteristics(nil, for: service) //15 we are looking for characteristics

   }

 }

func peripheral(_ peripheral: CBPeripheral, didDiscoverCharacteristicsFor service: CBService, error: Error?) //16 characteristics are found . We go through an array of found characteristics and read the data from those where there is for reading and subscribe to updates of those who have notify.

{

   guard let characteristics = service.characteristics else { return }

 for characteristic in characteristics

{

if characteristic.properties.contains(.read)

{

peripheral.readValue(for: characteristic)

}

if characteristic.properties.contains(.notify)

{

peripheral.setNotifyValue(true, for: characteristic)

}

   }

 }

 func peripheral(_ peripheral: CBPeripheral, didUpdateValueFor characteristic: CBCharacteristic, error: Error?) //17 this method receives renewed data from the device and we call the data reading method and update ui

{

   switch characteristic.uuid

{

case heartRateCharacteristicCBUUID:

let value = heartRateValue(from: characteristic)

heartRateReceived(value)

default:

print(“Unhandled UUID: \(characteristic.uuid)”)

   }

 }

 private func heartRateValue(from characteristic: CBCharacteristic) -> Int //18 we read the data

{

   guard let characteristicData = characteristic.value else { return -1 }

   let byteArray = [UInt8](characteristicData)

  // See: https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.characteristic.heart_rate_measurement.xml

   // The heart rate measurement is in the 2nd, or in the 2nd and 3rd bytes, i.e. one one or in two bytes

   // The first byte of the first bit specifies the length of the heart rate data, 0 == 1 byte, 1 == 2 bytes

   let firstByteValue = byteArray[0] & 0x01

   if firstByteValue == 0

{

// Heart Rate Value Format is in the 2nd byte

     return Int(byteArray[1])

   } else

{

     // Heart Rate Value Format is in the 2nd and 3rd bytes

     return (Int(byteArray[1]) << 8) + Int(byteArray[2])

   }

 }

}

 

Leave a Reply

Your email address will not be published. Required fields are marked *