SlideShare uma empresa Scribd logo
1 de 75
Baixar para ler offline
TODAY'S ADVENTURE
> Wearables & My Story
> Coding with BLE on iOS
> The importance of protocols
> Connection stability
> Testing with wearables
> Logging & monitoring
> Remote maintenance
> The End
WEARABLES
TODAY A WEARABLE WILL BE
> A piece of HW that sits somewhere on your body
> Easy to carry with you
> Provides useful data via sensors
> Uses BLE for data exchange with the outside world
> In need of an app to communicate with
> Custom: you know / have power on the internals
IOTMAYBE JUST A
SPECIAL CASE
WEARABLES
&
ME
BLE & IOS
CORE BLUETOOTH
The framework is an abstraction of the Bluetooth 4.0
specification for use with low energy devices. That said,
it hides many of the low-level details of the specification
from you, the developer, making it much easier for you to
develop apps that interact with Bluetooth low energy
devices.
— Apple Docs
CORE BORING!
!
PERIPHERAL
> Has data
> Advertises its presence
> It's our wearable
> CBPeripheral
PERIPHERAL
> It exposes services
> Services contain characteristics
> Characteristics allow data exchange
> You can define your own
CENTRAL
> Wants data
> Scans for advertising peripherals
> Connects to peripherals
> Explores services and characteristics
> Reads, writes, is notified by characteristics
> It's (part of) our app
> CBCentralManager
THE
BLUETOOTH
DANCE
1 - THE DANCE FLOOR
SCANNING
let central = CBCentralManager(delegate: self, queue: nil)
let serviceUUID = CBUUID(string: "ABC00001-A0B1-FFFF-1234-1A2B3DD11001")
// Set the delegate (someDelegate: CBCentralManagerDelegate)
central.delegate = someDelegate
// Start Scanning
central.scanForPeripherals(withServices: [serviceUUID], options: nil)
2 - POTENTIAL PARTNERS
DISCOVERY
var peripheral: CBPeripheral?
// CBCentralManagerDelegate discovery handler
func centralManager(_ central: CBCentralManager,
didDiscover peripheral: CBPeripheral,
advertisementData: [String : Any], rssi RSSI: NSNumber) {
if thisIsMy(peripheral) { // Check before connecting
central.stopScan() // Please do!
self.peripheral = peripheral // Keep a strong ref!
// Step 3 here
}
}
3 - WANNA DANCE?
CONNECTION
// central: CBCentralManager
// peripheral: CBPeripheral
central.connect(peripheral, options: nil)
FAILURE HANDLER
// CBCentralManagerDelegate method
func centralManager(_ central: CBCentralManager,
didFailToConnect peripheral: CBPeripheral,
error: Error?) {
// Recovery
// Notify users
// ...
// Give up? !
}
CONNECTION HANDLER
// CBCentralManagerDelegate method
func centralManager(_ central: CBCentralManager,
didConnect peripheral: CBPeripheral) {
// Start dancing!
// !"
}
UNENCRYPTED CHARACTERISTICS
No BLE encryption on the device side
> You can interface with the device immediately
> It will go back to advertising mode when disconnected
from the app
> It will need a new scan to be found (or a direct
connection via UUID)
ENCRYPTED
CHARACTERISTICS
Manual interaction required
ENCRYPTED
CHARACTERISTICS
Saves pairing at the OS level
(see Bluetooth settings)
ENCRYPTED CHARACTERISTICS
> The device reconnects automatically to iOS
> You'll need to retrieve it from known peripherals:
let peripherals = central
.retrieveConnectedPeripherals(withServices: [serviceUUID])
ENCRYPTED CHARACTERISTICS
The pairing can be "delicate":
> You can't retrieve the device anymore
> You can't connect to the retrieved device
> You can't exchange data with the device
You can't solve this with code:
> Soft solution: kill your app, forget device
> Hard solution: restart your phone
AFTER CONNECTING
peripheral.discoverServices([serviceUUID])
peripheral.discoverCharacteristics([charUUID], for: service)
peripheral.setNotifyValue(true, for: characteristic)
// In your CBPeripheralDelegate
func peripheral(_ peripheral: CBPeripheral,
didUpdateValueFor characteristic: CBCharacteristic,
error: Error?) {
if let data = characteristic.value { // data: Data
// Enjoy your data! !
}
}
WHAT NOW?
THOU SHALT HAVE A SHARED PROTOCOL
> Available services and characteristics
> Commands and command format
> Response format (how to parse bytes)
PROTOCOL EXAMPLE
// Command Characteristic
let charUUID = CBUUID(string: "ABC00001-A0B1-FFFF-1234-1A2B3DD11002")
let char: CBCharacteristic // We have already discovered this
// Available Commands
enum CommandId: UInt8 {
case test // 0
case readTemp // 1
case writeTemp // 2
}
// Issuing the Read Temperature command
let readTempData = Data(bytes: [CommandId.readTemp.rawValue])
peripheral.writeValue(readTempData, for: char, type: .withResponse)
PARSING THE RESPONSE
PARSING THE RESPONSE
// Inside didUpdateValueForCharacteristic handler
const uint8_t *data = (uint8_t *)[characteristic.value bytes];
uint8_t packetID = data[0];
if (packetID == TEMP_RESPONSE_ID) { // ID for the temperature response packet
uint32_t timestamp;
memcpy(&timestamp, &data[1], 4);
int8_t temperature;
memcpy(&temperature, &data[5], 1);
// Work with temp value & timestamp
}
OBJ-C? !
MESSING WITH THE PROTOCOL?
// V1
enum CommandId: UInt8 {
case test // 0
case readTemp // 1
case writeTemp // 2
}
// V2
enum CommandId: UInt8 {
case test // 0
case reset // 1 <=== NEW COMMAND HERE! !
case readTemp // 2
case writeTemp // 3
}
DEVICE RESET!
RECAP
> We know how to discover our custom wearable
> We know how to connect and pair it with iOS
> We know how to subscribe to its characteristics
> We know how to parse device data
> WE KNOW HOW TO DANCE! !"
CONNECTION STABILITY
CONNECTION STABILITY
> Your wearable device measures critical data
> It needs to be always connected
> The background is a completely different story:
For iOS apps, it is crucial to know whether your app is
running in the foreground or the background. An app must
behave differently in the background than in the foreground,
because system resources are more limited on iOS devices
BACKGROUND MODE
STATE PRESERVATION AND RESTORATION
let queue = DispatchQueue(label: "mySerialDispatchQueue")
let options = [CBCentralManagerOptionRestoreIdentifierKey:
"myCentralManagerIdentifier"]
let centralManager = CBCentralManager(delegate: self,
queue: queue,
options: options)
AS A RESULT...
> Your app will continue working in the background
> If your app is suspended, the system will track:
> the services it was scanning for
> the peripherals it was connected / connecting to
> the characteristics it was subscribed to
> Related BLE events will make the system relaunch your
app in the background
ERROR #1
ASSUMING APP RELAUNCH WILL ALWAYS WORK
If the users kills your app, there's no coming back from it
SOLUTION
✅ Let your users know
ERROR #2
ASSUMING THE BACKGROUND WILL JUST WORK
If the BLE connection is dropped in the background and the app gets suspended, it
won't be relaunched
SOLUTION
✅ Try to reconnect immediately
✅ If you need to do some processing, start a background task
UIApplication.shared
.beginBackgroundTask(expirationHandler: (() -> Void)?)
ERROR #3
ASSUMING YOU HAVE INFINITE TIME
"10 second" rule: each BLE event renews your background time for about 10
seconds.
SOLUTION
✅ Have your wearable ping your app more often than every 10 seconds
✅ Start a background task if you miss a packet
ERROR #4
TRUSTING IOS CHANGELOGS
iOS updates break the Bluetooth in subtle ways
SOLUTION
✅ TEST, TEST, TEST each iOS release
TESTING WITH
WEARABLES
BASIC TESTING
> Write your unit tests
> Do your TDD
> Automate your tests
> Maybe add some UI testing
> Use continuous integration
> Involve your QA engineer colleagues
...WITH WEARABLES?
> Focus on full system integration
> Involve all the components
> Track exactly what you're testing: HW revision, FW
version, OS, ...
> Have clearly defined test scenarios and store test
reports
> Sadly, the simulator won't work here
THE HUMAN SIMULATOR
YOU'RE NOT ALONE IN THIS
Make sure these people are your best friends:
> FW developer: custom FW, insight about the device...
> QA engineer: test scenarios, collecting reports...
> Your colleagues: will run around with you !
SAMPLE TEST SCENARIO
> Custom FW that simulates disconnections
> Move around the room, app in foreground, see what
happens
> Send the app to the background, see if it dies on you or
if it recovers the connection
> Check what happened (HW + SW)
> Repeat this on every FW / App / OS update!
LOGGING AND MONITORING
> NEVER forget about logging
> Remote logging (in the cloud)
> Via the app (no internet access on device)
> Session reconstruction from start to finish
A CASE SOLVED BY
LOGGING
REMOTE MAINTENANCE
REMOTE COMMANDS
// Note: this is only a partial implementation
enum RemoteCommandId: Int {
case ping = 0
case checkStatus = 1
case resetDevice = 2
// ...
}
REMOTE COMMANDS
struct RemoteCommand {
let id: RemoteCommandId
let delay: Int
let params: [String: Any]?
// ...
}
REMOTE COMMANDS
struct RemoteCommand {
// ...
static func parseRemoteCommand(userInfo: [AnyHashable : Any])
-> (Bool, RemoteCommand?) {
if let cmdIdInt = userInfo["command"] as? Int,
let cmdId = RemoteCommandId(rawValue: cmdIdInt) {
let delay = (userInfo["delay"] as? Int) ?? 0
let params = userInfo["parameters"] as? [String: Any]
let cmd = RemoteCommand(id: cmdId, delay: delay, params: params)
return (true, cmd)
}
return (false, nil)
}
SILENT NOTIFICATIONS
{
"aps" : {
"content-available" : 1
},
"command" : 1, // Check Status
"delay" : 0 // Now,
"parameters": [
// Your custom parameters
]
}
RECEIVING AND PARSING
let executor = RemoteExecutor()
func application(_ application: UIApplication,
didReceiveRemoteNotification userInfo: [AnyHashable : Any],
fetchCompletionHandler completionHandler:
@escaping (UIBackgroundFetchResult) -> Void) {
// Check if this is a remote command
let (isCommand, command) = RemoteCommand.parseRemoteCommand(userInfo: userInfo)
if isCommand {
executor.run(command: command)
}
completionHandler(.noData)
}
EXECUTING
// Note: this is only a partial implementation
class RemoteExecutor {
let peripheral: CBPeripheral
let char: CBCharacteristic
func run(command: RemoteCommand) {
switch command.id {
case .checkStatus:
// Turn command into Data
let cmdData = Data(bytes: [CommandId.checkStatus.rawValue])
peripheral.writeValue(cmdData, for: char, type: .withResponse)
default:
break
}
}
}
RECAP
> Know your BLE basics
> Use encrypted chars, but know that the iOS BLE stack can get stuck
> Don't be afraid to resort to ObjC
> Keep your connection stable, especially in the background
> Always test at the system-integration level
> Don't trust iOS updates
> Flood the cloud with logs
> Implement remote maintenance
THANK YOU!
ALBERTO GUARINO
@albeguarino

Mais conteúdo relacionado

Semelhante a Alberto Guarino "When iPhones and Wearables Dance the Bluetooth Dance: Lessons Learned"

Fault tolerance techniques tsp
Fault tolerance techniques tspFault tolerance techniques tsp
Fault tolerance techniques tsp
Pradeep Kumar TS
 
Smart homes using android
Smart homes using androidSmart homes using android
Smart homes using android
Droidcon Berlin
 
DEFCON 18- These Aren't the Permissions You're Looking For
DEFCON 18- These Aren't the Permissions You're Looking ForDEFCON 18- These Aren't the Permissions You're Looking For
DEFCON 18- These Aren't the Permissions You're Looking For
Michael Scovetta
 
Configuring ee (enterprise extender) between two ibm system i systems tech ...
Configuring ee (enterprise extender) between two ibm system i systems   tech ...Configuring ee (enterprise extender) between two ibm system i systems   tech ...
Configuring ee (enterprise extender) between two ibm system i systems tech ...
jbharo
 

Semelhante a Alberto Guarino "When iPhones and Wearables Dance the Bluetooth Dance: Lessons Learned" (20)

Parrot Drones Hijacking
Parrot Drones HijackingParrot Drones Hijacking
Parrot Drones Hijacking
 
Itsp documentation quadcopter flight controller based on kalman filters
Itsp documentation   quadcopter flight controller based on kalman filtersItsp documentation   quadcopter flight controller based on kalman filters
Itsp documentation quadcopter flight controller based on kalman filters
 
Fault tolerance techniques tsp
Fault tolerance techniques tspFault tolerance techniques tsp
Fault tolerance techniques tsp
 
iOS Bluetooth Low Energy (BLE) Remote Robot Interface
iOS Bluetooth Low Energy (BLE) Remote Robot InterfaceiOS Bluetooth Low Energy (BLE) Remote Robot Interface
iOS Bluetooth Low Energy (BLE) Remote Robot Interface
 
Synack Shakacon OSX Malware Persistence
Synack Shakacon OSX Malware PersistenceSynack Shakacon OSX Malware Persistence
Synack Shakacon OSX Malware Persistence
 
Smart homes using android
Smart homes using androidSmart homes using android
Smart homes using android
 
Taming event-driven software via formal verification
Taming event-driven software via formal verificationTaming event-driven software via formal verification
Taming event-driven software via formal verification
 
DEFCON 18- These Aren't the Permissions You're Looking For
DEFCON 18- These Aren't the Permissions You're Looking ForDEFCON 18- These Aren't the Permissions You're Looking For
DEFCON 18- These Aren't the Permissions You're Looking For
 
Embedded software development using BDD
Embedded software development using BDDEmbedded software development using BDD
Embedded software development using BDD
 
Android app (Presentation v2)
Android app (Presentation v2)Android app (Presentation v2)
Android app (Presentation v2)
 
Droidcon Turin 2015 - Android wear sdk introduction
Droidcon Turin 2015 - Android wear sdk introductionDroidcon Turin 2015 - Android wear sdk introduction
Droidcon Turin 2015 - Android wear sdk introduction
 
Android wear SDK introduction
Android wear SDK introductionAndroid wear SDK introduction
Android wear SDK introduction
 
A Computer Based Artificial Neural Network Controller with Interactive Audito...
A Computer Based Artificial Neural Network Controller with Interactive Audito...A Computer Based Artificial Neural Network Controller with Interactive Audito...
A Computer Based Artificial Neural Network Controller with Interactive Audito...
 
Backtrack Manual Part4
Backtrack Manual Part4Backtrack Manual Part4
Backtrack Manual Part4
 
WPSDK 7.1.1
WPSDK 7.1.1WPSDK 7.1.1
WPSDK 7.1.1
 
Configuring ee (enterprise extender) between two ibm system i systems tech ...
Configuring ee (enterprise extender) between two ibm system i systems   tech ...Configuring ee (enterprise extender) between two ibm system i systems   tech ...
Configuring ee (enterprise extender) between two ibm system i systems tech ...
 
Positive Hack Days. Pavlov. Network Infrastructure Security Assessment
Positive Hack Days. Pavlov. Network Infrastructure Security AssessmentPositive Hack Days. Pavlov. Network Infrastructure Security Assessment
Positive Hack Days. Pavlov. Network Infrastructure Security Assessment
 
Penetrating Windows 8 with syringe utility
Penetrating Windows 8 with syringe utilityPenetrating Windows 8 with syringe utility
Penetrating Windows 8 with syringe utility
 
11 background tasks and multitasking
11   background tasks and multitasking11   background tasks and multitasking
11 background tasks and multitasking
 
IoT: Internet of Things with Python
IoT: Internet of Things with PythonIoT: Internet of Things with Python
IoT: Internet of Things with Python
 

Mais de IT Event

Mais de IT Event (20)

Denis Radin - "Applying NASA coding guidelines to JavaScript or airspace is c...
Denis Radin - "Applying NASA coding guidelines to JavaScript or airspace is c...Denis Radin - "Applying NASA coding guidelines to JavaScript or airspace is c...
Denis Radin - "Applying NASA coding guidelines to JavaScript or airspace is c...
 
Sara Harkousse - "Web Components: It's all rainbows and unicorns! Is it?"
Sara Harkousse - "Web Components: It's all rainbows and unicorns! Is it?"Sara Harkousse - "Web Components: It's all rainbows and unicorns! Is it?"
Sara Harkousse - "Web Components: It's all rainbows and unicorns! Is it?"
 
Max Voloshin - "Organization of frontend development for products with micros...
Max Voloshin - "Organization of frontend development for products with micros...Max Voloshin - "Organization of frontend development for products with micros...
Max Voloshin - "Organization of frontend development for products with micros...
 
Roman Romanovsky, Sergey Rak - "JavaScript в IoT "
Roman Romanovsky, Sergey Rak - "JavaScript в IoT "Roman Romanovsky, Sergey Rak - "JavaScript в IoT "
Roman Romanovsky, Sergey Rak - "JavaScript в IoT "
 
Konstantin Krivlenia - "Continuous integration for frontend"
Konstantin Krivlenia - "Continuous integration for frontend"Konstantin Krivlenia - "Continuous integration for frontend"
Konstantin Krivlenia - "Continuous integration for frontend"
 
Illya Klymov - "Vue.JS: What did I swap React for in 2017 and why?"
Illya Klymov - "Vue.JS: What did I swap React for in 2017 and why?"Illya Klymov - "Vue.JS: What did I swap React for in 2017 and why?"
Illya Klymov - "Vue.JS: What did I swap React for in 2017 and why?"
 
Evgeny Gusev - "A circular firing squad: How technologies drag frontend down"
Evgeny Gusev - "A circular firing squad: How technologies drag frontend down"Evgeny Gusev - "A circular firing squad: How technologies drag frontend down"
Evgeny Gusev - "A circular firing squad: How technologies drag frontend down"
 
Vladimir Grinenko - "Dependencies in component web done right"
Vladimir Grinenko - "Dependencies in component web done right"Vladimir Grinenko - "Dependencies in component web done right"
Vladimir Grinenko - "Dependencies in component web done right"
 
Dmitry Bartalevich - "How to train your WebVR"
Dmitry Bartalevich - "How to train your WebVR"Dmitry Bartalevich - "How to train your WebVR"
Dmitry Bartalevich - "How to train your WebVR"
 
Aleksey Bogachuk - "Offline Second"
Aleksey Bogachuk - "Offline Second"Aleksey Bogachuk - "Offline Second"
Aleksey Bogachuk - "Offline Second"
 
James Allardice - "Building a better login with the credential management API"
James Allardice - "Building a better login with the credential management API"James Allardice - "Building a better login with the credential management API"
James Allardice - "Building a better login with the credential management API"
 
Fedor Skuratov "Dark Social: as messengers change the market of social media ...
Fedor Skuratov "Dark Social: as messengers change the market of social media ...Fedor Skuratov "Dark Social: as messengers change the market of social media ...
Fedor Skuratov "Dark Social: as messengers change the market of social media ...
 
Андрей Зайчиков "Архитектура распределенных кластеров NoSQL на AWS"
Андрей Зайчиков "Архитектура распределенных кластеров NoSQL на AWS"Андрей Зайчиков "Архитектура распределенных кластеров NoSQL на AWS"
Андрей Зайчиков "Архитектура распределенных кластеров NoSQL на AWS"
 
Алексей Рагозин "Java и linux борьба за микросекунды"
Алексей Рагозин "Java и linux борьба за микросекунды"Алексей Рагозин "Java и linux борьба за микросекунды"
Алексей Рагозин "Java и linux борьба за микросекунды"
 
Volodymyr Lyubinets "Introduction to big data processing with Apache Spark"
Volodymyr Lyubinets "Introduction to big data processing with Apache Spark"Volodymyr Lyubinets "Introduction to big data processing with Apache Spark"
Volodymyr Lyubinets "Introduction to big data processing with Apache Spark"
 
Наш ответ Uber’у
Наш ответ Uber’уНаш ответ Uber’у
Наш ответ Uber’у
 
Александр Крашенинников "Hadoop High Availability: опыт Badoo"
Александр Крашенинников "Hadoop High Availability: опыт Badoo"Александр Крашенинников "Hadoop High Availability: опыт Badoo"
Александр Крашенинников "Hadoop High Availability: опыт Badoo"
 
Leonid Vasilyev "Building, deploying and running production code at Dropbox"
Leonid Vasilyev  "Building, deploying and running production code at Dropbox"Leonid Vasilyev  "Building, deploying and running production code at Dropbox"
Leonid Vasilyev "Building, deploying and running production code at Dropbox"
 
Анатолий Пласковский "Миллионы карточных платежей за месяц, или как потерять ...
Анатолий Пласковский "Миллионы карточных платежей за месяц, или как потерять ...Анатолий Пласковский "Миллионы карточных платежей за месяц, или как потерять ...
Анатолий Пласковский "Миллионы карточных платежей за месяц, или как потерять ...
 
Mete Atamel "Resilient microservices with kubernetes"
Mete Atamel "Resilient microservices with kubernetes"Mete Atamel "Resilient microservices with kubernetes"
Mete Atamel "Resilient microservices with kubernetes"
 

Último

Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024
Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024
Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024
Victor Rentea
 
Finding Java's Hidden Performance Traps @ DevoxxUK 2024
Finding Java's Hidden Performance Traps @ DevoxxUK 2024Finding Java's Hidden Performance Traps @ DevoxxUK 2024
Finding Java's Hidden Performance Traps @ DevoxxUK 2024
Victor Rentea
 

Último (20)

Apidays New York 2024 - APIs in 2030: The Risk of Technological Sleepwalk by ...
Apidays New York 2024 - APIs in 2030: The Risk of Technological Sleepwalk by ...Apidays New York 2024 - APIs in 2030: The Risk of Technological Sleepwalk by ...
Apidays New York 2024 - APIs in 2030: The Risk of Technological Sleepwalk by ...
 
Rising Above_ Dubai Floods and the Fortitude of Dubai International Airport.pdf
Rising Above_ Dubai Floods and the Fortitude of Dubai International Airport.pdfRising Above_ Dubai Floods and the Fortitude of Dubai International Airport.pdf
Rising Above_ Dubai Floods and the Fortitude of Dubai International Airport.pdf
 
Polkadot JAM Slides - Token2049 - By Dr. Gavin Wood
Polkadot JAM Slides - Token2049 - By Dr. Gavin WoodPolkadot JAM Slides - Token2049 - By Dr. Gavin Wood
Polkadot JAM Slides - Token2049 - By Dr. Gavin Wood
 
DBX First Quarter 2024 Investor Presentation
DBX First Quarter 2024 Investor PresentationDBX First Quarter 2024 Investor Presentation
DBX First Quarter 2024 Investor Presentation
 
Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024
Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024
Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024
 
Exploring Multimodal Embeddings with Milvus
Exploring Multimodal Embeddings with MilvusExploring Multimodal Embeddings with Milvus
Exploring Multimodal Embeddings with Milvus
 
Platformless Horizons for Digital Adaptability
Platformless Horizons for Digital AdaptabilityPlatformless Horizons for Digital Adaptability
Platformless Horizons for Digital Adaptability
 
Vector Search -An Introduction in Oracle Database 23ai.pptx
Vector Search -An Introduction in Oracle Database 23ai.pptxVector Search -An Introduction in Oracle Database 23ai.pptx
Vector Search -An Introduction in Oracle Database 23ai.pptx
 
Elevate Developer Efficiency & build GenAI Application with Amazon Q​
Elevate Developer Efficiency & build GenAI Application with Amazon Q​Elevate Developer Efficiency & build GenAI Application with Amazon Q​
Elevate Developer Efficiency & build GenAI Application with Amazon Q​
 
Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...
Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...
Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...
 
DEV meet-up UiPath Document Understanding May 7 2024 Amsterdam
DEV meet-up UiPath Document Understanding May 7 2024 AmsterdamDEV meet-up UiPath Document Understanding May 7 2024 Amsterdam
DEV meet-up UiPath Document Understanding May 7 2024 Amsterdam
 
Finding Java's Hidden Performance Traps @ DevoxxUK 2024
Finding Java's Hidden Performance Traps @ DevoxxUK 2024Finding Java's Hidden Performance Traps @ DevoxxUK 2024
Finding Java's Hidden Performance Traps @ DevoxxUK 2024
 
ICT role in 21st century education and its challenges
ICT role in 21st century education and its challengesICT role in 21st century education and its challenges
ICT role in 21st century education and its challenges
 
Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...
 
EMPOWERMENT TECHNOLOGY GRADE 11 QUARTER 2 REVIEWER
EMPOWERMENT TECHNOLOGY GRADE 11 QUARTER 2 REVIEWEREMPOWERMENT TECHNOLOGY GRADE 11 QUARTER 2 REVIEWER
EMPOWERMENT TECHNOLOGY GRADE 11 QUARTER 2 REVIEWER
 
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemkeProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
 
MS Copilot expands with MS Graph connectors
MS Copilot expands with MS Graph connectorsMS Copilot expands with MS Graph connectors
MS Copilot expands with MS Graph connectors
 
"I see eyes in my soup": How Delivery Hero implemented the safety system for ...
"I see eyes in my soup": How Delivery Hero implemented the safety system for ..."I see eyes in my soup": How Delivery Hero implemented the safety system for ...
"I see eyes in my soup": How Delivery Hero implemented the safety system for ...
 
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
 
Introduction to Multilingual Retrieval Augmented Generation (RAG)
Introduction to Multilingual Retrieval Augmented Generation (RAG)Introduction to Multilingual Retrieval Augmented Generation (RAG)
Introduction to Multilingual Retrieval Augmented Generation (RAG)
 

Alberto Guarino "When iPhones and Wearables Dance the Bluetooth Dance: Lessons Learned"

