Le WIFI est incontournable lorsque l’on parle de développement mobile, on a souvent besoin de télécharger des données depuis un serveur, pour se faire avoir internet c’est mieux (sisi, je vous assure !). Nous allons voir dans cet article comment détecter en Swift :
- Si l’appareil est connecté à internet (en cellulaire ou avec le WIFI)
- Si la fonctionnalité WIFI est activée sur l’appareil (même si pas connecté à internet)
Détecter une connexion internet en Swift
Vous avez surement déjà eu besoin de détecter si un iPhone est connecté à internet, en Swift, c’est plutôt simple, en utilisant la librairie SystemConfiguration d’Apple. Voici, un exemple de fonction, faisant le job :
import SystemConfiguration public class WifiUtils { public static func isConnectedToNetwork() -> Bool { var zeroAddress = sockaddr_in() zeroAddress.sin_len = UInt8(MemoryLayout.size(ofValue: zeroAddress)) zeroAddress.sin_family = sa_family_t(AF_INET) let defaultRouteReachability = withUnsafePointer(to: &zeroAddress) { $0.withMemoryRebound(to: sockaddr.self, capacity: 1) { zeroSockAddress in SCNetworkReachabilityCreateWithAddress(nil, zeroSockAddress) } } var flags = SCNetworkReachabilityFlags() if !SCNetworkReachabilityGetFlags(defaultRouteReachability!, &flags) { return false } let isReachable = flags.contains(.reachable) let needsConnection = flags.contains(.connectionRequired) return (isReachable && !needsConnection) } }
Dans les grandes lignes, voilà comment fonctionne la méthode du dessus :
- On commence par initialiser la structure sockaddr_in, cette dernière est nécessaire pour pouvoir instancier un objet SCNetworkReachabilityCreateWithAddress
- En effet, l’interface SCNetworkReachability permet à une application de déterminer le status réseau et l’accessibilité du smartphone à internet. Un hôte distant est considéré comme accessible lorsqu’un paquet de données, arrive à quitter l’appareil.
- Pour tester, cela, on utilise la méthode SCNetworkReachabilityFlags, si cette dernière retourne un résultat, il nous suffit alors de tester le status des flags .reachable et .connectionRequired.
sockaddr_in, kezako ?
La structure sockaddr_in permet de décrire une adresse « internet », ou plus généralement, une adresse IP et un port. Regardons la définition de la structure :
struct sockaddr_in { __uint8_t sin_len; sa_family_t sin_family; in_port_t sin_port; struct in_addr sin_addr; char sin_zero[8]; };
Ici, on va se concentrer uniquement sur les deux premiers champs, le premier sin_len, représente la taille de la structure elle-même en UInt8, pour obtenir la taille de la structure sockaddr_in, on utilise la fonction size de la classe MemoryLayout. Le second, sin_family représente le type de famille de protocole que l’on souhaite gérer, ici on précise AF_INET, qui correspond à du IP v4.
Si vous voulez approfondir encore plus le sujet internet est votre ami, il y a de quoi s’amuser quand on touche un peu au réseau 😀 !
WIFI: hard off et soft off
Il est possible que l’on veuille détecter uniquement si la fonctionnalité WIFI est active mais pas forcément connectée à internet, dans le cas d’utilisation de services de localisation par exemple.
Il faut savoir que depuis la mise à jour iOS 11, il existe deux méthodes pour désactiver le WIFI :
- Une méthode hard off, c’est-à-dire la désactivation complète des scans WIFI, accessible depuis les réglages du téléphone. C’est cet état que la méthode que je vais vous expliquer permet de détecter.
- Une méthode soft off, cela correspond à la désactivation du WIFI depuis le Command center, mais cette dernière ne désactive pas totalement, le WIFI. En effet, la désactivation est temporaire. Le WIFI s’activera de lui-même le lendemain. Si vous voulez plus d’informations sur le sujet, je vous laisse lire cet excellent article de the verge.
Maintenant, la question que l’on se pose tous, c’est comment détecter le status du WIFI ? Il est difficile de trouver une solution parfaite, rien de formel ne semble exister. Après quelques recherches, j’ai fini par tomber sur ce gist, qui propose une solution au problème.
Lorsqu’un iPhone a la fonctionnalité WIFI d’activée, la méthode getifaddrs retourne deux interfaces nommées awdl0, autrement le WIFI est désactivé.
Vérifier si le WIFI est activé en Swift
Passons directement à la fonction :
import Foundation import SystemConfiguration public class WifiUtils { public static func isWifiEnabled() -> Bool { let set = NSCountedSet() var ifaddr: UnsafeMutablePointer<ifaddrs>? if getifaddrs(&ifaddr) == 0 { var ptr = ifaddr while ptr != nil { defer { ptr = ptr?.pointee.ifa_next } let flags = Int32(ptr!.pointee.ifa_flags) let name = String(validatingUTF8: ptr!.pointee.ifa_name) if (flags & IFF_UP) == IFF_UP { set.add(name ?? "") } } freeifaddrs(ifaddr) } return set.count(for: "awdl0") > 1 ? true : false } }
Analysons un peu le code :
- On commence par initialiser deux variables: un set qui va nous permettre de compter le nombre d’occurrences de l’interface awdl0 et un pointeur appelé ifaddr, qui permettra de pointer sur l’interface courante.
- Ensuite, on utilise la fameuse fonction getifaddrs qui prend en paramètre, le précédent pointeur, à chaque interface, on essaye de déferencer le pointeur, si cela réussit, on récupère son nom et on vérifie si le flag IFF_UP est à true (cela signifie que l’interface est active).
- Enfin, on retourne true, si on a trouvé deux fois l’interface awdl0, false autrement
Et voilà, pas si compliqué que ça ! Le seul bémol, c’est que je n’ai pas trouvé comment détecter une désactivation soft off, si vous avez une idée de comment faire, n’hésitez pas à intervenir !