Partager via


Étude de cas d’application multiplateforme : Tâche

TaskyPortable est une application de liste de tâches simple. Ce document explique comment il a été conçu et créé, en suivant les instructions du document Building Cross-Platform Applications . La discussion couvre les domaines suivants :

Processus de conception

Il est conseillé de créer une feuille de route pour ce que vous souhaitez obtenir avant de commencer à coder. Cela est particulièrement vrai pour le développement multiplateforme, où vous créez des fonctionnalités qui seront exposées de plusieurs façons. À partir d’une idée claire de ce que vous créez gagne du temps et de l’effort plus tard dans le cycle de développement.

Spécifications

La première étape de la conception d’une application consiste à identifier les fonctionnalités souhaitées. Il peut s’agir d’objectifs généraux ou de cas d’usage détaillés. Tasky a des exigences fonctionnelles simples :

  • Afficher une liste de tâches
  • Ajouter, modifier et supprimer des tâches
  • Définir l’état d’une tâche sur « terminé »

Vous devez envisager votre utilisation de fonctionnalités spécifiques à la plateforme. Tasky peut-il tirer parti du géofencing iOS ou de Windows Téléphone vignettes dynamiques ? Même si vous n’utilisez pas de fonctionnalités spécifiques à la plateforme dans la première version, vous devez planifier à l’avance pour vous assurer que vos couches métier et de données peuvent les prendre en charge.

Conception de l'interface utilisateur

Commencez par une conception générale qui peut être implémentée sur les plateformes cibles. Prenez soin de noter les contraintes d’interface utilisateur specficiques de la plateforme. Par exemple, un TabBarController iOS peut afficher plus de cinq boutons, tandis que l’équivalent windows Téléphone peut afficher jusqu’à quatre. Dessinez le flux d’écran à l’aide de l’outil de votre choix (travaux de papier).

Draw the screen-flow using the tool of your choice paper works

Modèle de données

Connaître les données à stocker permet de déterminer le mécanisme de persistance à utiliser. Consultez l’accès aux données multiplateforme pour plus d’informations sur les mécanismes de stockage disponibles et vous aider à décider entre eux. Pour ce projet, nous allons utiliser SQLite.NET.

La tâche doit stocker trois propriétés pour chaque objet « TaskItem » :

  • Name : chaîne
  • Remarques – Chaîne
  • Terminé – Boolean

Fonctionnalité de base

Considérez l’API que l’interface utilisateur devra consommer pour répondre aux exigences. Une liste de tâches nécessite les fonctions suivantes :

  • Répertorier toutes les tâches : pour afficher la liste d’écran principale de toutes les tâches disponibles
  • Obtenir une tâche : lorsqu’une ligne de tâche est touchée
  • Enregistrer une tâche : lorsqu’une tâche est modifiée
  • Supprimer une tâche : lorsqu’une tâche est supprimée
  • Créer une tâche vide : lors de la création d’une nouvelle tâche

Pour obtenir la réutilisation du code, cette API doit être implémentée une fois dans la bibliothèque de classes portable.

Implémentation

Une fois la conception de l’application acceptée, envisagez comment elle peut être implémentée en tant qu’application multiplateforme. Cela deviendra l’architecture de l’application. En suivant les instructions du document Création d’applications multiplateformes, le code de l’application doit être divisé en parties suivantes :

  • Code commun : projet commun qui contient du code réutilisable pour stocker les données de tâche ; exposez une classe Model et une API pour gérer l’enregistrement et le chargement des données.
  • Code spécifique à la plateforme : projets spécifiques à la plateforme qui implémentent une interface utilisateur native pour chaque système d’exploitation, utilisant le code commun comme « back end ».

Platform-specific projects implement a native UI for each operating system, utilizing the common code as the back end

Ces deux parties sont décrites dans les sections suivantes.

Code commun (PCL)

Tasky Portable utilise la stratégie de bibliothèque de classes portable pour partager du code commun. Consultez le document Options de code de partage pour obtenir une description des options de partage de code.

Tout le code commun, y compris la couche d’accès aux données, le code de base de données et les contrats, est placé dans le projet de bibliothèque.

Le projet PCL complet est illustré ci-dessous. Tout le code de la bibliothèque portable est compatible avec chaque plateforme ciblée. Quand elle est déployée, chaque application native référence cette bibliothèque.

