- Applications développées avec les langages/technologies Java ou Kotlin pour Android ou Objective-C ou Swift pour iOS/iPadOS.
- Applications développées avec des frameworks Xamarin, Flutter, etc. qui traduisent le code source (C#, Dart, ...) dans un code natif à travers des brides (ponts).
- Applications développées avec une technologies front (HTML, React, ...), parfois accompagnées de wrappers (PhoneGap, ...).
Technologie | Code métier | Code UI | Android | iOS / iPadOS |
---|---|---|---|---|
Android | Java/Kotlin | AXML | ✅ | ❌ |
iOS/iPadOS | Objective-C/Swift | XIB (Xcode Interface Builder, page par page) / Storyboard (toutes les pages). | ❌ | ✅ |
React Native | React (Typescript) | HTML, React, ... | ✅ | ✅ |
PWA | JavaScript, Typescript, ReactJS, Angular, Blazor (C#), ... | HTML, technologie front (ReactJS, Angular, Blaozor, Razor, ...), ... | ✅ | ✅ |
Flutter | Dart | Dart | ✅ | ✅ |
Xamarin.Android | C# | AXML (natif Android) | ✅ | ✅ |
Xamarin.iOS | C# | XIB, Storyboards (natif iOS) | ✅ | ✅ |
Xamarin.Forms | C# | XAML (partagé) | ✅ | ✅ |
Xamarin.Forms deviendra MAUI en novembre 2022.
Xamarin.X se base sur Mono (et pas .NET Framework/.NET Core/.NET). C'est une implémentation de .NET (grâce au standard ECMA-335) sur les distributations Linux (Ubuntu, Xubuntu, DebianOS, OpenSuse, ...).
Technologie | Installations Windows | Installations macOS |
---|---|---|
Xamarin.Android | SDK Android (pour les versions), JDK, Visual Studio avec les outils Xamarin, NDK, Emulateurs. | SDK Android (pour les versions), JDK, Visual Studio avec les outils Xamarin, NDK, Emulateurs. |
Xamarin.iOS | Visual Studio avec les outils Xamarin, macOS avec XCode et les SDK's iOS (pour apparayer l'émulateur avec Windows et tester depuis cet OS) ou un compte Apple Developer. | XCode avec les SDK's et simulateurs iOS, Visual Studio, Xamarin. |
Xamarin.Forms | Les deux installations ci-dessus. | Les deux installations ci-dessus. |
- SDK : Set Development Kit
- JDK : Java Development Kit
- NDK : Native Development Kit (C, C++, ...)
Informations complémentaires
- En italique, les outils qui ne sont pas obligatoires.
- Accélérer les émulateurs Android : https://docs.microsoft.com/xamarin/android/get-started/installation/android-emulator/hardware-acceleration?tabs=vswin&pivots=windows#hyper-v
- L'application doit avoir un fichier manifest.xml qui va contenir les informations de l'application (versions d'Android compatibles, nom de l'application, thème, permissions, activités, ...) ;
- Les ressources sont stockées dans le dossier
R
et sont indéxées dans une classe pour être utilisées grâce à la méthodeview.findById(int)
. - L'application se compose d'une ou plusieurs activités. Les activités ont un cycle de vie (
onCreate
,onStart
,onResume
,onPause
,onStop
,onDestroy
,onRestart
) ; - L'activité de démarrage doit être présicée par la propriété de l'attribut (
MainLauncher
).
- Le point d'entrée de l'application est la classe
Application
et la méthode statiqueMain(string[])
. La classeUIApplication
permet de définir le nom de la classe principale, par défaut AppDelegate. - L'
AppDelegate
permet de définir le comportement global de l'application iOS. - On retrouve des ViewController qui vont gérer les interactions entre les différentes "pages".
- Les fichiers
*.storyboard
vont définir l'interface graphique de notre application iOS, y compris la navigation. - Le fichier
info.plist
contient les informations relatives à mon application mobile : nom, périphériques, ...
- Framework qui permet de développer des applications mobiles (natives) sur Android et iOS à l'aide des langages C# (pour le code métier/behind) et XAML (pour l'interface graphique) ;
- Le point d'entrée est, par défaut, la classe
App
(fichierApp.xaml.cs
, qui hérite deXamarin.Forms.Application
) et défini la page de démarrage (PropriétéMainPage
) ; - Le fichier
App.xaml
contient les ressources (dictionnaires, thèmes, couleurs, ...) globales (accessibles depuis toute l'application) ; - Les fichiers
*.xaml.cs
sont le code behind des pages*.xaml
et sont liées à travers la propriétéx:Class
(côté xaml) ; - On peut réutiliser toutes nos connaissances C# pour développer notre application (syntaxe, méthodes, packages NuGet, ...) ;
Pour chaque événement, un lien est fait entre Xamarin.Forms et Xamarin.Android/Xamarin.iOS. Plus d'informations : https://jlamch.blogspot.com/2018/08/mobile-view-lifecycle-fixing.html
(TODO: copier code Mourad)
- Une liaison forte entre un élément et un autre (par exemple, entre un Label et un Slider).
- Différentes manières de créer une liaison (voir documentation officielle).
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="DataBindingDemos.AlternativeXamlBindingPage"
Title="Alternative XAML Binding">
<StackLayout Padding="10, 0">
<Label Text="TEXT"
FontSize="40"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand"
Scale="{Binding Value, Source={x:Reference slider},
Path=Value}" />
<Slider x:Name="slider"
Minimum="-2"
Maximum="2"
VerticalOptions="CenterAndExpand" />
</StackLayout>
</ContentPage>
Informations complémentaires :
- https://docs.microsoft.com/xamarin/xamarin-forms/enterprise-application-patterns/mvvm
- http://wpftutorial.net/MVVM.html (comparaison des patterns MVVM-MVC-MVP)
- Par défaut, une
ListView
permet d'afficher des éléments et n'a pas de template. Chaque élément aura pour contenu la valeur de la méthodeToString()
(soit pour unBlogPost
:ExpertsBlog.Entities.BlogPost
) ; - On peut personnaliser l'UI de chaque élément grâce à un DataTemplate ;
- Le DataTemplate peut être défini à l'intérieur d'un
ItemTemplate
(exemple 1) ou dans les ressources d'une page (exemple 2) ou de l'application (fichierApp.xaml
- exemple 3).
<ContentPage ...>
<ContentPage.Resources>
<!--Nothing, empty, nada, rien-->
</ContentPage.Resources>
<RefreshView>
<CollectionView ItemsSource="{Binding Items}">
<CollectionView.ItemTemplate>
<!-- ItemTemplate ne peut prendre qu'un objet de type DataTemplate -->
<DataTemplate>
<StackLayout>
<Label Text="{Binding Title}"/>
</StackLayout>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
<RefreshView>
</ContentPage>
<ContentPage ...>
<ContentPage.Resources>
<DataTemplate x:Key="BlogPostTemplate">
<StackLayout>
<Label Text="{Binding Title}"/>
</StackLayout>
</DataTemplate>
</ContentPage.Resources>
<RefreshView>
<CollectionView ItemsSource="{Binding Items}" ItemTemplate="{StaticResource BlogPostTemplate}"/>
<RefreshView>
</ContentPage>
App.xaml :
<Application ...>
<Application.Resources>
...
<DataTemplate x:Key="BlogPostTemplate">
<StackLayout>
<Label Text="{Binding Title}"/>
</StackLayout>
</DataTemplate>
...
</Application.Resources>
</Application>
MainPage.xaml :
<ContentPage ...>
...
<RefreshView>
<CollectionView ItemsSource="{Binding Items}" ItemTemplate="{StaticResource BlogPostTemplate}"/>
<RefreshView>
</ContentPage>
Ne pas confondre l'utilité de
RefreshView
,ListView
etCollectionView
.
Plus ou moins équivalent au pattern MVC et MVP. Plus d'informations : http://wpftutorial.net/MVVM.html
- View : Afficher les données, retransmettre le ViewModel et envoyer les modifications à effectuer (un champs texte qui envoie une nouvelle valeur au ViewModel) ;
- ViewModel : Envoyer/Recevoir des données, transformer, notifier un changement à la view (via l'implémentation de l'interface
System.ComponentModel.INotifyPropertyChanged
) ; - Model : Les objets qu'on va manipuler pendant le cycle de vie de notre application (DTO - Data Transfert Object).
public class DemoViewModel : System.ComponentModel.INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
/// <summary>
/// Méthode qui va effectuer la notification
/// </summary>
private void OnPropertyChanged(string propertyName)
{
// On vérifie que PropertyChanged n'est pas `null`
if (PropertyChanged == null)
{
return;
}
// this = instance de `DemoViewModel`
// Instancier l'événement qui va contenir le nom de la propriété à changer.
// On créé les arguments de l'événement.
var args = new PropertyChangedEventArgs(propertyName);
// On invoque l'événément en lui donnant le nom de la propriété à modifier.
PropertyChanged.Invoke(this, args);
}
/// <summary>
/// Méthode générique qui va notifier le changement de valeur d'une propriété.
/// </summary>
/// <typeparam name="T">Type de la propriété publique et du champ privé.</typeparam>
/// <param name="storage">Valeur avec sa réference (adresse en mémoire) du champ privé.</param>
/// <param name="value">Nouvelle valeur.</param>
/// <param name="propertyName">Le nom de la propriété qui va être modifiée.</param>
protected void SetProperty<T>(ref T storage, T value, [CallerMemberName] string propertyName = null)
{
// Vérifier l'égalité entre la valeur de `storage` et de `value`.
if (EqualityComparer<T>.Default.Equals(storage, value))
{
// Si la valeur est égale, on arrête.
return;
}
// On remplace la valeur à l'adresse de `storage` par la nouvelle valeur, `value`.
storage = value;
// On appelle la méthode `OnPropertyChanged(string)` qui va créer un événement de changement de valeur.
OnPropertyChanged(propertyName);
}
}
INotifyCollectionChanged
permet d'être notifié si une collection a été mise à jour ou pas (ajout, édition, suppression, etc). Cette interface est implémentée dansSystem.ObjectModel.ObservableCollection<T>
.
Possibilités :
- Gérer des routes de l'application ;
- Créer une interface graphique avec soit un menu hamburger (flyout) et/ou des onglets ;
- Chaque élément peut être modifié grâce aux templates ;
- Naviguer entre plusieurs pages ;
Créer un Shell
:
<Shell xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:demoshell.Views"
Title="Demoshell"
x:Class="Demoshell.AppShell">
<Shell.Resources>...</Shell.Resources>
<!-- Element du menu hamburger (flyout), nommé "About" et dont l'icone est spécifiée, permettant de changer de page -->
<FlyoutItem Title="About" Icon="icon_about.png">
<ShellContent Route="AboutPage" ContentTemplate="{DataTemplate local:AboutPage}" />
</FlyoutItem>
<!-- Element du menu cliquable et qui ne change pas directement le contenu de la page. Cet élément va s'afficher dans le flyout (par défaut, en bas des éventuels `FlyoutItem`) -->
<MenuItem Text="Logout" Clicked="OnMenuItemClicked" />
<!-- Barre à onglets, chaque `ShellContent` va représenter un onglet -->
<TabBar>
<ShellContent Route="LoginPage" ContentTemplate="{DataTemplate local:LoginPage}" />
</TabBar>
</Shell>
Enregistrer des routes (non visibles depuis le flyout ou depuis les onglets) :
public partial class AppShell : Xamarin.Forms.Shell
{
public AppShell()
{
InitializeComponent();
Routing.RegisterRoute(nameof(ItemDetailPage), typeof(ItemDetailPage));
Routing.RegisterRoute(nameof(NewItemPage), typeof(NewItemPage));
}
private void OnMenuItemClicked(object sender, EventArgs e)
{
// Do something with menu item.
}
}
Une application de blogs spécialisée dans les commerces de proximité.
Projet | Description |
---|---|
ExpertsBlog.Entities |
Les modèles (BlogPost , Category , Tag , ) qui serviront à notre API. |
ExpertsBlogs.Mobile |
Le code partagé de l'application. |
ExpertsBlogs.Mobile.Android |
Code spécifique de l'application Android. |
ExpertsBlogs.Mobile.iOS |
Code spécifique de l'application iOS/iPadOS. |
- Créer un projet Xamarin.Forms (vide) nommé
ExpertsBlog
. - Implémenter le pattern MVVM.
- Modifier la page d'accueil pour afficher une liste de
BlogPost
. - Modifier le
DataTemplate
de la liste à afficher.
- Ajouter un fichier à la racine du projet
ExpertsBlog.Mobile
(template "Forms ContentPage XAML", par exemple) nommé "AppShell" (les fichiersAppShell.xaml.cs
etAppShell.xaml
vont être créés). - Remplacer la classe parente (héritage) de la classe
ExpertsBlog.Mobile.AppShell
parXamarin.Forms.Shell
- Remplacer l'élément root du fichier xaml (designer) de
ContentPage
(ou autre) parShell
. - Modifier la page de démarrage de l'application par une nouvelle instance de
AppShell
(propriétéMainPage
du constructeur de la classeApp
). - Implémenter un Shell avec 2
FlyoutItem
qui affiche la liste des billets de blog et "A propos" qui affichera une page "A propos". - Ajouter la page "A propos"
- La page principale doit afficher la liste des billets de blog.