Push-Analytics und Protokollierung angepasster Events
Diese Seite behandelt die folgenden Workflows: native Push-Analytics (Öffnungen, beeinflusste Öffnungen und Campaign-Reporting) sowie die Protokollierung angepasster Daten (angepasste Events und Attribute) aus Push-Payloads. Nutzen Sie diesen Leitfaden, um festzustellen, welcher Workflow für Ihren Anwendungsfall gilt, und folgen Sie den Schritten für Ihre Plattform.
Voraussetzungen
Bevor Sie beginnen, schließen Sie die initiale Push-Benachrichtigungs-Integration für Ihre Plattform ab:
Native Push-Analytics vs. Protokollierung angepasster Events
Die folgenden Workflows haben jeweils unterschiedliche Reporting-Oberflächen.
| Analytics-Kategorie | Beschreibung | Wo sie angezeigt wird |
|---|---|---|
| Native Push-Analytics | Push-Metriken wie Öffnungen und beeinflusste Öffnungen, die mit Braze-Push-Campaigns verknüpft sind | Push-Campaign-Analytics, Currents-Nachrichten-Engagement-Events, Berichts-Builder |
| Angepasste Events und Attribute | Analytics, die Sie definieren und über SDK-Methoden oder den /users/track-Endpunkt protokollieren |
Nutzerprofile, Segmentierung, aktionsbasierte Campaigns und Canvases, Analytics für angepasste Events |

Das Protokollieren eines angepassten Events (z. B. push_notification_opened) ist nicht dasselbe wie das native Braze-Push-Öffnungs-Tracking. Angepasste Events füllen keine nativen Push-Campaign-Öffnungsmetriken oder Push-Attribution.
Was Braze automatisch protokolliert
Wenn Ihre SDK-Integration konfiguriert ist, protokolliert Braze automatisch grundlegende Kanal-Interaktionsdaten, einschließlich Push-Öffnungen und beeinflusster Öffnungen. Für Standard-Push-Analytics ist kein zusätzlicher Code erforderlich. Eine vollständige Liste der automatisch erfassten Daten finden Sie unter SDK-Datenerfassung.
Weitere Details finden Sie hier:
- SDK-Datenerfassung für eine vollständige Liste automatisch erfasster und optionaler Daten.
- Beeinflusste Öffnungen für Informationen darüber, wie Braze beeinflusste Öffnungen berechnet.
- Nachrichten-Engagement-Events für nachgelagerte Event-Schemas in Currents.
Native Push-Analytics bei angepasster Push-Verarbeitung beibehalten
Sie verwenden möglicherweise einen angepassten Push-Handler, wenn Sie mehrere Push-Anbieter integrieren, zusätzliche Payload-Daten verarbeiten oder eine angepasste Logik für die Benachrichtigungsanzeige implementieren müssen. Wenn Sie einen angepassten Push-Handler verwenden, müssen Sie Push-Payloads dennoch an Braze-SDK-Methoden übergeben. Dadurch kann Braze die eingebetteten Tracking-Daten extrahieren und native Push-Analytics (Öffnungen, beeinflusste Öffnungen und Zustellungsmetriken) protokollieren.
Wenn Sie einen angepassten FirebaseMessagingService haben, rufen Sie BrazeFirebaseMessagingService.handleBrazeRemoteMessage(...) innerhalb Ihrer onMessageReceived-Methode auf. Beachten Sie, dass Ihre FirebaseMessagingService-Unterklasse die Ausführung innerhalb von 9 Sekunden nach dem Aufruf abschließen muss, um nicht vom Android-System markiert oder beendet zu werden.
1
2
3
4
5
6
7
8
9
10
11
public class MyFirebaseMessagingService extends FirebaseMessagingService {
@Override
public void onMessageReceived(RemoteMessage remoteMessage) {
super.onMessageReceived(remoteMessage);
if (BrazeFirebaseMessagingService.handleBrazeRemoteMessage(this, remoteMessage)) {
// Braze processed a Braze push payload.
} else {
// Non-Braze payload: pass to your other handlers.
}
}
}
Ein vollständiges Implementierungsbeispiel finden Sie in der Braze Android SDK Firebase Push-Beispiel-App.
Bei einer manuellen Push-Integration leiten Sie Hintergrund- und Nutzerbenachrichtigungs-Callbacks an Braze weiter.
Hintergrund-Benachrichtigungen:
1
2
3
4
5
6
7
if let braze = AppDelegate.braze, braze.notifications.handleBackgroundNotification(
userInfo: userInfo,
fetchCompletionHandler: completionHandler
) {
return
}
completionHandler(.noData)
Nutzerbenachrichtigungs-Antworten:
1
2
3
4
5
6
7
if let braze = AppDelegate.braze, braze.notifications.handleUserNotification(
response: response,
withCompletionHandler: completionHandler
) {
return
}
completionHandler()
Vordergrund-Benachrichtigungen:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
func userNotificationCenter(
_ center: UNUserNotificationCenter,
willPresent notification: UNNotification,
withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void
) {
if let braze = AppDelegate.braze {
braze.notifications.handleForegroundNotification(notification: notification)
}
if #available(iOS 14.0, *) {
completionHandler([.banner, .list, .sound])
} else {
completionHandler([.alert, .sound])
}
}
Ein vollständiges Implementierungsbeispiel finden Sie im Braze Swift SDK Manual Push-Beispiel (AppDelegate.swift).
Für Web-Push konfigurieren Sie Ihren Service Worker und die SDK-Initialisierung wie unter Web-Push-Benachrichtigungen beschrieben.
Weitere Code-Beispiele finden Sie im Braze Web SDK-Repository.
Angepasste Daten aus Push-Payloads protokollieren
Verwenden Sie diesen Abschnitt, wenn Sie zusätzliche Daten aus Push-Payload-Schlüssel-Wert-Paaren protokollieren müssen, z. B. angepasste Events oder Attribute, die mit Ihrer Geschäftslogik verknüpft sind.
Weitere Informationen zu angepassten Events finden Sie unter Angepasste Events. Informationen zum Protokollieren angepasster Events über SDK-Methoden finden Sie unter Angepasste Events protokollieren.
Option A: Protokollierung über den /users/track-Endpunkt
Sie können Analytics in Echtzeit protokollieren, indem Sie den /users/track-Endpunkt aufrufen.
Um das Nutzerprofil zu identifizieren, fügen Sie braze_id in Ihre Push-Payload-Schlüssel-Wert-Paare ein.