When deployed, each native app will reference that library

Le diagramme de classes ci-dessous montre les classes regroupées par couche. La SQLiteConnection classe est un code réutilisable à partir du package Sqlite-NET. Les autres classes sont du code personnalisé pour Tasky. Les TaskItemManager classes et TaskItem les classes représentent l’API exposée aux applications spécifiques à la plateforme.

The TaskItemManager and TaskItem classes represent the API that is exposed to the platform-specific applications

L’utilisation d’espaces de noms pour séparer les couches permet de gérer les références entre chaque couche. Les projets spécifiques à la plateforme doivent uniquement inclure une using instruction pour la couche Entreprise. La couche d’accès aux données et la couche de données doivent être encapsulées par l’API exposée TaskItemManager dans la couche Métier.

Références

Les bibliothèques de classes portables doivent être utilisables sur plusieurs plateformes, chacune avec différents niveaux de prise en charge des fonctionnalités de plateforme et d’infrastructure. En raison de cela, il existe des limitations sur les packages et les bibliothèques d’infrastructure qui peuvent être utilisés. Par exemple, Xamarin.iOS ne prend pas en charge le mot clé c# dynamic . Par conséquent, une bibliothèque de classes portable ne peut pas utiliser de package qui dépend du code dynamique, même si ce code fonctionne sur Android. Visual Studio pour Mac vous empêchera d’ajouter des packages et références incompatibles, mais vous voudrez garder les limitations à l’esprit pour éviter les surprises ultérieurement.

Remarque : vous verrez que vos projets référencent les bibliothèques d’infrastructure que vous n’avez pas utilisées. Ces références sont incluses dans le cadre des modèles de projet Xamarin. Lorsque les applications sont compilées, le processus de liaison supprime le code non référencé. Par conséquent, même si System.Xml elle a été référencée, elle n’est pas incluse dans l’application finale, car nous n’utilisons aucune fonction Xml.

Couche de données (DL)

La couche données contient le code qui effectue le stockage physique des données , qu’il s’agisse d’une base de données, de fichiers plats ou d’un autre mécanisme. La couche de données Tasky se compose de deux parties : la bibliothèque SQLite-NET et le code personnalisé ajouté pour l’associer.

Tasky s’appuie sur le package NuGet Sqlite-net (publié par Frank Krueger) pour incorporer du code SQLite-NET qui fournit une interface de base de données ORM (Object-Relational Mapping). La TaskItemDatabase classe hérite et ajoute les méthodes CRUD (Create, Read, Update, Delete) requises SQLiteConnection pour lire et écrire des données dans SQLite. Il s’agit d’une implémentation réutilisable simple de méthodes CRUD génériques qui peuvent être réutilisées dans d’autres projets.

Il TaskItemDatabase s’agit d’un singleton, ce qui garantit que tous les accès se produisent sur la même instance. Un verrou est utilisé pour empêcher l’accès simultané à partir de plusieurs threads.

SQLite sur Windows Téléphone

Même si iOS et Android sont fournis avec SQLite dans le cadre du système d’exploitation, Windows Téléphone n’inclut pas de moteur de base de données compatible. Pour partager du code sur les trois plateformes, une version native windows phone de SQLite est requise. Consultez Utilisation d’une base de données locale pour plus d’informations sur la configuration de votre projet Windows Téléphone pour Sqlite.

Utilisation d’une interface pour généraliser l’accès aux données

La couche de données prend une dépendance pour BL.Contracts.IBusinessIdentity qu’elle puisse implémenter des méthodes d’accès aux données abstraites qui nécessitent une clé primaire. Toute classe Business Layer qui implémente l’interface peut ensuite être conservée dans la couche de données.

L’interface spécifie simplement une propriété entière pour agir en tant que clé primaire :

public interface IBusinessEntity {
    int ID { get; set; }
}

La classe de base implémente l’interface et ajoute les attributs SQLite-NET pour le marquer comme clé primaire incrémentante automatiquement. Toute classe de la couche Métier qui implémente cette classe de base peut ensuite être conservée dans la couche de données :

public abstract class BusinessEntityBase : IBusinessEntity {
    public BusinessEntityBase () {}
    [PrimaryKey, AutoIncrement]
    public int ID { get; set; }
}

