1. Introduction
Les cartes Wear OS permettent d'accéder facilement aux informations et aux actions dont les utilisateurs ont besoin pour effectuer une tâche. Il suffit de balayer l'écran à partir du cadran pour consulter les dernières prévisions ou lancer un minuteur.
Une carte s'exécute dans l'interface utilisateur du système au lieu de s'exécuter dans son propre conteneur d'application. Nous utilisons un service pour décrire la mise en page et le contenu de cette carte. L'UI du système affiche ensuite la carte si nécessaire.
Objectifs de l'atelier
Vous créerez une carte qui affichera les conversations récentes pour une application de chat. À partir de cette surface, l'utilisateur peut effectuer trois tâches courantes :
- Ouvrir une conversation
- Écrire un nouveau message
Points abordés
Dans cet atelier de programmation, vous apprendrez à écrire votre propre carte Wear OS, ce qui comprend les tâches suivantes :
- Créer un élément
TileService
- Tester une carte sur un appareil
- Prévisualiser l'interface utilisateur d'une carte dans Android Studio
- Développer l'interface utilisateur d'une carte
- Ajouter des images
- Gérer les interactions
Prérequis
- Connaissances de base du langage Kotlin
2. Configuration
Au cours de cette étape, vous configurerez votre environnement et téléchargerez le projet de démarrage.
Ce dont vous avez besoin
- Mise à jour groupée d'Android Studio Koala | 02/01/2024 Canary 1 ou version ultérieure
- Appareil ou émulateur Wear OS
Si vous ne savez pas comment utiliser Wear OS, nous vous recommandons de lire ce guide rapide avant de commencer. Il contient des instructions pour configurer un émulateur Wear OS et décrit comment naviguer dans le système.
Télécharger le code
Si git est installé, vous pouvez simplement exécuter la commande ci-dessous pour cloner le code à partir de ce dépôt.
git clone https://github.com/android/codelab-wear-tiles.git cd codelab-wear-tiles
Si vous n'avez pas git, cliquez sur le bouton ci-dessous pour télécharger l'ensemble du code de cet atelier de programmation :
Ouvrir un projet dans Android Studio
Dans la fenêtre "Welcome to Android Studio" (Bienvenue dans Android Studio), sélectionnez Open an Existing Project (Ouvrir un projet existant) ouFile > Open (Fichier > Ouvrir), puis sélectionnez le dossier [Emplacement de téléchargement].
3. Créer une carte de base
Le point d'entrée d'une carte est le service de cartes. Au cours de cette étape, vous allez enregistrer un service de cartes et définir une mise en page de carte.
HelloWorldTileService
Une classe qui implémente TileService
doit spécifier deux méthodes :
onTileResourcesRequest(requestParams: ResourcesRequest): ListenableFuture<Resources>
onTileRequest(requestParams: TileRequest): ListenableFuture<Tile>
La première méthode renvoie un objet Resources
qui mappe les ID de chaîne aux ressources image que nous utiliserons dans notre carte.
La seconde renvoie la description d'une carte, y compris sa mise en page. C'est là que nous définirons la mise en page d'une carte et la manière dont les données y sont liées.
Ouvrez HelloWorldTileService.kt
à partir du module start
. Toutes les modifications que vous allez apporter seront incluses dans ce module. Si vous voulez voir le résultat de cet atelier de programmation, il existe également un module finished
.
HelloWorldTileService
complète SuspendingTileService
, un wrapper compatible avec la coroutine Kotlin issu de la bibliothèque Horologist Tiles. Horologist est un groupe de bibliothèques Google visant à fournir aux développeurs Wear OS des fonctionnalités complémentaires qui sont couramment plébiscitées, mais qui ne sont pas encore disponibles dans Jetpack.
SuspendingTileService
fournit deux fonctions de suspension, qui sont des équivalents de coroutine des fonctions de TileService
:
suspend resourcesRequest(requestParams: ResourcesRequest): Resources
suspend tileRequest(requestParams: TileRequest): Tile
Pour en savoir plus sur les coroutines, consultez la documentation sur les coroutines Kotlin sur Android.
HelloWorldTileService
n'est pas encore terminé. Nous devons enregistrer le service dans notre fichier manifeste et fournir également une implémentation pour tileLayout
.
Enregistrer le service de cartes
Une fois le service de cartes enregistré dans le fichier manifeste, il apparaît dans la liste des cartes que l'utilisateur peut ajouter.
Ajoutez <service>
dans l'élément <application>
:
start/src/main/AndroidManifest.xml
<service
android:name="com.example.wear.tiles.hello.HelloWorldTileService"
android:icon="@drawable/ic_waving_hand_24"
android:label="@string/hello_tile_label"
android:description="@string/hello_tile_description"
android:exported="true"
android:permission="com.google.android.wearable.permission.BIND_TILE_PROVIDER">
<intent-filter>
<action android:name="androidx.wear.tiles.action.BIND_TILE_PROVIDER" />
</intent-filter>
<!-- The tile preview shown when configuring tiles on your phone -->
<meta-data
android:name="androidx.wear.tiles.PREVIEW"
android:resource="@drawable/tile_hello" />
</service>
L'icône et le libellé sont utilisés (comme des espaces réservés) lors du chargement initial de la carte ou en cas d'erreur lors du chargement. Les métadonnées à la fin définissent une image d'aperçu qui s'affiche dans le carrousel lorsque l'utilisateur ajoute une carte.
Définir la mise en page de la carte
HelloWorldTileService
possède une fonction appelée tileLayout
avec l'élément TODO()
comme corps. Nous allons maintenant remplacer cela par une implémentation dans laquelle nous définirons la mise en page de la carte :
start/src/main/java/com/example/wear/tiles/hello/HelloWorldTileService.kt
fun tileLayout(
context: Context,
deviceConfiguration: DeviceParametersBuilders.DeviceParameters,
message: String,
) =
materialScope(
context = context,
deviceConfiguration = deviceConfiguration,
allowDynamicTheme = false,
) {
primaryLayout(mainSlot = { text(message.layoutString) })
}
Et voilà notre première carte Wear OS créée. Installons cette carte et voyons ce à quoi elle ressemble.
4. Tester votre carte sur un appareil
Une fois le module de démarrage sélectionné dans le menu déroulant de la configuration d'exécution, vous pouvez installer l'application (module start
) sur votre appareil ou dans un émulateur, puis installer manuellement la carte, comme le ferait un utilisateur.
Toutefois, Android Studio propose un raccourci pour cette opération : appuyez sur l'icône "Run service" (Exécuter le service) (▷) dans la marge, puis sélectionnez "Run HelloWorldTileService" (Exécuter HelloWoldTileService). La carte sera alors installée et lancée sur un appareil connecté.
Cliquez sur "Run HelloWorldTileService" (Exécuter HelloWorldTileService) pour créer et exécuter votre carte sur un appareil connecté. Une capture d'écran semblable à celle ci-dessous devrait s'afficher.
L'icône représentant une main qui fait signe, qui s'affiche en haut de l'écran, est fournie par le système. Pour la modifier, modifiez la propriété android:icon
de l'élément <service>
de la carte dans le fichier manifeste.
Pour plus de commodité, ce processus crée également une "configuration d'exécution" "HelloWorldTileService" pour une utilisation ultérieure.
5. Ajouter des fonctions d'aperçu
Vous pouvez afficher un aperçu de l'interface utilisateur des cartes dans Android Studio. Cela permet de raccourcir la boucle de rétroaction lors du développement de l'interface utilisateur, ce qui augmente la vitesse de développement.
Ajoutez un aperçu de carte pour le HelloWorldTileService
à la fin du fichier HelloWorldTileService.kt
.
start/src/main/java/com/example/wear/tiles/hello/HelloWorldTileService.kt
@Preview(device = WearDevices.SMALL_ROUND, name = "Small Round")
@Preview(device = WearDevices.LARGE_ROUND, name = "Large Round")
internal fun helloLayoutPreview(context: Context): TilePreviewData {
return TilePreviewData {
TilePreviewHelper.singleTimelineEntryTileBuilder(
helloLayout(context, it.deviceConfiguration, "Hello, preview tile!")
)
.build()
}
}
Utilisez la vue d'écran partagé pour afficher un aperçu de la carte :
Notez que l'annotation @Composable
n'est pas utilisée. Bien que les cartes utilisent la même UI d'aperçu que les fonctions composables, elles n'utilisent pas Compose et ne sont pas composables.
6. Créer une carte de messages
La carte de messages que nous allons créer s'apparente davantage à une carte réelle. Contrairement à l'exemple HelloWorld, celui-ci présente les composants de Material 3 Expressive, affiche des images et gère les interactions pour ouvrir l'application.
MessagingTileService
MessagingTileService
complète la classe SuspendingTileService
que nous avons vue précédemment.
7. Ajouter des composants d'interface utilisateur
La bibliothèque ProtoLayout fournit des composants et des mises en page prédéfinis qui vous permettent de créer des cartes utilisant les derniers designs Material 3 Expressive pour Wear OS.
Ajoutez la dépendance Tiles Material au fichier build.gradle
:
start/build.gradle
implementation "androidx.wear.protolayout:protolayout-material3:$protoLayoutVersion"
Ajoutez le code de mise en page à la fonction tileLayout()
, en tant que corps de la fonction materialScope()
. Cette opération crée une mise en page composée de deux lignes (avec deux boutons chacune) et d'un bouton de bord.
Recherchez la ligne TODO() // Add primaryLayout() et remplacez-la par le code ci-dessous.
start/src/main/java/com/example/wear/tiles/messaging/tile/Layout.kt
primaryLayout(
mainSlot = {
// This layout code assumes "contacts" contains at least 4 elements, for sample code
// that can handle an arbitrary number of contacts, and also shows different numbers
// of contacts based on the physical screen size, see
// <https://github.com/android/wear-os-samples/tree/main/WearTilesKotlin>.
Column.Builder()
.apply {
setWidth(expand())
setHeight(expand())
addContent(
buttonGroup {
buttonGroupItem { contactButton(contacts[0]) }
buttonGroupItem { contactButton(contacts[1]) }
}
)
addContent(DEFAULT_SPACER_BETWEEN_BUTTON_GROUPS)
addContent(
buttonGroup {
buttonGroupItem { contactButton(contacts[2]) }
buttonGroupItem { contactButton(contacts[3]) }
}
)
}
.build()
},
bottomSlot = {
textEdgeButton(
onClick = clickable(), // TODO: Launch new conversation activity
labelContent = { text("New".layoutString) },
)
},
)
La fonction contactButton()
dans le même fichier crée les boutons de contact individuels. Si le contact est associé à une image, celle-ci s'affiche sur le bouton. Sinon, les initiales du contact sont utilisées.
À ce stade, vous remarquerez peut-être que, bien que la mise en page générale soit correcte, les images sont absentes :
Vous verrez la même chose si vous déployez la carte sur un appareil :
À l'étape suivante, nous allons résoudre le problème d'images manquantes.
8. Ajouter des images
De manière générale, les cartes se composent de deux éléments : une mise en page (qui fait référence à des ressources par des ID de chaîne) et les ressources elles-mêmes (qui peuvent être des images).
Pour le moment, notre code fournit la mise en page, mais pas les ressources elles-mêmes. Pour corriger l'aperçu, nous devons fournir les "ressources" de l'image. Pour ce faire, recherchez TODO: Add onTileResourceRequest et ajoutez le code ci-dessous en tant qu'argument nommé supplémentaire à TilePreviewData()
:
start/src/main/java/com/example/wear/tiles/messaging/tile/Layout.kt
// Additional named argument to TilePreviewData
onTileResourceRequest = { resourcesRequest ->
Resources.Builder()
.setVersion(resourcesRequest.version)
.apply {
contacts.forEach {
if (it.avatarSource is AvatarSource.Resource) {
addIdToImageMapping(
it.imageResourceId(),
it.avatarSource.resourceId
)
}
}
}
.build()
}
Les images devraient maintenant s'afficher dans l'aperçu :
Toutefois, si la carte est déployée sur un appareil, les images seront absentes. Pour résoudre ce problème, remplacez la fonction resourcesRequest()
dans Service.kt
par le code suivant :
start/src/main/java/com/example/wear/tiles/messaging/tile/Service.kt
override suspend fun resourcesRequest(
requestParams: ResourcesRequest
): Resources {
// resourceIds is a list of the ids we need to provide images for. If we're passed an empty
// list, set resourceIds to all resources.
val resourceIds =
requestParams.resourceIds.ifEmpty {
contacts.map { it.imageResourceId() }
}
// resourceMap maps (tile) resource ids to (Android) resource ids.
val resourceMap =
contacts
.mapNotNull {
when (it.avatarSource) {
is AvatarSource.Resource ->
it.imageResourceId() to
it.avatarSource.resourceId
else -> null
}
}
.toMap()
.filterKeys {
it in resourceIds
} // filter to only the resources we need
// Add images in the resourceMap to the Resources object, and return the result.
return Resources.Builder()
.setVersion(requestParams.version)
.apply {
resourceMap.forEach { (id, imageResource) ->
addIdToImageMapping(id, imageResource)
}
}
.build()
}
Désormais, les images s'affichent également lorsque la carte est déployée sur un appareil :
À l'étape suivante, nous traiterons les clics sur chacun des éléments.
9. Gérer les interactions
Les raccourcis vers les parcours utilisateur les plus importants sont l'un des principaux atouts d'une carte. À ne pas confondre avec le lanceur d'applications, qui ouvre simplement l'application ! Dans le cas présent, nous avons l'espace nécessaire pour fournir des raccourcis contextuels sur un écran spécifique de votre application.
Jusqu'à présent, nous avons utilisé une action fictive fournie par le clickable()
sans argument pour le chip et chacun des boutons. Cette approche convient pour les aperçus, qui ne sont pas interactifs, mais voyons comment ajouter des actions correspondant aux éléments.
LaunchAction
L'élément LaunchAction
peut être utilisé pour lancer une activité. Modifions Layout
de sorte que l'utilisateur puisse appuyer sur le bouton "New" (Nouveau) pour lancer le parcours utilisateur "New conversation" (Nouvelle conversation).
Recherchez la ligne TODO: Launch new conversation activity et remplacez clickable()
par :
start/src/main/java/com/example/wear/tiles/messaging/tile/Layout.kt
clickable(
id = "new_button",
action =
launchAction(
ComponentName(
"com.example.wear.tiles",
"com.example.wear.tiles.messaging.MainActivity",
),
mapOf(
MainActivity.EXTRA_JOURNEY to
ActionBuilders.stringExtra(
MainActivity.EXTRA_JOURNEY_NEW
)
),
),
)
Redéployez la carte. Désormais, au lieu de ne rien faire, le fait d'appuyer sur "New" (Nouveau) lance MainActivity
et démarre le parcours utilisateur "New conversation" (Nouvelle conversation) :
De même, modifiez Layout
pour que l'utilisateur puisse lancer une conversation avec un contact spécifique en appuyant sur un bouton.
Recherchez la ligne Launch open conversation activity (Lancer l'activité de conversation ouverte) et remplacez clickable()
par :
start/src/main/java/com/example/wear/tiles/messaging/tile/Layout.kt
clickable(
id = contact.id.toString(),
action =
launchAction(
ComponentName(
"com.example.wear.tiles",
"com.example.wear.tiles.messaging.MainActivity",
),
mapOf(
MainActivity.EXTRA_JOURNEY to
ActionBuilders.stringExtra(
MainActivity
.EXTRA_JOURNEY_CONVERSATION
),
MainActivity.EXTRA_CONVERSATION_CONTACT to
ActionBuilders.stringExtra(
contact.name
),
),
),
)
Redéployez la carte. Désormais, au lieu de ne rien faire, le fait d'appuyer sur un contact lancera une conversation avec ce dernier :
10. Félicitations
Félicitations ! Vous avez appris à créer une carte pour Wear OS.
Et maintenant ?
Pour en savoir plus, consultez les implémentations de Golden Tiles sur GitHub, le guide des cartes Wear OS et les consignes de conception.