Die Übergabe von braze_id identifiziert nur das Profil. Sie benötigen weiterhin Implementierungslogik, die Payload-Werte liest und die /users/track-Anfrage mit den Events oder Attributen sendet, die Sie protokollieren möchten.
Option B: Protokollierung über SDK-Methoden nach dem App-Start
Sie können Payload-Daten auch lokal speichern und angepasste Events und Attribute über SDK-Methoden protokollieren, nachdem die App initialisiert wurde. Dieser Ansatz ist üblich in Notification Content Extension-Flows, bei denen Analytics-Daten zuerst persistiert und beim nächsten App-Start gesendet werden.

Analytics werden erst an Braze gesendet, wenn die App gestartet wird. Abhängig von Ihren Einstellungen zum Schließen kann es eine Verzögerung zwischen dem Zeitpunkt geben, an dem die Nutzer:innen die Benachrichtigung schließen, und dem Zeitpunkt, an dem die App öffnet und Analytics sendet.
Protokollierung aus einer Notification Content Extension (Swift)
Die folgenden Schritte beschreiben, wie Sie angepasste Events, angepasste Attribute und Nutzerattribute aus einer Swift Notification Content Extension speichern und senden.
1. Schritt: App-Gruppen in Xcode konfigurieren
Fügen Sie in Xcode die App Groups-Fähigkeit zu Ihrem Haupt-App-Target hinzu. Aktivieren Sie App Groups und klicken Sie dann auf +, um eine neue Gruppe hinzuzufügen. Verwenden Sie die Bundle-ID Ihrer App, um den Gruppenbezeichner zu erstellen (z. B. group.com.company.appname.xyz). Aktivieren Sie App Groups sowohl für Ihr Haupt-App-Target als auch für das Content Extension-Target.