Voici un exemple de méthodes génériques dans la couche de données qui utilisent l’interface GetItem<T> :

public T GetItem<T> (int id) where T : BL.Contracts.IBusinessEntity, new ()
{
    lock (locker) {
        return Table<T>().FirstOrDefault(x => x.ID == id);
    }
}

Verrouillage pour empêcher l’accès simultané

Un verrou est implémenté dans la TaskItemDatabase classe pour empêcher l’accès simultané à la base de données. Cela permet de s’assurer que l’accès simultané à partir de différents threads est sérialisé (sinon, un composant d’interface utilisateur peut tenter de lire la base de données en même temps qu’un thread d’arrière-plan le met à jour). Voici un exemple de la façon dont le verrou est implémenté :

static object locker = new object ();
public IEnumerable<T> GetItems<T> () where T : BL.Contracts.IBusinessEntity, new ()
{
    lock (locker) {
        return (from i in Table<T> () select i).ToList ();
    }
}
public T GetItem<T> (int id) where T : BL.Contracts.IBusinessEntity, new ()
{
    lock (locker) {
        return Table<T>().FirstOrDefault(x => x.ID == id);
    }
}

La plupart du code de couche de données peut être réutilisé dans d’autres projets. Le seul code spécifique à l’application dans la couche est l’appel CreateTable<TaskItem> dans le TaskItemDatabase constructeur.

Couche d’accès aux données (DAL)

La TaskItemRepository classe encapsule le mécanisme de stockage de données avec une API fortement typée qui permet TaskItem aux objets d’être créés, supprimés, récupérés et mis à jour.

Utilisation de la compilation conditionnelle

La classe utilise la compilation conditionnelle pour définir l’emplacement du fichier : il s’agit d’un exemple d’implémentation de Platform Divergence. Propriété qui retourne le chemin d’accès se compile en code différent sur chaque plateforme. Les directives de compilateur spécifiques au code et à la plateforme sont présentées ici :

public static string DatabaseFilePath {
    get {
        var sqliteFilename = "TaskDB.db3";
#if SILVERLIGHT
        // Windows Phone expects a local path, not absolute
        var path = sqliteFilename;
#else
#if __ANDROID__
        // Just use whatever directory SpecialFolder.Personal returns
        string libraryPath = Environment.GetFolderPath(Environment.SpecialFolder.Personal); ;
#else
        // 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"); // Library folder
#endif
        var path = Path.Combine (libraryPath, sqliteFilename);
                #endif
                return path;
    }
}

Selon la plateforme, la sortie est «< chemin> d’application/Library/TaskDB.db3 » pour iOS, «< app path>/Documents/TaskDB.db3 » pour Android ou simplement « TaskDB.db3 » pour Windows Téléphone.

Couche Métier (BL)

La couche métier implémente les classes de modèle et une façade pour les gérer. Dans Tasky, le modèle est la TaskItem classe et TaskItemManager implémente le modèle Façade pour fournir une API pour la gestion TaskItems.

Façade

TaskItemManager encapsule les DAL.TaskItemRepository méthodes Get, Save et Delete qui seront référencées par les couches application et interface utilisateur.

Les règles d’entreprise et la logique sont placées ici si nécessaire , par exemple toutes les règles de validation qui doivent être satisfaites avant l’enregistrement d’un objet.

API pour code spécifique à la plateforme

Une fois le code commun écrit, l’interface utilisateur doit être générée pour collecter et afficher les données exposées par celui-ci. La TaskItemManager classe implémente le modèle Façade pour fournir une API simple pour que le code de l’application accède.

Le code écrit dans chaque projet spécifique à la plateforme est généralement étroitement couplé au SDK natif de cet appareil, et accède uniquement au code commun à l’aide de l’API définie par le TaskItemManager. Cela inclut les méthodes et les classes métier qu’il expose, telles que TaskItem.

Les images ne sont pas partagées entre les plateformes, mais ajoutées indépendamment à chaque projet. Cela est important, car chaque plateforme gère les images différemment, en utilisant différents noms de fichiers, répertoires et résolutions.

Les sections restantes décrivent les détails de l’implémentation spécifique à la plateforme de l’interface utilisateur Tasky.

Application iOS