  • 1.
  • 2.
  • 3. TODAY'S ADVENTURE > Wearables & My Story > Coding with BLE on iOS > The importance of protocols > Connection stability > Testing with wearables > Logging & monitoring > Remote maintenance > The End
  • 5.
  • 6.
  • 7.
  • 8.
  • 9. TODAY A WEARABLE WILL BE > A piece of HW that sits somewhere on your body > Easy to carry with you > Provides useful data via sensors > Uses BLE for data exchange with the outside world > In need of an app to communicate with > Custom: you know / have power on the internals
  • 12.
  • 13.
  • 14.
  • 16. CORE BLUETOOTH The framework is an abstraction of the Bluetooth 4.0 specification for use with low energy devices. That said, it hides many of the low-level details of the specification from you, the developer, making it much easier for you to develop apps that interact with Bluetooth low energy devices. — Apple Docs
  • 18. PERIPHERAL > Has data > Advertises its presence > It's our wearable > CBPeripheral
  • 19. PERIPHERAL > It exposes services > Services contain characteristics > Characteristics allow data exchange > You can define your own
  • 20.
  • 21.
  • 22. CENTRAL > Wants data > Scans for advertising peripherals > Connects to peripherals > Explores services and characteristics > Reads, writes, is notified by characteristics > It's (part of) our app > CBCentralManager
  • 24. 1 - THE DANCE FLOOR
  • 25. SCANNING let central = CBCentralManager(delegate: self, queue: nil) let serviceUUID = CBUUID(string: "ABC00001-A0B1-FFFF-1234-1A2B3DD11001") // Set the delegate (someDelegate: CBCentralManagerDelegate) central.delegate = someDelegate // Start Scanning central.scanForPeripherals(withServices: [serviceUUID], options: nil)
  • 26. 2 - POTENTIAL PARTNERS
  • 27. DISCOVERY var peripheral: CBPeripheral? // CBCentralManagerDelegate discovery handler func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) { if thisIsMy(peripheral) { // Check before connecting central.stopScan() // Please do! self.peripheral = peripheral // Keep a strong ref! // Step 3 here } }
  • 28. 3 - WANNA DANCE?
  • 29. CONNECTION // central: CBCentralManager // peripheral: CBPeripheral central.connect(peripheral, options: nil)
  • 30.
  • 31. FAILURE HANDLER // CBCentralManagerDelegate method func centralManager(_ central: CBCentralManager, didFailToConnect peripheral: CBPeripheral, error: Error?) { // Recovery // Notify users // ... // Give up? ! }
  • 32.
  • 33. CONNECTION HANDLER // CBCentralManagerDelegate method func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) { // Start dancing! // !" }
  • 34. UNENCRYPTED CHARACTERISTICS No BLE encryption on the device side > You can interface with the device immediately > It will go back to advertising mode when disconnected from the app > It will need a new scan to be found (or a direct connection via UUID)
  • 36. ENCRYPTED CHARACTERISTICS Saves pairing at the OS level (see Bluetooth settings)
  • 37. ENCRYPTED CHARACTERISTICS > The device reconnects automatically to iOS > You'll need to retrieve it from known peripherals: let peripherals = central .retrieveConnectedPeripherals(withServices: [serviceUUID])
  • 38. ENCRYPTED CHARACTERISTICS The pairing can be "delicate": > You can't retrieve the device anymore > You can't connect to the retrieved device > You can't exchange data with the device You can't solve this with code: > Soft solution: kill your app, forget device > Hard solution: restart your phone
  • 39. AFTER CONNECTING peripheral.discoverServices([serviceUUID]) peripheral.discoverCharacteristics([charUUID], for: service) peripheral.setNotifyValue(true, for: characteristic) // In your CBPeripheralDelegate func peripheral(_ peripheral: CBPeripheral, didUpdateValueFor characteristic: CBCharacteristic, error: Error?) { if let data = characteristic.value { // data: Data // Enjoy your data! ! } }
  • 41. THOU SHALT HAVE A SHARED PROTOCOL > Available services and characteristics > Commands and command format > Response format (how to parse bytes)
  • 42. PROTOCOL EXAMPLE // Command Characteristic let charUUID = CBUUID(string: "ABC00001-A0B1-FFFF-1234-1A2B3DD11002") let char: CBCharacteristic // We have already discovered this // Available Commands enum CommandId: UInt8 { case test // 0 case readTemp // 1 case writeTemp // 2 } // Issuing the Read Temperature command let readTempData = Data(bytes: [CommandId.readTemp.rawValue]) peripheral.writeValue(readTempData, for: char, type: .withResponse)
  • 44. PARSING THE RESPONSE // Inside didUpdateValueForCharacteristic handler const uint8_t *data = (uint8_t *)[characteristic.value bytes]; uint8_t packetID = data[0]; if (packetID == TEMP_RESPONSE_ID) { // ID for the temperature response packet uint32_t timestamp; memcpy(&timestamp, &data[1], 4); int8_t temperature; memcpy(&temperature, &data[5], 1); // Work with temp value & timestamp }
  • 46. MESSING WITH THE PROTOCOL? // V1 enum CommandId: UInt8 { case test // 0 case readTemp // 1 case writeTemp // 2 } // V2 enum CommandId: UInt8 { case test // 0 case reset // 1 <=== NEW COMMAND HERE! ! case readTemp // 2 case writeTemp // 3 }
  • 48. RECAP > We know how to discover our custom wearable > We know how to connect and pair it with iOS > We know how to subscribe to its characteristics > We know how to parse device data > WE KNOW HOW TO DANCE! !"
  • 50. CONNECTION STABILITY > Your wearable device measures critical data > It needs to be always connected > The background is a completely different story: For iOS apps, it is crucial to know whether your app is running in the foreground or the background. An app must behave differently in the background than in the foreground, because system resources are more limited on iOS devices
  • 52. STATE PRESERVATION AND RESTORATION let queue = DispatchQueue(label: "mySerialDispatchQueue") let options = [CBCentralManagerOptionRestoreIdentifierKey: "myCentralManagerIdentifier"] let centralManager = CBCentralManager(delegate: self, queue: queue, options: options)
  • 53. AS A RESULT... > Your app will continue working in the background > If your app is suspended, the system will track: > the services it was scanning for > the peripherals it was connected / connecting to > the characteristics it was subscribed to > Related BLE events will make the system relaunch your app in the background
  • 54. ERROR #1 ASSUMING APP RELAUNCH WILL ALWAYS WORK If the users kills your app, there's no coming back from it SOLUTION ✅ Let your users know
  • 55. ERROR #2 ASSUMING THE BACKGROUND WILL JUST WORK If the BLE connection is dropped in the background and the app gets suspended, it won't be relaunched SOLUTION ✅ Try to reconnect immediately ✅ If you need to do some processing, start a background task
  • 57. ERROR #3 ASSUMING YOU HAVE INFINITE TIME "10 second" rule: each BLE event renews your background time for about 10 seconds. SOLUTION ✅ Have your wearable ping your app more often than every 10 seconds ✅ Start a background task if you miss a packet
  • 58. ERROR #4 TRUSTING IOS CHANGELOGS iOS updates break the Bluetooth in subtle ways SOLUTION ✅ TEST, TEST, TEST each iOS release
  • 60. BASIC TESTING > Write your unit tests > Do your TDD > Automate your tests > Maybe add some UI testing > Use continuous integration > Involve your QA engineer colleagues
  • 61. ...WITH WEARABLES? > Focus on full system integration > Involve all the components > Track exactly what you're testing: HW revision, FW version, OS, ... > Have clearly defined test scenarios and store test reports > Sadly, the simulator won't work here
  • 63. YOU'RE NOT ALONE IN THIS Make sure these people are your best friends: > FW developer: custom FW, insight about the device... > QA engineer: test scenarios, collecting reports... > Your colleagues: will run around with you !
  • 64. SAMPLE TEST SCENARIO > Custom FW that simulates disconnections > Move around the room, app in foreground, see what happens > Send the app to the background, see if it dies on you or if it recovers the connection > Check what happened (HW + SW) > Repeat this on every FW / App / OS update!
  • 65. LOGGING AND MONITORING > NEVER forget about logging > Remote logging (in the cloud) > Via the app (no internet access on device) > Session reconstruction from start to finish
  • 66. A CASE SOLVED BY LOGGING
  • 68. REMOTE COMMANDS // Note: this is only a partial implementation enum RemoteCommandId: Int { case ping = 0 case checkStatus = 1 case resetDevice = 2 // ... }
  • 69. REMOTE COMMANDS struct RemoteCommand { let id: RemoteCommandId let delay: Int let params: [String: Any]? // ... }
  • 70. REMOTE COMMANDS struct RemoteCommand { // ... static func parseRemoteCommand(userInfo: [AnyHashable : Any]) -> (Bool, RemoteCommand?) { if let cmdIdInt = userInfo["command"] as? Int, let cmdId = RemoteCommandId(rawValue: cmdIdInt) { let delay = (userInfo["delay"] as? Int) ?? 0 let params = userInfo["parameters"] as? [String: Any] let cmd = RemoteCommand(id: cmdId, delay: delay, params: params) return (true, cmd) } return (false, nil) }
  • 71. SILENT NOTIFICATIONS { "aps" : { "content-available" : 1 }, "command" : 1, // Check Status "delay" : 0 // Now, "parameters": [ // Your custom parameters ] }
  • 72. RECEIVING AND PARSING let executor = RemoteExecutor() func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) { // Check if this is a remote command let (isCommand, command) = RemoteCommand.parseRemoteCommand(userInfo: userInfo) if isCommand { executor.run(command: command) } completionHandler(.noData) }
  • 73. EXECUTING // Note: this is only a partial implementation class RemoteExecutor { let peripheral: CBPeripheral let char: CBCharacteristic func run(command: RemoteCommand) { switch command.id { case .checkStatus: // Turn command into Data let cmdData = Data(bytes: [CommandId.checkStatus.rawValue]) peripheral.writeValue(cmdData, for: char, type: .withResponse) default: break } } }
  • 74. RECAP > Know your BLE basics > Use encrypted chars, but know that the iOS BLE stack can get stuck > Don't be afraid to resort to ObjC > Keep your connection stable, especially in the background > Always test at the system-integration level > Don't trust iOS updates > Flood the cloud with logs > Implement remote maintenance