2. Schritt: Auswählen, was protokolliert werden soll
Bevor Sie die Snippets implementieren, wählen Sie aus, welche Analytics-Kategorie Sie protokollieren möchten:
- Angepasste Events: Aktionen, die Nutzer:innen ausführen (z. B. einen Flow abschließen oder auf ein bestimmtes UI-Element tippen). Verwenden Sie angepasste Events für aktionsbasierte Trigger, Segmentierung und Event-Analytics. Weitere Informationen finden Sie unter Angepasste Events und Angepasste Events protokollieren.
- Angepasste Attribute: Profilfelder, die Sie definieren (z. B.
plan_tieroderpreferred_language) und im Laufe der Zeit aktualisieren. Weitere Informationen finden Sie unter Angepasste Attribute und Nutzerattribute festlegen. - Nutzerattribute: Standard-Profilfelder (z. B. E-Mail, Vorname und Telefonnummer). Im Beispielcode werden diese durch ein typisiertes
UserAttribute-Modell dargestellt und dann auf Braze-Nutzerfelder abgebildet.
Die Hilfsdateien in diesem Abschnitt (RemoteStorage, UserAttribute und EventName Dictionary) sind lokale Hilfsdateien, die von dieser Beispielimplementierung verwendet werden. Sie sind keine integrierten SDK-Klassen. Sie speichern aus Payloads abgeleitete Daten in UserDefaults, definieren ein typisiertes Modell für ausstehende Nutzer-Updates und standardisieren die Event-Payload-Konstruktion. Weitere Informationen zum lokalen Datenspeicherverhalten finden Sie unter Speicher.

