Skip to content

コンテンツカードを作成する

この記事では、カスタムコンテンツカードを実装するときに使用する基本的なアプローチと、3つの一般的なユースケースについて説明します。Content Cardsカスタマイズガイドの他の記事をすでに読んで、デフォルトでできることとカスタムコードが必要なことを理解していることを前提としています。特に、カスタムコンテンツカードの分析を記録する方法を理解しておくと役立ちます。

カードの作成

ステップ1:カスタムUIを作成する

まず、カードのレンダリングに使用するカスタムHTMLコンポーネントを作成します。

まず、独自のカスタムフラグメントを作成します。デフォルトのContentCardsFragmentはデフォルトのContent Cardsタイプのみを処理するように設計されていますが、出発点として適しています。

まず、独自のカスタムビューコントローラーコンポーネントを作成します。デフォルトのBrazeContentCardUI.ViewControllerはデフォルトのContent Cardsタイプのみを処理するように設計されていますが、出発点として適しています。

ステップ2:カードの更新をサブスクライブする

カードが更新されたときにデータの更新をサブスクライブするコールバック関数を登録します。Content Cardsオブジェクトを解析し、titlecardDescriptionimageUrlなどのペイロードデータを抽出してから、結果のモデルデータを使用してカスタムUIを生成できます。

Content Cardsのデータモデルを取得するには、Content Cardsの更新をサブスクライブします。特に以下のプロパティに注意してください。

  • id Content CardsのID文字列を表します。カスタムContent Cardsから分析をログに記録するために使用される一意の識別子です。
  • extras Brazeダッシュボードからのすべてのキーと値のペアを含みます。

idextras以外のすべてのプロパティは、カスタムContent Cardsの解析ではオプションです。データモデルの詳細については、各プラットフォームの統合記事を参照してください:AndroidiOSWeb

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import * as braze from "@braze/web-sdk";

braze.subscribeToContentCardsUpdates((updates) => {
  const cards = updates.cards;
// For example:
  cards.forEach(card => {
    if (card.isControl) {
      // Do not display the control card, but remember to call `logContentCardImpressions([card])`
    }
    else if (card instanceof braze.ClassicCard || card instanceof braze.CaptionedImage) {
      // Use `card.title`, `card.imageUrl`, etc.
    }
    else if (card instanceof braze.ImageOnly) {
      // Use `card.imageUrl`, etc.
    }
  })
});

braze.openSession();

ステップ2a:プライベートサブスクライバー変数を作成する

カードの更新をサブスクライブするには、まずカスタムクラスでサブスクライバーを保持するプライベート変数を宣言します。

1
2
// subscriber variable
private IEventSubscriber<ContentCardsUpdatedEvent> mContentCardsUpdatedSubscriber;

ステップ2b:更新をサブスクライブする

以下のコードを追加して、BrazeからのContent Cardsの更新をサブスクライブします。通常、カスタムContent CardsアクティビティのActivity.onCreate()内に配置します。

1
2
3
4
5
6
7
8
9
10
11
12
13
// Remove the previous subscriber before rebuilding a new one with our new activity.
Braze.getInstance(context).removeSingleSubscription(mContentCardsUpdatedSubscriber, ContentCardsUpdatedEvent.class);
mContentCardsUpdatedSubscriber = new IEventSubscriber<ContentCardsUpdatedEvent>() {
    @Override
    public void trigger(ContentCardsUpdatedEvent event) {
        // List of all Content Cards
        List<Card> allCards = event.getAllCards();

        // Your logic below
    }
};
Braze.getInstance(context).subscribeToContentCardsUpdates(mContentCardsUpdatedSubscriber);
Braze.getInstance(context).requestContentCardsRefresh();

ステップ2c:サブスクライブを解除する

カスタムアクティビティがビューから移動するときにサブスクライブを解除します。アクティビティのonDestroy()ライフサイクルメソッドに以下のコードを追加します。

1
Braze.getInstance(context).removeSingleSubscription(mContentCardsUpdatedSubscriber, ContentCardsUpdatedEvent.class);

ステップ2a:プライベートサブスクライバー変数を作成する

カードの更新をサブスクライブするには、まずカスタムクラスでサブスクライバーを保持するプライベート変数を宣言します。

1
private var contentCardsUpdatedSubscriber: IEventSubscriber<ContentCardsUpdatedEvent>? = null

ステップ2b:更新をサブスクライブする

以下のコードを追加して、BrazeからのContent Cardsの更新をサブスクライブします。通常、カスタムContent CardsアクティビティのActivity.onCreate()内に配置します。

1
2
3
4
5
6
7
8
9
10
// Remove the previous subscriber before rebuilding a new one with our new activity.
Braze.getInstance(context).subscribeToContentCardsUpdates(contentCardsUpdatedSubscriber)
Braze.getInstance(context).requestContentCardsRefresh()
  // List of all Content Cards
  val allCards = event.allCards

  // Your logic below
}
Braze.getInstance(context).subscribeToContentCardsUpdates(mContentCardsUpdatedSubscriber)
Braze.getInstance(context).requestContentCardsRefresh(true)

