
Das AppboyKit (auch bekannt als Objective-C SDK) wird nicht mehr unterstützt und wurde durch das Swift SDK ersetzt. Es wird keine neuen Features, Fehlerbehebungen, Sicherheitsupdates oder technischen Support mehr erhalten—Messaging und Analytics werden jedoch weiterhin wie gewohnt funktionieren. Weitere Informationen finden Sie unter Einführung in das neue Braze Swift SDK.

Suchen Sie nach dem grundlegenden Leitfaden zur Integration von Push-Benachrichtigungen für Entwickler:innen? Finden Sie ihn unter iOS-Push-Benachrichtigungsintegration.
Implementierungsleitfaden für Push-Benachrichtigungen
Dieser optionale Leitfaden für die erweiterte Implementierung beschreibt, wie Sie die App-Erweiterungen für Push-Benachrichtigungsinhalte nutzen können, um den größtmöglichen Erfolg mit Ihren Push-Nachrichten zu erzielen. Er enthält drei von unserem Team erstellte angepasste Anwendungsfälle, begleitende Code-Snippets und eine Anleitung zur Protokollierung von Analytics. Besuchen Sie das Braze Demo Repository! Beachten Sie, dass sich dieser Implementierungsleitfaden auf eine Swift-Implementierung konzentriert. Für Interessierte werden jedoch Objective-C-Snippets bereitgestellt.
App-Erweiterungen für Benachrichtigungsinhalte

Push-Benachrichtigungen, die auf verschiedenen Plattformen scheinbar einheitlich wirken, bieten weitreichende Anpassungsmöglichkeiten über das hinaus, was normalerweise in der Standard-UI implementiert wird. Wenn eine Push-Benachrichtigung erweitert wird, ermöglichen Erweiterungen für Benachrichtigungsinhalte eine angepasste Ansicht der erweiterten Push-Benachrichtigung.
Push-Benachrichtigungen können auf drei verschiedene Arten erweitert werden:
- Langes Drücken auf das Push-Banner
- Nach unten wischen auf dem Push-Banner
- Auf das Banner wischen und „Anzeigen“ auswählen
Diese angepassten Ansichten bieten intelligente Möglichkeiten, Kund:innen einzubinden, indem sie viele verschiedene Inhaltstypen anzeigen – darunter interaktive Benachrichtigungen, mit Nutzerdaten befüllte Benachrichtigungen und sogar Push-Nachrichten, die Informationen wie Telefonnummern und E-Mail-Adressen erfassen können. Auch wenn die Implementierung von Push-Benachrichtigungen auf diese Weise für manche ungewohnt sein mag – eines unserer bekannten Features bei Braze, Push Stories, ist ein hervorragendes Beispiel dafür, wie eine angepasste Ansicht für eine App-Erweiterung für Benachrichtigungsinhalte aussehen kann!
Voraussetzungen

- Push-Benachrichtigungen erfolgreich in Ihrer App integriert
- iOS 10 oder höher
- Die folgenden Dateien, die von Xcode basierend auf Ihrer Programmiersprache generiert werden:
Swift
- NotificationViewController.swift
- MainInterface.storyboard
Objective-C
- NotificationViewController.h
- NotificationViewController.m
- MainInterface.storyboard
Konfiguration angepasster Kategorien
Um eine angepasste Ansicht im Dashboard einzurichten, müssen Sie die Benachrichtigungs-Buttons aktivieren und Ihre angepasste Kategorie eingeben. Die vorab registrierte angepasste iOS-Kategorie, die Sie angeben, wird dann mit der UNNotificationExtensionCategory in der .plist Ihres Notification Content Extension Targets abgeglichen. Der hier angegebene Wert muss mit dem im Braze-Dashboard festgelegten Wert übereinstimmen.


