Condividi tramite


Utilizzo di tipi nativi nelle app multipiattaforma

Questo articolo illustra l'uso dei nuovi tipi nativi dell'API unificata iOS (nint, nuint, nfloat) in un'applicazione multipiattaforma in cui il codice viene condiviso con dispositivi non iOS, ad esempio Android o Windows Telefono OSes.

I tipi nativi di 64 tipi funzionano con le API iOS e Mac. Se si scrive anche codice condiviso in esecuzione in Android o Windows, sarà necessario gestire la conversione di tipi unificati in tipi .NET normali che è possibile condividere.

Questo documento illustra diversi modi per interagire con l'API unificata dal codice condiviso/comune.

Quando usare i tipi nativi

Le API unificate Xamarin.iOS e Xamarin.Mac includono ancora i inttipi di dati , uint e float , nonché i RectangleFtipi e PointFSizeF . Questi tipi di dati esistenti devono continuare a essere usati in qualsiasi codice condiviso multipiattaforma. I nuovi tipi di dati nativi devono essere usati solo quando si effettua una chiamata a un'API Mac o iOS in cui è necessario il supporto per i tipi con riconoscimento dell'architettura.

A seconda della natura del codice da condividere, potrebbe essere necessario gestire il codice multipiattaforma in alcuni casi con i ninttipi di dati e nuintnfloat . Ad esempio, una libreria che gestisce le trasformazioni su dati rettangolari che in precedenza usavano System.Drawing.RectangleF per condividere le funzionalità tra le versioni di Xamarin.iOS e Xamarin.Android di un'app, dovrà essere aggiornata per gestire i tipi nativi in iOS.

La modalità di gestione di queste modifiche dipende dalle dimensioni e dalla complessità dell'applicazione e dalla forma di condivisione del codice usata, come illustrato nelle sezioni seguenti.

Considerazioni sulla condivisione del codice

Come indicato nel documento Opzioni codice di condivisione, esistono due modi principali per condividere il codice tra progetti multipiattaforma: progetti condivisi e librerie di classi portabili. Quale dei due tipi è stato usato, limiterà le opzioni disponibili per la gestione dei tipi di dati nativi nel codice multipiattaforma.

Progetti della libreria di classi portabile

Una libreria di classi portabile (PCL) consente di specificare come destinazione le piattaforme che si desidera supportare e di usare le interfacce per fornire funzionalità specifiche della piattaforma.

Poiché il tipo di progetto PCL viene compilato in un .DLL oggetto e non ha alcun senso dell'API unificata, sarà necessario continuare a usare i tipi di dati esistenti (int, uint, float) nel codice sorgente della libreria di classi e nei tipi di libreria di classi e metodi della libreria di classi della libreria di classi e metodi nelle applicazioni front-end. Ad esempio:

using NativePCL;
...

CGRect rect = new CGRect (0, 0, 200, 200);
Console.WriteLine ("Rectangle Area: {0}", Transformations.CalculateArea ((RectangleF)rect));

Progetti condivisi

Il tipo progetto asset condiviso consente di organizzare il codice sorgente in un progetto separato che viene quindi incluso e compilato nelle singole app front-end specifiche della piattaforma e usare #if le direttive del compilatore in base alle esigenze della piattaforma per gestire i requisiti specifici della piattaforma.

Le dimensioni e la complessità delle applicazioni per dispositivi mobili front-end che utilizzano codice condiviso, insieme alle dimensioni e alla complessità del codice condiviso, devono essere prese in considerazione quando si sceglie il metodo di supporto per i tipi di dati nativi in un progetto di asset condiviso multipiattaforma.

In base a questi fattori, è possibile implementare i tipi di soluzioni seguenti usando le direttive del if __UNIFIED__ ... #endif compilatore per gestire le modifiche specifiche dell'API unificata al codice.

Uso di metodi duplicati

Si prenda l'esempio di una libreria che esegue trasformazioni sui dati rettangolari indicati in precedenza. Se la libreria contiene solo uno o due metodi molto semplici, è possibile scegliere di creare versioni duplicate di tali metodi per Xamarin.iOS e Xamarin.Android. Ad esempio:

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
    }
}