ステップ2c:サブスクライブを解除する

カスタムアクティビティがビューから移動するときにサブスクライブを解除します。アクティビティのonDestroy()ライフサイクルメソッドに以下のコードを追加します。

1
Braze.getInstance(context).removeSingleSubscription(contentCardsUpdatedSubscriber, ContentCardsUpdatedEvent::class.java)

Content Cardsのデータモデルにアクセスするには、brazeインスタンスでcontentCards.cardsを呼び出します。

1
let cards: [Braze.ContentCard] = AppDelegate.braze?.contentCards.cards

さらに、Content Cardsの変更を監視するためのサブスクリプションを維持できます。これには2つの方法があります。

  1. キャンセル可能なオブジェクトを維持する方法、または
  2. AsyncStreamを維持する方法。
キャンセル可能なオブジェクト
1
2
3
4
5
6
// This subscription is maintained through a Braze cancellable, which will observe for changes until the subscription is cancelled.
// You must keep a strong reference to the cancellable to keep the subscription active.
// The subscription is canceled either when the cancellable is deinitialized or when you call its `.cancel()` method.
let cancellable = AppDelegate.braze?.contentCards.subscribeToUpdates { [weak self] contentCards in
  // Implement your completion handler to respond to updates in `contentCards`.
}
AsyncStream
1
let stream: AsyncStream<[Braze.ContentCard]> = AppDelegate.braze?.contentCards.cardsStream
1
NSArray<BRZContentCardRaw *> *contentCards = AppDelegate.braze.contentCards.cards;

さらに、Content Cardsのサブスクリプションを維持したい場合は、subscribeToUpdatesを呼び出すことができます。

1
2
3
4
// This subscription is maintained through Braze cancellable, which will continue to observe for changes until the subscription is cancelled.
BRZCancellable *cancellable = [self.braze.contentCards subscribeToUpdates:^(NSArray<BRZContentCardRaw *> *contentCards) {
  // Implement your completion handler to respond to updates in `contentCards`.
}];

ステップ3:分析を実装する

Content Cardsのインプレッション、クリック、および却下は、カスタムビューでは自動的にログに記録されません。すべてのメトリクスをBrazeダッシュボードの分析に適切にログ記録するために、それぞれのメソッドを実装する必要があります。

ステップ4:カードをテストする(オプション)

Content Cardsをテストするには、以下の手順に従います。

  1. changeUser()メソッドを呼び出して、アプリケーションにアクティブユーザーを設定します。
  2. Brazeでキャンペーンに移動し、新しいContent Cardsキャンペーンを作成します。
  3. キャンペーンでテストを選択し、テストユーザーのuser-idを入力します。準備ができたら、テストを送信を選択します。まもなくデバイスでContent Cardsを起動できます。

テスト受信者として独自のユーザーIDを追加してContent Cardsをテストできることを示すBraze Content Cardsキャンペーン。

Content カードの配置

Content Cardsはさまざまな方法で使用できます。一般的な実装として、メッセージセンター、ダイナミック画像広告、画像カルーセルの3つがあります。これらの配置それぞれで、Content Cardsにキーと値のペア(データモデルのextrasプロパティ)を割り当て、その値に基づいてランタイム時にカードの動作、外観、機能をダイナミックに調整します。

メッセージ受信トレイ、ダイナミック画像広告、画像カルーセルの3つのContent カード配置例を示す図。

メッセージ受信トレイ

Content Cardsはメッセージセンターをシミュレートするために使用できます。この形式では、各メッセージがそれぞれのカードとなり、クリック時のイベントを制御するキーと値のペアを含んでいます。これらのキーと値のペアは、ユーザーが受信トレイのメッセージをクリックしたときに遷移先を決定するためにアプリケーションが参照するキー識別子です。キーと値のペアの値は任意です。

たとえば、おすすめ記事を有効にするための行動喚起カードと、新規購読者セグメント向けのクーポンコードカードの2つのメッセージカードを作成したい場合を考えます。

bodytitlebuttonTextのようなキーには、マーケターが設定できるシンプルな文字列値を持たせることができます。termsのようなキーには、法務部門が承認したフレーズの小さなコレクションを提供する値を持たせることができます。styleclass_typeのようなキーには、カードがアプリやサイトでどのようにレンダリングされるかを決定する文字列値を設定できます。

おすすめ記事カードのキーと値のペア:

キー
body Add your interests to your Politer Weekly profile for personal reading recommendations.
style info
class_type notification_center
card_priority 1

新規購読者クーポンのキーと値のペア:

キー
title Subscribe for unlimited games
body End of Summer Special - Enjoy 10% off Politer games
buttonText Subscribe Now
style promo
class_type notification_center
card_priority 2
terms new_subscribers_only
Androidの追加情報

AndroidおよびFireOS SDKでは、メッセージセンターのロジックは、Brazeのキーと値のペアから提供されるclass_typeの値によって制御されます。createContentCardableメソッドを使用して、これらのクラスタイプをフィルタリングおよび識別できます。

クリック時の動作にclass_typeを使用する
Content Cardsのデータをカスタムクラスに展開する際、データのContentCardClassプロパティを使用して、データを格納するために使用する具体的なサブクラスを決定します。

