Android 推送集成
|
收藏
1. 视频版讲解
2. 极光推送
2.1. 上报 "推送 ID"
在极光提供的 onRegister 接口中调用 SensorsDataAPI.sharedInstance().profilePushId("jiguang_id",s)。
若推送 ID 存在实效性,建议调用 SensorsDataAPI.sharedInstance().profileSet("push_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);
}
}
在调用神策 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))
2.2. 采集推送点击事件
神策 Android SDK 可以自动采集来自极光、个推、友盟推送的推送点击事件,请参考此文档开启采集。
2.3. 处理推送消息
非厂商通道可以在 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);
}
}
使用厂商通道的情况下,需要在厂商通道 Activity 的 onCreate,onNewIntent 中拿到 intent,解析出相应的参数再处理推送消息。
/**
* 如果使用了极光 VIP 的厂商通道(uri_activity/uri_action),需要在厂商消息打开的 Activity 中处理厂商通道消息。
* 处理厂商通道消息的点击事件的 Activity。
*/
public class OpenClickActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 处理厂商通道消息的点击
handlePushOpen();
}
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
// 处理厂商通道消息的点击
handlePushOpen();
}
/**
* 处理厂商通道消息的点击。
* <p>
* 华为通道消息数据:通过 getIntent().getData().toString(); 获取。
* 小米、vivo、OPPO、FCM 通道消息数据 :通过 getIntent().getExtras().getString("JMessageExtra") 获取。
* 魅族通道消息数据:通过 onNotifyMessageOpened 获取。
*/
private void handlePushOpen() {
try {
Intent intent = getIntent();
if (intent == null) {
return;
}
String pushData = null;
// 华为通道消息数据
if (getIntent().getData() != null) {
pushData = getIntent().getData().toString();
}
// 小米、vivo、OPPO、FCM 通道消息数据(魅族会回调 onNotifyMessageOpened )
if (TextUtils.isEmpty(pushData) && getIntent().getExtras() != null) {
pushData = getIntent().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();
}
}
}
3. 友盟推送
3.1. 上报 "推送 ID"
在 IUmengRegisterCallback 的 onSuccess 接口中调用 SensorsDataAPI.sharedInstance().profilePushId("umeng_id", token)。
若推送 ID 存在实效性,建议调用 SensorsDataAPI.sharedInstance().profileSet("push_id",s)。
代码示例
// 推送 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) {}
});
在调用神策 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());
3.2. 记录 「推送点击」事件并处理平台推送的消息
需要在 launchApp、openUrl、openActivity、dealWithCustomAction 这 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);
}
});
3.3. 厂商通道使用说明
需要在处理厂商通道的 Activity 的 onMessage 接口中处理消息,调用 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();
}
}
}
}
}
4. 个推推送
4.1. 上报 "推送 ID"
在 GTIntentService 的 onReceiveClientId 接口中调用 SensorsDataAPI.sharedInstance().profilePushId("getui_id",clientId)。
若推送 ID 存在实效性,建议调用 SensorsDataAPI.sharedInstance().profileSet("push_id",s)。
// 推送 ID 的处理
public class GeTuiService extends GTIntentService {
@Override
public void onReceiveClientId(Context context, String clientId) {
//上报个推 "推送 ID"
SensorsDataAPI.sharedInstance(context).profilePushId("getui_id", clientId);
}
}
在调用神策 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));
4.2. 记录 「推送点击」事件并处理平台推送的消息
需要在 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
*/
}
}
}
4.3. 厂商通道使用说明
首先需要在在推送设置的的 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
需要在处理厂商通道的 Activity 的 onCreate 中处理 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();
}
}
}
}
5. 测试推送
- 首先发送推送 ID 到神策后,选择上报推送 ID 的 key(这里以 jiguang_id 为例),点击测试推送。
- 填入测试机的推送 ID、推送标题、内容,如下图所示。
- 确认推送,可查看手机是否收到推送,以及查看埋点上报字段是否正确。
6. 附录
6.1. 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"));
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();
}
}
6.2. 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();
}
}
6.3. 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();
}
}
6.4. 附录方法的封装类
如果不想把附录中的示例方法一个个复制到项目中,可以使用封装好的工具类 SensorsFocusHelper 来调用示例方法。使用步骤如下:
- 下载 SensorsFocusHelper 类,解压后复制到项目中
- 给 SensorsFocusHelper 类添加 package 声明
- 调用 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 处理自定义消息,--> 请处理自定义消息
}
});
注:本文档内容为神策产品使用和技术细节说明文档,不包含适销类条款;具体企业采购产品和技术服务内容,以商业采购合同为准。