Un tutoriel sur les extensions d'application iOS 8
Publié: 2022-03-11Peu de gens avaient essayé auparavant (regardez ceci), mais c'est Apple avec le premier iPhone qui a défini à quoi devraient ressembler un Smartphone et un système d'exploitation mobile. Apple a fait une percée incroyable dans le matériel et l'expérience utilisateur. Cependant, nous oublions souvent qu'ils établissent également des normes sur la manière dont un système d'exploitation mobile doit fonctionner et sur la manière dont les applications d'un smartphone doivent être créées.
Construire des murs en béton entre les applications, les rendant complètement isolées et inconscientes les unes des autres, était la meilleure méthode pour les sécuriser et protéger leurs données. Toutes les activités étaient étroitement surveillées par iOS, et il n'y avait qu'une poignée d'actions qu'une application aurait pu faire en dehors de son champ d'application.
« L'abstinence est la meilleure des protections ! - mais où est le plaisir là-dedans ?
Cela leur a pris du temps; trop longtemps si vous me demandez, mais avec iOS 8, Apple a décidé de s'amuser. iOS 8 a introduit un nouveau concept appelé App Extensions. Cette nouvelle fonctionnalité n'a pas fait tomber les murs entre les applications, mais elle a ouvert quelques portes offrant un contact doux mais tangible entre certaines applications. La dernière mise à jour a donné aux développeurs iOS la possibilité de personnaliser l'écosystème iOS, et nous sommes impatients de voir cette voie s'ouvrir également.
Que sont les extensions d'application iOS 8 et comment fonctionnent-elles ?
En termes simples, les extensions d'application iOS 8 offrent une nouvelle méthode d'interaction avec votre application, sans la démarrer ni l'afficher à l'écran.
Comme prévu, Apple s'est assuré de rester au courant de tout, il n'y a donc qu'une poignée de nouveaux points d'entrée que votre application peut fournir :
- Aujourd'hui (également appelé widget) - une extension affichée dans la vue Aujourd'hui du Centre de notifications affiche de brèves informations et permet d'effectuer des tâches rapides.
- Partager - une extension qui permet à votre application de partager du contenu avec des utilisateurs sur les réseaux sociaux et d'autres services de partage.
- Action - une extension qui permet de créer des boutons d'action personnalisés dans la feuille d'action pour permettre aux utilisateurs d'afficher ou de transformer le contenu provenant d'une application hôte.
- Édition de photos - une extension qui permet aux utilisateurs de modifier une photo ou une vidéo dans l'application Photos.
- Fournisseur de documents - une extension utilisée pour permettre à d'autres applications d'accéder aux documents gérés par votre application.
- Clavier personnalisé - une extension qui remplace le clavier système.
Les extensions d'application ne sont pas des applications autonomes. Ils fournissent des fonctionnalités étendues de l'application (accessibles à partir d'autres applications, appelées applications hôtes) qui sont censées être efficaces et concentrées sur une seule tâche. Ils ont leur propre binaire, leur propre signature de code et leur propre ensemble d'éléments, mais sont livrés via l'App Store dans le cadre du binaire de l'application contenante. Une application (contenante) peut avoir plusieurs extensions. Une fois que l'utilisateur a installé une application dotée d'extensions, celles-ci seront disponibles sur iOS.
Prenons un exemple : un utilisateur trouve une image à l'aide de Safari, appuie sur le bouton de partage et choisit l'extension de votre application pour le partage. Safari "parle" au framework iOS Social, qui charge et présente l'extension. Le code de l'extension s'exécute, transmet les données à l'aide des canaux de communication instanciés du système et, une fois la tâche terminée, Safari supprime la vue de l'extension. Peu de temps après, le système met fin au processus et votre application n'a jamais été affichée à l'écran. Pourtant, il a complété une fonction de partage d'images.
iOS, utilisant la communication inter-processus, est responsable de s'assurer que l'application hôte et une extension d'application peuvent fonctionner ensemble. Les développeurs utilisent des API de haut niveau fournies par le point d'extension et le système, ils n'ont donc jamais à se soucier des mécanismes de communication sous-jacents.
Cycle de la vie
Les extensions d'application ont un cycle de vie différent de celui des applications iOS. L'application hôte lance le cycle de vie de l'extension en réponse à l'action d'un utilisateur. Ensuite, le système instancie l'extension d'application et configure un canal de communication entre eux. La vue de l'extension s'affiche dans le contexte de l'application hôte à l'aide des éléments reçus dans la demande de l'application hôte. Une fois la vue de l'extension affichée, l'utilisateur peut interagir avec elle. En réponse à l'action de l'utilisateur, l'extension complète la demande de l'application hôte en exécutant/annulant immédiatement la tâche ou, si nécessaire, en lançant un processus en arrière-plan pour l'exécuter. Juste après cela, l'application hôte supprime la vue de l'extension et l'utilisateur revient à son contexte précédent dans l'application hôte. Les résultats de l'exécution de ce processus peuvent être renvoyés à l'application hôte une fois le processus terminé. L'extension se termine généralement peu de temps après avoir terminé la demande reçue de l'application hôte (ou démarre un processus d'arrière-plan pour l'exécuter).
Le système ouvre l'extension de l'action d'un utilisateur à partir de l'application hôte, l'extension affiche l'interface utilisateur, effectue certaines tâches et renvoie des données à l'application hôte (si cela convient au type d'extension). L'application contenant n'est même pas en cours d'exécution pendant que son extension est en cours d'exécution.
Création d'une extension d'application - Exemple pratique à l'aide de l'extension Aujourd'hui
Les extensions Aujourd'hui, également appelées widgets , sont situées dans la vue Aujourd'hui du centre de notification. Ils sont un excellent moyen de présenter un contenu à jour pour l'utilisateur (comme afficher les conditions météorologiques) ou d'effectuer des tâches rapides (comme marquer les choses effectuées dans le widget d'une application de liste de tâches). Je dois souligner ici que l' entrée au clavier n'est pas prise en charge .
Créons une extension Today qui affichera les informations les plus récentes de notre application (code sur GitHub). Afin d'exécuter ce code, veuillez vous assurer que vous avez (re)configuré le groupe d'applications pour le projet (sélectionnez votre équipe de développement, gardez à l'esprit que le nom du groupe d'applications doit être unique et suivez les instructions de Xcode).
Création d'un nouveau widget
Comme nous l'avons déjà dit, les extensions d'application ne sont pas des applications autonomes. Nous avons besoin d'une application conteneur sur laquelle nous allons construire l'extension d'application. Une fois que nous avons notre application contenante, nous choisissons d'ajouter une nouvelle cible en naviguant vers Fichier -> Nouveau -> Cible dans Xcode. À partir de là, nous choisissons le modèle de notre nouvelle cible pour ajouter une extension aujourd'hui.
À l'étape suivante, nous pouvons choisir notre nom de produit. C'est le nom qui apparaîtra dans la vue Aujourd'hui du Centre de notifications. Il existe également une option pour choisir le langage entre Swift et Objective-C à cette étape. Une fois ces étapes terminées, Xcode crée un modèle Today, qui fournit des fichiers d'en-tête et d'implémentation par défaut pour la classe principale (nommée TodayViewController
) avec le fichier Info.plist
et un fichier d'interface (un storyboard ou un fichier .xib). Le fichier Info.plist
, par défaut, ressemble à ceci :
<key>NSExtension</key> <dict> <key>NSExtensionMainStoryboard</key> <string>MainInterface</string> <key>NSExtensionPointIdentifier</key> <string>com.apple.widget-extension</string> </dict>
Si vous ne souhaitez pas utiliser le storyboard fourni par le modèle, supprimez la clé NSExtensionMainStoryboard
et ajoutez la clé NSExtensionPrincipalClass
avec le nom de votre contrôleur de vue comme valeur.
Un widget Aujourd'hui doit :
- assurez-vous que le contenu est toujours à jour
- répondre de manière appropriée aux interactions des utilisateurs
- fonctionnent bien (les widgets iOS doivent utiliser la mémoire à bon escient ou ils seront terminés par le système)
Partage de données et conteneur partagé
L'extension d'application et son application contenante ont toutes deux accès aux données partagées dans leur conteneur partagé défini de manière privée - qui est un moyen de communication indirecte entre l'application contenante et l'extension.
N'aimez-vous pas la façon dont Apple rend ces choses si « simples » ? :)
Le partage de données NSUserDefaults
est simple et un cas d'utilisation courant. Par défaut, l'extension et l'application qui la contient utilisent des ensembles de données NSUserDefaults
distincts et ne peuvent pas accéder aux conteneurs de l'autre. Pour modifier ce comportement, iOS a introduit les groupes d'applications . Après avoir activé les groupes d'applications sur l'application contenante et l'extension, au lieu d'utiliser [NSUserDefaults standardUserDefaults]
utilisez [[NSUserDefaults alloc] initWithSuiteName:@"group.yourAppGroupName"]
pour accéder au même conteneur partagé.
Mise à jour du widget
Pour s'assurer que le contenu est toujours à jour, l'extension Today fournit une API pour gérer l'état d'un widget et gérer les mises à jour de contenu. Le système capture occasionnellement des instantanés de la vue du widget. Ainsi, lorsque le widget devient visible, l'instantané le plus récent s'affiche jusqu'à ce qu'il soit remplacé par une version en direct de la vue. Une conformation au protocole NCWidgetProviding
est importante pour mettre à jour l'état d'un widget avant qu'un instantané ne soit pris. Une fois que le widget reçoit l'appel widgetPerformUpdateWithCompletionHandler:
, la vue du widget doit être mise à jour avec le contenu le plus récent et le gestionnaire d'achèvement doit être appelé avec l'une des constantes suivantes pour décrire le résultat de la mise à jour :

