Skip to content



Implementierungsleitfaden für Content Cards

Dieser optionale Leitfaden für die erweiterte Implementierung enthält Hinweise zur Code-Anpassung für Content Cards, drei von unserem Team entwickelte Anwendungsfälle, begleitende Code-Snippets sowie eine Anleitung zur Protokollierung von Impressionen, Klicks und Ausblendungen. Besuchen Sie unser Braze Demo Repository hier! Beachten Sie, dass sich dieser Implementierungsleitfaden auf eine Swift-Implementierung konzentriert, aber für Interessierte auch Objective-C-Snippets bereitgestellt werden.

Hinweise zur Code-Anpassung

Content Cards als angepasste Objekte

Ähnlich wie ein Raketenschiff, das einen Booster hinzufügt, können Ihre eigenen angepassten Objekte erweitert werden, um als Content Cards zu fungieren. Begrenzte API-Oberflächen wie diese bieten die Flexibilität, mit verschiedenen Daten-Backends austauschbar zu arbeiten. Dies kann durch die Konformität mit dem ContentCardable-Protokoll und die Implementierung des Initialisierers (wie in den folgenden Code-Snippets zu sehen) erreicht werden. Durch die Verwendung der ContentCardData-Struktur können Sie auf die ABKContentCard-Daten zugreifen. Die ABKContentCard-Payload wird verwendet, um die ContentCardData-Struktur und das angepasste Objekt selbst zu initialisieren – alles aus einem Dictionary-Typ über den Initialisierer, den das Protokoll mitbringt.

Der Initialisierer enthält auch ein ContentCardClassType-enum. Dieses enum wird verwendet, um zu entscheiden, welches Objekt initialisiert werden soll. Durch die Verwendung von Schlüssel-Wert-Paaren im Braze-Dashboard können Sie einen expliziten class_type-Schlüssel festlegen, der bestimmt, welches Objekt initialisiert werden soll. Diese Schlüssel-Wert-Paare für Content Cards sind in der Variable extras auf der ABKContentCard enthalten. Eine weitere zentrale Komponente des Initialisierers ist der Wörterbuchparameter metaData. metaData enthält alles aus der ABKContentCard, aufgeteilt in eine Reihe von Schlüsseln und Werten. Nachdem die relevanten Karten geparst und in Ihre angepassten Objekte umgewandelt wurden, kann die App mit ihnen arbeiten, als ob sie aus JSON oder einer anderen Quelle instanziiert worden wären.

Sobald Sie diese Hinweise zur Code-Anpassung verstanden haben, sehen Sie sich unsere Anwendungsfälle an, um mit der Implementierung Ihrer angepassten Objekte zu beginnen.

ContentCardable-Protokoll
Ein ContentCardData-Objekt, das die ABKContentCard-Daten zusammen mit einem ContentCardClassType-enum darstellt. Ein Initialisierer, der zur Instanziierung angepasster Objekte mit ABKContentCard-Metadaten verwendet wird.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
protocol ContentCardable {
  var contentCardData: ContentCardData? { get }
  init?(metaData: [ContentCardKey: Any], classType contentCardClassType: ContentCardClassType)
}

extension ContentCardable {
  var isContentCard: Bool {
    return contentCardData != nil
  }

  func logContentCardClicked() {
    BrazeManager.shared.logContentCardClicked(idString: contentCardData?.contentCardId)
  }

  func logContentCardDismissed() {
    BrazeManager.shared.logContentCardDismissed(idString: contentCardData?.contentCardId)
  }

  func logContentCardImpression() {
    BrazeManager.shared.logContentCardImpression(idString: contentCardData?.contentCardId)
  }
}

Content-Card-Datenstruktur
ContentCardData stellt die ausgewerteten Werte einer ABKContentCard dar.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
struct ContentCardData: Hashable {
  let contentCardId: String
  let contentCardClassType: ContentCardClassType
  let createdAt: Double
  let isDismissable: Bool
  ...
  // other Content Card properties such as expiresAt, pinned, etc.
}

