プッシュ通知データを記録する
Braze SDKを通してプッシュ通知データを記録する方法を学習する。
Braze でのログ記録(推奨)
/users/track エンドポイント を呼び出すことで、分析をリアルタイムで記録できます。分析を記録するには、Braze ダッシュボードからbraze_id 値を送信して、更新するユーザープロファイルを識別します。

データの手動ロギング
給与読み込むの内容に応じて、FirebaseMessagingService.onMessageReceived インプリメンテーションまたはスタートアップアクティビティ内で分析を手動で記録できます。FirebaseMessagingService サブクラスは、Androidシステムによって[ フラグが設定されたり、終了したりしないように、起動後9 秒で実行を終了する必要があります。
Braze APIでデータをロギングする(推奨)
ログ分析は、Braze API /users/track エンドポイントを使用してリアルタイムで実行できます。分析をログに記録するには、braze_id 値をキーと値のペアフィールド (次のスクリーンショットを参照) に送信し、更新するユーザープロファイルを識別します。

手動でデータを記録する
手動でログを記録するには、まず Xcode 内でワークスペースを設定してから、分析を作成、保存、および取得する必要があります。これには、お客様の側でカスタム開発者の作業が必要になります。以下に示すコードスニペットは、これを解決するのに役立ちます。
分析はモバイルアプリケーションがその後起動されるまでBrazeに送信されないことに注意することが重要です。つまり、削除設定に応じて、プッシュ通知が破棄されてモバイルアプリが起動し、分析が取得されるまでに不確定な期間が存在することがよくあります。この場合バッファーがすべてのユースケースに影響するとは限りませんが、影響を考慮して、必要に応じて、アプリケーションを開いてこの問題に対処するようにユーザー体験を調整する必要があります。
に送信されます。
ステップ1:Xcode内でアプリグループを構成する
Xcode で App Groups 機能を追加します。アプリにワークスペースがない場合は、メインアプリターゲットの機能に移動し、App Groups をオンにして、[+ 追加] ボタンをクリックします。次に、アプリのバンドルIDを使用してワークスペースを作成します。例えば、アプリのバンドルIDがcom.company.appnameの場合、ワークスペースの名前をgroup.com.company.appname.xyzにすることができます。メインアプリターゲットとコンテンツ拡張ターゲットの両方で App Groups がオンになっていることを確認します。

ステップ 2:コードスニペットの統合
以下のコードスニペットは、カスタムイベント、カスタム属性、およびユーザー属性を保存および送信する方法についての役立つ参考情報です。このガイドではUserDefaultsの用語で説明しますが、コードの表現はヘルパーファイルRemoteStorageの形式になります。また、追加のヘルパーファイル UserAttributes と EventName Dictionary もあり、ユーザー属性の送信と保存に使用されます。
カスタムイベントの保存
カスタムイベントを保存するには、分析をゼロから作成する必要があります。これを行うには、辞書を作成し、メタデータを入力し、ヘルパーファイルを使用してデータを保存します。
- イベントメタデータを使用して辞書を初期化します
- イベントデータを取得して保存するには、
userDefaultsを初期化します - 既存の配列がある場合は、既存の配列に新しいデータを追加して保存します
- 既存の配列がない場合は、新しい配列を
userDefaultsに保存します
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:RemoteStorageKeyPendingCustomAttributes];
} else {
// 4
[remoteStorage store:@[ customEventDictionary ] forKey:RemoteStorageKeyPendingCustomAttributes];
}
}
カスタムイベントの Braze への送信
通知コンテンツアプリの拡張機能から保存された分析をログに記録するのに最適なタイミングは SDK の初期化直後です。これは、保留中のイベントをループして「イベント名」キーをチェックし、Brazeに適切な値を設定し、次回この機能が必要なときのためにストレージをクリアすることで実行できます。
- 保留中のイベントの配列をループします
pendingEvents辞書の各キーと値のペアをループします- 「Event Name」のキーを明示的にチェックし、それに応じて値を設定します
- 他のすべてのキー値が
properties辞書に追加されます - 個別のカスタムイベントを記録します
- すべての保留中のイベントをストレージから削除します
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 == 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 {
AppDelegate.braze?.logCustomEvent(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];
}
カスタム属性の保存
カスタム属性を保存するには、分析をゼロから作成する必要があります。これを行うには、辞書を作成し、メタデータを入力し、ヘルパーファイルを使用してデータを保存します。
- 属性メタデータを使用してディクショナリを初期化します
- 属性データを取得して格納するには、
userDefaultsを初期化します - 既存の配列がある場合は、既存の配列に新しいデータを追加して保存します
- 既存の配列がない場合は、新しい配列を
userDefaultsに保存します
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];
}
}
カスタム属性の Braze への送信
通知コンテンツアプリの拡張機能から保存された分析をログに記録するのに最適なタイミングは SDK の初期化直後です。これは、保留中の属性をループし、Braze で適切なカスタム属性を設定し、次回この関数が必要になったときに備えてストレージをクリアすることで実行できます。
- 保留中の属性の配列をループスルーします
pendingAttributes辞書の各キーと値のペアをループします- 対応するキーと値で個々のカスタム属性を記録する
- ストレージからすべての保留中の属性を削除します
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]];
}
}
ユーザー属性の保存
ユーザー属性を保存する際には、どのタイプの属性が更新されているかを判別するためにカスタムオブジェクトを作成することをお勧めします(email、first_name、phone_numberなど)。オブジェクトは、UserDefaults からの保管 / 取得に対応している必要があります。これを行う方法の一例については、UserAttribute ヘルパーファイルを参照してください。
- エンコードされた
UserAttributeオブジェクトを対応する型で初期化します - イベントデータを取得して保存するには、
userDefaultsを初期化します - 既存の配列がある場合は、既存の配列に新しいデータを追加して保存します
- 既存の配列がない場合は、新しい配列を
userDefaultsに保存します
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.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)
}
}
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];
}
}
Braze へのユーザー属性の送信
通知コンテンツアプリの拡張機能から保存された分析をログに記録するのに最適なタイミングは SDK の初期化直後です。これは、保留中の属性をループし、Braze で適切なカスタム属性を設定し、次回この関数が必要になったときに備えてストレージをクリアすることで実行できます。
pendingAttributesデータの配列をループします- 属性データからエンコードされた
UserAttributeオブジェクトを初期化します - ユーザー属性タイプ (電子メール) に基づいて特定のユーザーフィールドを設定します
- ストレージからすべての保留中のユーザー属性を削除します
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):
user?.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 Helper File
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
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)
}
}
}
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 (!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 Helper File
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.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)
}
}
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 Helper File
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
@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
GitHub でこのページを編集