-
NCUpdateResultNewData
- Le nouveau contenu nécessite de redessiner la vue -
NCUpdateResultNoDate
- Le widget ne nécessite pas de mise à jour -
NCUpdateResultFailed
- Une erreur s'est produite lors du processus de mise à jour
- (void)widgetPerformUpdateWithCompletionHandler:(void (^)(NCUpdateResult))completionHandler { // Perform any setup necessary in order to update the view. // If an error is encountered, use NCUpdateResultFailed // If there's no update required, use NCUpdateResultNoData // If there's an update, use NCUpdateResultNewData [self updateTableView]; completionHandler(NCUpdateResultNewData); }
Contrôler quand le widget est visible
Pour contrôler quand un widget est affiché, utilisez la setHasContent:forWidgetWithBundleIdentifier:
de la classe NCWidgetController
. Cette méthode vous permettra de spécifier l'état du contenu du widget. Il peut être appelé depuis le widget ou depuis l'application qui le contient (si elle est active). Vous pouvez passer un indicateur NO
ou YES
à cette méthode, définissant que le contenu du widget est prêt ou non. Si le contenu n'est pas prêt, iOS n'affichera pas votre widget lorsque la vue Aujourd'hui est ouverte.
NCWidgetController *widgetController = [[NCWidgetController alloc] init]; [widgetController setHasContent:YES forWidgetWithBundleIdentifier:@"com.your-company.your-app.your-widget"];
Ouverture de l'application contenante à partir du widget
Le widget Aujourd'hui est la seule extension qui peut demander l'ouverture de son application contenante en appelant la openURL:completionHandler:
Pour garantir que l'application contenante s'ouvre d'une manière logique dans le contexte de la tâche actuelle de l'utilisateur, un schéma d'URL personnalisé (que le widget et l'application contenante peuvent utiliser) doit être défini.
[self.extensionContext openURL:[NSURL URLWithString:@"customURLsheme://URLpath"] completionHandler:nil];
Considérations relatives à l'interface utilisateur
Lors de la conception de votre widget, tirez parti de la classe UIVisualEffectView
, en gardant à l'esprit que les vues qui doivent être floues/vibrantes doivent être ajoutées à contentView
et non directement à UIVisualEffectView
. Les widgets (conformes au protocole NCWidgetProviding
) doivent charger les états mis en cache dans viewWillAppear:
afin de correspondre à l'état de la vue de la dernière viewWillDisappear:
puis passer en douceur aux nouvelles données lorsqu'elles arrivent, ce qui n'est pas le cas avec une vue normale contrôleur (l'interface utilisateur est configurée dans viewDidLoad
et gère les animations et le chargement des données dans viewWillAppear
). Les widgets doivent être conçus pour effectuer une tâche ou ouvrir l'application contenante en un seul clic. L'entrée au clavier n'est pas disponible dans un widget. Cela signifie que toute interface utilisateur nécessitant une saisie de texte ne doit pas être utilisée.
L'ajout de défilements dans un widget, à la fois vertical et horizontal, n'est pas possible. Ou plus précisément, l'ajout d'une vue de défilement est possible mais le défilement ne fonctionnera pas. Le geste de défilement horizontal dans une vue de défilement dans l'extension Aujourd'hui sera intercepté par le centre de notification, ce qui entraînera le défilement d'Aujourd'hui vers le Centre de notification. Le défilement vertical d'une vue de défilement à l'intérieur d'une extension Aujourd'hui sera interrompu par le défilement de la vue d'aujourd'hui.
Remarques techniques
Ici, je vais souligner quelques points importants à garder à l'esprit lors de la création d'une extension d'application.
Fonctionnalités communes à toutes les extensions
Les éléments suivants s'appliquent à toutes les extensions :
L'objet sharedApplication est interdit : les extensions d'application ne peuvent pas accéder à un objet sharedApplication ni utiliser aucune des méthodes liées à cet objet.
La caméra et le microphone sont interdits : les extensions d'application ne peuvent pas accéder à la caméra ou au microphone de l'appareil (mais ce n'est pas le cas pour tous les éléments matériels). Cela est dû à l'indisponibilité de certaines API. Pour accéder à certains éléments matériels de l'extension d'application, vous devrez vérifier si son API est disponible pour les extensions d'application ou non (avec la vérification de la disponibilité de l'API décrite ci-dessus).
La plupart des tâches en arrière-plan sont interdites : les extensions d'application ne peuvent pas effectuer de tâches en arrière-plan de longue durée, à l'exception du lancement de chargements ou de téléchargements, ce qui est décrit ci-dessous.
AirDrop est interdit : les extensions d'application ne peuvent pas recevoir (mais peuvent envoyer) des données à l'aide d'AirDrop.
Chargement/téléchargement en arrière-plan
La seule tâche pouvant être effectuée en arrière-plan est le chargement/téléchargement, à l'aide de l' NSURLSession object
.
Une fois la tâche de chargement/téléchargement lancée, l'extension peut terminer la demande de l'application hôte et se terminer sans aucun effet sur le résultat de la tâche. Si l'extension n'est pas en cours d'exécution au moment où la tâche en arrière-plan se termine, le système lance l'application contenante en arrière-plan et la méthode déléguée de l' application:handleEventsForBackgroundURLSession:completionHandler:
est appelée.
L'application dont l'extension lance une tâche NSURLSession
en arrière-plan doit avoir un conteneur partagé configuré auquel l'application contenante et son extension peuvent accéder.
Assurez-vous de créer différentes sessions d'arrière-plan pour l'application contenante et chacune de ses extensions d'application (chaque session d'arrière-plan doit avoir un identifiant unique). Ceci est important car un seul processus peut utiliser une session en arrière-plan à la fois.
Action contre partage
Les différences entre les extensions Action et Share ne sont pas tout à fait claires du point de vue du codeur, car en pratique, elles sont très similaires. Le modèle de Xcode pour la cible d'extension de partage utilise SLComposeServiceViewController
, qui fournit une interface utilisateur de vue de composition standard que vous pouvez utiliser pour le partage social, mais ce n'est pas obligatoire. Une extension de partage peut également hériter directement de UIViewController pour une conception entièrement personnalisée, de la même manière qu'une extension d'action peut hériter de SLComposeServiceViewController
.
Les différences entre ces deux types d'extensions résident dans la manière dont elles sont censées être utilisées. Avec l'extension Action, vous pouvez créer une extension sans interface utilisateur propre (par exemple, une extension utilisée pour traduire le texte sélectionné et renvoyer la traduction à l'application hôte). L'extension de partage vous permet de partager des commentaires, des photos, des vidéos, de l'audio, des liens, etc. directement depuis l'application hôte. Le UIActivityViewController
pilote à la fois les extensions Action et Share, où les extensions Share sont présentées sous forme d'icônes de couleur dans la rangée supérieure et les extensions d'action sont présentées sous forme d'icônes monochromes dans la rangée inférieure (Image 2.1).
API interdites
Les API marquées dans les fichiers d'en-tête avec la macro NS_EXTENSION_UNAVAILABLE
, ou une macro similaire pour l'indisponibilité, ne peuvent pas être utilisées (par exemple : les frameworks d'interface utilisateur HealthKit et EventKit dans iOS 8 ne peuvent être utilisés dans aucune extension d'application).
Si vous partagez du code entre une application et une extension, vous devez garder à l'esprit que même le fait de faire référence à une API non autorisée pour l'extension d'application entraînera le rejet de votre application de l'App Store. Vous pouvez choisir de gérer cela en refactorisant les classes partagées en hiérarchies, avec un parent commun et différentes sous-classes pour différentes cibles. Une autre façon consiste à utiliser le pré-processeur par des vérifications #ifdef
. Parce qu'il n'y a toujours pas de cible conditionnelle intégrée, vous devez créer la vôtre.
Une autre bonne façon de le faire est de créer votre propre framework intégré. Assurez-vous simplement qu'il ne contiendra aucune API indisponible pour les extensions. Pour configurer une extension d'application pour l'utilisation d'un framework intégré, accédez aux paramètres de construction de la cible et définissez le paramètre « Requérir uniquement l'API App-Extension-Safe » sur Oui. Lors de la configuration du projet Xcode, dans la phase de construction Copier les fichiers, "Frameworks" doit être choisi comme destination pour le framework intégré. Si vous choisissez la destination "SharedFrameworks", votre soumission sera rejetée par l'App Store.
Remarque sur la rétrocompatibilité
Bien que les extensions d'application ne soient disponibles que depuis iOS 8, vous pouvez rendre votre application contenante disponible pour les versions iOS antérieures.
Conformité de l'interface utilisateur Apple
Gardez à l'esprit les directives d'interface utilisateur iOS d'Apple lors de la conception d'une extension d'application. Vous devez vous assurer que l'extension de votre application est universelle, quel que soit l'appareil pris en charge par votre application contenante. Pour vous assurer que l'extension d'application est universelle, utilisez le paramètre de génération de la famille d'appareils ciblés dans Xcode en spécifiant la valeur « iPhone/iPad » (parfois appelée universelle).
Conclusion
Les extensions d'application ont certainement l'impact le plus visible dans iOS 8. Étant donné que 79 % des appareils utilisent déjà iOS 8 (tel que mesuré par l'App Store le 13 avril 2015), les extensions d'application sont des fonctionnalités incroyables dont les applications devraient tirer parti. En combinant les restrictions de l'API et la manière de partager les données entre les extensions et leur application contenante, il semble qu'Apple ait réussi à répondre à l'une des plus grandes plaintes concernant la plate-forme sans compromettre son modèle de sécurité. Il n'y a toujours aucun moyen pour les applications tierces de partager directement leurs données entre elles. Bien que ce soit un tout nouveau concept, il semble très prometteur.