Da Push-Benachrichtigungen mit Inhaltserweiterungen nicht immer offensichtlich sind, empfiehlt es sich, einen Call-to-Action einzufügen, der Ihre Nutzer:innen dazu auffordert, ihre Push-Benachrichtigungen zu erweitern.
Anwendungsfälle und Implementierungs-Walkthrough
Es gibt drei Typen von Push-Benachrichtigungs-Content-App-Erweiterungen. Jeder Typ enthält einen Konzept-Walkthrough, mögliche Anwendungsfälle sowie einen Einblick, wie Push-Benachrichtigungsvariablen im Braze-Dashboard aussehen und verwendet werden können:
- Interaktive Push-Benachrichtigung
- Personalisierte Push-Benachrichtigungen
- Push-Benachrichtigungen zur Informationserfassung
Interaktive Push-Benachrichtigung
Push-Benachrichtigungen können innerhalb einer Content Extension auf Nutzeraktionen reagieren. Für Nutzer:innen mit iOS 12 oder höher bedeutet dies, dass Sie Ihre Push-Nachrichten in vollständig interaktive Push-Benachrichtigungen verwandeln können! Diese Interaktivität bietet viele Möglichkeiten, Ihre Nutzer:innen mit Ihren Benachrichtigungen zu begeistern. Das folgende Beispiel zeigt eine Push-Benachrichtigung, bei der Nutzer:innen ein Zuordnungsspiel in der erweiterten Benachrichtigung spielen können.

Dashboard-Konfiguration
Um eine angepasste Ansicht im Dashboard einzurichten, geben Sie in den Einstellungen für Benachrichtigungs-Buttons die spezifische Kategorie ein, die Sie anzeigen möchten. Anschließend müssen Sie in der .plist Ihrer Notification Content Extension ebenfalls die angepasste Kategorie für das Attribut UNNotificationExtensionCategory festlegen. Der hier angegebene Wert muss mit dem im Braze-Dashboard gesetzten Wert übereinstimmen. Um schließlich Nutzerinteraktionen in einer Push-Benachrichtigung zu aktivieren, setzen Sie den Schlüssel UNNotificationExtensionInteractionEnabled auf „true“.


Weitere Anwendungsfälle
Push Content Extensions sind eine spannende Möglichkeit, Interaktivität in Ihre Aktionen und Anwendungen einzuführen. Einige Beispiele sind ein Spiel für Nutzer:innen, ein Glücksrad für Rabatte oder ein „Gefällt mir“-Button, um ein Angebot oder einen Song zu speichern.
Bereit, Analytics zu protokollieren?
Besuchen Sie den folgenden Abschnitt, um besser zu verstehen, wie der Datenfluss aussehen sollte.
Personalisierte Push-Benachrichtigungen

Push-Benachrichtigungen können nutzerspezifische Informationen in einer Content Extension anzeigen. Das begleitende Beispiel zeigt eine Push-Benachrichtigung, nachdem Nutzer:innen eine bestimmte Aufgabe (einen Braze-Lernkurs) abgeschlossen haben, und fordert nun dazu auf, die Benachrichtigung zu erweitern, um den Fortschritt zu überprüfen. Die hier bereitgestellten Informationen sind nutzerspezifisch und können ausgelöst werden, wenn eine Sitzung abgeschlossen oder eine bestimmte Nutzeraktion durchgeführt wird, indem ein API-Trigger verwendet wird.
Dashboard-Konfiguration
Um eine personalisierte Push-Benachrichtigung im Dashboard einzurichten, müssen Sie die spezifische Kategorie registrieren, die angezeigt werden soll, und dann innerhalb der Schlüssel-Wert-Paare mithilfe von Standard-Liquid die entsprechenden Nutzerattribute festlegen, die die Nachricht anzeigen soll. Diese Ansichten können basierend auf bestimmten Nutzerattributen eines bestimmten Nutzerprofils personalisiert werden.