Nel codice precedente, poiché la routine è molto semplice, è stata usata la CalculateArea compilazione condizionale e è stata creata una versione separata e unificata dell'API del metodo . D'altra parte, se la libreria conteneva molte routine o più routine complesse, questa soluzione non sarebbe fattibile, perché presenterebbe un problema mantenendo tutti i metodi sincronizzati per le modifiche o le correzioni di bug.

Uso degli overload dei metodi

In tal caso, la soluzione potrebbe essere quella di creare una versione di overload dei metodi che usano tipi di dati a 32 bit in modo che ora accettano CGRect come parametro e/o un valore restituito, convertirlo in un RectangleF oggetto (sapendo che la conversione da nfloat a float è una conversione con perdita) e chiamare la versione originale della routine per eseguire il lavoro effettivo. Ad esempio:

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
    }
}

Anche in questo caso, si tratta di una soluzione valida, purché la perdita di precisione non influisca sui risultati per le esigenze specifiche dell'applicazione.

Uso delle direttive alias

Per le aree in cui la perdita di precisione è un problema, un'altra possibile soluzione consiste nell'usare using direttive per creare un alias per i tipi di dati Native e CoreGraphics includendo il codice seguente all'inizio dei file di codice sorgente condiviso e convertendo i valori nintnecessari intfloatuint in o : nuintnfloat

#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

In questo modo il codice di esempio diventa:

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
    }
}

Si noti che in questo caso il CalculateArea metodo è stato modificato in modo da restituire un oggetto nfloat anziché lo standard float. Questa operazione è stata eseguita in modo che non venga visualizzato un errore di compilazione che tenta di convertire in modo implicito il nfloat risultato del calcolo (poiché entrambi i valori moltiplicati sono di tipo nfloat) in un float valore restituito.

Se il codice viene compilato ed eseguito in un dispositivo API non unificato, esegue il using nfloat = global::System.Single; mapping di nfloat a un Single oggetto che convertirà in modo implicito in un che float consente all'applicazione front-end di utilizzare di chiamare il CalculateArea metodo senza modifiche.

Uso delle conversioni dei tipi nell'app Front End

Nel caso in cui le applicazioni front-end eseguono solo alcune chiamate alla libreria di codice condivisa, un'altra soluzione potrebbe essere quella di lasciare invariata la libreria ed eseguire il cast dei tipi nell'applicazione Xamarin.iOS o Xamarin.Mac quando si chiama la routine esistente. Ad esempio:

using NativeShared;
...

CGRect rect = new CGRect (0, 0, 200, 200);
Console.WriteLine ("Rectangle Area: {0}", Transformations.CalculateArea ((RectangleF)rect));

Se l'applicazione che usa esegue centinaia di chiamate alla libreria di codice condivisa, questa potrebbe non essere una buona soluzione.

In base all'architettura dell'applicazione, è possibile usare una o più delle soluzioni precedenti per supportare i tipi di dati nativi (se necessario) nel codice multipiattaforma.

Applicazioni Xamarin.Forms

Di seguito è necessario usare Xamarin.Forms per interfacce utente multipiattaforma che verranno condivise anche con un'applicazione API unificata:

  • L'intera soluzione deve usare la versione 1.3.1 (o successiva) del pacchetto NuGet Xamarin.Forms.
  • Per i rendering personalizzati di Xamarin.iOS, usare gli stessi tipi di soluzioni presentate in precedenza in base al modo in cui il codice dell'interfaccia utente è stato condiviso (Progetto condiviso o PCL).

Come in un'applicazione multipiattaforma standard, i tipi di dati a 32 bit esistenti devono essere usati in qualsiasi codice condiviso multipiattaforma per la maggior parte delle situazioni. I nuovi tipi di dati nativi devono essere usati solo quando si effettua una chiamata a un'API Mac o iOS in cui è necessario il supporto per i tipi con riconoscimento dell'architettura.

Per altri dettagli, vedere la documentazione relativa all'aggiornamento di app Xamarin.Forms esistenti.

Riepilogo

In questo articolo è stato illustrato quando usare i tipi di dati nativi in un'applicazione API unificata e le relative implicazioni multipiattaforma. Sono state presentate diverse soluzioni che possono essere usate in situazioni in cui i nuovi tipi di dati nativi devono essere usati nelle librerie multipiattaforma. È stata anche illustrata una guida rapida al supporto delle API unificate nelle applicazioni multipiattaforma Xamarin.Forms.