Le Bluetooth a un talent rare : vous faire briller pendant la démo et transpirer sur le terrain. Se connecter au capteur posé sur votre bureau prend cinq minutes ; le garder connecté au sous-sol, après que quelqu'un a appuyé sur le bouton reset « pour voir », prend le reste du projet. Alors quand Google et Apple touchent la même année exactement ces recoins-là, avec Android 17 le 16 juin et iOS 27 le 14 septembre, ça mérite un café, même si rien de tout cela n'a approché la scène d'une keynote.
Le bouton reset, ce grand classique
Vous connaissez la scène. Quelqu'un appuie sur reset, l'appareil oublie ses clés de chiffrement, le téléphone se souvient encore des siennes, et les deux se regardent comme deux anciens camarades de classe qui ne se reconnaissent plus à une soirée. Depuis Android 16, votre app l'apprend par ACTION_KEY_MISSING, et le remède consistait jusqu'ici à envoyer l'utilisateur dans les Réglages pour dissocier puis réassocier l'appareil, généralement pendant qu'il écrit à votre support en majuscules.
Android 17 ajoute la réassociation autonome, et elle concerne toutes les apps, quelle que soit leur cible. Quand une association est perdue, le système essaie de la reconstruire en arrière-plan et demande à l'utilisateur de confirmer dans sa propre boîte de dialogue, ce qui revient à reconnaître, enfin, que « allez bidouiller dans les Réglages » n'a jamais été une expérience utilisateur. Trois détails comptent pour votre code. Les nouvelles clés ne remplacent les anciennes que si la nouvelle connexion est au moins aussi sûre que l'association précédente, donc un appareil imposteur ne peut pas se glisser avec une sécurité au rabais. ACTION_KEY_MISSING n'est plus diffusé que si cette tentative échoue : votre écran d'erreur reste, il prend juste plus de jours de congé. Et la demande d'association transporte désormais un extra EXTRA_PAIRING_CONTEXT : quand il vaut PAIRING_CONTEXT_REPAIRING, c'est le système qui recolle les morceaux et non une toute nouvelle association, et votre app peut afficher « reconnexion de votre capteur » plutôt qu'un message qui ressemble à la fin du monde.
Le schéma joue deux fois la même panne. Sous Android 16, le capteur réinitialisé fait échouer la connexion chiffrée, l'app reçoit ACTION_KEY_MISSING, et l'utilisateur doit dissocier puis réassocier l'appareil à la main dans les Réglages. Sous Android 17, le système envoie une demande d'association avec le contexte de réassociation, l'utilisateur confirme dans une boîte de dialogue, les nouvelles clés ne remplacent les anciennes que si la sécurité est au moins égale, et ACTION_KEY_MISSING n'arrive que si cette tentative échoue.
Google estime que la plupart des apps n'ont rien à changer, mais que les fabricants d'appareils et les équipes qui font l'app compagnon doivent vérifier que le matériel comme l'app encaissent proprement ce changement d'association. Pour une fois, le test est d'une simplicité réjouissante : supprimez l'association sur l'appareil lui-même, ou dissociez-le dans les Réglages, et regardez ce que fait votre app. Pop-corn facultatif.
La boucle qui lit du vide, très vite
Le second changement ne s'applique qu'une fois que votre app cible Android 17 (API 37), ce que Google Play vous demandera tôt ou tard, comme pour l'API 36. Si vous utilisez des sockets Bluetooth classiques (RFCOMM, le lien façon port série que beaucoup d'appareils industriels et médicaux parlent encore avec fierté), read() sur le flux d'entrée du socket renvoie maintenant -1 quand le socket est fermé ou que la connexion tombe, ce que le contrat d'InputStream annonce depuis à peu près l'aube de Java. Un code qui attendait une IOException pour sortir de la boucle va donc tourner sur -1, à lire du vide à pleine vitesse en réchauffant gentiment la poche de l'utilisateur. La correction tient en une ligne, et autant l'écrire aujourd'hui pour que la boucle se tienne bien sur toutes les versions :
suspend fun readFrames(socket: BluetoothSocket, onFrame: (ByteArray) -> Unit) =
withContext(Dispatchers.IO) {
val input = socket.inputStream
val buffer = ByteArray(1024)
try {
while (isActive) {
val count = input.read(buffer)
if (count == -1) break // Android 17 : le lien est coupé, sans exception
onFrame(buffer.copyOf(count))
}
} catch (e: IOException) {
// Les versions plus anciennes, et les vraies erreurs d'E/S, arrivent ici
} finally {
socket.close()
}
}
Pendant ce temps, l'iPhone apprend à mesurer
Apple, fidèle à elle-même, a choisi le jouet le plus brillant : Core Bluetooth prend désormais en charge le Bluetooth Channel Sounding, présenté dans la session WWDC26 Find your accessory with Bluetooth Channel Sounding. Jusqu'ici, deviner la distance d'un accessoire voulait dire lire la force du signal (le RSSI), à peu près aussi précis que d'estimer sa vitesse au bruit du moteur. Avec Channel Sounding, l'iPhone envoie des tonalités sur les canaux de la bande 2,4 GHz, l'accessoire les renvoie, et le téléphone calcule la distance d'après la façon dont elles reviennent. On vérifie la prise en charge avec CBCentralManager.supportsFeatures(.channelSounding), on lance une session sur un périphérique connecté, et les résultats arrivent en mètres par une méthode du délégué ; Nearby Interaction peut ajouter la direction, avec un coup de main de la caméra si vous l'autorisez.
Et maintenant, les petites lignes, parce qu'avec Apple il y a toujours des petites lignes. L'iPhone doit avoir la puce sans fil N1 d'Apple, arrivée avec la famille iPhone 17, donc les iPhone plus anciens en restent au « tu chauffes, tu refroidis ». L'accessoire doit gérer le Bluetooth 6.3 avec un ensemble précis de fonctions Channel Sounding, donc votre matériel actuel ne l'obtiendra pas par une mise à jour du firmware si sa puce ne les prend pas déjà en charge. La session se met en pause dès que votre app passe en arrière-plan. Et l'accessoire doit avoir été configuré avec AccessorySetupKit, et c'est par là que je commencerais dès maintenant, projet de mesure de distance ou pas.
La porte d'entrée qu'Apple aimerait vous voir prendre
AccessorySetupKit est arrivé avec iOS 18. Au lieu de demander la permission Bluetooth puis de scanner les brosses à dents de tout le quartier, votre app affiche un sélecteur système avec la photo et le nom de votre produit, l'utilisateur touche une fois, et votre app obtient l'accès à cet accessoire-là, sans aucune demande de permission Bluetooth. Que Channel Sounding l'exige, c'est la manière polie d'Apple de montrer la porte qu'elle veut voir tout le monde emprunter, et vos utilisateurs apprécieront une fenêtre inquiétante de moins :
import AccessorySetupKit
import CoreBluetooth
import UIKit
@MainActor
final class SensorSetup {
private let session = ASAccessorySession()
private let serviceUUID = CBUUID(string: "FEAA")
var onSensorAdded: ((UUID) -> Void)?
func start() {
session.activate(on: .main) { [weak self] event in
guard event.eventType == .accessoryAdded,
let id = event.accessory?.bluetoothIdentifier else { return }
// Le même identifiant que Core Bluetooth : retrievePeripherals(withIdentifiers:), puis connect
self?.onSensorAdded?(id)
}
}
func addSensor() {
let descriptor = ASDiscoveryDescriptor()
descriptor.bluetoothServiceUUID = serviceUUID
let item = ASPickerDisplayItem(
name: "Capteur",
productImage: UIImage(named: "sensor") ?? UIImage(),
descriptor: descriptor
)
session.showPicker(for: [item]) { error in
if let error { print("Sélecteur fermé : \(error)") }
}
}
}
N'oubliez pas l'Info.plist (NSAccessorySetupKitSupports avec Bluetooth, et vos UUID de service dans NSAccessorySetupBluetoothServices), sinon le sélecteur refusera très poliment de trouver votre capteur, et vous passerez une heure délicieuse à vous demander pourquoi.
Concrètement, je ferais quoi ?
La bonne nouvelle d'abord : rien ici n'exige de tout réécrire. Sur Android, je corrigerais la boucle de lecture aujourd'hui, puis je passerais un après-midi à appuyer sur le bouton reset d'un vrai appareil pendant que l'app est ouverte (enfin une excuse légitime), pour m'assurer que l'état « reconnexion » ressemble à un plan et pas à un plantage. Sur iOS, je ferais passer la configuration par AccessorySetupKit si ce n'est pas déjà fait, puisqu'il supprime une demande de permission tout de suite et ouvre la porte à la distance plus tard. Et si votre équipe matériel choisit une puce pour l'an prochain, glissez les mots « Bluetooth 6.3 » à la prochaine réunion, de préférence avant la commande des cartes et pas après.
Si vous voulez de l'aide
Les apps Bluetooth et NFC, du premier scan à la dernière mise à jour de firmware, c'est tout le sujet de la page application Bluetooth, BLE et NFC. Si vous préférez d'abord savoir comment votre app actuelle encaisse une association perdue ou un lien coupé, l'audit en cinq jours regarde exactement ça.
Sources : Android 17, changements pour toutes les apps, Android 17, changements pour les apps qui ciblent Android 17, référence BluetoothDevice, Transfer Bluetooth data, Android 17 is here, Find your accessory with Bluetooth Channel Sounding (WWDC26), Meet AccessorySetupKit (WWDC24), Apple Newsroom, iPhone 17, Apple Newsroom, 14 septembre 2026.