# iOS App-push統合
# App-pushの自動収集プラン
自動リサイクルプランは、SDK内部で各プラットフォーム(現在の段階ではFCM)のpush tokenおよびプッシュメッセージのクリックイベント(te_ops_push_click)を自動的に送信するプランです。
- データ収集SDKのバージョンを3.0.1-beata.1にアップグレードしてください。
pod 'ThinkingSDK', '3.0.1-beata.1'
- 自動リサイクルプッシュリンクを起動します
TDConfig *config = [[TDConfig alloc] initWithAppId:appId serverUrl:serverUrl];
config.enableAutoPush = YES; //プッシュ通知の自動回収を有効にする
[TDAnalytics startAnalyticsWithConfig:config];
- アカウントの切り替え
アカウントを切り替えた後、loginを呼び出す必要があります。SDK内部では、自動的にプッシュトークンがuser_setインタフェースを介して新しいアカウントに送信されます。
[TDAnalytics login:@"new_account_id"];
#
# App-pushの手動収集プラン
# FCMプッシュ
# 1.1 "pushID"を送信
- ログインまたはアカウント切り替え後に、FCMのtokenをアップロードします。
NSString *appid = @"appid";
NSString *url = @"url";
TDConfig *config = [TDConfig new];
config.appid = appid;
config.configureURL = url;
ThinkingAnalyticsSDK *instance = [ThinkingAnalyticsSDK startWithConfig:config];
[[FIRMessaging messaging] tokenWithCompletion:^(NSString *token, NSError *error) {
if (error != nil) {
NSLog(@"Error getting FCM registration token: %@", error);
} else {
NSLog(@"FCM registration token: %@", token);
[instance user_set:@{@"fcm_token": token}];
}
}];
# 1.2. クリックイベントの収集と送信
ユーザーがpushをクリックしたときにプッシュクリックイベントをアップロードすることができ、onCreateまたはonNewIntentでプッシュパラメータを取得できます。
// Handle notification messages after display notification is tapped by the user.
- (void)userNotificationCenter:(UNUserNotificationCenter *)center
didReceiveNotificationResponse:(UNNotificationResponse *)response
withCompletionHandler:(void(^)(void))completionHandler {
NSDictionary *userInfo = response.notification.request.content.userInfo;
trackAppOpenNotification(userInfo)
completionHandler();
}
# 1.3. プッシュメッセージの処理
ユーザーがプッシュ通知をクリックすると、システムのプッシュクリックコールバックでプッシュパラメータを取得できます。以下の2つのオプションから1つを選択してください。
- 通常パラメータ:handleTEPushActionメソッドを呼び出します。
- 透過パラメータ:handlePassThroughActionメソッドを呼び出します。
// Handle notification messages after display notification is tapped by the user.
- (void)userNotificationCenter:(UNUserNotificationCenter *)center
didReceiveNotificationResponse:(UNNotificationResponse *)response
withCompletionHandler:(void(^)(void))completionHandler {
NSDictionary *userInfo = response.notification.request.content.userInfo;
//通常パラメータ
handleTEPushAction(userInfo)
//透過パラメータ
handlePassThroughAction(userInfo)
completionHandler();
}
# APNs push
# 2.1 "pushID"を送信する
- ログインまたはアカウントの切り替え後にAPNs Device Tokenをアップロードします。
// ログイン後、再度APNs Device Tokenを送信します。
[TDAnalytics login:<#login ID#>];
NSString *token = [self getDviceToken];
[TDAnalytics userSet:@{ @"#apns_token": token }];
- application:didRegisterForRemoteNotificationsWithDeviceToken: コールバックで APNs Device Tokenを送信します
+// TA SDKの初期化後、APNsコールバックでAPNs Device Tokenを報告します。
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
NSString *token = [self formatDeviceTokenToHexStr:deviceToken];
[TDAnalytics userSet:@{ @"#apns_token": token }];
//APNs Device Tokenを記録して、アカウントを切り替える際に再度送信できるようにします。
[self holdDviceToken:token];
}
// (NSData *)deviceToken を (NSString *)deviceToken に変換します
- (NSString *)formatDeviceTokenToHexStr:(NSData *)deviceToken {
NSString *tokenStr;
if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 13.0) {
const unsigned *tokenBytes = [deviceToken bytes];
tokenStr = [NSString stringWithFormat:@"%08x%08x%08x%08x%08x%08x%08x%08x",
ntohl(tokenBytes[0]), ntohl(tokenBytes[1]), ntohl(tokenBytes[2]),
ntohl(tokenBytes[3]), ntohl(tokenBytes[4]), ntohl(tokenBytes[5]),
ntohl(tokenBytes[6]), ntohl(tokenBytes[7])];
} else {
tokenStr = [[deviceToken description] stringByReplacingOccurrencesOfString:@"<" withString:@""];
tokenStr = [tokenStr stringByReplacingOccurrencesOfString:@">" withString:@""];
tokenStr = [tokenStr stringByReplacingOccurrencesOfString:@" " withString:@""];
}
return tokenStr;
}
# 2.2 クリックイベントを収集する
// iOS10以下の場合、pushをクリックするコールバックとなります
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {
trackAppOpenNotification(userInfo);
completionHandler(UIBackgroundFetchResultNewData);
}
// iOS10以上の場合、pushをクリックするコールバックとなります
- (void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void(^)(void))completionHandler {
NSDictionary *userInfo = response.notification.request.content.userInfo;
trackAppOpenNotification(userInfo);
completionHandler(); // システムはこのメソッドを実行することを要求しています。
}
# 2.3 プッシュメッセージの処理
以下の2つの方法から1つを選択してください。
- 通常パラメーター:handleTEPushActionメソッドを呼び出します。
- 透過パラメーター:handlePassThroughActionメソッドを呼び出します。
// iOS10以下の場合、pushをクリックするコールバックとなります
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {
//通常パラメーター
handleTEPushAction(userInfo)
//透過パラメーター
handlePassThroughAction(userInfo)
completionHandler(UIBackgroundFetchResultNewData);
}
// iOS10以上の場合、pushをクリックするコールバックとなります
- (void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void(^)(void))completionHandler {
NSDictionary *userInfo = response.notification.request.content.userInfo;
//通常パラメーター
handleTEPushAction(userInfo)
//透過パラメーター
handlePassThroughAction(userInfo)
completionHandler(); // システムはこのメソッドを実行することを要求しています。
}
# push到達イベントを収集する
# NotificationServiceを有効
プロジェクトには、通知拡張のTargetを新規作成する必要があります。例えば:TANotification
# ThinkingDataPushExtensionの統合
CocoaPodsを使用してThinkingDataPushExtensionを統合します。
pod 'ThinkingDataPushExtension'
# イベントを収集
NotificationService.mファイルに次のコードを追加してください:
- (void)didReceiveNotificationRequest:(UNNotificationRequest *)request withContentHandler:(void (^)(UNNotificationContent * _Nonnull))contentHandler {
self.contentHandler = contentHandler;
self.bestAttemptContent = [request.content mutableCopy];
// 以下のコードを追加してイベントを収集します
NSString *appId = @"your app id in TE";
NSString *serverUrl = @"your server url in TE";
NSString *accountId = @"user account id. AccountId and DistinctId cannot be empty at the same time";
NSString *distinctId = @"user distinct id. AccountId and DistinctId cannot be empty at the same time";
BOOL result = [TDPushExtension handleNotificationRequest:request withContentHandler:contentHandler appId:appId serverUrl:serverUrl accountId:accountId distinctID:distinctId];
if (result) {
return;
}
self.contentHandler(self.bestAttemptContent);
}
パラメータの説明:
- appId:TEのバックエンドでプロジェクトのAPP IDを確認できます。
- serverUrl:TEのバックエンドでプロジェクトのreceiver urlを確認できます。
- accountId:現在のユーザーに対して送信されるプッシュのためのユニークなIDです。具体的な定義については、TEのユーザー識別ルールを参照してください。このフィールドは、プッシュデータ構造に手動で追加する必要があり、プッシュを受け取った際に手動で解析する必要があります。
- distinctId:現在のユーザーに対して送信されるプッシュのための訪問者IDです。具体的な定義については、TEのユーザー識別ルールを参照してください。このフィールドは、プッシュデータ構造に手動で追加する必要があり、プッシュを受け取った際に手動で解析する必要があります。
# 付録
# クライアントが受け取ったプッシュパラメータの例
{
"te_extras": {
//プッシュ通知のリンク方法
"ops_loading_type": "OPEN_APP",
//透過パラメータ
"passthrough_params": {
"param1": "abc",
"param2": 101,
"param3": [{
"subText1": "xyz",
"subText2": 2
}]
},
//TEエンゲージでのチャネルレシートプロパティ
"#ops_receipt_properties": {
"ops_task_id": "0082",
"ops_project_id": 1,
"ops_task_instance_id": "0082_20230331",
"ops_push_language": "default",
"ops_task_exec_detail_id": "55"
}
}
}
# 自動収集が成功したかどうかを確認する方法はありますか?
- プッシュ通知のアクセス後、初回起動またはトークン変更時に、以下のイベントが送信されますか。
{
"#type": "user_set",
"#time": "2023-11-13 15:50:55.729",
"#distinct_id": "distinct",
"properties": {
"FCM_id": "190e35f7e15c8481caa"
},
"#uuid": "9f233c31-a664-46ff-94d6-f767a3098c3a"
}
- プッシュ通知をクリックしてアプリを起動し、te_ops_push_clickイベントが送信されるかどうかを観察し、イベントのプロパティにops_receipt_propertiesが含まれているかどうかを確認します。
{
"#type": "track",
"#time": "2023-03-16 16:08:32.191",
"#distinct_id": "90d80464-6832-43f1-80d9-bd93fc09c4fe",
"#event_name": "te_ops_push_click",
"properties": {
"#lib_version": "3.0.1-beata.1",
"#carrier": "au",
"#os": "Android",
"#device_id": "6262ca7f71e6aca3",
"#screen_height": 2400,
"#bundle_id": "jp.thinkingdata.random",
"#device_model": "M2012K11AC",
"#screen_width": 1080,
"#system_language": "jp",
"#install_time": "2023-03-10 11:24:44.285",
"#simulator": false,
"#lib": "Android",
"#manufacturer": "Galaxy",
"#os_version": "11",
"#app_version": "1.0",
"#fps": 60,
"#network_type": "WIFI",
"#ram": "2.7\/7.4",
"#disk": "4.6\/106.3",
"#device_type": "Phone",
"ops_receipt_properties": {
"ops_project_id": 1,
"ops_request_id": "3b21d2a8-8d3d-44fa-b460-3bb311ed3bcd"
},
"#zone_offset": 9
},
"#uuid": "7a977e23-b78a-4433-baae-ead17ad2fde9"
}
# trackAppOpenNotification
public static void trackAppOpenNotification(String extras) {
try {
if (TextUtils.isEmpty(extras)) {
return;
}
JSONObject jsonObject = new JSONObject(extras);
JSONObject properties = new JSONObject();
Object obj = json.opt("#ops_receipt_properties");
JSONObject ops = null;
if (obj instanceof String) {
ops = new JSONObject(( String ) obj);
} else if (obj instanceof JSONObject) {
ops = ( JSONObject ) obj;
}
properties.put("#ops_receipt_properties", ops);
ThinkingAnalyticsSDK instance = ThinkingAnalyticsSDK.sharedInstance(null, "appId", "serverUrl");
instance.track("te_ops_push_click", properties);
//すぐ送信
instance.flush();
} catch (Exception e) {
e.printStackTrace();
}
}
# handleTEPushAction
public static void handleTEPushAction(String extras) {
try {
if (TextUtils.isEmpty(extras)) {
return;
}
JSONObject jsonObject = new JSONObject(extras);
String type = jsonObject.optString("ops_loading_type");
if ("OPEN_APP".equals(type)) {
// TODO アプリを開くメッセージの処理--> Appを起動してください
} else if ("OPEN_URL".equals(type)) {
String url = jsonObject.optString("ops_url");
if (!TextUtils.isEmpty(url)) {
// TODO URLを開くメッセージの処理,--> URLを処理してください
}
} else if ("CUSTOMIZED".equals(type)) {
String custom = jsonObject.optString("ops_customized");
if (!TextUtils.isEmpty(custom)) {
// TODO カスタムメッセージの処理,--> カスタムメッセージを処理してください
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
# handleTEPassThroughAction
public static void handleTEPassThroughAction(String extras) {
try {
if (TextUtils.isEmpty(extras)) {
return;
}
JSONObject jsonObject = new JSONObject(extras);
String params = jsonObject.optString("passthrough_params");
//paramsは透過パラメータであり、次に具体的なロジックの実装が続きます。
} catch (Exception e) {
e.printStackTrace();
}
}