1. 极光推送

1.1. 上报推送 ID

为了保证登录之后的用户也能设置 registrationID 属性,需要在 - registrationIDCompletionHandler: 回调和调用神策 - login: 接口之后,各上报一次 registrationID

// 神策 SDK 初始化之后,在极光回调中上报 registrationID
[JPUSHService registrationIDCompletionHandler:^(int resCode, NSString *registrationID) {
    // 将 registrationID 保存到神策用户表的 jiguang_id 字段中(这⾥的 jiguang_id 只是一个示例字段)
    [[SensorsAnalyticsSDK sharedInstance] set:@"jiguang_id" to:registrationID];
}];
OBJECTIVE-C
// login 之后,再次上报 registrationID
[[SensorsAnalyticsSDK sharedInstance] login:<#登录 ID#>];
[[SensorsAnalyticsSDK sharedInstance] set:@"jiguang_id" to:registrationID];
OBJECTIVE-C

1.2. 采集推送点击事件

神策 iOS SDK 可以自动采集来自极光的推送点击事件,请参考文档开启采集。

1.3. 处理平台推送的消息

//  iOS10以下,点击通知的回调
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {
 
  // Required, iOS 7 Support
  [JPUSHService handleRemoteNotification:userInfo];
 
	// 处理平台推送的消息
	[SensorsFocusHelper dealSensorsFocusAction:userInfo link:^(NSString * _Nonnull urlString) {
        // TODO 处理打开 URL 消息,--> 请处理 URL
    } customize:^(NSDictionary * _Nonnull customizedDic) {
        // TODO 处理自定义消息,--> 请处理自定义消息
    }];
  completionHandler(UIBackgroundFetchResultNewData);
}
 
// iOS10以上,点击通知的回调
- (void)jpushNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void(^)(void))completionHandler  API_AVAILABLE(ios(10.0)){
    // Required
    NSDictionary *userInfo = response.notification.request.content.userInfo;
    if ([response.notification.request.trigger isKindOfClass:[UNPushNotificationTrigger class]]) {
        [JPUSHService handleRemoteNotification:userInfo];
    }
 
	// 处理平台推送的消息
	[SensorsFocusHelper dealSensorsFocusAction:userInfo link:^(NSString * _Nonnull urlString) {
        // TODO 处理打开 URL 消息,--> 请处理 URL
    } customize:^(NSDictionary * _Nonnull customizedDic) {
        // TODO 处理自定义消息,--> 请处理自定义消息
    }];
    completionHandler();  // 系统要求执行这个方法
}
OBJECTIVE-C

2. 友盟推送

2.1. 上报 deviceToken

为了保证登录之后的用户也能设置 deviceToken 属性,需要在获取到 deviceToken 时和调用神策 -login:  接口之后,各上报一次 deviceToken