Handhabung von Schlüssel-Wert-Paaren
Die folgende Methode didReceive wird aufgerufen, wenn die Content Extension eine Benachrichtigung empfangen hat. Sie befindet sich innerhalb des NotificationViewController. Die im Dashboard bereitgestellten Schlüssel-Wert-Paare werden im Code durch die Verwendung eines userInfo-Dictionarys dargestellt.
Parsen von Schlüssel-Wert-Paaren aus Push-Benachrichtigungen
func didReceive(_ notification: UNNotification) {
let userInfo = notification.request.content.userInfo
guard let value = userInfo["YOUR-KEY-VALUE-PAIR"] as? String,
let otherValue = userInfo["YOUR-OTHER-KEY-VALUE-PAIR"] as? String,
else { fatalError("Key-Value Pairs are incorrect.")}
...
}
- (void)didReceiveNotification:(nonnull UNNotification *)notification {
NSDictionary *userInfo = notification.request.content.userInfo;
if (userInfo[@"YOUR-KEY-VALUE-PAIR"] && userInfo[@"YOUR-OTHER-KEY-VALUE-PAIR"]) {
...
} else {
[NSException raise:NSGenericException format:@"Key-Value Pairs are incorrect"];
}
}
Weitere Anwendungsfälle
Die Möglichkeiten für fortschrittsbasierte und nutzerfokussierte Push Content Extensions sind endlos. Einige Beispiele sind die Möglichkeit, den Fortschritt über verschiedene Plattformen hinweg zu teilen, freigeschaltete Erfolge anzuzeigen, Stempelkarten oder sogar Onboarding-Checklisten.
Bereit, Analytics zu protokollieren?
Besuchen Sie den folgenden Abschnitt, um besser zu verstehen, wie der Datenfluss aussehen sollte.
Push-Benachrichtigung zur Informationserfassung
Push-Benachrichtigungen können Nutzerinformationen innerhalb einer Content Extension erfassen, sodass Sie die Grenzen dessen erweitern können, was mit einer Push-Benachrichtigung möglich ist. Wenn Sie den folgenden dargestellten Ablauf betrachten, kann die Ansicht auf Statusänderungen reagieren. Diese Statusänderungskomponenten sind in jedem Bild dargestellt.
- Nutzer:innen erhalten eine Push-Benachrichtigung.
- Die Push-Benachrichtigung wird geöffnet und fordert die Nutzer:innen zur Eingabe von Informationen auf.
- Informationen werden eingegeben und wenn sie gültig sind, wird der Registrierungs-Button angezeigt.
- Die Bestätigungsansicht wird angezeigt und die Push-Benachrichtigung wird geschlossen.
Beachten Sie, dass die hier angeforderten Informationen ein breites Spektrum abdecken können, wie z. B. die Erfassung von SMS-Nummern – sie müssen nicht E-Mail-spezifisch sein.
Dashboard-Konfiguration
Um eine Push-Benachrichtigung mit Informationserfassung im Dashboard einzurichten, müssen Sie Ihre angepasste Kategorie registrieren und festlegen sowie die benötigten Schlüssel-Wert-Paare bereitstellen. Wie im Beispiel zu sehen, können Sie auch ein Bild in Ihre Push-Benachrichtigung einfügen. Dazu müssen Sie Rich-Benachrichtigungen integrieren, den Benachrichtigungsstil in Ihrer Campaign auf Rich-Benachrichtigung setzen und ein Rich-Push-Bild einfügen.

Handhabung von Button-Aktionen
Jeder Aktions-Button wird eindeutig identifiziert. Der Code prüft, ob Ihr Antwort-Bezeichner dem actionIdentifier entspricht, und weiß dann, dass die Nutzer:innen den Aktions-Button geklickt haben.
Handhabung von Antworten auf Push-Benachrichtigungs-Aktions-Buttons
func didReceive(_ response: UNNotificationResponse, completionHandler completion: @escaping (UNNotificationContentExtensionResponseOption) -> Void) {
if response.actionIdentifier == "YOUR-REGISTER-IDENTIFIER" {
// do something
} else {
// do something else
}
}
- (void)didReceiveNotificationResponse:(UNNotificationResponse *)response completionHandler:(void (^)(UNNotificationContentExtensionResponseOption))completion {
if ([response.actionIdentifier isEqualToString:@"YOUR-REGISTER-IDENTIFIER"]) {
completion(UNNotificationContentExtensionResponseOptionDismiss);
} else {
completion(UNNotificationContentExtensionResponseOptionDoNotDismiss);
}
}
Push-Benachrichtigungen schließen
Push-Benachrichtigungen können durch Drücken eines Aktions-Buttons automatisch geschlossen werden. Es gibt drei vorgefertigte Optionen zum Schließen von Push-Benachrichtigungen, die empfohlen werden:
completion(.dismiss)– Schließt die Benachrichtigungcompletion(.doNotDismiss)– Benachrichtigung bleibt geöffnetcompletion(.dismissAndForward)– Push wird geschlossen und die Nutzer:innen werden in die Anwendung weitergeleitet.
Weitere Anwendungsfälle
Nutzereingaben über Push-Benachrichtigungen anzufordern ist eine spannende Möglichkeit, die viele Unternehmen nicht nutzen. In diesen Push-Nachrichten können Sie nicht nur grundlegende Informationen wie Name, E-Mail oder Nummer abfragen, sondern auch Nutzer:innen auffordern, ein unvollständiges Nutzerprofil zu vervollständigen oder sogar Feedback einzureichen.
Bereit, Analytics zu protokollieren?
Besuchen Sie den folgenden Abschnitt, um besser zu verstehen, wie der Datenfluss aussehen sollte.
Analytics protokollieren
Protokollierung über die Braze-API (empfohlen)
Die Protokollierung von Analytics kann nur in Echtzeit erfolgen, indem der Server der Kundin bzw. des Kunden unseren /users/track-Endpunkt aufruft. Um Analytics zu protokollieren, senden Sie den braze_id-Wert im Schlüssel-Wert-Paar-Feld mit (wie im folgenden Screenshot gezeigt), um zu identifizieren, welches Nutzerprofil aktualisiert werden soll.

