Část 4 – Práce s několika platformami

Manipulace s rozdíly a funkcemi platformy

Rozdíly nejsou jen "multiplatformní" problémem; zařízení na stejné platformě mají různé funkce (zejména širokou škálu dostupných zařízení s Androidem). Nejběžnější a základní je velikost obrazovky, ale jiné atributy zařízení se mohou lišit a vyžadovat, aby aplikace kontrolovala určité funkce a chovala se jinak na základě jejich přítomnosti (nebo nepřítomnosti).

To znamená, že všechny aplikace musí řešit řádné snížení funkčnosti nebo jinak prezentovat neattraktivní sadu funkcí jmenovatele s nejnižším společným jmenovatelem. Hloubková integrace Xamarinu s nativními sadami SDK jednotlivých platforem umožňuje aplikacím využívat funkce specifické pro danou platformu, takže je vhodné navrhovat aplikace tak, aby tyto funkce používaly.

Přehled různých funkcí platforem najdete v dokumentaci k možnostem platformy.

Příklady rozdílnosti platforem

Základní prvky, které existují napříč platformami

Existují některé charakteristiky mobilních aplikací, které jsou univerzální. Jedná se o koncepty vyšší úrovně, které jsou obecně pravdivé pro všechna zařízení, a proto můžou tvořit základ návrhu vaší aplikace:

  • Výběr funkcí prostřednictvím karet nebo nabídek
  • Seznamy dat a posouvání
  • Jedno zobrazení dat
  • Úprava jednotlivých zobrazení dat
  • Navigace zpět

Při navrhování toku obrazovky vysoké úrovně můžete na těchto konceptech založit běžné uživatelské prostředí.

Atributy specifické pro platformu

Kromě základních prvků, které existují na všech platformách, budete muset řešit klíčové rozdíly v návrhu platformy. Možná budete muset zvážit (a napsat kód speciálně pro zpracování) těchto rozdílů:

  • Velikosti obrazovek – Některé platformy (jako jsou iOS a starší verze Windows Telefon) mají standardizované velikosti obrazovky, které jsou poměrně jednoduché pro cílení. Zařízení s Androidem mají širokou škálu rozměrů obrazovky, které vyžadují větší úsilí na podporu ve vaší aplikaci.
  • Metafory navigace – liší se na různých platformách (např. tlačítko zpět, ovládací prvek Panorama UI) a v rámci platforem (Android 2 a 4, i Telefon vs. iPad).
  • Klávesnice – Některá zařízení s Androidem mají fyzické klávesnice, zatímco jiné mají jenom softwarovou klávesnici. Kód, který zjišťuje, kdy je v těchto rozdílech citlivá část obrazovky na softwarové klávesnici.
  • Dotykové ovládání a gesta – Podpora operačního systému pro rozpoznávání gest se liší, zejména ve starších verzích každého operačního systému. Starší verze Androidu mají velmi omezenou podporu operací dotykového ovládání, což znamená, že podpora starších zařízení může vyžadovat samostatný kód.
  • Nabízená oznámení – Na každé platformě existují různé možnosti/implementace (např. Živé dlaždice ve Windows).

Funkce specifické pro zařízení

Určení minimálních funkcí požadovaných pro aplikaci; nebo při rozhodování o tom, jaké další funkce mají využívat na jednotlivých platformách. Kód bude potřeba k detekci funkcí a zakázání funkcí nebo nabízení alternativ (např. alternativou k geografickému umístění může být umožnit uživateli zadat umístění nebo zvolit z mapy):

  • Kamera – Funkce se liší v různých zařízeních: některá zařízení nemají kameru, jiné mají přední i zadní kamery. Některé kamery jsou schopné nahrávání videa.
  • Geo-location & maps – Podpora GPS nebo Wi-Fi polohy není k dispozici na všech zařízeních. Aplikace musí také vyhovět různým úrovním přesnosti, které jednotlivé metody podporují.
  • Accelerometer, gyroskop a kompas – Tyto funkce se často nacházejí pouze ve výběru zařízení na každé platformě, takže aplikace téměř vždy potřebují poskytovat náhradní řešení, pokud hardware není podporovaný.
  • Twitter a Facebook – pouze integrované v iOS5 a iOS6. Na starších verzích a dalších platformách budete muset poskytovat vlastní ověřovací funkce a rozhraní přímo s rozhraním API jednotlivých služeb.
  • Near Field Communications (NFC) – pouze na (některých) telefonech s Androidem (v době psaní).

Práce s platformou Divergence

Existují dva různé přístupy k podpoře více platforem ze stejného základu kódu, z nichž každá má vlastní sadu výhod a nevýhod.

  • Model abstrakce platformy – obchodní fasáda poskytuje jednotný přístup napříč platformami a abstrahuje konkrétní implementace platformy do jednoho sjednoceného rozhraní API.
  • Divergent Implementace – Vyvolání konkrétních funkcí platformy prostřednictvím divergent implementací prostřednictvím nástrojů architektury, jako jsou rozhraní a dědičnost nebo podmíněná kompilace.

Abstrakce platformy

Abstrakce třídy