/** 远程通知注册成功委托 */
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
      
    [UMessage registerDeviceToken:deviceToken];
 
    if (![deviceToken isKindOfClass:[NSData class]]) return;
    const unsigned *tokenBytes = (const unsigned *)[deviceToken bytes];
    NSString *hexToken = [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])];
    // 将 deviceToken 保存到神策用户表 umeng_id 中(这里的 umeng_id 只是一个示例字段)
    [[SensorsAnalyticsSDK sharedInstance] set:@"umeng_id" to:hexToken];
 
    /**
	 * 将 hexToken 进行缓存
	 */
}
OBJECTIVE-C
[[SensorsAnalyticsSDK sharedInstance] login:<#登录 ID#>];

// 为了保证登录后的用户也能正确设置 deviceToken,调用 login 之后,需要再次上报。
NSString *hexToken = <#取出之前缓存的 hexToken#>
[[SensorsAnalyticsSDK sharedInstance] set:@"umeng_id" to:hexToken];
OBJECTIVE-C

2.2. 记录 「推送打开」事件并处理智能运营平台推送的消息

// iOS10 一下版本,iOS 7 Support
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {
    [UMessage didReceiveRemoteNotification:userInfo];
 
    // 记录 推送打开 事件
	[SensorsFocusHelper trackSensorsFocusAppOpenNotificationWithUserInfo:userInfo];
	// 处理平台推送的消息
	[SensorsFocusHelper dealSensorsFocusAction:userInfo link:^(NSString * _Nonnull urlString) {
        // TODO 处理打开 URL 消息,--> 请处理 URL
    } customize:^(NSDictionary * _Nonnull customizedDic) {
        // TODO 处理自定义消息,--> 请处理自定义消息
    }];
    completionHandler(UIBackgroundFetchResultNewData);
}
 
//  iOS 10: 点击通知进入App时触发,在该方法内统计有效用户点击数
- (void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void (^)())completionHandler {
 
    NSDictionary *userInfo = response.notification.request.content.userInfo;
    if ([response.notification.request.trigger isKindOfClass:[UNPushNotificationTrigger class]]) {
        [UMessage didReceiveRemoteNotification:userInfo];
    }
 
	// 记录 推送打开 事件
	[SensorsFocusHelper trackSensorsFocusAppOpenNotificationWithUserInfo:userInfo];
	// 处理平台推送的消息
	[SensorsFocusHelper dealSensorsFocusAction:userInfo link:^(NSString * _Nonnull urlString) {
        // TODO 处理打开 URL 消息,--> 请处理 URL
    } customize:^(NSDictionary * _Nonnull customizedDic) {
        // TODO 处理自定义消息,--> 请处理自定义消息
    }];
 
    completionHandler();  // 系统要求执行这个方法
}
OBJECTIVE-C

3. 个推推送

3.1. 上报推送 ID

为了保证登录之后的用户也能设置 clientId 属性,需要在 GeTuiSdkDelegate 协议方法 GeTuiSdkDidRegisterClient:  和调用神策 - login: 接口之后,各上报一次 clientId。

- (void)GeTuiSdkDidRegisterClient:(NSString *)clientId {
    // 将clientId 保存到用户表的 getui_id 字段中(这里的 getui_id 只是一个示例字段)
    [[SensorsAnalyticsSDK sharedInstance] set:@"getui_id" to:clientId];
}
OBJECTIVE-C
// 为了保证登录后的用户也能正确设置 clientId,调用 login 之后,再次上报 clientId
[[SensorsAnalyticsSDK sharedInstance] login:<#登录 ID#>];
[[SensorsAnalyticsSDK sharedInstance] set:@"getui_id" to:GeTuiSdk.clientId];
OBJECTIVE-C

3.2. 记录 「推送打开」事件并处理智能运营平台推送的消息

// iOS10 一下版本,iOS 7 Support
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {
    // [ GTSdk ]:将收到的APNs信息传给个推统计
    [GeTuiSdk handleRemoteNotification:userInfo];
 
	// 记录 推送打开 事件
	[SensorsFocusHelper trackSensorsFocusAppOpenNotificationWithUserInfo:userInfo];
	// 处理平台推送的消息
	[SensorsFocusHelper dealSensorsFocusAction:userInfo link:^(NSString * _Nonnull urlString) {
        // TODO 处理打开 URL 消息,--> 请处理 URL
    } customize:^(NSDictionary * _Nonnull customizedDic) {
        // TODO 处理自定义消息,--> 请处理自定义消息
    }];
    completionHandler(UIBackgroundFetchResultNewData);
}
 
//  iOS 10: 点击通知进入App时触发,在该方法内统计有效用户点击数
- (void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void (^)())completionHandler {
 
    NSDictionary *userInfo = response.notification.request.content.userInfo;
    if ([response.notification.request.trigger isKindOfClass:[UNPushNotificationTrigger class]]) {
	    // [ GTSdk ]:将收到的APNs信息传给个推统计
    	[GeTuiSdk handleRemoteNotification:userInfo];
	}
	// 记录 推送打开 事件
	[SensorsFocusHelper trackSensorsFocusAppOpenNotificationWithUserInfo:userInfo];
	// 处理平台推送的消息
	[SensorsFocusHelper dealSensorsFocusAction:userInfo link:^(NSString * _Nonnull urlString) {
        // TODO 处理打开 URL 消息,--> 请处理 URL
    } customize:^(NSDictionary * _Nonnull customizedDic) {
        // TODO 处理自定义消息,--> 请处理自定义消息
    }];
    completionHandler();  // 系统要求执行这个方法
}
OBJECTIVE-C

4. 测试推送

  1. 首先发送推送 ID 到神策后,选择上报推送 ID 的 key(这里以 jiguang_id 为例),点击测试推送。
  2. 填入测试机的推送 ID、推送标题、内容,如下图所示。
  3. 确认推送,可查看手机是否收到推送,以及查看埋点上报字段是否正确。

5. 附录

5.1. + trackSensorsFocusAppOpenNotificationWithUserInfo: 方法详情

/**
 * 埋点“App 打开推送”事件。
 *
 * @param userInfo 包含与远程通知相关的信息的字典
 */
+ (void)trackSensorsFocusAppOpenNotificationWithUserInfo:(NSDictionary *)userInfo {
    NSMutableDictionary *pushProperties = [NSMutableDictionary dictionary]; // track 字典
    @try { // sf_data
        NSData *jsonData = [userInfo[@"sf_data"] dataUsingEncoding:NSUTF8StringEncoding];
        NSError *error;
        NSDictionary *sfDictionary = [NSJSONSerialization JSONObjectWithData:jsonData options:NSJSONReadingMutableContainers error:&error];
        if (!error && [sfDictionary isKindOfClass:NSDictionary.class]) {
            pushProperties[@"$sf_msg_id"] = sfDictionary[@"sf_msg_id"]; // SF 消息 id
            pushProperties[@"$sf_plan_id"] = sfDictionary[@"sf_plan_id"];
            pushProperties[@"$sf_audience_id"] = sfDictionary[@"sf_audience_id"];
            pushProperties[@"$sf_plan_strategy_id"] = sfDictionary[@"sf_plan_strategy_id"];
            pushProperties[@"$sf_plan_type"] = sfDictionary[@"sf_plan_type"];
            pushProperties[@"$sf_strategy_unit_id"] = sfDictionary[@"sf_strategy_unit_id"];
			pushProperties[@"$sf_enter_plan_time"] = sfDictionary[@"sf_enter_plan_time"];
			pushProperties[@"$sf_channel_id"] = sfDictionary[@"$sf_channel_id"];
			pushProperties[@"$sf_channel_category"] = sfDictionary[@"sf_channel_category"];
			pushProperties[@"$sf_channel_service_name"] = sfDictionary[@"sf_channel_service_name"];

            if ([sfDictionary[@"sf_landing_type"] isEqualToString:@"LINK"]) { // 打开 URL
                pushProperties[@"$sf_link_url"] = sfDictionary[@"sf_link_url"];
            }
            NSDictionary *customizedParams = sfDictionary[@"customized"];
            if ([customizedParams isKindOfClass:NSDictionary.class]) {
                [pushProperties addEntriesFromDictionary:customizedParams];
            }
        }
    } @catch (NSException *exception) {
    }
    @try { // aps alert
        NSDictionary *apsAlert = userInfo[@"aps"][@"alert"];
        if ([apsAlert isKindOfClass:NSDictionary.class]) {
            pushProperties[@"$sf_msg_title"] = apsAlert[@"title"]; // 推送标题
            pushProperties[@"$sf_msg_content"] = apsAlert[@"body"]; // 推送内容
        }
        else if ([apsAlert isKindOfClass:NSString.class]) {
            pushProperties[@"$sf_msg_content"] = apsAlert; // 推送内容
        }
    } @catch (NSException *exception) {
    }
    [SensorsAnalyticsSDK.sharedInstance track:@"$AppPushClick" withProperties:pushProperties];
}
OBJECTIVE-C

5.2. + dealSensorsFocusAction: link:customize: 方法详情

/// 神策智能运营处理推送消息,做页面跳转
/// @param userInfo 包含与远程通知相关的信息的字典
/// @param aLink 打开 URL 的回调
/// @param aCustomized 处理自定义消息回调
+ (BOOL)dealSensorsFocusAction:(NSDictionary *)userInfo link:(void (^)(NSString * _Nonnull))aLink customize:(void (^)(NSDictionary * _Nonnull))aCustomized {
    @try {
           // 解析 sf_data
           NSString *jsonString = userInfo[@"sf_data"];
           NSData *jsonData = [jsonString dataUsingEncoding:NSUTF8StringEncoding];
           NSError *error;
           NSDictionary *sfDictionary = [NSJSONSerialization JSONObjectWithData:jsonData options:NSJSONReadingMutableContainers error:&error];
           if (!sfDictionary || error) {
               return NO;
           }

           NSString *sf_landing_type = sfDictionary[@"sf_landing_type"];
           if ([sf_landing_type isEqualToString:@"LINK"]) {
                // 打开 URL
               NSString *url = sfDictionary[@"sf_link_url"];
               if (aLink) {
                   aLink(url);
               }

           }
           else if ([sf_landing_type isEqualToString:@"CUSTOMIZED"]) {
               // 处理自定义消息
               // 如果你们已经有了根据附加字段跳转逻辑,此处无需处理。(因为神策智能运营发的推送消息会兼容极光控制台的 "附加字段")
               NSDictionary *customized = sfDictionary[@"customized"];
               if (aCustomized) {
                   aCustomized(customized);
               }
           }
           return YES;
       } @catch (NSException *exception) {
       }
       return NO;
}
OBJECTIVE-C


5.3. 附录方法的封装类

如果不想把附录中的示例方法一个个复制到项目中,可以使用封装好的工具类 SensorsFocusHelper 来调用示例方法。使用步骤如下:

  1. 下载 SensorsFocusHelper 类,解压后复制到项目中
  2. 引入 SensorsFocusHelper.h 
  3. 调用 SensorsFocusHelper 类中的同名方法

附录中 + dealSensorsFocusAction: link:customize: 方法需要开发者在 TODO 注释的位置添加上具体的业务跳转逻辑,SensorsFocusHelper 类将具体的业务跳转逻辑封装成 block 回调,具体的使用方式请参考以下示例:

[SensorsFocusHelper dealSensorsFocusAction:userInfo link:^(NSString * _Nonnull urlString) {
      // TODO 处理打开 URL 消息,--> 请处理 URL
 } customize:^(NSDictionary * _Nonnull customizedDic) {
      // TODO 处理自定义消息,--> 请处理自定义消息
}];
OBJECTIVE-C