Loupe

#Universal App Récupérer le type de connexion utilisé (3G, 4G, Wifi, Ethernet, etc…)

 

Récemment, j’ai eu pour mission de développer un système de sondes, pour tracker les interactions des utilisateurs au sein d’une application. Les informations remontées par ces sondes sont multiples, et parmi ces informations, il fallait indiquer le type de connexion à l’instant T. Etant sur une Universal App, il fallait pouvoir gérer les deux plateformes, on sait que sur Windows Phone, on a notre carte sim et donc des connexions du type 3G, 4G, etc… et la possibilité d’être en Wifi. Pour Windows, on a la possibilité de se connecter en l’Ethernet, en Wifi, et aussi avec une carte sim, certaines tablettes supportant celles-ci. Dans un premier temps, voyons comment nous allons récupérer les informations, puis, dans un second temps, comment nous allons les traiter pour obtenir ce que l’on veut.

 

De quelles données avons-nous besoin?

 

Tout d’abord, définissons ce que nous voulons récupérer :

public enum NetworkCategory
{
    None,
    Wifi,
    _4G,
    _3G,
    _2G,
    Edge,
    Ethernet,
    // Connexion mobile mais non identifiée (erreur, etc..)
    UnknownMobile
}

 

Ensuite, pour pouvoir accéder aux données nécessaires, nous allons utiliser la méthode NetworkInformation.GetInternetConnectionProfile.

// On récupère le ConnectionProfile, qui est null sans connexion (ex : mode avion)
var profile = NetworkInformation.GetInternetConnectionProfile();
if (profile == null || profile.NetworkAdapter == null)
{
    return NetworkCategory.None;
}

// L'interface type "Iana" (uint) permet d'identifier le type de protocole
var interfaceType = profile.NetworkAdapter.IanaInterfaceType;

 

Une fois le profil récupéré, la donnée qui nous intéresse est IanaInterfaceType. Cet identifiant va nous permettre de faire une première différenciation entre les protocoles Wifi, Ethernet et ceux relatifs aux connexions mobiles. La doc MSDN du IanaInterfaceType fournit déjà quelques valeurs, cependant toutes les valeurs sont référencées sur le lien suivant : https://www.iana.org/assignments/ianaiftype-mib/ianaiftype-mib. Je vous souhaite bonne chance pour tout comprendre !

Toutefois, nous avons les informations nécessaires, ce qui nous permet d’établir les constantes suivantes :

private const uint IANA_WIFI = 71;

private const uint IANA_ETHERNET = 6;

private const uint IANA_MOBILE = 243;

private const uint IANA_MOBILE2 = 244;

 

Les deux premiers sont facilement reconnaissables depuis le document IANA, les deux autres aussi, car référencés comme 3GPP WWAN et 3GPP2 WWAN, 3GPP étant responsable de la production des spécifications techniques des systèmes mobiles de 3ème génération.

if (interfaceType == IANA_WIFI)
{
    return NetworkCategory.Wifi;
}

if (interfaceType == IANA_ETHERNET)
{
    return NetworkCategory.Ethernet;
}

// Si l'interface IANA correspond au mobile et que le WwanConnectionProfileDetails n'est pas null,
// On approfondit la recherche pour déterminer le type de connexion mobile
if ((interfaceType == IANA_MOBILE || interfaceType == IANA_MOBILE2) && profile.WwanConnectionProfileDetails != null)
{
    // Logique mobile
}

Les deux premières conditions sont plutôt explicites, et nous avons donc déjà la gestion du Wifi et de l’Ethernet, il ne reste plus qu’à implémenter la partie mobile. Et pour cela nous allons avoir besoin du WwanConnectionProfileDetails.

 

Comment différencier la 3G de la 4G, et puis les autres ?

Cette partie va s’articuler autour d’une énumération : WwanDataClass. Il est important de connaitre et comprendre les différentes valeurs de WwanDataClass, afin de pouvoir les catégoriser et donc faire le lien avec notre propre énumération NetworkCategory.

Voici la catégorisation que j’ai réussi à mettre en place en me renseignant sur chacun des protocoles selon différentes sources sur Internet :

switch (wwanClass)
{
    // Edge
    case WwanDataClass.Edge:
        return NetworkCategory.Edge;
    // GPRS : 2G
    case WwanDataClass.Gprs:
        return NetworkCategory._2G;
    // Les WwanDataClass suivants sont du type 3G (voir https://fr.wikipedia.org/wiki/CDMA2000)
    case WwanDataClass.Cdma1xEvdo:
    case WwanDataClass.Cdma1xEvdoRevA:
    case WwanDataClass.Cdma1xEvdv:
    case WwanDataClass.Cdma1xEvdoRevB:
    case WwanDataClass.Cdma3xRtt:
    case WwanDataClass.Cdma1xRtt:
    // Types HSPA, à ne pas confondre avec HSPA+, donc 3G et non H+
    case WwanDataClass.Umts:
    case WwanDataClass.Hsupa:
    case WwanDataClass.Hsdpa:
        return NetworkCategory._3G;
    // LTE = 4G standard
    case WwanDataClass.LteAdvanced:
    case WwanDataClass.CdmaUmb:
        return NetworkCategory._4G;
    // Pas de profil ou non identifié
    case WwanDataClass.Custom:
        return NetworkCategory.UnknownMobile;
    default:
        return NetworkCategory.UnknownMobile;
}

 