extension ContentCardData: Equatable {
  static func ==(lhs: ContentCardData, rhs: ContentCardData) -> Bool {
    return lhs.contentCardId == rhs.contentCardId
  }
}

ContentCardable-Protokoll
Ein ContentCardData-Objekt, das die ABKContentCard-Daten zusammen mit einem ContentCardClassType-enum darstellt, ein Initialisierer, der zur Instanziierung angepasster Objekte mit ABKContentCard-Metadaten verwendet wird.

1
2
3
4
5
6
7
8
9
10
11
12
@protocol ContentCardable <NSObject>

@property (nonatomic, strong) ContentCardData *contentCardData;
- (instancetype __nullable)initWithMetaData:(NSDictionary *)metaData
                                  classType:(enum ContentCardClassType)classType;

- (BOOL)isContentCard;
- (void)logContentCardImpression;
- (void)logContentCardClicked;
- (void)logContentCardDismissed;

@end

Content-Card-Datenstruktur
ContentCardData stellt die ausgewerteten Werte einer ABKContentCard dar.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@interface ContentCardData : NSObject

+ (ContentCardClassType)contentCardClassTypeForString:(NSString *)rawValue;

- (instancetype)initWithIdString:(NSString *)idString
                       classType:(ContentCardClassType)classType
                       createdAt:(double)createdAt isDismissible:(BOOL)isDismissible;

@property (nonatomic, readonly) NSString *contentCardId;
@property (nonatomic) ContentCardClassType classType;
@property (nonatomic, readonly) double *createdAt;
@property (nonatomic, readonly) BOOL isDismissible;
...
// other Content Card properties such as expiresAt, pinned, etc.

@end

Angepasster Objekt-Initialisierer
Die Metadaten von ABKContentCard werden verwendet, um die Variablen Ihres Objekts zu füllen. Die im Braze-Dashboard eingerichteten Schlüssel-Wert-Paare sind im Wörterbuch „extras“ dargestellt.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
extension CustomObject: ContentCardable {
  init?(metaData: [ContentCardKey: Any], classType contentCardClassType: ContentCardClassType) {
    guard let idString = metaData[.idString] as? String,
      let createdAt = metaData[.created] as? Double,
      let isDismissable = metaData[.dismissable] as? Bool,
      let extras = metaData[.extras] as? [AnyHashable: Any],
      else { return nil }

    let contentCardData = ContentCardData(contentCardId: idString, contentCardClassType: contentCardClassType, createdAt: createdAt, isDismissable: isDismissable)
    let customObjectProperty = extras["YOUR-CUSTOM-OBJECT-PROPERTY"] as? String

    self.init(contentCardData: contentCardData, property: customObjectProperty)
  }
}

Identifizieren von Typen
Das ContentCardClassType-enum stellt den class_type-Wert im Braze-Dashboard dar. Dieser Wert wird auch als Filter-Bezeichner verwendet, um Content Cards an verschiedenen Stellen anzuzeigen.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
enum ContentCardClassType: Hashable {
  case yourValue
  case yourOtherValue
  ...
  case none

  init(rawType: String?) {
    switch rawType?.lowercased() {
    case "your_value": // these values much match the value set in the Braze dashboard
      self = .yourValue
    case "your_other_value": // these values much match the value set in the Braze dashboard
      self = .yourOtherValue
    ...
    default:
      self = .none
    }
  }
}