Použití rozhraní nebo základních tříd definovaných ve sdíleném kódu a implementované nebo rozšířené v projektech specifických pro platformu. Psaní a rozšiřování sdíleného kódu pomocí abstrakcí tříd je zvláště vhodné pro přenosné knihovny tříd, protože mají k dispozici omezenou podmnožinu architektury a nemohou obsahovat direktivy kompilátoru pro podporu větví kódu specifických pro platformu.

Rozhraní

Pomocí rozhraní můžete implementovat třídy specifické pro platformu, které se dají dál předávat do sdílených knihoven, abyste mohli využívat běžné kódy.

Rozhraní je definováno ve sdíleném kódu a předáno do sdílené knihovny jako parametr nebo vlastnost.

Aplikace specifické pro platformu pak mohou rozhraní implementovat a stále využívat sdílené kódy ke zpracování.

Výhody

Implementace může obsahovat kód specifický pro platformu a dokonce odkazovat na externí knihovny specifické pro platformu.

Nevýhody

Musíme vytvářet a předávat implementace do sdíleného kódu. Pokud se rozhraní používá hluboko ve sdíleném kódu, skončí předání prostřednictvím více parametrů metody nebo jinak vysunutí přes řetěz volání. Pokud sdílený kód používá velké množství různých rozhraní, musí být všechny vytvořeny a nastaveny ve sdíleném kódu někde.

Dědičnost

Sdílený kód může implementovat abstraktní nebo virtuální třídy, které by mohly být rozšířeny v jednom nebo více projektech specifických pro platformu. To se podobá použití rozhraní, ale s určitým chováním je již implementováno. Existují různé názory na to, jestli rozhraní nebo dědičnost představují lepší volbu návrhu: zejména proto, že jazyk C# umožňuje pouze jednu dědičnost, může určovat způsob, jakým je možné rozhraní API navrhovat dopředu. Používejte dědičnost s opatrností.

Výhody a nevýhody rozhraní platí stejně pro dědičnost, s další výhodou, že základní třída může obsahovat nějaký implementační kód (možná celá implementace nezávislá na platformě, která může být volitelně rozšířena).

Xamarin.Forms

Viz dokumentace k Xamarin.Forms .

Další multiplatformní knihovny

Tyto knihovny také nabízejí víceplatformní funkce pro vývojáře v jazyce C#:

Podmíněná kompilace

V některých situacích bude váš sdílený kód stále muset na každé platformě pracovat jinak, případně přistupovat ke třídám nebo funkcím, které se chovají odlišně. Podmíněná kompilace funguje nejlépe s projekty sdílených prostředků, kde se na stejný zdrojový soubor odkazuje ve více projektech, které mají definované různé symboly.

Projekty Xamarin vždy definují __MOBILE__ , které jsou pravdivé pro projekty aplikací pro iOS i Android (všimněte si dvojitého podtržítka před a po opravě těchto symbolů).

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

iOS

Xamarin.iOS definuje __IOS__ , které můžete použít k detekci zařízení s iOSem.

#if __IOS__
// iOS-specific code
#endif

K dispozici jsou také symboly specifické pro sledování a televizi:

#if __TVOS__
// tv-specific stuff
#endif

#if __WATCHOS__
// watch-specific stuff
#endif

Android

Kód, který by měl být zkompilován pouze do aplikací Xamarin.Android, může použít následující:

#if __ANDROID__
// Android-specific code
#endif

Každá verze rozhraní API také definuje novou direktivu kompilátoru, takže takový kód vám umožní přidat funkce, pokud cílí novější rozhraní API. Každá úroveň rozhraní API obsahuje všechny symboly nižší úrovně. Tato funkce není ve skutečnosti užitečná pro podporu více platforem; __ANDROID__ obvykle bude stačit symbol.

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

Mac

Xamarin.Mac definuje __MACOS__ , které můžete použít ke kompilaci pouze pro macOS:

#if __MACOS__
// macOS-specific code
#endif

Univerzální platforma Windows (UPW)

Použijte WINDOWS_UWP. Kolem řetězce nejsou žádná podtržítka, jako jsou symboly platformy Xamarin.

#if WINDOWS_UWP
// UWP-specific code
#endif

Použití podmíněné kompilace

Jednoduchý případový příklad podmíněné kompilace je nastavení umístění souboru pro soubor databáze SQLite. Tři platformy mají mírně odlišné požadavky pro určení umístění souboru:

  • iOS – Apple preferuje umístění neuživatelských dat do konkrétního umístění (adresář knihovny), ale pro tento adresář neexistuje žádná systémová konstanta. K sestavení správné cesty se vyžaduje kód specifický pro platformu.
  • Android – Systémová cesta vrácená Environment.SpecialFolder.Personal je přijatelné umístění pro uložení souboru databáze.
  • Windows Telefon – Mechanismus izolovaného úložiště neumožňuje zadat úplnou cestu, pouze relativní cestu a název souboru.
  • Univerzální platforma Windows – používá Windows.Storage rozhraní API.

Následující kód používá podmíněnou kompilaci k zajištění DatabaseFilePath správného nastavení pro každou platformu:

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

Výsledkem je třída, která se dá sestavit a použít na všech platformách a umístit soubor databáze SQLite do jiného umístění na každé platformě.