Utilisation de types natifs dans des applications multiplateformes
Cet article traite de l’utilisation des nouveaux types natifs d’API unifiée iOS (nint, nuint, nfloat) dans une application multiplateforme où le code est partagé avec des appareils non iOS tels qu’Android ou Windows Téléphone OS.
Les types natifs de 64 types fonctionnent avec les API iOS et Mac. Si vous écrivez également du code partagé qui s’exécute sur Android ou Windows, vous devez gérer la conversion des types unifiés en types .NET standard que vous pouvez partager.
Ce document décrit différentes façons d’interagir avec l’API unifiée à partir de votre code partagé/commun.
Quand utiliser les types natifs
Les API unifiées Xamarin.iOS et Xamarin.Mac incluent toujours les int
types de uint
float
données, ainsi que les types et PointF
les RectangleF
SizeF
types. Ces types de données existants doivent continuer à être utilisés dans n’importe quel code partagé et multiplateforme. Les nouveaux types de données natifs ne doivent être utilisés que lors de l’appel à une API Mac ou iOS où la prise en charge des types prenant en charge l’architecture est requise.
Selon la nature du code partagé, il peut arriver que le code multiplateforme ait besoin de traiter les types de données et nfloat
les nint
nuint
types de données. Par exemple : une bibliothèque qui gère les transformations sur des données rectangulaires qui utilisaient précédemment System.Drawing.RectangleF
pour partager des fonctionnalités entre les versions Xamarin.iOS et Xamarin.Android d’une application, doit être mise à jour pour gérer les types natifs sur iOS.
La façon dont ces modifications sont gérées dépend de la taille et de la complexité de l’application et de la forme de partage de code qui a été utilisé, comme nous le verrons dans les sections suivantes.
Considérations relatives au partage de code
Comme indiqué dans le document Options de code de partage, il existe deux façons principales de partager du code entre des projets multiplateformes : projets partagés et bibliothèques de classes portables. Lequel des deux types a été utilisé, limite les options dont nous disposons lors de la gestion des types de données natifs dans du code multiplateforme.
Projets de bibliothèque de classes portables
Une bibliothèque de classes portable (PCL) vous permet de cibler les plateformes que vous souhaitez prendre en charge et d’utiliser des interfaces pour fournir des fonctionnalités spécifiques à la plateforme.
Étant donné que le type de projet PCL est compilé vers le .DLL
bas et qu’il n’a aucun sens de l’API unifiée, vous serez obligé de continuer à utiliser les types de données existants (int
, , uint
float
) dans le code source PCL et le type caster les appels aux classes et méthodes de la bibliothèque PCL dans les applications frontales. Par exemple :
using NativePCL;
...
CGRect rect = new CGRect (0, 0, 200, 200);
Console.WriteLine ("Rectangle Area: {0}", Transformations.CalculateArea ((RectangleF)rect));
Projets partagés
Le type de projet de ressource partagée vous permet d’organiser votre code source dans un projet distinct qui est ensuite inclus et compilé dans les applications frontales spécifiques à la plateforme, et d’utiliser #if
des directives de compilateur en fonction des besoins spécifiques à la plateforme.
La taille et la complexité des applications mobiles frontales qui consomment du code partagé, ainsi que la taille et la complexité du code partagé, doivent être prises en compte lors du choix de la méthode de prise en charge des types de données natifs dans un projet de ressource partagée multiplateforme.
En fonction de ces facteurs, les types de solutions suivants peuvent être implémentés à l’aide des if __UNIFIED__ ... #endif
directives du compilateur pour gérer les modifications spécifiques de l’API unifiée au code.
Utilisation de méthodes dupliquées
Prenons l’exemple d’une bibliothèque qui effectue des transformations sur des données rectangulaires indiquées ci-dessus. Si la bibliothèque ne contient qu’une ou deux méthodes très simples, vous pouvez choisir de créer des versions en double de ces méthodes pour Xamarin.iOS et Xamarin.Android. Par exemple :
using System;
using System.Drawing;
#if __UNIFIED__
using CoreGraphics;
#endif
namespace NativeShared
{
public class Transformations
{
#region Constructors
public Transformations ()
{
}
#endregion
#region Public Methods
#if __UNIFIED__
public static nfloat CalculateArea(CGRect rect) {
// Calculate area...
return (rect.Width * rect.Height);
}
#else
public static float CalculateArea(RectangleF rect) {
// Calculate area...
return (rect.Width * rect.Height);
}
#endif
#endregion
}
}
Dans le code ci-dessus, étant donné que la CalculateArea
routine est très simple, nous avons utilisé la compilation conditionnelle et créé une version d’API unifiée distincte de la méthode. En revanche, si la bibliothèque contenait de nombreuses routines ou plusieurs routines complexes, cette solution ne serait pas réalisable, car elle présenterait un problème gardant toutes les méthodes synchronisées pour les modifications ou les correctifs de bogues.
Utilisation de surcharges de méthode
Dans ce cas, la solution peut être de créer une version surchargée des méthodes à l’aide de types de données 32 bits afin qu’elles prennent CGRect
désormais comme paramètre et/ou une valeur de retour, convertissent cette valeur en une RectangleF
(sachant que la conversion nfloat
en float
est une conversion de perte) et appelez la version d’origine de la routine pour effectuer le travail réel. Par exemple :
using System;
using System.Drawing;
#if __UNIFIED__
using CoreGraphics;
#endif
namespace NativeShared
{
public class Transformations
{
#region Constructors
public Transformations ()
{
}
#endregion
#region Public Methods
#if __UNIFIED__
public static nfloat CalculateArea(CGRect rect) {
// Call original routine to calculate area
return (nfloat)CalculateArea((RectangleF)rect);
}
#endif
public static float CalculateArea(RectangleF rect) {
// Calculate area...
return (rect.Width * rect.Height);
}
#endregion
}
}
Là encore, il s’agit d’une bonne solution tant que la perte de précision n’affecte pas les résultats pour les besoins spécifiques de votre application.
Utilisation des directives d’alias
Pour les zones où la perte de précision est un problème, une autre solution possible consiste à utiliser using
des directives pour créer un alias pour les types de données Native et CoreGraphics en incluant le code suivant en haut des fichiers de code source partagés et en convertissant les valeurs nécessairesint
, uint
ou float
en nuint
nint
nfloat
:
#if __UNIFIED__
// Mappings Unified CoreGraphic classes to MonoTouch classes
using RectangleF = global::CoreGraphics.CGRect;
using SizeF = global::CoreGraphics.CGSize;
using PointF = global::CoreGraphics.CGPoint;
#else
// Mappings Unified types to MonoTouch types
using nfloat = global::System.Single;
using nint = global::System.Int32;
using nuint = global::System.UInt32;
#endif
Ainsi, notre exemple de code devient :
using System;
using System.Drawing;
#if __UNIFIED__
// Map Unified CoreGraphic classes to MonoTouch classes
using RectangleF = global::CoreGraphics.CGRect;
using SizeF = global::CoreGraphics.CGSize;
using PointF = global::CoreGraphics.CGPoint;
#else
// Map Unified types to MonoTouch types
using nfloat = global::System.Single;
using nint = global::System.Int32;
using nuint = global::System.UInt32;
#endif
namespace NativeShared
{
public class Transformations
{
#region Constructors
public Transformations ()
{
}
#endregion
#region Public Methods
public static nfloat CalculateArea(RectangleF rect) {
// Calculate area...
return (rect.Width * rect.Height);
}
#endregion
}
}
Notez que ici, nous avons modifié la CalculateArea
méthode pour retourner une nfloat
valeur au lieu de la norme float
. Cette opération a été effectuée afin que nous n’obtenions pas d’erreur de compilation essayant de convertir implicitement le nfloat
résultat de notre calcul (étant donné que les deux valeurs multipliées sont de type nfloat
) en une float
valeur de retour.
Si le code est compilé et exécuté sur un appareil d’API non unifié, celui-ci using nfloat = global::System.Single;
nfloat
est mappé à un Single
qui est implicitement converti en une float
autorisation permettant à l’application frontale consommatrice d’appeler la CalculateArea
méthode sans modification.
Utilisation des conversions de types dans l’application frontale
Si vos applications frontales n’effectuent qu’une poignée d’appels à votre bibliothèque de code partagée, une autre solution peut être de laisser la bibliothèque inchangée et d’effectuer un cast de type dans l’application Xamarin.iOS ou Xamarin.Mac lors de l’appel de la routine existante. Par exemple :
using NativeShared;
...
CGRect rect = new CGRect (0, 0, 200, 200);
Console.WriteLine ("Rectangle Area: {0}", Transformations.CalculateArea ((RectangleF)rect));
Si l’application consommatrice effectue des centaines d’appels à la bibliothèque de code partagée, cela peut ne pas être une bonne solution.
En fonction de l’architecture de notre application, nous pouvons finir par utiliser une ou plusieurs des solutions ci-dessus pour prendre en charge les types de données natifs (si nécessaire) dans notre code multiplateforme.
Xamarin.Forms Applications
Vous devez utiliser Xamarin.Forms pour les interfaces utilisateur multiplateformes qui seront également partagées avec une application d’API unifiée :
- La solution entière doit utiliser la version 1.3.1 (ou ultérieure) du package NuGet Xamarin.Forms.
- Pour tout rendu personnalisé Xamarin.iOS, utilisez les mêmes types de solutions présentés ci-dessus en fonction de la façon dont le code de l’interface utilisateur a été partagé (Projet partagé ou PCL).
Comme dans une application multiplateforme standard, les types de données 32 bits existants doivent être utilisés dans n’importe quel code partagé et multiplateforme pour la plupart des situations. Les nouveaux types de données natifs doivent être utilisés uniquement lors de l’appel à une API Mac ou iOS où la prise en charge des types prenant en charge l’architecture est requise.
Pour plus d’informations, consultez notre documentation sur la mise à jour des applications Xamarin.Forms existantes.
Résumé
Dans cet article, nous avons vu quand utiliser les types de données natifs dans une application d’API unifiée et leurs implications entre plateformes. Nous avons présenté plusieurs solutions qui peuvent être utilisées dans des situations où les nouveaux types de données natifs doivent être utilisés dans des bibliothèques multiplateformes. En outre, nous avons vu un guide rapide pour prendre en charge les API unifiées dans les applications multiplateformes Xamarin.Forms.