Partie 4 : Utilisation de plusieurs plateformes

Gestion de la divergence de plateforme &fonctionnalités

La divergence n’est pas seulement un problème « multiplateforme » ; les appareils sur la plateforme « identique » ont des fonctionnalités différentes (en particulier la grande variété d’appareils Android disponibles). La taille d’écran la plus évidente et la plus simple est, mais d’autres attributs d’appareil peuvent varier et exiger qu’une application case activée pour certaines fonctionnalités et se comporte différemment en fonction de leur présence (ou absence).

Cela signifie que toutes les applications doivent gérer une dégradation normale des fonctionnalités, ou présenter un ensemble de fonctionnalités sans assistance, le plus bas-commun-dénominateur. L’intégration approfondie de Xamarin aux kits SDK natifs de chaque plateforme permet aux applications de tirer parti des fonctionnalités spécifiques à la plateforme. Il est donc judicieux de concevoir des applications pour utiliser ces fonctionnalités.

Consultez la documentation fonctionnalités de la plateforme pour obtenir une vue d’ensemble de la façon dont les plateformes diffèrent dans les fonctionnalités.

Exemples de divergence de plateforme

Éléments fondamentaux qui existent sur plusieurs plateformes

Il existe certaines caractéristiques des applications mobiles universelles. Il s’agit de concepts de niveau supérieur qui sont généralement vrais pour tous les appareils et peuvent donc constituer la base de la conception de votre application :

  • Sélection de fonctionnalités par le biais d’onglets ou de menus
  • Listes de données et de défilement
  • Vues uniques des données
  • Modification d’affichages uniques de données
  • Navigation vers l’arrière

Lorsque vous concevez votre flux d’écran de haut niveau, vous pouvez baser une expérience utilisateur courante sur ces concepts.

Attributs spécifiques à la plateforme

Outre les éléments de base qui existent sur toutes les plateformes, vous devez résoudre les principales différences de plateforme dans votre conception. Vous devrez peut-être prendre en compte (et écrire du code spécifiquement pour gérer) ces différences :

  • Tailles d’écran : certaines plateformes (comme iOS et les versions antérieures de Windows Téléphone) ont des tailles d’écran standardisées qui sont relativement simples à cibler. Les appareils Android ont une grande variété de dimensions d’écran, ce qui nécessite plus d’efforts pour prendre en charge votre application.
  • Métaphores de navigation : diffèrent entre les plateformes (par exemple, bouton « précédent », contrôle de l’interface utilisateur Panorama) et au sein des plateformes (Android 2 et 4, i Téléphone vs iPad).
  • Claviers : certains appareils Android ont des claviers physiques, tandis que d’autres n’ont qu’un clavier logiciel. Le code qui détecte lorsqu’un clavier logiciel masque une partie de l’écran doit être sensible à ces différences.
  • Interactions tactiles et mouvements : la prise en charge du système d’exploitation pour la reconnaissance des mouvements varie, en particulier dans les versions antérieures de chaque système d’exploitation. Les versions antérieures d’Android ont une prise en charge très limitée des opérations tactiles, ce qui signifie que la prise en charge des appareils plus anciens peut nécessiter un code distinct
  • Notifications Push : il existe différentes fonctionnalités/implémentations sur chaque plateforme (par exemple. Vignettes dynamiques sur Windows).

Fonctionnalités spécifiques à l’appareil