Avant de pouvoir utiliser ce switch, il va falloir utiliser WwanConnectionProfileDetails pour récupérer le WwanDataClass actuel. Cependant, avant de s’attaquer à l’analyse de cette valeur, il est important de comprendre le fonctionnement des Flags. Je vous conseille ce lien Codeproject qui explique parfaitement et de manière simple le concept.

Pour résumé, il est possible, grâce à l’attribut Flags de traiter une énumération comme un champ de bits, ce qui permet par extension d’avoir une valeur d’Enum qui correspond à plusieurs valeurs en même temps. Je vous invite vivement à parcourir le lien précédent si vous êtes étranger aux Flags.

Nous allons devoir utiliser la méthode HasFlag qui va permettre de déterminer si une valeur particulière est présente dans une autre valeur de l’enum. Il est nécessaire de comprendre le principe du OU logique ainsi que du ET logique lors de la comparaison des bits.

Notamment pour la valeur par défaut (None) de WwanDataClass qui est égale à 0, car lorsqu’on envoi 0 à la méthode HasFlag, nous obtiendrons True, alors ce ne sera pas logique fonctionnellement dans notre cas spécifique. Il est donc important de traiter cette valeur à part.
Passons à la pratique :

// On récupère le WwanDataClass actuel
var wwanProfiles = profile.WwanConnectionProfileDetails.GetCurrentDataClass();

// Si None, on renvoit tout de suite un UnkownMobile
if(wwanProfiles.Equals(WwanDataClass.None))
{
    return NetworkCategory.None;
}

// On récupère la liste de l'enum WwanDataClass pour boucler dessus
var wwanList = EnumListHelper<WwanDataClass>.Get().ToList();
// On exclut None pour ne pas fausser la recherche
wwanList.Remove(WwanDataClass.None);

WwanDataClass? wwanClass = null;
foreach (var wwan in wwanList)
{
    if (wwanProfiles.HasFlag(wwan)) // ou utiliser le ET logique  (wwanProfiles & wwan) == wwan) 
    {
        // On récupère le premier qui correspond et on break
        wwanClass = wwan;
        break;
    }
}

 

On gère donc tout de suite le cas du WwanDataClass.None en renvoyant un NetworkCategory.None.
Ensuite, grâce à un petit Helper, je génère la liste contenant toutes les valeurs possible de WwanDataClass, puis j’exclue la valeur non désirée : WwanDataClass.None.

public class EnumListHelper<T> where T : struct
{
    public static IEnumerable<T> Get()
    {
        return Enum.GetValues(typeof(T)).Cast<T>();
    }
}

 

On peut ainsi boucler sur la liste et vérifier les valeurs une à une. Après plusieurs tests sur plusieurs cartes sim, j’ai estimé qu’il pouvait être pertinent de récupérer la première valeur qui match. Un des cas probants était une carte 3G qui renvoyait (Hsupa | Hsdpa), donc les deux en même temps.

Une fois la bonne valeur récupérée, on peut enfin appliquer le switch que nous avons vu précédemment pour récupérer la catégorie que nous désirons tant !
Attention cependant à cette ligne  :

var wwanProfiles = profile.WwanConnectionProfileDetails.GetCurrentDataClass();

 

En jouant avec les paramètres du téléphone (forcer la 3G, remettre en 4G, forcer la 2G…) je suis arrivé sur un cas où la méthode en question levait une exception interne, j’ai donc mis un try/catch autour pour renvoyer un UnkownMobile dans ce cas là, ne pouvant donc pas identifier clairement le type de connexion.

Vous trouverez sur ce lien gist le code source entier.

 

Pour finir

Au final, pour une fonctionnalité qui semble “aisée”, nous avons abordé de nombreux concepts, comme les Flags et les différentes spécifications autour des divers protocoles de connexion. Libre à vous d’approfondir le sujet, et comme moi, de se renseigner un peu plus en détail sur certaines technologies en particulier comme le LTE, qui est le standard 4G, par opposition à l’UMB qui a été abandonné en 2008.

Aussi, libre à vous de catégoriser comme il vous semble les différents WwanDataClass, vous pouvez par exemple augmenter le nombre de catégorie pour les préciser, si nécessaire. Pour ma part, je n’avais besoin que de catégories générales.

En espérant que ce petit Helper pourra vous servir, bons développements à tous !

Ces billets pourraient aussi vous intéresser

Vous nous direz ?!

Commentaires

comments powered by Disqus