1
2
3
4
5
6
7
8
9
10
11
 private fun createContentCardable(metadata: Map<String, Any>, type: ContentCardClass?): ContentCardable?{
        return when(type){
            ContentCardClass.AD -> Ad(metadata)
            ContentCardClass.MESSAGE_WEB_VIEW -> WebViewMessage(metadata)
            ContentCardClass.NOTIFICATION_CENTER -> FullPageMessage(metadata)
            ContentCardClass.ITEM_GROUP -> Group(metadata)
            ContentCardClass.ITEM_TILE -> Tile(metadata)
            ContentCardClass.COUPON -> Coupon(metadata)
            else -> null
        }
    }

次に、メッセージリストに対するユーザーのインタラクションを処理する際、メッセージのタイプを使用してユーザーに表示するビューを決定できます。

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
override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        //...
        listView.onItemClickListener = AdapterView.OnItemClickListener { parent, view, position, id ->
           when (val card = dataProvider[position]){
                is WebViewMessage -> {
                    val intent = Intent(this, WebViewActivity::class.java)
                    val bundle = Bundle()
                    bundle.putString(WebViewActivity.INTENT_PAYLOAD, card.contentString)
                    intent.putExtras(bundle)
                    startActivity(intent)
                }
                is FullPageMessage -> {
                    val intent = Intent(this, FullPageContentCard::class.java)
                    val bundle = Bundle()
                    bundle.putString(FullPageContentCard.CONTENT_CARD_IMAGE, card.icon)
                    bundle.putString(FullPageContentCard.CONTENT_CARD_TITLE, card.messageTitle)
                    bundle.putString(FullPageContentCard.CONTENT_CARD_DESCRIPTION, card.cardDescription)
                    intent.putExtras(bundle)
                    startActivity(intent)
                }
            }

        }
    }

クリック時の動作にclass_typeを使用する
Content Cardsのデータをカスタムクラスに展開する際、データのContentCardClassプロパティを使用して、データを格納するために使用する具体的なサブクラスを決定します。

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
private ContentCardable createContentCardable(Map<String, ?> metadata,  ContentCardClass type){
    switch(type){
        case ContentCardClass.AD:{
            return new Ad(metadata);
        }
        case ContentCardClass.MESSAGE_WEB_VIEW:{
            return new WebViewMessage(metadata);
        }
        case ContentCardClass.NOTIFICATION_CENTER:{
            return new FullPageMessage(metadata);
        }
        case ContentCardClass.ITEM_GROUP:{
            return new Group(metadata);
        }
        case ContentCardClass.ITEM_TILE:{
            return new Tile(metadata);
        }
        case ContentCardClass.COUPON:{
            return new Coupon(metadata);
        }
        default:{
            return null;
        }
    }
}

次に、メッセージリストに対するユーザーのインタラクションを処理する際、メッセージのタイプを使用してユーザーに表示するビューを決定できます。

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
@Override
protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState)
        //...
        listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id){
               ContentCardable card = dataProvider.get(position);
               if (card instanceof WebViewMessage){
                    Bundle intent = new Intent(this, WebViewActivity.class);
                    Bundle bundle = new Bundle();
                    bundle.putString(WebViewActivity.INTENT_PAYLOAD, card.getContentString());
                    intent.putExtras(bundle);
                    startActivity(intent);
                }
                else if (card instanceof FullPageMessage){
                    Intent intent = new Intent(this, FullPageContentCard.class);
                    Bundle bundle = Bundle();
                    bundle.putString(FullPageContentCard.CONTENT_CARD_IMAGE, card.getIcon());
                    bundle.putString(FullPageContentCard.CONTENT_CARD_TITLE, card.getMessageTitle());
                    bundle.putString(FullPageContentCard.CONTENT_CARD_DESCRIPTION, card.getCardDescription());
                    intent.putExtras(bundle)
                    startActivity(intent)
                }
            }

        });
    }

完全にカスタムされたカルーセルフィードにContent Cardsを設定し、ユーザーがスワイプして追加のおすすめカードを表示できるようにすることができます。デフォルトでは、Content Cardsは作成日順(最新のものが最初)にソートされ、ユーザーは対象となるすべてのカードを表示できます。

Content Cardsカルーセルを実装するには:

  1. Content Cardsの変更を監視し、Content Cardsの到着を処理するカスタムロジックを作成します。
  2. カルーセルに一度に表示するカードの特定数を決定するカスタムクライアントサイドロジックを作成します。たとえば、配列から最初の5つのContent カードオブジェクトを選択したり、キーと値のペアを導入して条件ロジックを構築したりできます。

画像のみ

Content Cardsは必ずしも「カード」のような外観である必要はありません。たとえば、Content Cardsはホームページや指定されたページの上部に永続的に表示されるダイナミック画像として表示できます。

これを実現するには、マーケターが画像のみタイプのContent Cardsを使用してキャンペーンまたはキャンバスステップを作成します。次に、Content Cardsを補足コンテンツとして使用するのに適切なキーと値のペアを設定します。

New Stuff!