Angepasster Objekt-Initialisierer
Die Metadaten von ABKContentCard werden verwendet, um die Variablen Ihres Objekts zu füllen. Die im Braze-Dashboard eingerichteten Schlüssel-Wert-Paare sind im Wörterbuch „extras“ dargestellt.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
- (id _Nullable)initWithMetaData:(nonnull NSDictionary *)metaData classType:(enum ContentCardClassType)classType {
  self = [super init];
  if (self) {
    if ([metaData objectForKey:ContentCardKeyIdString] && [metaData objectForKey:ContentCardKeyCreated] && [metaData objectForKey:ContentCardKeyDismissible] && [metaData objectForKey:ContentCardKeyExtras]) {
      NSDictionary  *extras = metaData[ContentCardKeyExtras];
      NSString *idString = metaData[ContentCardKeyIdString];
      double createdAt = [metaData[ContentCardKeyCreated] doubleValue];
      BOOL isDismissible = metaData[ContentCardKeyDismissible];

      if ([extras objectForKey: @"YOUR-CUSTOM-PROPERTY")
        _customObjectProperty = extras[@"YOUR-CUSTOM-OBJECT-PROPERTY"];

      self.contentCardData = [[ContentCardData alloc] initWithIdString:idString classType:classType createdAt:createdAt isDismissible:isDismissible];

      return self;
    }
  }
  return nil;
}

Identifizieren von Typen
Das ContentCardClassType-enum stellt den class_type-Wert im Braze-Dashboard dar. Dieser Wert wird auch als Filter-Bezeichner verwendet, um Content Cards an verschiedenen Stellen anzuzeigen.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
typedef NS_ENUM(NSInteger, ContentCardClassType) {
  ContentCardClassTypeNone = 0,
  ContentCardClassTypeYourValue,
  ContentCardClassTypeYourOtherValue,
  ...
};

+ (NSArray *)contentCardClassTypeArray {
  return @[ @"", @"your_value", @"your_other_value" ];
}

+ (ContentCardClassType)contentCardClassTypeForString:(NSString*)rawValue {
  if ([[self contentCardClassTypeArray] indexOfObject:rawValue] == NSNotFound) {
    return ContentCardClassTypeNone;
  } else {
    NSInteger value = [[self contentCardClassTypeArray] indexOfObject:rawValue];
    return (ContentCardClassType) value;
  }
}

Content Cards anfordern
Solange der Beobachter noch im Speicher gehalten wird, kann der Benachrichtigungs-Callback vom Braze SDK erwartet werden.

1
2
3
4
func loadContentCards() {
  BrazeManager.shared.addObserverForContentCards(observer: self, selector: #selector(contentCardsUpdated))
  BrazeManager.shared.requestContentCardsRefresh()
}

SDK-Callback für Content Cards verarbeiten
Leiten Sie den Benachrichtigungs-Callback an die Hilfsdatei weiter, um die Payload-Daten für Ihre angepassten Objekte zu parsen.

1
2
3
4
5
@objc func contentCardsUpdated(_ notification: Notification) {
  guard let contentCards = BrazeManager.shared.handleContentCardsUpdated(notification, for: [.yourValue]) as? [CustomObject],!contentCards.isEmpty else { return }

 // do something with your array of custom objects
}

Mit Content Cards arbeiten
Der class_type wird als Filter übergeben, um nur Content Cards zurückzugeben, die einen passenden class_type haben.

1
2
3
4
5
func handleContentCardsUpdated(_ notification: Notification, for classTypes: [ContentCardClassType]) -> [ContentCardable] {
  guard let updateIsSuccessful = notification.userInfo?[ABKContentCardsProcessedIsSuccessfulKey] as? Bool, updateIsSuccessful, let cards = contentCards else { return [] }

  return convertContentCards(cards, for: classTypes)
}

Content Cards anfordern
Solange der Beobachter noch im Speicher gehalten wird, kann der Benachrichtigungs-Callback vom Braze SDK erwartet werden.

1
2
3
4
- (void)loadContentCards {
  [[BrazeManager shared] addObserverForContentCards:self selector:@selector(contentCardsUpdated:)];
  [[BrazeManager shared] requestContentCardsRefresh];
}

SDK-Callback für Content Cards verarbeiten
Leiten Sie den Benachrichtigungs-Callback an die Hilfsdatei weiter, um die Payload-Daten für Ihre angepassten Objekte zu parsen.

1
2
3
4
5
6
- (void)contentCardsUpdated:(NSNotification *)notification {
  NSArray *classTypes = @[@(ContentCardClassTypeYourValue)];
  NSArray *contentCards = [[BrazeManager shared] handleContentCardsUpdated:notification forClassTypes:classTypes];

  // do something with your array of custom objects
}

Mit Content Cards arbeiten
Der class_type wird als Filter übergeben, um nur Content Cards zurückzugeben, die einen passenden class_type haben.

1
2
3
4
5
6
7
8
- (NSArray *)handleContentCardsUpdated:(NSNotification *)notification forClassType:(ContentCardClassType)classType {
  BOOL updateIsSuccessful = [notification.userInfo[ABKContentCardsProcessedIsSuccessfulKey] boolValue];
  if (updateIsSuccessful) {
    return [self convertContentCards:self.contentCards forClassType:classType];
  } else {
    return @[];
  }
}

Mit Payload-Daten arbeiten
Durchläuft das Array der Content Cards in einer Schleife und parst nur die Karten mit einem passenden class_type. Die Payload einer ABKContentCard wird in ein Dictionary geparst.

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
func convertContentCards(_ cards: [ABKContentCard], for classTypes: [ContentCardClassType]) -> [ContentCardable] {
  var contentCardables: [ContentCardable] = []

  for card in cards {
    let classTypeString = card.extras?[ContentCardKey.classType.rawValue] as? String
    let classType = ContentCardClassType(rawType: classTypeString)
    guard classTypes.contains(classType) else { continue }

    var metaData: [ContentCardKey: Any] = [:]
    switch card {
    case let banner as ABKBannerContentCard:
      metaData[.image] = banner.image
    case let captioned as ABKCaptionedImageContentCard:
      metaData[.title] = captioned.title
      metaData[.cardDescription] = captioned.cardDescription
      metaData[.image] = captioned.image
    case let classic as ABKClassicContentCard:
      metaData[.title] = classic.title
      metaData[.cardDescription] = classic.cardDescription
    default:
      break
    }

    metaData[.idString] = card.idString
    metaData[.created] = card.created
    metaData[.dismissible] = card.dismissible
    metaData[.urlString] = card.urlString
    metaData[.extras] = card.extras
    ...
    // other Content Card properties such as expiresAt, pinned, etc.

    if let contentCardable = contentCardable(with: metaData, for: classType) {
      contentCardables.append(contentCardable)
    }
  }
  return contentCardables
}

Angepasste Objekte aus Content-Card-Payload-Daten initialisieren
Der class_type wird verwendet, um zu bestimmen, welche Ihrer angepassten Objekte aus den Payload-Daten initialisiert werden sollen.

1
2
3
4
5
6
7
8
9
10
11
func contentCardable(with metaData: [ContentCardKey: Any], for classType: ContentCardClassType) -> ContentCardable? {
  switch classType {
  case .yourValue:
    return CustomObject(metaData: metaData, classType: classType)
  case .yourOtherValue:
    return OtherCustomObject(metaData: metaData, classType: classType)
  ...
  default:
    return nil
  }
}

Mit Payload-Daten arbeiten
Durchläuft das Array der Content Cards in einer Schleife und parst nur die Karten mit einem passenden class_type. Die Payload einer ABKContentCard wird in ein Dictionary geparst.

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
- (NSArray *)convertContentCards:(NSArray<ABKContentCard*> *)cards forClassType:(ContentCardClassType)classType {
  NSMutableArray *contentCardables = [[NSMutableArray alloc] init];      for (ABKContentCard *card in cards) {
    NSString *classTypeString = [card.extras objectForKey:ContentCardKeyClassType];
    ContentCardClassType cardClassType = [ContentCardData contentCardClassTypeForString: classTypeString];
    if (cardClassType != classType) { continue; }

    NSMutableDictionary *metaData = [[NSMutableDictionary alloc] init];
    if ([card isKindOfClass:[ABKBannerContentCard class]]) {
      ABKBannerContentCard *banner = (ABKBannerContentCard *)card;
      metaData[ContentCardKeyImage] = banner.image;
    } else if ([card isKindOfClass:[ABKCaptionedImageContentCard class]]) {
      ABKCaptionedImageContentCard *captioned = (ABKCaptionedImageContentCard *)card;
      metaData[ContentCardKeyTitle] = captioned.title;
      metaData[ContentCardKeyCardDescription] = captioned.cardDescription;
      metaData[ContentCardKeyImage] = captioned.image;
    } else if ([card isKindOfClass:[ABKClassicContentCard class]]) {
      ABKClassicContentCard *classic = (ABKClassicContentCard *)card;
      metaData[ContentCardKeyCardDescription] = classic.title;
      metaData[ContentCardKeyImage] = classic.image;
    }

    metaData[ContentCardKeyIdString] = card.idString;
    metaData[ContentCardKeyCreated] = [NSNumber numberWithDouble:card.created];
    metaData[ContentCardKeyDismissible] = [NSNumber numberWithBool:card.dismissible];
    metaData[ContentCardKeyUrlString] = card.urlString;
    metaData[ContentCardKeyExtras] = card.extras;
    ...
    // other Content Card properties such as expiresAt, pinned, etc.

    id<ContentCardable> contentCardable = [self contentCardableWithMetaData:metaData forClassType:classType];
    if (contentCardable) {
      [contentCardables addObject:contentCardable];
    }
  }

  return contentCardables;
}

Angepasste Objekte aus Content-Card-Payload-Daten initialisieren
Der class_type wird verwendet, um zu bestimmen, welche Ihrer angepassten Objekte aus den Payload-Daten initialisiert werden sollen.

1
2
3
4
5
6
7
8
9
10
11
- (id<ContentCardable>)contentCardableWithMetaData:(NSDictionary *)metaData forClassType:(ContentCardClassType)classType {
  switch (classType) {
    case ContentCardClassTypeYourValue:
      return [[CustomObject alloc] initWithMetaData:metaData classType:classType];
    case ContentCardClassTypeYourOtherValue:
      return nil;
    ...
    default:
      return nil;
  }
}

Anwendungsfälle

Im Folgenden finden Sie drei Anwendungsfälle. Jeder Anwendungsfall enthält eine ausführliche Erklärung, relevante Code-Snippets sowie einen Blick darauf, wie Content-Card-Variablen im Braze-Dashboard aussehen und verwendet werden können:

Content Cards als zusätzlicher Inhalt

Sie können Content Cards nahtlos in einen bestehenden Feed einfügen, sodass Daten aus mehreren Feeds gleichzeitig geladen werden können. Dadurch entsteht ein zusammenhängendes, harmonisches Erlebnis mit Braze Content Cards und vorhandenen Feed-Inhalten.

Das Beispiel auf der rechten Seite zeigt eine UICollectionView mit einer hybriden Liste von Artikeln, die über lokale Daten und von Braze bereitgestellte Content Cards gefüllt werden. Auf diese Weise können Content Cards nicht von bestehenden Inhalten unterschieden werden.

Dashboard-Konfiguration

Diese Content Card wird über eine API-getriggerte Campaign mit API-getriggerten Schlüssel-Wert-Paaren zugestellt. Dies ist ideal für Campaigns, bei denen die Werte der Karte von externen Faktoren abhängen, um zu bestimmen, welche Inhalte den Nutzer:innen angezeigt werden sollen. Beachten Sie, dass class_type zum Zeitpunkt der Einrichtung bekannt sein sollte.

Die Schlüssel-Wert-Paare für den Anwendungsfall mit ergänzenden Content Cards. In diesem Beispiel werden verschiedene Aspekte der Karte wie „tile_id“, „tile_deeplink“ und „tile_title“ mit Liquid festgelegt.

Bereit für die Protokollierung von Analytics?

Im folgenden Abschnitt wird näher beschrieben, wie der Datenfluss aussehen sollte.

Content Cards in einer Nachrichtenzentrale


Content Cards können in einem Nachrichtenzentrale-Format verwendet werden, bei dem jede Nachricht eine eigene Karte ist. Jede Nachricht in der Nachrichtenzentrale wird über eine Content-Card-Payload gefüllt, und jede Karte enthält zusätzliche Schlüssel-Wert-Paare für die On-Click-UI/UX. Im folgenden Beispiel verweist eine Nachricht auf eine beliebige angepasste Ansicht, während eine andere eine Webansicht öffnet, die angepasstes HTML anzeigt.

Dashboard-Konfiguration

Für die folgenden Nachrichtentypen muss das Schlüssel-Wert-Paar class_type zu Ihrer Dashboard-Konfiguration hinzugefügt werden. Die hier zugewiesenen Werte sind willkürlich, sollten aber zwischen den Klassentypen unterscheidbar sein. Diese Schlüssel-Wert-Paare sind die Bezeichner, anhand derer die Anwendung entscheidet, wohin navigiert werden soll, wenn Nutzer:innen auf eine gekürzte Posteingangs-Nachricht klicken.

Die Schlüssel-Wert-Paare für diesen Anwendungsfall umfassen:

  • message_header festgelegt als Full Page
  • class_type festgelegt als message_full_page

Die Schlüssel-Wert-Paare für diesen Anwendungsfall umfassen:

  • message_header festgelegt als HTML
  • class_type festgelegt als message_webview
  • message_title

Diese Nachricht sucht ebenfalls nach einem HTML-Schlüssel-Wert-Paar, aber wenn Sie mit einer Web-Domain arbeiten, ist auch ein URL-Schlüssel-Wert-Paar gültig.

Weitere Erklärung

Die Logik der Nachrichtenzentrale wird vom contentCardClassType gesteuert, der durch die Schlüssel-Wert-Paare von Braze bereitgestellt wird. Mit der Methode addContentCardToView können Sie diese Klassentypen sowohl filtern als auch identifizieren.

Verwendung von class_type für On-Click-Verhalten
Wenn eine Nachricht angeklickt wird, bestimmt ContentCardClassType, wie der nächste Bildschirm gefüllt werden soll.

1
2
3
4
5
6
7
8
9
10
func addContentCardToView(with message: Message) {
    switch message.contentCardData?.contentCardClassType {
      case .message(.fullPage):
        loadContentCardFullPageView(with: message as! FullPageMessage)
      case .message(.webView):
        loadContentCardWebView(with: message as! WebViewMessage)
      default:
        break
    }
}

Verwendung von class_type für On-Click-Verhalten
Wenn eine Nachricht angeklickt wird, bestimmt ContentCardClassType, wie der nächste Bildschirm gefüllt werden soll.

1
2
3
4
5
6
7
8
9
10
11
12
- (void)addContentCardToView:(Message *)message {
  switch (message.contentCardData.classType) {
    case ContentCardClassTypeMessageFullPage:
      [self loadContentCardFullPageView:(FullPageMessage *)message];
      break;
    case ContentCardClassTypeMessageWebview:
      [self loadContentCardWebView:(WebViewMessage *)message];
      break;
    default:
      break;
  }
}
Bereit für die Protokollierung von Analytics?

Im folgenden Abschnitt wird näher beschrieben, wie der Datenfluss aussehen sollte.

Eine interaktive Content Card mit einer 50-Prozent-Rabattaktion erscheint unten links im Bildschirm. Nach dem Klick wird die Aktion auf den Warenkorb angewendet.

Interaktive Content Cards


Content Cards können genutzt werden, um dynamische und interaktive Erlebnisse für Ihre Nutzer:innen zu schaffen. Im Beispiel auf der rechten Seite erscheint an der Kasse ein Content-Card-Popup, das den Nutzer:innen Last-Minute-Aktionen bietet.

Gut platzierte Karten wie diese sind eine großartige Möglichkeit, den Nutzer:innen einen „Anstoß“ zu bestimmten Aktionen zu geben.


Dashboard-Konfiguration

Die Dashboard-Konfiguration für interaktive Content Cards ist unkompliziert. Die Schlüssel-Wert-Paare für diesen Anwendungsfall umfassen einen discount_percentage, der als gewünschter Rabattbetrag festgelegt ist, und einen class_type, der als coupon_code festgelegt ist. Diese Schlüssel-Wert-Paare sorgen dafür, dass typspezifische Content Cards gefiltert und auf dem Checkout-Bildschirm angezeigt werden.

Bereit für die Protokollierung von Analytics?

Im folgenden Abschnitt wird näher beschrieben, wie der Datenfluss aussehen sollte.

Dark-Mode-Anpassung

Standardmäßig reagieren die Content-Card-Ansichten automatisch auf Änderungen im Dark Mode auf dem Gerät mit einer Reihe von Themenfarben.

Dieses Verhalten kann wie in unserer Anleitung für angepasste Stile beschrieben außer Kraft gesetzt werden.

Protokollieren von Impressionen, Klicks und Ausblendungen

Nachdem Sie Ihre angepassten Objekte so erweitert haben, dass sie als Content Cards fungieren, können Sie wertvolle Metriken wie Impressionen, Klicks und Ausblendungen schnell protokollieren. Dies kann mit Hilfe eines ContentCardable-Protokolls geschehen, das auf eine Hilfsdatei verweist und ihr Daten bereitstellt, die vom Braze SDK erfasst werden.

Komponenten der Implementierung

Analytics protokollieren
Die Protokollierungsmethoden können direkt aus Objekten aufgerufen werden, die dem ContentCardable-Protokoll entsprechen.

1
2
3
customObject.logContentCardImpression()
customObject.logContentCardClicked()
customObject.logContentCardDismissed()

ABKContentCard abrufen
Der von Ihrem angepassten Objekt übergebene idString wird verwendet, um die zugehörige Content Card für die Protokollierung von Analytics zu identifizieren.

1
2
3
4
5
6
7
8
9
10
11
extension BrazeManager {
  func logContentCardImpression(idString: String?) {
    guard let contentCard = getContentCard(forString: idString) else { return }

    contentCard.logContentCardImpression()
  }

  private func getContentCard(forString idString: String?) -> ABKContentCard? {
    return contentCards?.first(where: { $0.idString == idString })
  }
}

Analytics protokollieren
Die Protokollierungsmethoden können direkt aus Objekten aufgerufen werden, die dem ContentCardable-Protokoll entsprechen.

1
2
3
[customObject logContentCardImpression];
[customObject logContentCardClicked];
[customObject logContentCardDismissed];

ABKContentCard abrufen
Der von Ihrem angepassten Objekt übergebene idString wird verwendet, um die zugehörige Content Card für die Protokollierung von Analytics zu identifizieren.

1
2
3
4
5
6
7
8
9
10
11
- (void)logContentCardImpression:(NSString *)idString {
  ABKContentCard *contentCard = [self getContentCard:idString];
  [contentCard logContentCardImpression];
}

- (ABKContentCard *)getContentCard:(NSString *)idString {
  NSPredicate *predicate = [NSPredicate predicateWithFormat:@"self.idString == %@", idString];
  NSArray *filteredArray = [self.contentCards filteredArrayUsingPredicate:predicate];

  return filteredArray.firstObject;
}

Hilfsdateien

ContentCardKey-Hilfsdatei
1
2
3
4
5
6
7
8
enum ContentCardKey: String {
  case idString
  case created
  case classType = "class_type"
  case dismissible
  case extras
  ...
}
1
2
3
4
5
6
static NSString *const ContentCardKeyIdString = @"idString";
static NSString *const ContentCardKeyCreated = @"created";
static NSString *const ContentCardKeyClassType = @"class_type";
static NSString *const ContentCardKeyDismissible = @"dismissible";
static NSString *const ContentCardKeyExtras = @"extras";
...
New Stuff!