Manuelle Protokollierung
Die manuelle Protokollierung erfordert zunächst die Konfiguration von App-Gruppen in Xcode und anschließend das Erstellen, Speichern und Abrufen von Analytics. Dies erfordert etwas angepasste Entwicklungsarbeit auf Ihrer Seite. Die folgenden Code-Snippets helfen Ihnen dabei.
Außerdem ist zu beachten, dass Analytics erst an Braze gesendet werden, wenn die mobile App anschließend gestartet wird. Das bedeutet, dass je nach Ihren Einstellungen zum Schließen oft ein unbestimmter Zeitraum zwischen dem Schließen einer Push-Benachrichtigung und dem Start der mobilen App besteht, in dem die Analytics abgerufen werden. Obwohl dieser Zeitpuffer nicht alle Anwendungsfälle beeinflusst, sollten Nutzer:innen die Auswirkungen berücksichtigen und gegebenenfalls ihre User Journey so anpassen, dass sie das Öffnen der Anwendung einschließt, um dieses Problem zu beheben.

Schritt 1: App-Gruppen in Xcode konfigurieren
Fügen Sie die Fähigkeit App Groups hinzu. Falls Sie noch keine App-Gruppe in Ihrer App haben, gehen Sie zu den Fähigkeiten des Haupt-App-Targets, aktivieren Sie App Groups und klicken Sie auf „+“. Verwenden Sie die Bundle-ID Ihrer App, um die App-Gruppe zu erstellen. Wenn die Bundle-ID Ihrer App beispielsweise com.company.appname lautet, können Sie Ihre App-Gruppe group.com.company.appname.xyz nennen. Stellen Sie sicher, dass App Groups sowohl für Ihr Haupt-App-Target als auch für das Content-Extension-Target aktiviert sind.