Déterminez les fonctionnalités minimales requises pour l’application ; ou lorsque vous décidez des fonctionnalités supplémentaires à tirer parti de chaque plateforme. Le code sera nécessaire pour détecter les fonctionnalités et désactiver les fonctionnalités ou proposer des alternatives (par exemple, une alternative à la géolocalication peut permettre à l’utilisateur de taper un emplacement ou de choisir parmi une carte) :

  • Caméra : les fonctionnalités diffèrent entre les appareils : certains appareils n’ont pas de caméra, d’autres ont des caméras avant et arrière. Certaines caméras sont capables d’enregistrer des vidéos.
  • Géolocal &cartes : la prise en charge de l’emplacement GPS ou Wi-Fi n’est pas présente sur tous les appareils. Les applications doivent également répondre aux différents niveaux de précision pris en charge par chaque méthode.
  • Accéléromètre, gyroscope et boussole : ces fonctionnalités sont souvent trouvées dans une sélection d’appareils sur chaque plateforme, de sorte que les applications doivent presque toujours fournir un secours lorsque le matériel n’est pas pris en charge.
  • Twitter et Facebook – uniquement « intégré » sur iOS5 et iOS6 respectivement. Sur les versions antérieures et d’autres plateformes, vous devez fournir vos propres fonctions d’authentification et interface directement avec l’API de chaque service.
  • Near Field Communications (NFC) : uniquement sur (certains) téléphones Android (au moment de l’écriture).

Gestion de la divergence de plateforme

Il existe deux approches différentes pour prendre en charge plusieurs plateformes à partir de la même base de code, chacune avec son propre ensemble d’avantages et d’inconvénients.

  • Abstraction de plateforme – Modèle Façade métier, fournit un accès unifié entre les plateformes et extrait les implémentations de plateforme particulières en une API unifiée unique.
  • Implémentation divergente : appel de fonctionnalités de plateforme spécifiques via des implémentations divergentes via des outils architecturaux tels que les interfaces et l’héritage ou la compilation conditionnelle.

Abstraction de plateforme

Abstraction de classe

Utilisation d’interfaces ou de classes de base définies dans le code partagé et implémentées ou étendues dans des projets spécifiques à la plateforme. L’écriture et l’extension du code partagé avec des abstractions de classe sont particulièrement adaptées aux bibliothèques de classes portables, car elles ont un sous-ensemble limité de l’infrastructure disponible et ne peuvent pas contenir de directives du compilateur pour prendre en charge les branches de code spécifiques à la plateforme.

Interfaces

L’utilisation d’interfaces vous permet d’implémenter des classes spécifiques à la plateforme qui peuvent toujours être passées dans vos bibliothèques partagées pour tirer parti du code commun.

L’interface est définie dans le code partagé et transmise à la bibliothèque partagée en tant que paramètre ou propriété.

Les applications spécifiques à la plateforme peuvent ensuite implémenter l’interface et tirer parti du code partagé pour le traiter.

Avantages

L’implémentation peut contenir du code spécifique à la plateforme et même référencer des bibliothèques externes spécifiques à la plateforme.

Inconvénients

Avoir à créer et passer des implémentations dans le code partagé. Si l’interface est utilisée en profondeur dans le code partagé, elle finit par être transmise par plusieurs paramètres de méthode ou par le biais d’une autre transmission par le biais de la chaîne d’appels. Si le code partagé utilise de nombreuses interfaces différentes, ils doivent tous être créés et définis dans le code partagé quelque part.

Héritage

Le code partagé peut implémenter des classes abstraites ou virtuelles qui peuvent être étendues dans un ou plusieurs projets spécifiques à la plateforme. Cela est similaire à l’utilisation d’interfaces, mais avec un comportement déjà implémenté. Il existe différents points de vue sur la façon dont les interfaces ou l’héritage sont un meilleur choix de conception : en particulier, car C# autorise uniquement l’héritage unique, il peut dicter la façon dont vos API peuvent être conçues à l’avenir. Utilisez l’héritage avec précaution.

Les avantages et inconvénients des interfaces s’appliquent également à l’héritage, avec l’avantage supplémentaire que la classe de base peut contenir un code d’implémentation (peut-être une implémentation indépendante de la plateforme entière qui peut éventuellement être étendue).

Xamarin.Forms

Consultez la documentation Xamarin.Forms .

Autres bibliothèques multiplateformes

Ces bibliothèques offrent également des fonctionnalités multiplateformes pour les développeurs C# :

Compilation conditionnelle

