Personnaliser le flux pour les cartes de contenu
Un flux de cartes de contenu correspond à la séquence de cartes de contenu dans vos applications mobiles ou Web. Cet article traite de la configuration du moment où le flux est actualisé, de l’ordre des cartes, de la gestion de plusieurs flux et des messages d’erreur « flux vide ». Pour obtenir la liste complète des types de cartes de contenu, consultez À propos des cartes de contenu.
À propos du cycle de vie de la session
Une session désigne la période pendant laquelle le SDK Braze suit l’activité des utilisateurs dans votre application après son lancement. Vous pouvez également forcer une nouvelle session en appelant lachangeUser()méthode.
Par défaut, une session commence lorsque vous appelez pour la premièrebraze.openSession() fois . La session restera active pendant un maximum de30minutes d’inactivité (à moins que vous ne modifiiez le délai d’expiration par défaut de la session ou que l’utilisateur ne ferme l’application).
Si vous avez configuré le rappel du cycle de ](/docs/fr/developer_guide/platform_integration_guides/android/initial_sdk_setup/android_sdk_integration/#step-4-tracking-user-sessions-in-android)vie des activités pour Android, Braze appellera automatiquementopenSession() etcloseSession()pour chaque activité de votre application.
Par défaut, une session commence lorsqueopenSession() est appelé pour la première fois. Si votre application passe en arrière-plan puis revient au premier plan, le SDK vérifiera si plus de 10 secondes se sont écoulées depuis le début de la session (à moins que vous ne modifiiez le délai d’expiration par défaut de la session). Dans ce cas, une nouvelle session débutera. Veuillez noter que si l’utilisateur ferme votre application alors qu’elle est en arrière-plan, les données de session risquent de ne pas être envoyées à Braze tant qu’il n’aura pas rouvert l’application.
Appeler necloseSession() mettra pas immédiatement fin à la session. Au lieu de cela, la session prendra fin après 10 secondes si l’utilisateur openSession()ne la relance pas en démarrant une autre activité.
Par défaut, une session commence lorsque vous appelez Braze.init(configuration:). Cela se produit lorsque le déclencheurUIApplicationWillEnterForegroundNotificationde la notification est activé, ce qui signifie que l’application est passée au premier plan.
Si votre application passe en arrière-plan, le UIApplicationDidEnterBackgroundNotificationdéclencheur est activé. L’application ne reste pas dans une session active lorsqu’elle est en arrière-plan. Lorsque votre application revient au premier plan, le SDK compare le temps écoulé depuis le début de la session au délai d’expiration de la session (à moins que vous ne modifiiez le délai d’expiration par défaut). Si le temps écoulé depuis le début de la session dépasse le délai d’expiration, une nouvelle session commence.
Actualiser le flux
Actualisation automatique
Par défaut, le flux de cartes de contenu s’actualise automatiquement lorsque :
- Une nouvelle session est lancée
- Le flux par défaut de cartes de contenu est fermé puis rouvert après plus de 60 secondes depuis la dernière actualisation.
Pour afficher dynamiquement des cartes de contenu à jour sans les actualiser manuellement, sélectionnez À la première impression lors de la création de la carte. Ces cartes seront actualisées dès qu’elles seront disponibles.
Actualisation manuelle
Pour actualiser manuellement le flux à un moment précis :
Demandez à tout moment une actualisation manuelle des cartes de contenu Braze à partir du SDK Web en appelant requestContentCardsRefresh().
Vous pouvez également appeler getCachedContentCards pour obtenir toutes les cartes actuellement disponibles depuis la dernière actualisation des cartes de contenu.
1
2
3
4
5
import * as braze from "@braze/web-sdk";
function refresh() {
braze.requestContentCardsRefresh();
}
Demandez à tout moment une actualisation manuelle des cartes de contenu Braze à partir du SDK Android en appelant requestContentCardsRefresh.
1
Braze.getInstance(context).requestContentCardsRefresh();
1
Braze.getInstance(context).requestContentCardsRefresh()
Demandez à tout moment une actualisation manuelle des cartes de contenu Braze à partir du SDK Swift en appelant la méthode requestRefresh de la classe Braze.ContentCards :
Dans Swift, les cartes de contenu peuvent être actualisées soit avec un gestionnaire d’achèvement facultatif, soit avec un retour asynchrone en utilisant les API de concurrence natives de Swift.
Gestionnaire d’achèvement
1
2
3
AppDelegate.braze?.contentCards.requestRefresh { result in
// Implement completion handler
}
Async/Await
1
let contentCards = await AppDelegate.braze?.contentCards.requestRefresh()
1
2
3
[AppDelegate.braze.contentCards requestRefreshWithCompletion:^(NSArray<BRZContentCardRaw *> * contentCards, NSError * error) {
// Implement completion handler
}];
Limite de débit
Braze utilise un algorithme de compartiments à jetons pour appliquer les limites de débit suivantes :
- Jusqu’à 5 appels d’actualisation par appareil, partagés entre les utilisateurs et les appels à
openSession() - Une fois la limite atteinte, un nouvel appel devient disponible toutes les 180 secondes (3 minutes)
- Le système conserve jusqu’à cinq appels que vous pouvez utiliser à tout moment
subscribeToContentCards()renverra toujours les cartes mises en cache, même lorsque la limite de débit est atteinte
Le SDK Braze applique également des limites de débit pour garantir les performances et la fiabilité. Gardez cela à l’esprit lorsque vous effectuez des tests automatisés ou des tests d’assurance qualité manuels. Consultez les limites de débit du SDK Braze pour plus d’informations.
Personnaliser l’ordre d’affichage des cartes
Vous pouvez modifier l’ordre d’affichage de vos cartes de contenu. Cela vous permet d’affiner l’expérience utilisateur en donnant la priorité à certains types de contenu, comme les promotions urgentes.
Personnalisez l’ordre d’affichage des cartes de contenu dans votre flux en utilisant le paramètre filterFunction de showContentCards():. Par exemple :
1
2
3
braze.showContentCards(null, (cards) => {
return sortBrazeCards(cards); // Where sortBrazeCards is your sorting function that returns the sorted card array
});
Le ContentCardsFragment s’appuie sur un IContentCardsUpdateHandler pour gérer tout tri ou modification des cartes de contenu avant leur affichage dans le flux. Un gestionnaire de mise à jour personnalisé peut être défini via setContentCardUpdateHandler sur votre ContentCardsFragment.
Voici le IContentCardsUpdateHandler par défaut, qui peut servir de point de départ pour la personnalisation :
Afficher l’exemple Java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
public class DefaultContentCardsUpdateHandler implements IContentCardsUpdateHandler {
// Interface that must be implemented and provided as a public CREATOR
// field that generates instances of your Parcelable class from a Parcel.
public static final Parcelable.Creator<DefaultContentCardsUpdateHandler> CREATOR = new Parcelable.Creator<DefaultContentCardsUpdateHandler>() {
public DefaultContentCardsUpdateHandler createFromParcel(Parcel in) {
return new DefaultContentCardsUpdateHandler();
}
public DefaultContentCardsUpdateHandler[] newArray(int size) {
return new DefaultContentCardsUpdateHandler[size];
}
};
@Override
public List<Card> handleCardUpdate(ContentCardsUpdatedEvent event) {
List<Card> sortedCards = event.getAllCards();
// Sort by pinned, then by the 'updated' timestamp descending
// Pinned before non-pinned
Collections.sort(sortedCards, new Comparator<Card>() {
@Override
public int compare(Card cardA, Card cardB) {
// A displays above B
if (cardA.getIsPinned() && !cardB.getIsPinned()) {
return -1;
}
// B displays above A
if (!cardA.getIsPinned() && cardB.getIsPinned()) {
return 1;
}
// At this point, both A & B are pinned or both A & B are non-pinned
// A displays above B since A is newer
if (cardA.getUpdated() > cardB.getUpdated()) {
return -1;
}
// B displays above A since A is newer
if (cardA.getUpdated() < cardB.getUpdated()) {
return 1;
}
// At this point, every sortable field matches so keep the natural ordering
return 0;
}
});
return sortedCards;
}
// Parcelable interface method
@Override
public int describeContents() {
return 0;
}
// Parcelable interface method
@Override
public void writeToParcel(Parcel dest, int flags) {
// No state is kept in this class so the parcel is left unmodified
}
}
Afficher l’exemple Kotlin
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
class DefaultContentCardsUpdateHandler : IContentCardsUpdateHandler {
override fun handleCardUpdate(event: ContentCardsUpdatedEvent): List<Card> {
val sortedCards = event.allCards
// Sort by pinned, then by the 'updated' timestamp descending
// Pinned before non-pinned
sortedCards.sortWith(Comparator sort@{ cardA: Card, cardB: Card ->
// A displays above B
if (cardA.isPinned && !cardB.isPinned) {
return@sort -1
}
// B displays above A
if (!cardA.isPinned && cardB.isPinned) {
return@sort 1
}
// At this point, both A & B are pinned or both A & B are non-pinned
// A displays above B since A is newer
if (cardA.updated > cardB.updated) {
return@sort -1
}
// B displays above A since A is newer
if (cardA.updated < cardB.updated) {
return@sort 1
}
0
})
return sortedCards
}
// Parcelable interface method
override fun describeContents(): Int {
return 0
}
// Parcelable interface method
override fun writeToParcel(dest: Parcel, flags: Int) {
// No state is kept in this class so the parcel is left unmodified
}
companion object {
// Interface that must be implemented and provided as a public CREATOR
// field that generates instances of your Parcelable class from a Parcel.
val CREATOR: Parcelable.Creator<DefaultContentCardsUpdateHandler?> = object : Parcelable.Creator<DefaultContentCardsUpdateHandler?> {
override fun createFromParcel(`in`: Parcel): DefaultContentCardsUpdateHandler? {
return DefaultContentCardsUpdateHandler()
}
override fun newArray(size: Int): Array<DefaultContentCardsUpdateHandler?> {
return arrayOfNulls(size)
}
}
}
}
Le code source de ContentCardsFragment est disponible sur GitHub.
Pour filtrer et trier les cartes de contenu dans Jetpack Compose, définissez le paramètre cardUpdateHandler. Par exemple :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
ContentCardsList(
cardUpdateHandler = {
it.sortedWith { cardA, cardB ->
// A displays above B
if (cardA.isPinned && !cardB.isPinned) {
return@sortedWith -1
}
// B displays above A
if (!cardA.isPinned && cardB.isPinned) {
return@sortedWith 1
}
// At this point, both A & B are pinned or both A & B are non-pinned
// A displays above B since A is newer
if (cardA.updated > cardB.updated) {
return@sortedWith -1
}
// B displays above A since A is newer
if (cardA.updated < cardB.updated) {
return@sortedWith 1
}
0
}
}
)
Personnalisez l’ordre du flux de cartes en modifiant directement la variable statique Attributes.defaults.
1
2
3
4
5
6
7
8
9
10
11
12
13
var attributes = BrazeContentCardUI.ViewController.Attributes.defaults
attributes.transform = { cards in
cards.sorted {
if $0.pinned && !$1.pinned {
return true
} else if !$0.pinned && $1.pinned {
return false
} else {
return $0.createdAt > $1.createdAt
}
}
}
let viewController = BrazeContentCardUI.ViewController(braze: AppDelegate.braze, attributes: attributes)
La personnalisation via BrazeContentCardUI.ViewController.Attributes n’est pas disponible en Objective-C.
Personnaliser le message « flux vide »
Lorsqu’un utilisateur n’est éligible à aucune carte de contenu, le SDK affiche un message d’erreur « flux vide » indiquant : « Nous n’avons pas de mises à jour. Veuillez vérifier à nouveau plus tard. » Vous pouvez personnaliser ce message d’erreur de la manière suivante :

Le SDK Web ne permet pas de remplacer le texte du « flux vide » par programmation. Vous pouvez choisir de le remplacer à chaque affichage du flux, mais cela n’est pas recommandé car le flux peut mettre un certain temps à s’actualiser et le texte du flux vide ne s’affichera pas immédiatement.
Si le ContentCardsFragment détermine que l’utilisateur n’est éligible à aucune carte de contenu, il affiche le message d’erreur du flux vide.
Un adaptateur spécial, le EmptyContentCardsAdapter, remplace l’adaptateur standard ContentCardAdapter pour afficher ce message d’erreur. Pour définir le message personnalisé, remplacez la ressource de chaîne de caractères com_braze_feed_empty.
Le style utilisé pour afficher ce message est accessible via Braze.ContentCardsDisplay.Empty et est reproduit dans l’extrait de code suivant :
1
2
3
4
5
6
7
8
9
<style name="Braze.ContentCardsDisplay.Empty">
<item name="android:lineSpacingExtra">1.5dp</item>
<item name="android:text">@string/com_braze_feed_empty</item>
<item name="android:textColor">@color/com_braze_content_card_empty_text_color</item>
<item name="android:textSize">18.0sp</item>
<item name="android:gravity">center</item>
<item name="android:layout_height">match_parent</item>
<item name="android:layout_width">match_parent</item>
</style>
Pour plus d’informations sur la personnalisation des éléments de style des cartes de contenu, consultez Personnaliser le style.
Pour personnaliser le message d’erreur « flux vide » avec Jetpack Compose, vous pouvez passer une emptyString à ContentCardsList. Vous pouvez également transmettre emptyTextStyle à ContentCardListStyling pour personnaliser davantage ce message.
1
2
3
4
5
6
ContentCardsList(
emptyString = "No messages today",
style = ContentCardListStyling(
emptyTextStyle = TextStyle(...)
)
)
Si vous souhaitez afficher un Composable à la place, vous pouvez passer emptyComposable à ContentCardsList. Si emptyComposable est spécifié, emptyString ne sera pas utilisé.
1
2
3
4
5
6
7
8
ContentCardsList(
emptyComposable = {
Image(
painter = painterResource(id = R.drawable.noMessages),
contentDescription = "No messages"
)
}
)
Personnalisez l’état vide du contrôleur de vue en définissant les Attributes associés.
1
2
3
4
var attributes = BrazeContentCardUI.ViewController.Attributes.defaults
attributes.emptyStateMessage = "This is a custom empty state message"
attributes.emptyStateMessageFont = .preferredFont(forTextStyle: .title1)
attributes.emptyStateMessageColor = .secondaryLabel
Modifiez le texte qui s’affiche automatiquement dans les flux de cartes de contenu vides en redéfinissant les chaînes de caractères localisables des cartes de contenu dans le fichier ContentCardsLocalizable.strings de votre application.
Si vous souhaitez mettre à jour ce message dans différentes langues, recherchez la langue correspondante dans la structure du dossier Resources avec la chaîne de caractères ContentCardsLocalizable.strings.
Implémenter plusieurs flux
Les cartes de contenu peuvent être filtrées dans votre application afin que seules certaines cartes soient affichées, ce qui vous permet de disposer de plusieurs flux de cartes de contenu pour différents cas d’utilisation. Par exemple, vous pouvez gérer à la fois un flux transactionnel et un flux marketing. Pour ce faire, créez différentes catégories de cartes de contenu en définissant des paires clé-valeur dans le tableau de bord de Braze. Ensuite, créez des flux dans votre application ou votre site qui traitent ces types de cartes de contenu différemment, en filtrant certains types et en affichant les autres.
Étape 1 : Définir des paires clé-valeur sur les cartes
Lors de la création d’une campagne de cartes de contenu, définissez des données de paires clé-valeur sur chaque carte. Vous utiliserez cette paire clé-valeur pour catégoriser les cartes. Les paires clé-valeur sont stockées dans la propriété extras du modèle de données de la carte.
Pour cet exemple, nous allons définir une paire clé-valeur avec la clé feed_type qui désignera dans quel flux de cartes de contenu la carte doit s’afficher. La valeur correspondra à vos flux personnalisés, par exemple home_screen ou marketing.
Étape 2 : Filtrer les cartes de contenu
Une fois les paires clé-valeur attribuées, créez un flux avec une logique qui affichera les cartes souhaitées et filtrera les cartes d’autres types. Dans cet exemple, nous n’afficherons que les cartes dont la paire clé-valeur correspond à feed_type: "Transactional".
L’exemple suivant affiche le flux de cartes de contenu pour les cartes de type Transactional :
1
2
3
4
5
6
7
8
9
/**
* @param {String} feed_type - value of the "feed_type" KVP to filter
*/
function showCardsByFeedType(feed_type) {
braze.showContentCards(null, function(cards) {
return cards.filter((card) => card.extras["feed_type"] === feed_type);
});
}
Ensuite, vous pouvez configurer un bouton de basculement pour votre flux personnalisé :
1
2
3
4
// show the "Transactional" feed when this button is clicked
document.getElementById("show-transactional-feed").onclick = function() {
showCardsByFeedType("Transactional");
};
Pour plus d’informations, consultez la documentation des méthodes du SDK.
Par défaut, le flux de cartes de contenu s’affiche dans un ContentCardsFragment et IContentCardsUpdateHandler renvoie une liste de cartes à afficher après avoir reçu un ContentCardsUpdatedEvent du SDK Braze. Cependant, il ne fait que trier les cartes et ne gère pas directement le filtrage.
Étape 2.1 : Créer un gestionnaire personnalisé
Vous pouvez filtrer les cartes de contenu en implémentant un IContentCardsUpdateHandler personnalisé en utilisant les paires clé-valeur définies par Card.getExtras() dans le tableau de bord, puis en le modifiant pour supprimer de la liste toutes les cartes qui ne correspondent pas à la valeur de feed_type que vous avez définie précédemment.
Afficher l’exemple Java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
private IContentCardsUpdateHandler getUpdateHandlerForFeedType(final String desiredFeedType) {
return new IContentCardsUpdateHandler() {
@Override
public List<Card> handleCardUpdate(ContentCardsUpdatedEvent event) {
// Use the default card update handler for a first
// pass at sorting the cards. This is not required
// but is done for convenience.
final List<Card> cards = new DefaultContentCardsUpdateHandler().handleCardUpdate(event);
final Iterator<Card> cardIterator = cards.iterator();
while (cardIterator.hasNext()) {
final Card card = cardIterator.next();
// Make sure the card has our custom KVP
// from the dashboard with the key "feed_type"
if (card.getExtras().containsKey("feed_type")) {
final String feedType = card.getExtras().get("feed_type");
if (!desiredFeedType.equals(feedType)) {
// The card has a feed type, but it doesn't match
// our desired feed type, remove it.
cardIterator.remove();
}
} else {
// The card doesn't have a feed
// type at all, remove it
cardIterator.remove();
}
}
// At this point, all of the cards in this list have
// a feed type that explicitly matches the value we put
// in the dashboard.
return cards;
}
};
}
Afficher l’exemple Kotlin
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
private fun getUpdateHandlerForFeedType(desiredFeedType: String): IContentCardsUpdateHandler {
return IContentCardsUpdateHandler { event ->
// Use the default card update handler for a first
// pass at sorting the cards. This is not required
// but is done for convenience.
val cards = DefaultContentCardsUpdateHandler().handleCardUpdate(event)
val cardIterator = cards.iterator()
while (cardIterator.hasNext()) {
val card = cardIterator.next()
// Make sure the card has our custom KVP
// from the dashboard with the key "feed_type"
if (card.extras.containsKey("feed_type")) {
val feedType = card.extras["feed_type"]
if (desiredFeedType != feedType) {
// The card has a feed type, but it doesn't match
// our desired feed type, remove it.
cardIterator.remove()
}
} else {
// The card doesn't have a feed
// type at all, remove it
cardIterator.remove()
}
}
// At this point, all of the cards in this list have
// a feed type that explicitly matches the value we put
// in the dashboard.
cards
}
}
Étape 2.2 : L’ajouter à un fragment
Après avoir créé un IContentCardsUpdateHandler, créez un ContentCardsFragment qui l’utilise. Ce flux personnalisé peut être utilisé comme n’importe quel autre ContentCardsFragment. Dans les différentes parties de votre application, affichez différents flux de cartes de contenu en fonction de la clé fournie dans le tableau de bord. Chaque flux ContentCardsFragment affichera un ensemble unique de cartes grâce au IContentCardsUpdateHandler personnalisé sur chaque fragment.
Afficher l’exemple Java
1
2
3
// We want a Content Cards feed that only shows "Transactional" cards.
ContentCardsFragment customContentCardsFragment = new ContentCardsFragment();
customContentCardsFragment.setContentCardUpdateHandler(getUpdateHandlerForFeedType("Transactional"));
Afficher l’exemple Kotlin
1
2
3
// We want a Content Cards feed that only shows "Transactional" cards.
val customContentCardsFragment = ContentCardsFragment()
customContentCardsFragment.contentCardUpdateHandler = getUpdateHandlerForFeedType("Transactional")
Pour filtrer les cartes de contenu affichées dans ce flux, utilisez cardUpdateHandler. Par exemple :
1
2
3
4
5
6
7
ContentCardsList(
cardUpdateHandler = {
it.filter { card ->
card.extras["feed_type"] == "Transactional"
}
}
)
The following example will show the Content Cards feed for Transactional type cards:
1
2
// Filter cards by the `Transactional` feed type based on your key-value pair.
let transactionalCards = cards.filter { $0.extras["feed_type"] as? String == "Transactional" }
Pour aller plus loin, les cartes présentées dans le contrôleur de vue peuvent être filtrées en définissant la propriété transform sur votre structure Attributes afin de n’afficher que les cartes filtrées selon vos critères.
1
2
3
4
5
6
7
var attributes = BrazeContentCardUI.ViewController.Attributes.defaults
attributes.transform = { cards in
cards.filter { $0.extras["feed_type"] as? String == "Transactional" }
}
// Pass your attributes containing the transformed cards to the Content Card UI.
let viewController = BrazeContentCardUI.ViewController(braze: AppDelegate.braze, attributes: attributes)
1
2
3
4
5
6
7
// Filter cards by the `Transactional` feed type based on your key-value pair.
NSMutableArray<BRZContentCardRaw *> *transactionalCards = [[NSMutableArray alloc] init];
for (BRZContentCardRaw *card in AppDelegate.braze.contentCards.cards) {
if ([card.extras[@"feed_type"] isEqualToString:@"Transactional"]) {
[transactionalCards addObject:card];
}
}
Modifier cette page sur GitHub