Il n’existe qu’une poignée de classes requises pour implémenter l’application tasky iOS à l’aide du projet PCL commun pour stocker et récupérer des données. Le projet iOS Xamarin.iOS complet est illustré ci-dessous :

iOS project is shown here

Les classes sont affichées dans ce diagramme, regroupées en couches.

The classes are shown in this diagram, grouped into layers

Références

L’application iOS fait référence aux bibliothèques sdk spécifiques à la plateforme, par exemple. Xamarin.iOS et MonoTouch.Dialog-1.

Il doit également référencer le TaskyPortableLibrary projet PCL. La liste des références est affichée ici :

The references list is shown here

La couche Application et la couche Interface utilisateur sont implémentées dans ce projet à l’aide de ces références.

Couche Application (AL)

La couche Application contient des classes spécifiques à la plateforme requises pour « lier » les objets exposés par le PCL à l’interface utilisateur. L’application spécifique à iOS a deux classes pour vous aider à afficher les tâches :

  • EditingSource : cette classe est utilisée pour lier des listes de tâches à l’interface utilisateur. Étant donné que MonoTouch.Dialog nous avons été utilisés pour la liste des tâches, nous devons implémenter cet assistance pour activer la fonctionnalité de balayage à supprimer dans le UITableView . Le balayage vers la suppression est courant sur iOS, mais pas sur Android ou Windows Téléphone. Par conséquent, le projet spécifique à iOS est le seul qui l’implémente.
  • TaskDialog : cette classe est utilisée pour lier une seule tâche à l’interface utilisateur. Il utilise l’API MonoTouch.Dialog Réflexions ion pour « wrap » l’objet TaskItem avec une classe qui contient les attributs appropriés pour permettre à l’écran d’entrée d’être correctement mis en forme.

La TaskDialog classe utilise MonoTouch.Dialog des attributs pour créer un écran en fonction des propriétés d’une classe. La classe se présente comme suit :

public class TaskDialog {
    public TaskDialog (TaskItem task)
    {
        Name = task.Name;
        Notes = task.Notes;
        Done = task.Done;
    }
    [Entry("task name")]
    public string Name { get; set; }
    [Entry("other task info")]
    public string Notes { get; set; }
    [Entry("Done")]
    public bool Done { get; set; }
    [Section ("")]
    [OnTap ("SaveTask")]    // method in HomeScreen
    [Alignment (UITextAlignment.Center)]
    public string Save;
    [Section ("")]
    [OnTap ("DeleteTask")]  // method in HomeScreen
    [Alignment (UITextAlignment.Center)]
    public string Delete;
}

Notez que les OnTap attributs nécessitent un nom de méthode : ces méthodes doivent exister dans la classe où l’objet MonoTouch.Dialog.BindingContext est créé (dans ce cas, la HomeScreen classe abordée dans la section suivante).

Couche d’interface utilisateur (IU)

La couche Interface utilisateur se compose des classes suivantes :

  1. AppDelegate : contient des appels à l’API Apparence pour styler les polices et les couleurs utilisées dans l’application. Tasky est une application simple, il n’existe donc aucune autre tâche d’initialisation en FinishedLaunching cours d’exécution.
  2. Écrans : sous-classes de UIViewController ce qui définissent chaque écran et son comportement. Les écrans associent l’interface utilisateur à des classes Application Layer et à l’API commune ( TaskItemManager ). Dans cet exemple, les écrans sont créés dans le code, mais ils peuvent avoir été conçus à l’aide du Générateur d’interface de Xcode ou du concepteur storyboard.
  3. Images : les éléments visuels sont une partie importante de chaque application. Tasky a des images d’écran de démarrage et d’icône, qui pour iOS doivent être fournies en résolution régulière et Rétine.

Écran d'accueil

L’écran d’accueil est un MonoTouch.Dialog écran qui affiche une liste de tâches à partir de la base de données SQLite. Il hérite et implémente du DialogViewController code pour définir la Root collection d’objets TaskItem à afficher.

It inherits from DialogViewController and implements code to set the Root to contain a collection of TaskItem objects for display

Les deux méthodes principales liées à l’affichage et à l’interaction avec la liste des tâches sont les suivantes :

  1. PopulateTable : utilise la méthode de TaskManager.GetTasks la couche métier pour récupérer une collection d’objets TaskItem à afficher.
  2. Sélectionné : lorsqu’une ligne est tactile, affiche la tâche dans un nouvel écran.