Schritt 2: Code-Snippets integrieren
Die folgenden Code-Snippets sind eine hilfreiche Referenz zum Speichern und Senden von angepassten Events, angepassten Attributen und Nutzerattributen. Dieser Leitfaden verwendet UserDefaults als Begriffe, aber die Code-Darstellung erfolgt in Form einer Hilfsdatei RemoteStorage. Es gibt auch zusätzliche Hilfsdateien UserAttributes und EventName Dictionary, die beim Senden und Speichern von Nutzerattributen verwendet werden. Alle Hilfsdateien finden Sie am Ende dieses Leitfadens.
Angepasste Events speichern
Um angepasste Events zu speichern, müssen Sie die Analytics als neues Design erstellen. Dies geschieht, indem Sie ein Dictionary erstellen, es mit Metadaten füllen und die Daten über eine Hilfsdatei speichern.
- Initialisieren Sie ein Dictionary mit Event-Metadaten
- Initialisieren Sie
userDefaults, um die Event-Daten abzurufen und zu speichern - Wenn bereits ein Array vorhanden ist, fügen Sie neue Daten an das vorhandene Array an und speichern Sie es
- Wenn kein Array vorhanden ist, speichern Sie das neue Array in
userDefaults
func saveCustomEvent(with properties: [String: Any]? = nil) {
// 1
let customEventDictionary = Dictionary(eventName: "YOUR-EVENT-NAME", properties: properties)
// 2
let remoteStorage = RemoteStorage(storageType: .suite)
// 3
if var pendingEvents = remoteStorage.retrieve(forKey: .pendingCustomEvents) as? [[String: Any]] {
pendingEvents.append(contentsOf: [customEventDictionary])
remoteStorage.store(pendingEvents, forKey: .pendingCustomEvents)
} else {
// 4
remoteStorage.store([customEventDictionary], forKey: .pendingCustomEvents)
}
}
- (void)saveCustomEvent:(NSDictionary<NSString *, id> *)properties {
// 1
NSDictionary<NSString *, id> *customEventDictionary = [[NSDictionary alloc] initWithEventName:@"YOUR-EVENT-NAME" properties:properties];
// 2
RemoteStorage *remoteStorage = [[RemoteStorage alloc] initWithStorageType:StorageTypeSuite];
NSMutableArray *pendingEvents = [[remoteStorage retrieveForKey:RemoteStorageKeyPendingCustomEvents] mutableCopy];
// 3
if (pendingEvents) {
[pendingEvents addObject:customEventDictionary];
[remoteStorage store:pendingEvents forKey:RemoteStorageKeyPendingCustomAttributes];
} else {
// 4
[remoteStorage store:@[ customEventDictionary ] forKey:RemoteStorageKeyPendingCustomAttributes];
}
}
Angepasste Events an Braze senden
Nachdem das SDK initialisiert wurde, ist der beste Zeitpunkt, um alle gespeicherten Analytics aus einer Notification-Content-App-Extension zu protokollieren. Dies kann durch Durchlaufen aller ausstehenden Events, Prüfen des Schlüssels „Event Name“, Setzen der entsprechenden Werte in Braze und anschließendes Leeren des Speichers für den nächsten Aufruf dieser Funktion erfolgen.
- Durchlaufen Sie das Array ausstehender Events
- Durchlaufen Sie jedes Schlüssel-Wert-Paar im
pendingEvents-Dictionary - Prüfen Sie explizit den Schlüssel auf „Event Name“, um den Wert entsprechend zu setzen
- Jedes andere Schlüssel-Wert-Paar wird dem
properties-Dictionary hinzugefügt - Protokollieren Sie das einzelne angepasste Event
- Entfernen Sie alle ausstehenden Events aus dem Speicher
func logPendingCustomEventsIfNecessary() {
let remoteStorage = RemoteStorage(storageType: .suite)
guard let pendingEvents = remoteStorage.retrieve(forKey: .pendingCustomEvents) as? [[String: Any]] else { return }
// 1
for event in pendingEvents {
var eventName: String?
var properties: [AnyHashable: Any] = [:]
// 2
for (key, value) in event {
if key == PushNotificationKey.eventName.rawValue {
// 3
if let eventNameValue = value as? String {
eventName = eventNameValue
} else {
print("Invalid type for event_name key")
}
} else {
// 4
properties[key] = value
}
}
// 5
if let eventName = eventName {
logCustomEvent(eventName, withProperties: properties)
}
}
// 6
remoteStorage.removeObject(forKey: .pendingCustomEvents)
}
- (void)logPendingEventsIfNecessary {
RemoteStorage *remoteStorage = [[RemoteStorage alloc] initWithStorageType:StorageTypeSuite];
NSArray *pendingEvents = [remoteStorage retrieveForKey:RemoteStorageKeyPendingCustomEvents];
// 1
for (NSDictionary<NSString *, id> *event in pendingEvents) {
NSString *eventName = nil;
NSMutableDictionary *properties = [NSMutableDictionary dictionary];
// 2
for (NSString* key in event) {
if ([key isEqualToString:@"event_name"]) {
// 3
if ([[event objectForKey:key] isKindOfClass:[NSString class]]) {
eventName = [event objectForKey:key];
} else {
NSLog(@"Invalid type for event_name key");
}
} else {
// 4
properties[key] = event[key];
}
}
// 5
if (eventName != nil) {
[[Appboy sharednstance] logCustomEvent:eventName withProperties:properties];
}
}
// 6
[remoteStorage removeObjectForKey:RemoteStorageKeyPendingCustomEvents];
}
Angepasste Attribute speichern
Um angepasste Attribute zu speichern, müssen Sie die Analytics als neues Design erstellen. Dies geschieht, indem Sie ein Dictionary erstellen, es mit Metadaten füllen und die Daten mithilfe einer Hilfsdatei speichern.
- Initialisieren Sie ein Dictionary mit Attribut-Metadaten
- Initialisieren Sie
userDefaults, um die Attributdaten abzurufen und zu speichern - Wenn bereits ein Array vorhanden ist, fügen Sie neue Daten an das vorhandene Array an und speichern Sie es
- Wenn kein Array vorhanden ist, speichern Sie das neue Array in
userDefaults
func saveCustomAttribute() {
// 1
let customAttributeDictionary: [String: Any] = ["YOUR-CUSTOM-ATTRIBUTE-KEY": "YOUR-CUSTOM-ATTRIBUTE-VALUE"]
// 2
let remoteStorage = RemoteStorage(storageType: .suite)
// 3
if var pendingAttributes = remoteStorage.retrieve(forKey: .pendingCustomAttributes) as? [[String: Any]] {
pendingAttributes.append(contentsOf: [customAttributeDictionary])
remoteStorage.store(pendingAttributes, forKey: .pendingCustomAttributes)
} else {
// 4
remoteStorage.store([customAttributeDictionary], forKey: .pendingCustomAttributes)
}
}
- (void)saveCustomAttribute {
// 1
NSDictionary<NSString *, id> *customAttributeDictionary = @{ @"YOUR-CUSTOM-ATTRIBUTE-KEY": @"YOUR-CUSTOM-ATTRIBUTE-VALUE" };
// 2
RemoteStorage *remoteStorage = [[RemoteStorage alloc] initWithStorageType:StorageTypeSuite];
NSMutableArray *pendingAttributes = [[remoteStorage retrieveForKey:RemoteStorageKeyPendingCustomAttributes] mutableCopy];
// 3
if (pendingAttributes) {
[pendingAttributes addObject:customAttributeDictionary];
[remoteStorage store:pendingAttributes forKey:RemoteStorageKeyPendingCustomAttributes];
} else {
// 4
[remoteStorage store:@[ customAttributeDictionary ] forKey:RemoteStorageKeyPendingCustomAttributes];
}
}
Angepasste Attribute an Braze senden
Nachdem das SDK initialisiert wurde, ist der beste Zeitpunkt, um alle gespeicherten Analytics aus einer Notification-Content-App-Extension zu protokollieren. Dies kann durch Durchlaufen der ausstehenden Attribute, Setzen des entsprechenden angepassten Attributs in Braze und anschließendes Leeren des Speichers für den nächsten Aufruf dieser Funktion erfolgen.
- Durchlaufen Sie das Array ausstehender Attribute
- Durchlaufen Sie jedes Schlüssel-Wert-Paar im
pendingAttributes-Dictionary - Protokollieren Sie das einzelne angepasste Attribut mit dem entsprechenden Schlüssel und Wert
- Entfernen Sie alle ausstehenden Attribute aus dem Speicher
func logPendingCustomAttributesIfNecessary() {
let remoteStorage = RemoteStorage(storageType: .suite)
guard let pendingAttributes = remoteStorage.retrieve(forKey: .pendingCustomAttributes) as? [[String: Any]] else { return }
// 1
pendingAttributes.forEach { setCustomAttributesWith(keysAndValues: $0) }
// 4
remoteStorage.removeObject(forKey: .pendingCustomAttributes)
}
func setCustomAttributesWith(keysAndValues: [String: Any]) {
// 2
for (key, value) in keysAndValues {
// 3
if let value = value as? [String] {
setCustomAttributeArrayWithKey(key, andValue: value)
} else {
setCustomAttributeWithKey(key, andValue: value)
}
}
}
- (void)logPendingCustomAttributesIfNecessary {
RemoteStorage *remoteStorage = [[RemoteStorage alloc] initWithStorageType:StorageTypeSuite];
NSArray *pendingAttributes = [remoteStorage retrieveForKey:RemoteStorageKeyPendingCustomAttributes];
// 1
for (NSDictionary<NSString*, id> *attribute in pendingAttributes) {
[self setCustomAttributeWith:attribute];
}
// 4
[remoteStorage removeObjectForKey:RemoteStorageKeyPendingCustomAttributes];
}
- (void)setCustomAttributeWith:(NSDictionary<NSString *, id> *)keysAndValues {
// 2
for (NSString *key in keysAndValues) {
// 3
[self setCustomAttributeWith:key andValue:[keysAndValues objectForKey:key]];
}
}
Nutzerattribute speichern
Beim Speichern von Nutzerattributen wird empfohlen, ein angepasstes Objekt zu erstellen, um zu entschlüsseln, welcher Attributtyp aktualisiert wird (email, first_name, phone_number usw.). Das Objekt sollte kompatibel mit dem Speichern/Abrufen über UserDefaults sein. Ein Beispiel dafür finden Sie in der Hilfsdatei UserAttribute.
- Initialisieren Sie ein codiertes
UserAttribute-Objekt mit dem entsprechenden Typ - Initialisieren Sie
userDefaults, um die Event-Daten abzurufen und zu speichern - Wenn bereits ein Array vorhanden ist, fügen Sie neue Daten an das vorhandene Array an und speichern Sie es
- Wenn kein Array vorhanden ist, speichern Sie das neue Array in
userDefaults
func saveUserAttribute() {
// 1
guard let data = try? PropertyListEncoder().encode(UserAttribute.userAttributeType("USER-ATTRIBUTE-VALUE")) else { return }
// 2
let remoteStorage = RemoteStorage(storageType: .suite)
// 3
if var pendingAttributes = remoteStorage.retrieve(forKey: .pendingUserAttributes) as? [Data] {
pendingAttributes.append(contentsOf: [data])
remoteStorage.store(pendingAttributes, forKey: .pendingUserAttributes)
} else {
// 4
remoteStorage.store([data], forKey: .pendingUserAttributes)
}
}
- (void)saveUserAttribute {
// 1
UserAttribute *userAttribute = [[UserAttribute alloc] initWithUserField:@"USER-ATTRIBUTE-VALUE" attributeType:UserAttributeTypeEmail];
NSError *error;
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:userAttribute requiringSecureCoding:YES error:&error];
if (error != nil) {
// log error
}
// 2
RemoteStorage *remoteStorage = [[RemoteStorage alloc] initWithStorageType:StorageTypeSuite];
NSMutableArray *pendingAttributes = [[remoteStorage retrieveForKey:RemoteStorageKeyPendingUserAttributes] mutableCopy];
// 3
if (pendingAttributes) {
[pendingAttributes addObject:data];
[remoteStorage store:pendingAttributes forKey:RemoteStorageKeyPendingUserAttributes];
} else {
// 4
[remoteStorage store:@[data] forKey:RemoteStorageKeyPendingUserAttributes];
}
}
Nutzerattribute an Braze senden
Nachdem das SDK initialisiert wurde, ist der beste Zeitpunkt, um alle gespeicherten Analytics aus einer Notification-Content-App-Extension zu protokollieren. Dies kann durch Durchlaufen der ausstehenden Attribute, Setzen des entsprechenden angepassten Attributs in Braze und anschließendes Leeren des Speichers für den nächsten Aufruf dieser Funktion erfolgen.
- Durchlaufen Sie das Array der
pendingAttributes-Daten - Initialisieren Sie ein codiertes
UserAttribute-Objekt aus den Attributdaten - Setzen Sie das spezifische Nutzerfeld basierend auf dem Nutzerattribut-Typ (E-Mail)
- Entfernen Sie alle ausstehenden Nutzerattribute aus dem Speicher
func logPendingUserAttributesIfNecessary() {
let remoteStorage = RemoteStorage(storageType: .suite)
guard let pendingAttributes = remoteStorage.retrieve(forKey: .pendingUserAttributes) as? [Data] else { return }
// 1
for attributeData in pendingAttributes {
// 2
guard let userAttribute = try? PropertyListDecoder().decode(UserAttribute.self, from: attributeData) else { continue }
// 3
switch userAttribute {
case .email(let email):
user?.email = email
}
}
// 4
remoteStorage.removeObject(forKey: .pendingUserAttributes)
}
- (void)logPendingUserAttributesIfNecessary {
RemoteStorage *remoteStorage = [[RemoteStorage alloc] initWithStorageType:StorageTypeSuite];
NSArray *pendingAttributes = [remoteStorage retrieveForKey:RemoteStorageKeyPendingUserAttributes];
// 1
for (NSData *attributeData in pendingAttributes) {
NSError *error;
// 2
UserAttribute *userAttribute = [NSKeyedUnarchiver unarchivedObjectOfClass:[UserAttribute class] fromData:attributeData error:&error];
if (error != nil) {
// log error
}
// 3
if (userAttribute) {
switch (userAttribute.attributeType) {
case UserAttributeTypeEmail:
[self user].email = userAttribute.userField;
break;
}
}
}
// 4
[remoteStorage removeObjectForKey:RemoteStorageKeyPendingUserAttributes];
}
Hilfsdateien
RemoteStorage-Hilfsdatei
enum RemoteStorageKey: String, CaseIterable {
// MARK: - Notification Content Extension Analytics
case pendingCustomEvents = "pending_custom_events"
case pendingCustomAttributes = "pending_custom_attributes"
case pendingUserAttributes = "pending_user_attributes"
}
enum RemoteStorageType {
case standard
case suite
}
class RemoteStorage: NSObject {
private var storageType: RemoteStorageType = .standard
private lazy var defaults: UserDefaults = {
switch storageType {
case .standard:
return .standard
case .suite:
return UserDefaults(suiteName: "YOUR-DOMAIN-IDENTIFIER")!
}
}()
init(storageType: RemoteStorageType = .standard) {
self.storageType = storageType
}
func store(_ value: Any, forKey key: RemoteStorageKey) {
defaults.set(value, forKey: key.rawValue)
}
func retrieve(forKey key: RemoteStorageKey) -> Any? {
return defaults.object(forKey: key.rawValue)
}
func removeObject(forKey key: RemoteStorageKey) {
defaults.removeObject(forKey: key.rawValue)
}
func resetStorageKeys() {
for key in RemoteStorageKey.allCases {
defaults.removeObject(forKey: key.rawValue)
}
}
}
@interface RemoteStorage ()
@property (nonatomic) StorageType storageType;
@property (nonatomic, strong) NSUserDefaults *defaults;
@end
@implementation RemoteStorage
- (id)initWithStorageType:(StorageType)storageType {
if (self = [super init]) {
self.storageType = storageType;
}
return self;
}
- (void)store:(id)value forKey:(RemoteStorageKey)key {
[[self defaults] setValue:value forKey:[self rawValueForKey:key]];
}
- (id)retrieveForKey:(RemoteStorageKey)key {
return [[self defaults] objectForKey:[self rawValueForKey:key]];
}
- (void)removeObjectForKey:(RemoteStorageKey)key {
[[self defaults] removeObjectForKey:[self rawValueForKey:key]];
}
- (void)resetStorageKeys {
[[self defaults] removeObjectForKey:[self rawValueForKey:RemoteStorageKeyPendingCustomEvents]];
[[self defaults] removeObjectForKey:[self rawValueForKey:RemoteStorageKeyPendingCustomAttributes]];
[[self defaults] removeObjectForKey:[self rawValueForKey:RemoteStorageKeyPendingUserAttributes]];
}
- (NSUserDefaults *)defaults {
if (!self.defaults) {
switch (self.storageType) {
case StorageTypeStandard:
return [NSUserDefaults standardUserDefaults];
break;
case StorageTypeSuite:
return [[NSUserDefaults alloc] initWithSuiteName:@"YOUR-DOMAIN-IDENTIFIER"];
}
} else {
return self.defaults;
}
}
- (NSString*)rawValueForKey:(RemoteStorageKey)remoteStorageKey {
switch(remoteStorageKey) {
case RemoteStorageKeyPendingCustomEvents:
return @"pending_custom_events";
case RemoteStorageKeyPendingCustomAttributes:
return @"pending_custom_attributes";
case RemoteStorageKeyPendingUserAttributes:
return @"pending_user_attributes";
default:
[NSException raise:NSGenericException format:@"Unexpected FormatType."];
}
}
UserAttribute-Hilfsdatei
enum UserAttribute: Hashable {
case email(String?)
}
// MARK: - Codable
extension UserAttribute: Codable {
private enum CodingKeys: String, CodingKey {
case email
}
func encode(to encoder: Encoder) throws {
var values = encoder.container(keyedBy: CodingKeys.self)
switch self {
case .email(let email):
try values.encode(email, forKey: .email)
}
}
init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)
let email = try values.decode(String.self, forKey: .email)
self = .email(email)
}
}
@implementation UserAttribute
- (id)initWithUserField:(NSString *)userField attributeType:(UserAttributeType)attributeType {
if (self = [super init]) {
self.userField = userField;
self.attributeType = attributeType;
}
return self;
}
- (void)encodeWithCoder:(NSCoder *)encoder {
[encoder encodeObject:self.userField forKey:@"userField"];
[encoder encodeInteger:self.attributeType forKey:@"attributeType"];
}
- (id)initWithCoder:(NSCoder *)decoder {
if (self = [super init]) {
self.userField = [decoder decodeObjectForKey:@"userField"];
NSInteger attributeRawValue = [decoder decodeIntegerForKey:@"attributeType"];
self.attributeType = (UserAttributeType) attributeRawValue;
}
return self;
}
@end
EventName-Dictionary-Hilfsdatei
extension Dictionary where Key == String, Value == Any {
init(eventName: String, properties: [String: Any]? = nil) {
self.init()
self[PushNotificationKey.eventName.rawValue] = eventName
if let properties = properties {
for (key, value) in properties {
self[key] = value
}
}
}
}
@implementation NSDictionary (Helper)
- (id)initWithEventName:(NSString *)eventName properties:(NSDictionary *)properties {
self = [self init];
if (self) {
dict[@"event_name"] = eventName;
for(id key in properties) {
dict[key] = properties[key];
}
}
return self;
}
@end