消息推送大部分App都要,这里引用了阿里云推送,不过说的是数据结构设计和研究。
iOS/Android 消息推送,展示位常见如果下:
1.系统通知栏
2.app站内消息
3.具体业务(比如首页广告)
4.可能还有更多产品设计
这三个展示位的点击都可能跳转某个详情页面,往往同一条消息1、2、3展示位上的内容是一样的,那么跳转的详情也是同一个。
但展示位的代码要写三处,为了相同功能减少重复代码,我们尽量从源头统一数据结构。
虽然现状是写多套代码来解析数据来实现跳转到详情,但成长还是要的,那么我们来分析一下iOS系统通知栏拿到的消息结构。
系统版本不同也有多个不同的方法,这里我们就不讨论iOS的如何收发通知,从我们能拿到消息体开始说,下面这个方法我们可以看到有个userInfo,这个就是我们要的数据。
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult result))completionHandler
真机调试转换成json字符串如下:
{
"out_trade_no": "a7240cda8b12c0194e3524924221",
"body": "亲~退款金额已经原路退回至您的账户,请注意查收。查看退款状态",
"aps": {
"sound": "default",
"alert": {
"title": "退款成功~",
"body": "亲~退款金额已经原路退回至您的账户,请注意查收。查看退款状态"
},
"badge": 2
},
"push": "billRefunded",
"m": "1706138425693242387008&&ALIYUN_28175695_170684231569342287008&&ALIYUN_d450ef0b54d84606a7b9e1d5377bb3eb&&00&&@apns",
"type": "billRefunded",
"i": 431314695169776342074208,
"link_type": "3"
}
"aps"这一层数据结构是iOS系统规定好的,我们说说这以前外的,其实这是我们要用来跳转页面时用到的参数。每个不同的业务功能,我们都要重新手动解析一遍,而且内容不固定,我们要做的就是固定一个数结构,比如:
{
"aps": {
"sound": "default",
"alert": {
"title": "退款成功~",
"body": "亲~退款金额已经原路退回至您的账户,请注意查收。查看退款状态"
},
"badge": 2
},
"extend_data": {
"out_trade_no": "a7240cda8b12c0194e3524924221",
"body": "亲~退款金额已经原路退回至您的账户,请注意查收。查看退款状态",
"push": "billRefunded",
"m": "1706138425693242387008&&ALIYUN_28175695_170684231569342287008&&ALIYUN_d450ef0b54d84606a7b9e1d5377bb3eb&&00&&@apns",
"type": "billRefunded",
"i": 431314695169776342074208,
"link_type": "3"
}
}
扩展数据都放在extend_data里,这个结构里的字段我们就可以和另外2个展示位数据结构保持一致,点击跳转逻辑就可以统一了。
为什么最开始拿到数据的结构是混乱的?我们溯源一下,用的阿里推送,那消息内容肯定经过了他们的,扒拉了一下代码调用阿里SDK代码片段如下:
PushRequest request = new PushRequest();
request.setTarget("ACCOUNT");
//唯一标识
request.setTargetValue(pushNotify.getUniqueIdentifier());
request.setTitle(pushNotify.getTitle());
Map<String,String> map = new HashMap<>();
map.put("body", pushNotify.getBody());
map.put("push", pushNotify.getFunction());
if (pushNotify.getParam() !=null){
pushNotify.getParam().forEach((k,v)->
map.put(k,v));
}
//ios推送
if (pushNotify.getSystem() == 1){
request.setPushType("NOTICE");
request.setBody(pushNotify.getBody());
request.setDeviceType("iOS");
request.setIOSApnsEnv("PRODUCT");
switch (pushNotify.getAppName()){
case "app_a":{
request.setAppKey(aliconfig.getapp_aKey());
break;
}
case "app_b":{
request.setAppKey(aliconfig.getapp_bKey());
break;
}
case "app_c":{
request.setAppKey(aliconfig.getapp_cKey());
break;
}
case "app_d":{
request.setAppKey(aliconfig.getapp_dKey());
// request.setIOSApnsEnv("DEV");//iOS的通知是通过APNs中心来发送的,需要填写对应的环境信息。"DEV" : 表示开发环境 "PRODUCT" : 表示生产环境
break;
}
default:{
break;
}
}
//获取消息未读数量集合
List<PushNotify> pushNotifyList = repository.findByUniqueIdentifierAndStatusInAndAppName(pushNotify.getUniqueIdentifier(), Arrays.asList(0), pushNotify.getAppName());
request.setIOSBadge(pushNotifyList.size()); // iOS应用图标右上角角标
request.setIOSMusic("default"); // iOS通知声音
// request.setIOSSubtitle("来自测试的副标题");//iOS10通知副标题的内容
// request.setIOSNotificationCategory("iOS10 Notification Category");//指定iOS10通知Category
// request.setIOSMutableContent(true);//是否允许扩展iOS通知内容
request.setIOSRemind(true); // 消息推送时设备不在线(既与移动推送的服务端的长连接通道不通),则这条推送会做为通知,通过苹果的APNs通道送达一次。注意:离线消息转通知仅适用于生产环境
// request.setIOSRemindBody("iOSRemindBody");//iOS消息转通知时使用的iOS通知内容,仅当iOSApnsEnv=PRODUCT && iOSRemind为true时有效
request.setIOSExtParameters(new Gson().toJson(map)); //通知的扩展属性(注意 : 该参数要以json map的格式传入,否则会解析出错)
}else{
request.setPushType("MESSAGE");
request.setBody(new Gson().toJson(map));
request.setDeviceType("ANDROID");
// request.setAppKey(aliconfig.getAppAndriodKey()); //andriod key
switch (pushNotify.getAppName()){
case "ucloud":{
request.setAppKey(aliconfig.getAppAndriodKey());
break;
}
case "ubake":{
request.setAppKey(aliconfig.getUbakeAndriodKey());
break;
}
case "ubakes":{
request.setAppKey(aliconfig.getUbakesAndriodKey());
break;
}
default:{
break;
}
}
// request.setAndroidNotifyType("BOTH");//通知的提醒方式 "VIBRATE" : 震动 "SOUND" : 声音 "BOTH" : 声音和震动 NONE : 静音
// request.setAndroidNotificationBarType(1);//通知栏自定义样式0-100
// request.setAndroidNotificationBarPriority(1);//通知栏自定义样式0-100
// request.setAndroidOpenType("URL"); //点击通知后动作 "APPLICATION" : 打开应用 "ACTIVITY" : 打开AndroidActivity "URL" : 打开URL "NONE" : 无跳转
// request.setAndroidOpenUrl("http://www.baidu.com"); //Android收到推送后打开对应的url,仅当AndroidOpenType="URL"有效
// request.setAndroidActivity("com.alibaba.push2.demo.XiaoMiPushActivity"); // 设定通知打开的activity,仅当AndroidOpenType="Activity"有效
// request.setAndroidMusic("default"); // Android通知音乐
// request.setAndroidPopupActivity("com.ali.demo.PopupActivity");//设置该参数后启动辅助弹窗功能, 此处指定通知点击后跳转的Activity(辅助弹窗的前提条件:1. 集成第三方辅助通道;2. StoreOffline参数设为true)
// request.setAndroidPopupTitle("Popup Title");
// request.setAndroidPopupBody("Popup Body");
// request.setAndroidExtParameters("{\"push\":\"contact\"}"); //设定通知的扩展属性
// request.setAndroidNotificationChannel("law");
request.setStoreOffline(true); // 离线消息是否保存,若保存, 在推送时候,用户即使不在线,下一次上线则会收到
}
PushResponse pushResponse = client.getAcsResponse(request);
最重要的就是
request.setIOSExtParameters(new Gson().toJson(map)); // iOS
request.setBody(new Gson().toJson(map));// Android
iOS和Android用的同一套数据源,所以才会产生那么多乱七八糟的字段。
有时间重新整一下这段发送消息代码吧。
网友评论