Die Beispiele für Hilfsdateien in diesem Abschnitt sind iOS-spezifisch (Swift und Objective-C). Für Android- und Web-Ansätze zur Protokollierung angepasster Events und Attribute siehe Angepasste Events protokollieren (Android, Web) und Nutzerattribute festlegen (Android, Web).
Angepasste Events speichern
Erstellen Sie den Analytics-Payload, indem Sie ein Dictionary aufbauen, Metadaten befüllen und es mit der Hilfsdatei speichern.
- Initialisieren Sie ein Dictionary mit Event-Metadaten.
- Initialisieren Sie
userDefaults, um Event-Daten abzurufen und zu speichern. - Wenn ein vorhandenes Array gefunden wird, anhängen und speichern.
- Wenn kein Array vorhanden ist, ein neues Array speichern.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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)
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
- (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:RemoteStorageKeyPendingCustomEvents];
} else {
// 4
[remoteStorage store:@[ customEventDictionary ] forKey:RemoteStorageKeyPendingCustomEvents];
}
}
Angepasste Events an Braze senden
Protokollieren Sie gespeicherte Analytics direkt nach der SDK-Initialisierung.
- Durchlaufen Sie die ausstehenden Events.
- Durchlaufen Sie die Schlüssel-Wert-Paare in jedem Event.
- Prüfen Sie auf den
event_name-Schlüssel. - Fügen Sie die verbleibenden Schlüssel-Wert-Paare zum
properties-Dictionary hinzu. - Protokollieren Sie jedes angepasste Event.
- Entfernen Sie ausstehende Events aus dem Speicher.
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
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 == "event_name" {
// 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 {
AppDelegate.braze?.logCustomEvent(name: eventName, properties: properties)
}
}
// 6
remoteStorage.removeObject(forKey: .pendingCustomEvents)
}
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
- (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) {
[AppDelegate.braze logCustomEvent:eventName properties:properties];
}
}
// 6
[remoteStorage removeObjectForKey:RemoteStorageKeyPendingCustomEvents];
}
Angepasste Attribute speichern
Erstellen Sie das Analytics-Dictionary von Grund auf und persistieren Sie es.
- Initialisieren Sie ein Dictionary mit Attribut-Metadaten.
- Initialisieren Sie
userDefaults, um Attributdaten abzurufen und zu speichern. - Wenn ein vorhandenes Array gefunden wird, anhängen und speichern.
- Wenn kein Array vorhanden ist, ein neues Array speichern.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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)
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
- (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
Protokollieren Sie gespeicherte Analytics direkt nach der SDK-Initialisierung.
- Durchlaufen Sie die ausstehenden Attribute.
- Durchlaufen Sie jedes Schlüssel-Wert-Paar.
- Protokollieren Sie jeden angepassten Attribut-Schlüssel und -Wert.
- Entfernen Sie ausstehende Attribute aus dem Speicher.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
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)
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
- (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 erstellen Sie ein angepasstes Objekt, das erfasst, welches Nutzerfeld aktualisiert wird (email, first_name, phone_number usw.). Das Objekt sollte mit dem Speichern und Abrufen über UserDefaults kompatibel sein. Ein Beispiel finden Sie in der UserAttribute-Hilfsdatei im Tab Hilfsdateien.
- Initialisieren Sie ein codiertes
UserAttribute-Objekt mit dem entsprechenden Typ. - Initialisieren Sie
userDefaults, um die Daten abzurufen und zu speichern. - Wenn ein vorhandenes Array gefunden wird, anhängen und speichern.
- Wenn kein Array vorhanden ist, ein neues Array speichern.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
func saveUserAttribute() {
// 1
guard let data = try? PropertyListEncoder().encode(UserAttribute.email("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)
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
- (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
Protokollieren Sie gespeicherte Analytics direkt nach der SDK-Initialisierung.
- Durchlaufen Sie die
pendingAttributes-Daten. - Decodieren Sie jedes
UserAttribute. - Setzen Sie Nutzerfelder basierend auf dem Attributtyp.
- Entfernen Sie ausstehende Nutzerattribute aus dem Speicher.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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):
AppDelegate.braze?.user.set(email: email)
}
}
// 4
remoteStorage.removeObject(forKey: .pendingUserAttributes)
}
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
- (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];
}
RemoteStorage-Hilfsdatei
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
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:
// Use the App Group identifier you created in Step 1.
return UserDefaults(suiteName: "group.com.company.appname.xyz")!
}
}()
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)
}
}
}
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
@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 (!_defaults) {
switch (self.storageType) {
case StorageTypeStandard:
_defaults = [NSUserDefaults standardUserDefaults];
break;
case StorageTypeSuite:
_defaults = [[NSUserDefaults alloc] initWithSuiteName:@"group.com.company.appname.xyz"];
break;
}
}
return _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
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
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.encodeIfPresent(email, forKey: .email)
}
}
init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)
let email = try values.decodeIfPresent(String.self, forKey: .email)
self = .email(email)
}
}
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
@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
1
2
3
4
5
6
7
8
9
10
11
12
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
}
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@implementation NSMutableDictionary (Helper)
+ (instancetype)dictionaryWithEventName:(NSString *)eventName
properties:(NSDictionary *)properties {
NSMutableDictionary *dict = [NSMutableDictionary dictionary];
dict[@"event_name"] = eventName;
if (properties) {
for (id key in properties) {
dict[key] = properties[key];
}
}
return dict;
}
@end
Ergebnisse analysieren
Verwenden Sie die Reporting-Oberfläche, die zur Analytics-Kategorie passt:
| Analytics-Kategorie | Wo Sie es in Braze einsehen können |
|---|---|
| Native Push-Analytics | Um Push-Öffnungsmetriken auf Campaign-Ebene anzuzeigen, navigieren Sie zur Seite Campaign Analytics Ihrer Push-Campaign. Für Metrik-Definitionen siehe Beeinflusste Öffnungen. Um angepasste Analytics-Ansichten zu erstellen, navigieren Sie zu Analytics > Report Builder (New). Für Navigationsschritte siehe Berichts-Builder. Für Event-Schemas auf Warehouse-Ebene siehe Nachrichten-Engagement-Events. |
| Angepasste Events und Attribute | Um Trends angepasster Events anzuzeigen, navigieren Sie zu Analytics > Bericht zu angepassten Events. Weitere Details finden Sie unter Angepasste Events. Um Werte auf Nutzerebene zu prüfen, navigieren Sie zur Seite Nutzer:innen suchen und öffnen Sie ein Profil. Für die Schritte siehe Nutzerprofile. Um Zielgruppen nach diesen Werten zu filtern, navigieren Sie zu Zielgruppe > Segments. Für Navigationsschritte siehe Segment erstellen und Filteroptionen unter Segmentierungsfilter. |
Informationen zur Erstellung angepasster Berichte finden Sie unter Berichts-Builder.