Il existe certaines situations où votre code partagé devra toujours fonctionner différemment sur chaque plateforme, et éventuellement accéder à des classes ou fonctionnalités qui se comportent différemment. La compilation conditionnelle fonctionne mieux avec les projets de ressources partagées, où le même fichier source est référencé dans plusieurs projets qui ont des symboles différents définis.

Les projets Xamarin définissent __MOBILE__ toujours ce qui est vrai pour les projets d’application iOS et Android (notez le trait de soulignement double et post-correctif sur ces symboles).

#if __MOBILE__
// Xamarin iOS or Android-specific code
#endif

iOS

Xamarin.iOS définit __IOS__ ce que vous pouvez utiliser pour détecter les appareils iOS.

#if __IOS__
// iOS-specific code
#endif

Il existe également des symboles spécifiques à la télévision et à la montre :

#if __TVOS__
// tv-specific stuff
#endif

#if __WATCHOS__
// watch-specific stuff
#endif

Android

Le code qui ne doit être compilé que dans les applications Xamarin.Android peut utiliser les éléments suivants :

#if __ANDROID__
// Android-specific code
#endif

Chaque version de l’API définit également une nouvelle directive du compilateur. Par conséquent, le code comme celui-ci vous permet d’ajouter des fonctionnalités si des API plus récentes sont ciblées. Chaque niveau d’API inclut tous les symboles de niveau « inférieur ». Cette fonctionnalité n’est pas vraiment utile pour prendre en charge plusieurs plateformes ; généralement, le __ANDROID__ symbole sera suffisant.

#if __ANDROID_11__
// code that should only run on Android 3.0 Honeycomb or newer
#endif

Mac

Xamarin.Mac définit __MACOS__ ce que vous pouvez utiliser pour compiler uniquement pour macOS :

#if __MACOS__
// macOS-specific code
#endif

Plateforme Windows universelle (UWP)

Utiliser WINDOWS_UWP. Il n’existe aucun trait de soulignement entourant la chaîne, comme les symboles de la plateforme Xamarin.

#if WINDOWS_UWP
// UWP-specific code
#endif

Utilisation de la compilation conditionnelle

Un exemple simple d’étude de cas de compilation conditionnelle définit l’emplacement du fichier de base de données SQLite. Les trois plateformes ont des exigences légèrement différentes pour spécifier l’emplacement du fichier :

  • iOS : Apple préfère que les données non-utilisateur soient placées dans un emplacement spécifique (répertoire bibliothèque), mais il n’existe aucune constante système pour ce répertoire. Le code spécifique à la plateforme est requis pour générer le chemin d’accès approprié.
  • Android : le chemin d’accès système retourné par Environment.SpecialFolder.Personal est un emplacement acceptable pour stocker le fichier de base de données.
  • Windows Téléphone : le mécanisme de stockage isolé n’autorise pas la spécification d’un chemin d’accès complet, simplement un chemin relatif et un nom de fichier.
  • plateforme Windows universelle : utilise des Windows.Storage API.

Le code suivant utilise la compilation conditionnelle pour vous assurer que le DatabaseFilePath code est correct pour chaque plateforme :

public static string DatabaseFilePath
{
    get
    {
        var filename = "TodoDatabase.db3";
#if SILVERLIGHT
        // Windows Phone 8
        var path = filename;
#else

#if __ANDROID__
        string libraryPath = Environment.GetFolderPath(Environment.SpecialFolder.Personal);
#else
#if __IOS__
        // we need to put in /Library/ on iOS5.1 to meet Apple's iCloud terms
        // (they don't want non-user-generated data in Documents)
        string documentsPath = Environment.GetFolderPath (Environment.SpecialFolder.Personal); // Documents folder
        string libraryPath = Path.Combine (documentsPath, "..", "Library");
#else
        // UWP
        string libraryPath = Windows.Storage.ApplicationData.Current.LocalFolder.Path;
#endif
#endif
        var path = Path.Combine(libraryPath, filename);
#endif
        return path;
    }
}

Le résultat est une classe qui peut être générée et utilisée sur toutes les plateformes, en plaçant le fichier de base de données SQLite à un emplacement différent sur chaque plateforme.