Écran Détails de la tâche

Les détails de la tâche sont un écran d’entrée qui permet aux tâches d’être modifiées ou supprimées.

Tasky utilise MonoTouch.Dialogl’API Réflexions ion de l’écran pour afficher l’écran. Il n’existe donc aucune UIViewController implémentation. Au lieu de cela, la HomeScreen classe instancie et affiche une DialogViewController classe à l’aide de la TaskDialog couche Application.

Cette capture d’écran montre un écran vide qui illustre la définition du Entry texte de filigrane dans les champs Nom et Notes :

This screenshot shows an empty screen that demonstrates the Entry attribute setting the watermark text in the Name and Notes fields

La fonctionnalité de l’écran Détails de la tâche (par exemple, l’enregistrement ou la suppression d’une tâche) doit être implémentée dans la HomeScreen classe, car il s’agit de l’emplacement où il MonoTouch.Dialog.BindingContext est créé. Les méthodes suivantes HomeScreen prennent en charge l’écran Détails de la tâche :

  1. ShowTaskDetails : crée un MonoTouch.Dialog.BindingContext écran pour afficher un écran. Il crée l’écran d’entrée à l’aide de la réflexion pour récupérer les noms et les types de propriétés de la TaskDialog classe. Des informations supplémentaires, telles que le texte de filigrane pour les zones d’entrée, sont implémentées avec des attributs sur les propriétés.
  2. SaveTask : cette méthode est référencée dans la TaskDialog classe via un OnTap attribut. Elle est appelée lorsque l’option Enregistrer est enfoncée et utilise une MonoTouch.Dialog.BindingContext pour récupérer les données entrées par l’utilisateur avant d’enregistrer les modifications à l’aide TaskItemManager de .
  3. DeleteTask : cette méthode est référencée dans la TaskDialog classe via un OnTap attribut. Il utilise TaskItemManager pour supprimer les données à l’aide de la clé primaire (propriété ID).

Application Android

Le projet Xamarin.Android complet est illustré ci-dessous :

Android project is pictured here

Diagramme de classes, avec des classes regroupées par couche :

The class diagram, with classes grouped by layer

Références

Le projet d’application Android doit référencer l’assembly Xamarin.Android spécifique à la plateforme pour accéder aux classes à partir du Kit de développement logiciel (SDK) Android.

Il doit également référencer le projet PCL (par exemple, TaskyPortableLibrary) pour accéder au code commun des données et de la couche métier.

TaskyPortableLibrary to access the common data and business layer code

Couche Application (AL)

Comme pour la version iOS que nous avons examinée précédemment, la couche Application dans la version Android contient des classes spécifiques à la plateforme requises pour « lier » les objets exposés par core à l’interface utilisateur.

TaskListAdapter : pour afficher une liste<T> d’objets, nous devons implémenter un adaptateur pour afficher des objets personnalisés dans un ListView. L’adaptateur contrôle la disposition utilisée pour chaque élément de la liste . Dans ce cas, le code utilise une disposition SimpleListItemCheckedintégrée Android.

Interface utilisateur (IU)

La couche d’interface utilisateur de l’application Android est une combinaison de code et de balisage XML.

  • Ressources/Disposition : dispositions d’écran et conception de cellule de ligne implémentées en tant que fichiers AXML. L’AXML peut être écrit manuellement ou disposé visuellement à l’aide du Concepteur d’interface utilisateur Xamarin pour Android.
  • Ressources/Dessinable : images (icônes) et bouton personnalisé.
  • Écrans : sous-classes d’activité qui définissent chaque écran et son comportement. Lie l’interface utilisateur avec les classes Application Layer et l’API commune (TaskItemManager).

Écran d'accueil

L’écran d’accueil se compose d’une sous-classe HomeScreen Activité et du HomeScreen.axml fichier qui définit la disposition (position du bouton et de la liste des tâches). L’écran ressemble à ceci :

The screen looks like this

Le code d’écran d’accueil définit les gestionnaires permettant de cliquer sur le bouton et de cliquer sur les éléments de la liste, ainsi que de remplir la liste dans la OnResume méthode (afin qu’elle reflète les modifications apportées dans l’écran Détails de la tâche). Les données sont chargées à l’aide TaskItemManager de la couche Métier et de TaskListAdapter la couche Application.

