视频版讲解

Android 推送集成

极光推送 

上报 "推送 ID"

在极光提供的 onRegister 接口中调用 SensorsDataAPI.sharedInstance().profilePushId("jiguang_id",s)。

若推送 ID 存在实效性,建议调用 SensorsDataAPI.sharedInstance().profileSet("jiguang_id",s)。

// 推送 ID 的处理
public class MyJPushMessageReceiver extends JPushMessageReceiver {
    @Override
    public void onRegister(Context context, String s) {
        super.onRegister(context, s);
        //上报极光 "推送 ID"
        SensorsDataAPI.sharedInstance().profilePushId("jiguang_id", s);
    }
}
JAVA

在调用神策 SDK login 接口之后调用 SensorsDataAPI.sharedInstance().profilePushId("jiguang_id",JPushInterface.getRegistrationID(this))

SensorsDataAPI.sharedInstance().login(userId);
// 在调用神策 SDK login 接口后,也需要调用 profilePushId 接口上报极光 "推送 ID"
SensorsDataAPI.sharedInstance().profilePushId("jiguang_id",JPushInterface.getRegistrationID(this))
JAVA

采集推送点击事件

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

处理推送消息

/**
 * 配置的通知跳转目标地址处理推送消息。
 */
public class OpenClickActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // 处理推送消息的点击
        handlePushOpen(getIntent());
    }

    @Override
    protected void onNewIntent(Intent intent) {
        super.onNewIntent(intent);
        // 处理推送消息的点击
        handlePushOpen(intent);
    }

    /**
     * 处理推送消息的点击。
     * 
     * 华为通道消息数据:通过 intent.getData().toString(); 获取。
     * 小米、vivo、OPPO、FCM、魅族、极光通道消息数据 :通过 intent.getExtras().getString("JMessageExtra") 获取。
     */
    private void handlePushOpen(Intent intent) {
        try {
            if (intent == null) {
                return;
            }
            String pushData = null;
            // 华为通道消息数据
            if (intent.getData() != null) {
                pushData = intent.getData().toString();
            }
            // 小米、vivo、OPPO、FCM、魅族、极光通道消息数据
            if (TextUtils.isEmpty(pushData) && intent.getExtras() != null) {
                pushData = intent.getExtras().getString("JMessageExtra");
            }
            if (TextUtils.isEmpty(pushData)) {
                return;
            }
            JSONObject jsonObject = new JSONObject(pushData);
            // 推送消息附加字段
            String extras = jsonObject.optString("n_extras");
            // 处理神策智能运营推送的 "打开 App"、"打开 URL"、"自定义消息" 动作
            handleSensorsFocusPushMessage(extras);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
JAVA

若未配置通知跳转目标地址时在 onNotifyMessageOpened 接口中处理推送消息

public class MyJPushMessageReceiver extends JPushMessageReceiver {
    @Override
    public void onNotifyMessageOpened(Context context, NotificationMessage notificationMessage) {
        super.onNotifyMessageOpened(context, notificationMessage);
        if (notificationMessage == null) return;
        // 处理神策 Sensors Focus 推送的 "打开 App"、"打开 URL 消息"、"自定义消息" 的动作
        handleSensorsFocusPushMessage(notificationMessage.notificationExtras);
    }
}
JAVA

非厂商通道可以在 onNotifyMessageOpened 接口中处理推送消息

public class MyJPushMessageReceiver extends JPushMessageReceiver {
    @Override
    public void onNotifyMessageOpened(Context context, NotificationMessage notificationMessage) {
        super.onNotifyMessageOpened(context, notificationMessage);
        if (notificationMessage == null) return;
        // 处理神策 Sensors Focus 推送的 "打开 App"、"打开 URL 消息"、"自定义消息" 的动作
        handleSensorsFocusPushMessage(notificationMessage.notificationExtras);
    }
}
JAVA

使用厂商通道的情况下,需要在厂商通道 ActivityonCreateonNewIntent 中拿到 intent,解析出相应的参数再处理推送消息

/**
 * 如果使用了极光 VIP 的厂商通道(uri_activity/uri_action),需要在厂商消息打开的 Activity 中处理厂商通道消息。
 * 处理厂商通道消息的点击事件的 Activity。
 */
public class OpenClickActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // 处理厂商通道消息的点击
        handlePushOpen(getIntent());
    }

    @Override
    protected void onNewIntent(Intent intent) {
        super.onNewIntent(intent);
        // 处理厂商通道消息的点击
        handlePushOpen(intent);
    }

    /**
     * 处理厂商通道消息的点击。
     * 
     * 华为通道消息数据:通过 intent.getData().toString(); 获取。
     * 小米、vivo、OPPO、FCM 通道消息数据 :通过 intent.getExtras().getString("JMessageExtra") 获取。
     * 魅族通道消息数据:通过 onNotifyMessageOpened 获取。
     */
    private void handlePushOpen(Intent intent) {
        try {
            if (intent == null) {
                return;
            }
            String pushData = null;
            // 华为通道消息数据
            if (intent.getData() != null) {
                pushData = intent.getData().toString();
            }
            // 小米、vivo、OPPO、FCM 通道消息数据(魅族会回调 onNotifyMessageOpened )
            if (TextUtils.isEmpty(pushData) && intent.getExtras() != null) {
                pushData = intent.getExtras().getString("JMessageExtra");
            }
            if (TextUtils.isEmpty(pushData)) {
                return;
            }
            JSONObject jsonObject = new JSONObject(pushData);
            // 推送消息附加字段
            String extras = jsonObject.optString("n_extras");
            // 处理神策智能运营推送的 "打开 App"、"打开 URL"、"自定义消息" 动作
            handleSensorsFocusPushMessage(extras);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
JAVA

友盟推送

上报 "推送 ID"

IUmengRegisterCallbackonSuccess 接口中调用 SensorsDataAPI.sharedInstance().profilePushId("umeng_id", token)

若推送 ID 存在实效性,建议调用 SensorsDataAPI.sharedInstance().profileSet("umeng_id",token)。

代码示例

// 推送 ID 的处理
PushAgent.getInstance(context).register(new IUmengRegisterCallback() {
    @Override
    public void onSuccess(String token) {
        //上报友盟 "推送 ID"
        SensorsDataAPI.sharedInstance().profilePushId("umeng_id", token);
    }

    @Override
    public void onFailure(String s, String s1) {}
});
JAVA

在调用神策 SDK login 接口之后调用 SensorsDataAPI.sharedInstance().profilePushId("umeng_id",PushAgent.getInstance(this).getRegistrationId())。

SensorsDataAPI.sharedInstance().login(userId);
//在调用神策 SDK login 接口后,也需要调用 profilePushId 接口上报友盟 "推送 ID"
SensorsDataAPI.sharedInstance().profilePushId("umeng_id",PushAgent.getInstance(this).getRegistrationId());
JAVA

记录 「推送点击」事件并处理平台推送的消息

需要在 launchAppopenUrlopenActivitydealWithCustomAction 这 4 个接口中调用 trackAppOpenNotification(uMessage.extra, uMessage.title, uMessage.text) handleSensorsFocusPushMessage(notificationExtras)。

PushAgent.getInstance(context).setNotificationClickHandler(new UmengNotificationClickHandler() {

    @Override
    public void launchApp(Context context, UMessage uMessage) {
        super.launchApp(context, uMessage);
        // 触发 App 打开推送消息 事件
        trackAppOpenNotification(uMessage.extra, uMessage.title, uMessage.text);
        // 处理神策智能运营推送消息的动作(神策智能运营的推送消息必须在 launchApp 接口中处理)
        handleSensorsFocusPushMessage(uMessage.extra);
    }

    @Override
    public void openUrl(Context context, UMessage uMessage) {
        super.openUrl(context, uMessage);
        // 触发 App 打开推送消息 事件
        trackAppOpenNotification(uMessage.extra, uMessage.title, uMessage.text);
    }

    @Override
    public void dealWithCustomAction(Context context, UMessage uMessage) {
        super.dealWithCustomAction(context, uMessage);
        // 触发 App 打开推送消息 事件
        trackAppOpenNotification(uMessage.extra, uMessage.title, uMessage.text);
    }

    @Override
    public void openActivity(Context context, UMessage uMessage) {
        super.openActivity(context, uMessage);
        // 触发 App 打开推送消息 事件
        trackAppOpenNotification(uMessage.extra, uMessage.title, uMessage.text);
    }
});
JAVA

厂商通道使用说明

需要在处理厂商通道的 ActivityonMessage 接口中处理消息,调用 trackAppOpenNotification(extraStr, title, content)handleSensorsFocusPushMessage(notificationExtras)。

/**
 * 友盟厂商通道消息的 Activity 。
 * <p>
 * 该 Activity 需继承自 UmengNotifyClickActivity,同时实现父类的 onMessage 方法,
 * 对该方法的 intent 参数进一步解析即可,该方法异步调用,不阻塞主线程。
 * 并设置 launchMode="singleTask" 和 exported="true"
 */
public class HandlePushActivity extends UmengNotifyClickActivity {

    /**
     * 处理友盟厂商通道消息
     */
    @Override
    public void onMessage(Intent intent) {
        super.onMessage(intent);
        if (intent != null) {
            // 如果你们使用了友盟的厂商通道消息,需要在 onMessage 处理厂商通道消息!!!
            String messageBody = intent.getStringExtra(AgooConstants.MESSAGE_BODY);
            Log.e("TODO", "厂商通道消息:" + messageBody);
            if (!TextUtils.isEmpty(messageBody)) {
                try {
                    JSONObject push = new JSONObject(messageBody);
                    JSONObject extra = push.optJSONObject("extra");
                    String extraStr = null;
                    if (extra != null) {
                        extraStr = extra.toString();
                        // 处理神策智能运营推送消息的动作
                        handleSensorsFocusPushMessage(extraStr);
                    }
                    // 推送标题
                    String title = push.optJSONObject("body").optString("title");
                    // 推送内容
                    String content = push.optJSONObject("body").optString("text");
                    // 触发 App 打开推送消息 事件
                    trackAppOpenNotification(extraStr, title, content);
                    Log.e("TODO",
                            String.format("title: %s。content:%s。extraStr: %s。", title, content, extraStr));
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
JAVA

个推推送

上报 "推送 ID"

GTIntentServiceonReceiveClientId 接口中调用 SensorsDataAPI.sharedInstance().profilePushId("getui_id",clientId)。

若推送 ID 存在实效性,建议调用 SensorsDataAPI.sharedInstance().profileSet("getui_id",clientId)。

// 推送 ID 的处理
public class GeTuiService extends GTIntentService {
    @Override
    public void onReceiveClientId(Context context, String clientId) {
        //上报个推 "推送 ID"
        SensorsDataAPI.sharedInstance(context).profilePushId("getui_id", clientId);
    }
}
JAVA

在调用神策 SDK login 接口之后调用 SensorsDataAPI.sharedInstance().profilePushId("getui_id", PushManager.getInstance().getClientid(context))。

SensorsDataAPI.sharedInstance().login(userId);
//在调用神策 SDK login 接口后,也需要调用 profilePushId 接口上报个推 "推送 ID"
SensorsDataAPI.sharedInstance().profilePushId("getui_id", PushManager.getInstance().getClientid(context));
JAVA

记录 「推送点击」事件并处理平台推送的消息

需要在 onNotificationMessageClicked 记录通知消息被点击的通知标题和通知内容,在 onReceiveMessageData 接口中记录事件并处理平台推送的消息。

public class GeTuiService extends GTIntentService {
	private boolean isNotificationClick = false;
    private String title;
    private String content;

    /**
     * 点击通知消息。
	 * 上报「推送点击」事件需要在 onReceiveMessageData 接口获取 Sensors Focus 的消息内容,因此此处先将通知的标题和内容保存到成员变量中
     */
    @Override
    public void onNotificationMessageClicked(Context context, GTNotificationMessage gtNotificationMessage) {
        title = gtNotificationMessage.getTitle();
        content = gtNotificationMessage.getContent();
        isNotificationClick = true;
    }

	/**
     * 处理透传消息到达 或 通知消息的点击
     */
    @Override
    public void onReceiveMessageData(Context context, GTTransmitMessage gtTransmitMessage) {
        if(context ==null || gtTransmitMessage ==null)return;

        /*
         * 透传消息的处理,此处仅仅演示了 sf_data 推送的相关字段,注意,如果你有原有的逻辑也有相关处理
         * 的逻辑,需要做一定的兼容处理。
         */
        byte[] payload = gtTransmitMessage.getPayload();
        String sfData = new String(payload);

		/*
         * onReceiveMessageData 在 透传消息的到达 与 通知消息的点击 时都会被回调,但只有 通知消息的点击 时需要上报「推送到达」事件。
         * 因此通过 isNotificationClick 变量来判断本次 onReceiveMessageData 被调用是由于 透传消息到达 还是 通知消息的点击
         */
		if (isNotificationClick) {
            isNotificationClick = false;
            trackAppOpenNotification(sfData, title, content);
        	handleSensorsFocusConfig(sfData);
        }else{
        	/*
			 * 透传消息到达需要自定义处理。例如从 sfData 获取出标题和内容来手动触发一个 notification
			 * 透传消息有点击的话,也需要调用 trackAppOpenNotification
         	 */
		}
    }
}
JAVA

厂商通道使用说明

首先需要在在推送设置的的 intent 模板配置 intent,以下为配置示例,开发者可根据自己的项目进行配置。

示例代码

intent://www.test.com/path?custom=aaa#Intent;scheme=yang;launchFlags=0x10000000;component=com.sensorsdata.android.push/.HandlePushActivity;S.sf_key={sf_data:{sf_data},title:{sf_customized.title},content:{sf_customized.content}};end
XML


需要在处理厂商通道的 ActivityonCreate 中处理 intent,解析出相应的参数,调用 trackAppOpenNotification(extras, title, content)

public class HandlePushActivity extends AppCompatActivity {

	private static final String TAG = "HandlePushActivity";
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_test);
        handlePushIntent();
    }

    /**
     * 处理推送消息的 Intent
     */
    private void handlePushIntent() {
        Intent intent = getIntent();
        if (intent != null) {
            // 拿到自定义透传字段的值
            String sf_key = intent.getStringExtra("sf_key");
            Log.i(TAG, sf_key);
  			if (TextUtils.isEmpty(sf_key)) {
                return;
            }
			try {
				JSONObject jsonObject = new JSONObject(sf_key);
                String title = jsonObject.optString("title");
                String content = jsonObject.optString("content");
				String extras = jsonObject.optString("sf_data");
                trackAppOpenNotification(extras, title, content);
            } catch (JSONException e) {
                e.printStackTrace();
            }
        }
    }

}
JAVA

阿里云推送

上报 "推送 ID"

CommonCallback 的 onSuccess 接口中调用 SensorsDataAPI.sharedInstance().profilePushId("aliyun_id", token)

若推送 ID 存在实效性,建议调用 SensorsDataAPI.sharedInstance().profileSet("aliyun_id",token)。

代码示例

// 推送 ID 的处理
pushService.register(context, new CommonCallback() {  
    @Override  
    public void onSuccess(String response) {  
        //上报阿里云 "推送 ID"
        SensorsDataAPI.sharedInstance().profilePushId("aliyun_id", "android_" + pushService.getDeviceId());
    }  
    @Override  
    public void onFailed(String errorCode, String errorMessage) {  
 
    }  
});
JAVA

在调用神策 SDK login 接口之后调用 SensorsDataAPI.sharedInstance().profilePushId("aliyun_id",PushServiceFactory.getCloudPushService().getDeviceId())。

SensorsDataAPI.sharedInstance().login(userId);
//在调用神策 SDK login 接口后,也需要调用 profilePushId 接口上报阿里云 "推送 ID"
SensorsDataAPI.sharedInstance().profilePushId("aliyun_id","android_" + PushServiceFactory.getCloudPushService().getDeviceId());
JAVA

记录 「推送点击」事件并处理平台推送的消息

需要在 onNotificationonNotificationOpenedonNotificationClickedWithNoActiononNotificationReceivedInApp 这 4 个接口中调用 trackAppOpenNotification(extraMap,title,summary) handleSensorsFocusPushMessage(extraMap)。

public class AliyunmessageReceiver extends MessageReceiver {

    @RequiresApi(api = Build.VERSION_CODES.O)
    @Override
    public void onNotification(Context context, String title, String summary, Map<String, String> extraMap) {
        //处理神策智能运营推送消息的动作
        handleSensorsFocusPushMessage(extraMap);
    }

    @Override
    public void onMessage(Context context, CPushMessage cPushMessage) {
	    //处理神策智能运营推送消息的动作
        handleSensorsFocusPushMessage(extraMap);
    }

    @Override
    public void onNotificationOpened(Context context, String title, String summary, String extraMap) {
        // 触发 App 打开推送消息 事件
        trackAppOpenNotification(extraMap,title,summary);
    }

    @Override
    protected void onNotificationClickedWithNoAction(Context context, String title, String summary, String extraMap) {
        // 触发 App 打开推送消息 事件
        trackAppOpenNotification(extraMap,title,summary);
    }

    @Override
    protected void onNotificationReceivedInApp(Context context, String title, String summary, Map<String, String> extraMap, int openType, String openActivity, String openUrl) {
        //处理神策智能运营推送消息的动作
        handleSensorsFocusPushMessage(extraMap);
    }

    ......
}
JAVA

厂商通道使用说明

需要在处理厂商通道的 ActivityonSysNoticeOpened 接口中处理消息,调用 trackAppOpenNotification(extMap, title, summary)handleSensorsFocusPushMessage(extMap)。

public class PopupPushActivity extends AndroidPopupActivity {
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    }
    /**
     * 实现通知打开回调方法,获取通知相关信息
     * @param title     标题
     * @param summary   内容
     * @param extMap    额外参数
     */
    @Override
    protected void onSysNoticeOpened(String title, String summary, Map<String, String> extMap) {
        // 处理神策智能运营推送消息的动作
        handleSensorsFocusPushMessage(extMap); 
        // 触发 App 打开推送消息 事件 
        trackAppOpenNotification(extMap, title, summary);
    }
}
JAVA

腾讯云推送

上报 "推送 ID"

XGIOperateCallback 的 onSuccess 接口中调用 SensorsDataAPI.sharedInstance().profilePushId("tencent_id", token)

若推送 ID 存在实效性,建议调用 SensorsDataAPI.sharedInstance().profileSet("tencent_id",token)。

代码示例

// 推送 ID 的处理 
XGPushManager.registerPush(context, new XGIOperateCallback() {
    @Override
    public void onSuccess(Object data, int flag) {
        //上报腾讯云 "推送 ID"
        SensorsDataAPI.sharedInstance().profilePushId("tencent_id", "android_" + data.toString());
    }

    @Override
    public void onFail(Object data, int errCode, String msg) {
    }
});
JAVA

在调用神策 SDK login 接口之后调用 SensorsDataAPI.sharedInstance().profilePushId("tencent_id",XGPushConfig.getToken(context))。

SensorsDataAPI.sharedInstance().login(userId);
//在调用神策 SDK login 接口后,也需要调用 profilePushId 接口上报腾讯云 "推送 ID"
SensorsDataAPI.sharedInstance().profilePushId("tencent_id","android_" + XGPushConfig.getToken(context));
JAVA

记录 「推送点击」事件并处理平台推送的消息

需要在 onTextMessageonNotificationClickedResult、onNotificationShowedResult 这 2 个接口中调用 handleSensorsFocusPushMessage(xgPushTextMessage.getCustomContent()) trackAppOpenNotification(xgPushClickedResult.getCustomContent(), xgPushClickedResult.getTitle(), xgPushClickedResult.getContent())。

public class TencentMessageReceiver extends XGPushBaseReceiver {

    @Override
    public void onTextMessage(Context context, XGPushTextMessage xgPushTextMessage) {
        //处理神策智能运营推送消息的动作
        handleSensorsFocusPushMessage(xgPushTextMessage.getCustomContent());
    }

    @Override
    public void onNotificationClickedResult(Context context, XGPushClickedResult xgPushClickedResult) {
		//触发 App 打开推送消息 事件
        trackAppOpenNotification(xgPushClickedResult.getCustomContent(), xgPushClickedResult.getTitle(), xgPushClickedResult.getContent());
    }

    @Override
    public void onNotificationShowedResult(Context context, XGPushShowedResult xgPushShowedResult) {
		//处理神策智能运营推送消息的动作
        handleSensorsFocusPushMessage(xgPushTextMessage.getCustomContent());
    }

    @Override
    public void onRegisterResult(Context context, int i, XGPushRegisterResult xgPushRegisterResult) {
    }

    ......
}
JAVA

厂商通道使用说明

厂商通道也是通过 onNotificationShowedResult 和  onNotificationClickedResult 处理到达和点击,因此不需要额外配置。

华为推送

上报 "推送 ID"

在自定义的继承 HmsMessageService 的类中 onNewToken 接口中调用 SensorsDataAPI.sharedInstance().profilePushId("huawei_id", token)

若推送 ID 存在实效性,建议调用 SensorsDataAPI.sharedInstance().profileSet("huawei_id",token)。

代码示例

public class SensorsHuaweiMessageService extends HmsMessageService {

    @Override
    public void onNewToken(String token) {
        //上报华为 "推送 ID"
        SensorsDataAPI.sharedInstance().profilePushId("huawei_id", "android_" + token);
    }

    .......
}
JAVA

在调用神策 SDK login 接口之后调用 SensorsDataAPI.sharedInstance().profilePushId("tencent_id",HmsInstanceId.getInstance(context).getToken(appId, tokenScope))。

SensorsDataAPI.sharedInstance().login(userId);
//在调用神策 SDK login 接口后,也需要调用 profilePushId 接口上报华为 "推送 ID"
String appId = "your APP_ID";
String tokenScope = "HCM";
SensorsDataAPI.sharedInstance().profilePushId("huawei_id","android_" + HmsInstanceId.getInstance(context).getToken(appId, tokenScope));
JAVA

记录 「推送点击」事件并处理平台推送的消息

需要在 onMessageReceived 这个接口中调用 handleSensorsFocusConfig(remoteMessage.getData()) trackAppOpenNotification(remoteMessage.getData(),remoteMessage.getNotification().getTitle(),remoteMessage.getNotification().getBody())

public class SensorsHuaweiMessageService extends HmsMessageService {

    @Override
    public void onMessageReceived(RemoteMessage remoteMessage) {
        super.onMessageReceived(remoteMessage);
        ////处理神策智能运营推送消息的动作
        handleSensorsFocusConfig(remoteMessage.getData());
        //触发 App 打开推送消息 事件
        trackAppOpenNotification(remoteMessage.getData(),remoteMessage.getNotification().getTitle(),remoteMessage.getNotification().getBody());
    }

    .......
}
JAVA

OPPO 推送

上报 "推送 ID"

ICallBackResultServiceonRegister 接口中调用 SensorsDataAPI.sharedInstance().profilePushId("oppo_id", token)

若推送 ID 存在实效性,建议调用 SensorsDataAPI.sharedInstance().profileSet("oppo_id",token)。

代码示例

HeytapPushManager.register(context, appKey, appSecret, new ICallBackResultService() {
    @Override
    public void onRegister(int i, String s) {
        //上报OPPO "推送 ID"
        SensorsDataAPI.sharedInstance().profilePushId("oppo_id", s);
    }

    ......
});
JAVA

在调用神策 SDK login 接口之后调用 SensorsDataAPI.sharedInstance().profilePushId("oppo_id",HeytapPushManager.getRegisterID())。

SensorsDataAPI.sharedInstance().login(userId);
//在调用神策 SDK login 接口后,也需要调用 profilePushId 接口上报OPPO "推送 ID"
SensorsDataAPI.sharedInstance().profilePushId("oppo_id",HeytapPushManager.getRegisterID());
JAVA

记录 「推送点击」事件并处理平台推送的消息

需要在 processMessage 这 1 个接口中调用 handleSensorsFocusConfig(message.getDataExtra())trackAppOpenNotification(message.getDataExtra(), message.getTitle(), message.getContent())

public class PushMessageService extends CompatibleDataMessageCallbackService {
    
    @Override
    public void processMessage(Context context, DataMessage message) {
        super.processMessage(context.getApplicationContext(), message);
        //处理神策智能运营推送消息的动作
        handleSensorsFocusConfig(message.getDataExtra());
        //触发 App 打开推送消息 事件
        trackAppOpenNotification(message.getDataExtra(), message.getTitle(), message.getContent());
    }
}
JAVA

VIVO 推送

上报 "推送 ID"

在自定义的继承 OpenClientPushMessageReceiver 的类中 onReceiveRegId 接口中调用 SensorsDataAPI.sharedInstance().profilePushId("vivo_id",s)

若推送 ID 存在实效性,建议调用 SensorsDataAPI.sharedInstance().profileSet("vivo_id",s)。

代码示例

public class PushMessageReceiverImpl extends OpenClientPushMessageReceiver {

    @Override
    public void onReceiveRegId(Context context, String s) {
		//上报VIVO "推送 ID"
        SensorsDataAPI.sharedInstance().profilePushId("vivo_id", s);
    }

    ......
}
JAVA

在调用神策 SDK login 接口之后调用 SensorsDataAPI.sharedInstance().profilePushId("vivo_id",PushClient.getInstance(PushApplication.this).getRegId())。

SensorsDataAPI.sharedInstance().login(userId);
//在调用神策 SDK login 接口后,也需要调用 profilePushId 接口上报VIVO "推送 ID"
SensorsDataAPI.sharedInstance().profilePushId("vivo_id",PushClient.getInstance(PushApplication.this).getRegId());
JAVA

记录 「推送点击」事件并处理平台推送的消息

需要在 onTransmissionMessageonNotificationMessageClicked 这 2 个接口中调用 handleSensorsFocusConfig(unvarnishedMessage.getParams()) trackAppOpenNotification(unvarnishedMessage.getParams(), unvarnishedMessage.getTitle(), unvarnishedMessage.getContent())

public class PushMessageReceiverImpl extends OpenClientPushMessageReceiver {
	
	......

    @Override
    public void onTransmissionMessage(Context context, UnvarnishedMessage unvarnishedMessage) {
        super.onTransmissionMessage(context, unvarnishedMessage);
		//处理神策智能运营推送消息的动作
        handleSensorsFocusConfig(unvarnishedMessage.getParams());
    }

    @Override
    public void onNotificationMessageClicked(Context context, UPSNotificationMessage unvarnishedMessage) {
        super.onNotificationMessageClicked(context, unvarnishedMessage);
        //触发 App 打开推送消息 事件
        trackAppOpenNotification(unvarnishedMessage.getParams(), unvarnishedMessage.getTitle(), unvarnishedMessage.getContent());
    }
}
JAVA

小米推送

上报 "推送 ID"

在自定义的继承 PushMessageReceiver 的类中 onCommandResultonReceiveRegisterResult 接口中调用 SensorsDataAPI.sharedInstance().profilePushId("xiaomi_id", token)

若推送 ID 存在实效性,建议调用 SensorsDataAPI.sharedInstance().profileSet("xiaomi_id",token)。

代码示例

public class DemoMessageReceiver extends PushMessageReceiver {

    @Override
    public void onCommandResult(Context context, MiPushCommandMessage message) {
        String command = message.getCommand();
        List<String> arguments = message.getCommandArguments();
        String cmdArg1 = ((arguments != null && arguments.size() > 0) ? arguments.get(0) : null);
        if (MiPushClient.COMMAND_REGISTER.equals(command)) {
            if (message.getResultCode() == ErrorCode.SUCCESS) {
                //上报小米 "推送 ID"
                SensorsDataAPI.sharedInstance().profilePushId("xiaomi_id", "android_" + cmdArg1);
            }
        }
    }

    @Override
    public void onReceiveRegisterResult(Context context, MiPushCommandMessage message) {
        String command = message.getCommand();
        List<String> arguments = message.getCommandArguments();
        String cmdArg1 = ((arguments != null && arguments.size() > 0) ? arguments.get(0) : null);
        if (MiPushClient.COMMAND_REGISTER.equals(command)) {
            if (message.getResultCode() == ErrorCode.SUCCESS) {
                //上报小米 "推送 ID"
                SensorsDataAPI.sharedInstance().profilePushId("xiaomi_id", "android_" + cmdArg1);
            }
        }
    }
}
JAVA

在调用神策 SDK login 接口之后调用 SensorsDataAPI.sharedInstance().profilePushId("xiaomi_id",MiPushClient.getRegId(context))。

SensorsDataAPI.sharedInstance().login(userId);
//在调用神策 SDK login 接口后,也需要调用 profilePushId 接口上报小米 "推送 ID"
SensorsDataAPI.sharedInstance().profilePushId("xiaomi_id","android_" + MiPushClient.getRegId(context));
JAVA

记录 「推送点击」事件并处理平台推送的消息

需要在 onReceivePassThroughMessageonNotificationMessageArrivedonNotificationMessageClicked 这 2 个接口中调用 handleSensorsFocusConfig(message.getExtra())trackAppOpenNotification(message.getExtra(), message.getTitle(), message.getContent())

public class DemoMessageReceiver extends PushMessageReceiver {

    @Override
    public void onReceivePassThroughMessage(Context context, MiPushMessage message) {   
        //处理神策智能运营推送消息的动作
        handleSensorsFocusConfig(message.getExtra()); 
    }

    @Override
    public void onNotificationMessageClicked(Context context, MiPushMessage message) {
        //触发 App 打开推送消息 事件
        trackAppOpenNotification(message.getExtra(), message.getTitle(), message.getContent());
    }

    @Override
    public void onNotificationMessageArrived(Context context, MiPushMessage message) {
        //处理神策智能运营推送消息的动作
        handleSensorsFocusConfig(message.getExtra());
    }

    ......
}
JAVA

FCM 推送

上报 "推送 ID"

OnCompleteListeneronComplete 接口中调用 SensorsDataAPI.sharedInstance().profilePushId("fcm_id", token)

若推送 ID 存在实效性,建议调用 SensorsDataAPI.sharedInstance().profileSet("fcm_id",token)。

代码示例

// 推送 ID 的处理  
FirebaseMessaging.getInstance().getToken()
        .addOnCompleteListener(new OnCompleteListener<String>() {
            @Override
            public void onComplete(Task<String> task) {
                if (!task.isSuccessful()) {
                    return;
                }
                String token = task.getResult();
                //上报FCM "推送 ID"
                SensorsDataAPI.sharedInstance().profilePushId("fcm_id", data);
            }
        });
JAVA

在调用神策 SDK login 接口之后调用 SensorsDataAPI.sharedInstance().profilePushId("fcm_id",FirebaseMessaging.getInstance().getToken().getResult())。

SensorsDataAPI.sharedInstance().login(userId);
//在调用神策 SDK login 接口后,也需要调用 profilePushId 接口上报FCM "推送 ID"
SensorsDataAPI.sharedInstance().profilePushId("fcm_id",FirebaseMessaging.getInstance().getToken().getResult());
JAVA

记录 「推送点击」事件并处理平台推送的消息

需要在 onMessageReceived 这个接口中调用 handleSensorsFocusConfig(remoteMessage.getData()) trackAppOpenNotification(remoteMessage.getData(), remoteMessage.getNotification().getTitle(), remoteMessage.getNotification().getBody())

public class MyFirebaseMessagingService extends FirebaseMessagingService {

    @Override
    public void onMessageReceived(RemoteMessage remoteMessage) {
        //处理神策智能运营推送消息的动作
        handleSensorsFocusConfig(remoteMessage.getData());
        //触发 App 打开推送消息 事件
        trackAppOpenNotification(remoteMessage.getData(), remoteMessage.getNotification().getTitle(), remoteMessage.getNotification().getBody());
    }
    ......
}
JAVA

UniPush 推送

上报推送 ID

为了保证登录之后的用户也能设置 cid 属性,需要在获取到 cid 以及调用神策 - login: 接口各上报一次。由于 UniPush 目前有 1.0 和 2.0 两个版本,下面以 2.0 版本来说明,1.0 版本的 请参考 DCloud 官网文档。

uni.getPushClientId({
  success: (res) => {
    let cid = res.cid;
    sensors.setProfile({ "uni-id": cid }); // uni_id 只是一个示例字段
  },
  fail(err) {
    console.log(err);
  }
});
JS
// 为了保证登录后的用户也能正确设置 cid,调用 login 之后,再次上报 cid
sensors.login("<#登录 id#>");
sensors.setProfile({"uni-id":cid});
JS

记录 「推送点击」事件并处理智能运营平台推送的消息

uni.onPushMessage((result) => {
  let data = result.data;
  if (typeof data !== "string") {
    let sf_data = data.payload.sf_data;
    //记录推送事件,此处需参考 trackSensorsFocusAppOpenNotificationWithUserInfo 中的 json 解析逻辑赋值事件属性
    let sf_properties = {};
    sf_properties.$sf_plan_id = sf_data.sf_plan_id;
    ...
    sensors.track("$AppPushClick", sf_properties);
    // 根据解析的字段,发现跳转 url 然后进行跳转操作
  }
});
JS

测试推送

  1. 首先发送推送 ID 到神策后,选择上报推送 ID 的 key(这里以 jiguang_id 为例),点击测试推送。
  2. 填入测试机的推送 ID、推送标题、内容,如下图所示,其中通知栏图标和高级设置可根据需求进行配置。
  3. 确认推送,可查看手机是否收到推送,以及查看埋点上报字段是否正确。

附录

trackAppOpenNotification 方法详情

因各个推送不同,开发者可根据实际的字段及业务需求进行字段的解析。

 /**
 * 埋点 App 打开推送消息
 * <p>
 * 事件名:$AppPushClick
 *
 * @param extras 推送消息的 extras(参数类型只能传 String 或 Map<String,String>)
 * @param notificationTitle 推送消息的标题
 * @param notificationContent 推送消息的内容
 */
public static void trackAppOpenNotification(String extras, String notificationTitle, String notificationContent) {
    try {
        JSONObject jsonObject = null;
        if (!TextUtils.isEmpty(extras)) {
            jsonObject = new JSONObject(extras);
        }
        JSONObject properties = new JSONObject();
        // 获取消息标题,并保存在事件属性 msg_title 中
        properties.put("$sf_msg_title", notificationTitle);
        // 获取消息 ID,并保存在事件属性 msg_id 中
        properties.put("$sf_msg_content", notificationContent);
        if (jsonObject != null) {
            properties.put("$sf_msg_id", jsonObject.opt("$sf_msg_id"));
            properties.put("$sf_plan_id", jsonObject.opt("$sf_plan_id"));
            if (!"null".equals(jsonObject.opt("$sf_audience_id"))) {
                properties.put("$sf_audience_id", jsonObject.opt("$sf_audience_id"));
            }
            properties.put("$sf_link_url", jsonObject.opt("$sf_link_url"));
            properties.put("$sf_plan_strategy_id", jsonObject.opt("$sf_plan_strategy_id"));
            properties.put("$sf_plan_type", jsonObject.opt("$sf_plan_type"));
            //在画布中,$sf_strategy_unit_id 是由 画布ID 和 策略器ID(节点ID)拼接的,然后策略器名称会通过维度字典进行映射
			properties.put("$sf_strategy_unit_id", jsonObject.opt("$sf_strategy_unit_id"));
			properties.put("$sf_enter_plan_time", jsonObject.opt("$sf_enter_plan_time"));
            properties.put("$sf_channel_id", jsonObject.opt("$sf_channel_id"));
            properties.put("$sf_channel_category", jsonObject.opt("$sf_channel_category"));
            properties.put("$sf_channel_service_name", jsonObject.opt("$sf_channel_service_name"));
        }
        // 使用神策分析追踪 "App 消息推送成功" 事件
        SensorsDataAPI.sharedInstance().track("$AppPushClick", properties);
    } catch (Exception e) {
        e.printStackTrace();
    }
}
JAVA

handleSensorsFocusPushMessage 方法详情

/**
 * 处理神策智能运营推送消息。
 * TODO 此方法只是解析了神策智能运营的推送消息,具体的业务跳转逻辑需要开发者加上!!!
 *
 * @param notificationExtras 推送消息的 extra
 */
public static void handleSensorsFocusPushMessage(Object notificationExtras) {
    try {
        String sfData = null;
        if (notificationExtras != null) {
            if (notificationExtras instanceof String) {
                sfData = new JSONObject((String) notificationExtras).optString("sf_data");
            } else if (notificationExtras instanceof Map) {
                sfData = new JSONObject((Map) notificationExtras).optString("sf_data");
            }
        }
        if (!TextUtils.isEmpty(sfData)) {
            JSONObject sfJson = new JSONObject(sfData);
            if ("OPEN_APP".equals(sfJson.optString("sf_landing_type"))) {
                // TODO 处理打开 App 消息,--> 请启动 App
                Log.e("TODO", "-- 请启动 App --");
            } else if ("LINK".equals(sfJson.optString("sf_landing_type"))) {
                String url = sfJson.optString("sf_link_url");
                if (!TextUtils.isEmpty(url)) {
                    // TODO 处理打开 URL 消息,--> 请处理 URL
                    Log.e("TODO", "-- 请处理打开 URL --: " + url);
                }
            } else if ("CUSTOMIZED".equals(sfJson.optString("sf_landing_type"))) {
                JSONObject custom = sfJson.optJSONObject("customized");
                if (custom != null) {
                    // TODO 处理自定义消息,--> 请处理自定义消息
                    Log.e("TODO", "-- 请处理自定义消息--: " + custom);
                }
            }
        }
    } catch (Exception e) {
        e.printStackTrace();
    }
}
JAVA

handleSensorsFocusConfig 方法详情

/**
 * 处理神策智能运营推送消息。
 * TODO 此方法只是解析了神策智能运营的推送消息,具体的业务跳转逻辑需要开发者加上!!!
 *
 * @param sfData 配置
 */
public static void handleSensorsFocusConfig(String sfData) {
    try {
        if (!TextUtils.isEmpty(sfData)) {
            JSONObject sfJson = new JSONObject(sfData);
            if ("OPEN_APP".equals(sfJson.optString("sf_landing_type"))) {
                // TODO 处理打开 App 消息,--> 请启动 App
                Log.e("TODO", "-- 请启动 App --");
            } else if ("LINK".equals(sfJson.optString("sf_landing_type"))) {
                String url = sfJson.optString("sf_link_url");
                if (!TextUtils.isEmpty(url)) {
                    // TODO 处理打开 URL 消息,--> 请处理 URL
                    Log.e("TODO", "-- 请处理打开 URL --: " + url);
                }
            } else if ("CUSTOMIZED".equals(sfJson.optString("sf_landing_type"))) {
                JSONObject custom = sfJson.optJSONObject("customized");
                if (custom != null) {
                    // TODO 处理自定义消息,--> 请处理自定义消息
                    Log.e("TODO", "-- 请处理自定义消息--: " + custom);
                }
            }
        }
    } catch (Exception e) {
        e.printStackTrace();
    }
}
JAVA

附录方法的封装类

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

  1. 下载 SensorsFocusHelper 类,解压后复制到项目中
  2. 给 SensorsFocusHelper 类添加 package 声明
  3. 调用 SensorsFocusHelper 类中的同名方法

附录中的 handleSensorsFocusPushMessage 方法与 handleSensorsFocusConfig 方法需要开发者在 TODO 注释的位置添加上具体的业务跳转逻辑,SensorsFocusHelper 类将具体的业务跳转逻辑封装成接口 SensorsFocusHandler,具体的使用方式请参考以下示例:

SensorsFocusHelper.handleSensorsFocusPushMessage(notificationExtras, new SensorsFocusHelper.SensorsFocusHandler() {
            @Override
            public void handleOpenApp() {
                // TODO 处理打开 App 消息,--> 请启动 App
            }

            @Override
            public void handleLink(String url) {
                // TODO 处理打开 URL 消息,--> 请处理 URL
            }

            @Override
            public void handleCustomized(JSONObject customProperties) {
                // TODO 处理自定义消息,--> 请处理自定义消息
            }
        });
JAVA