Écran Détails de la tâche

L’écran Détails de la tâche se compose également d’une Activity sous-classe et d’un fichier de disposition AXML. La disposition détermine l’emplacement des contrôles d’entrée et la classe C# définit le comportement à charger et enregistrer des TaskItem objets.

The class defines the behavior to load and save TaskItem objects

Toutes les références à la bibliothèque PCL sont via la TaskItemManager classe.

Application Windows Téléphone

Le projet Windows Téléphone complet :

Windows Phone App The complete Windows Phone project

Le diagramme ci-dessous présente les classes regroupées en couches :

This diagram presents the classes grouped into layers

Références

Le projet spécifique à la plateforme doit référencer les bibliothèques spécifiques à la plateforme requises (par Microsoft.Phone exemple) System.Windowspour créer une application Windows Téléphone valide.

Il doit également référencer le projet PCL (par exemple TaskyPortableLibrary) pour utiliser la classe et la TaskItem base de données.

TaskyPortableLibrary to utilize the TaskItem class and database

Couche Application (AL)

Là encore, comme avec les versions iOS et Android, la couche application se compose des éléments non visuels qui aident à lier des données à l’interface utilisateur.

ViewModels

ViewModels encapsule les données du PCL ( TaskItemManager) et les présente de manière à pouvoir être consommées par la liaison de données Silverlight/XAML. Il s’agit d’un exemple de comportement spécifique à la plateforme (comme indiqué dans le document Applications multiplateformes).

Interface utilisateur (IU)

XAML dispose d’une fonctionnalité de liaison de données unique qui peut être déclarée dans le balisage et réduire la quantité de code requise pour afficher les objets :

  1. Pages : fichiers XAML et leur codebehind définissent l’interface utilisateur et référencent les ViewModels et le projet PCL pour afficher et collecter des données.
  2. Images : écran de démarrage, images d’arrière-plan et d’icône sont une partie clé de l’interface utilisateur.

MainPage

La classe MainPage utilise l’option pour afficher des TaskListViewModel données à l’aide des fonctionnalités de liaison de données de XAML. La page est définie sur le modèle d’affichage DataContext , qui est rempli de manière asynchrone. La {Binding} syntaxe dans le code XAML détermine la façon dont les données sont affichées.

TaskDetailsPage

Chaque tâche s’affiche en liant TaskViewModel le code XAML défini dans TaskDetailsPage.xaml. Les données de tâche sont récupérées via la TaskItemManager couche Métier.

Résultats

Les applications résultantes ressemblent à ceci sur chaque plateforme :

iOS

L’application utilise la conception d’interface utilisateur standard iOS, telle que le bouton « ajouter » positionné dans la barre de navigation et à l’aide de l’icône intégrée plus (+). Il utilise également le comportement du bouton « Précédent » par défaut UINavigationController et prend en charge « balayer vers supprimer » dans le tableau.

It also uses the default UINavigationController back button behavior and supports swipe-to-delete in the tableIt also uses the default UINavigationController back button behavior and supports swipe-to-delete in the table

Android

L’application Android utilise des contrôles intégrés, y compris la disposition intégrée pour les lignes qui nécessitent une « graduation » affichée. Le comportement de retour matériel/système est pris en charge en plus d’un bouton précédent à l’écran.

The hardware/system back behavior is supported in addition to an on-screen back buttonThe hardware/system back behavior is supported in addition to an on-screen back button

Windows Phone

L’application Windows Téléphone utilise la disposition standard, remplit la barre d’application en bas de l’écran au lieu d’une barre de navigation en haut.

The Windows Phone app uses the standard layout, populating the app bar at the bottom of the screen instead of a nav bar at the topThe Windows Phone app uses the standard layout, populating the app bar at the bottom of the screen instead of a nav bar at the top

Résumé

Ce document a fourni une explication détaillée de la façon dont les principes de conception d’application en couches ont été appliqués à une application simple pour faciliter la réutilisation du code sur trois plateformes mobiles : iOS, Android et Windows Téléphone.

Il a décrit le processus utilisé pour concevoir les couches d’application et a discuté de ce que le code et les fonctionnalités ont été implémentés dans chaque couche.

Le code peut être téléchargé à partir de github.