前言

这里用的是uni-app自带的UniPush1.0(个推服务),所以只针对UniPush1.0介绍实现步骤。

建议查阅的文章:

当然现在已经出了UniPush2.0(HBuilderX 3.5.1及其以上版本支持),新项目的话还是推荐使用UniPush2.0

如果要使用UniPush2.0,请移步 UniPush 2.0 使用指南

效果预览

前五张图片是Android(HUAWEI P30 Pro)真机效果,后面三张是Ios(iPhone XS Max)真机效果。

概述

产品介绍

UniPushDCloud联合个推公司推出的集成型统一推送服务,内建了苹果、华为、小米、OPPO、VIVO、魅族、谷歌 FCM 等手机厂商的系统级推送和个推等第三方推送。

国内AndroidPush是一个混乱的世界,因为GooglePush服务FCM 被墙(从HBuilderX2.7.10开始,支持谷歌FCM,参考: UniPush支持谷歌推送FCM配置指南),所以一些国内的安卓手机厂商各自做了自己的推送,比如华为、小米、OPPO、VIVO、魅族等,但还有很多国产手机厂商没有提供官方推送方案。三方独立公司如个推,则提供了独立的 push 方案。

在没有UniPush以前,如果只使用三方push,会在很多国产手机上因为节电设置而无法保活push进程,导致无法推送。

而如果每个安卓手机的官方Push SDK都集成开发一遍,这么多平台,工作量会非常巨大,管理维护也很麻烦。

UniPush解决了这个难题,开发者只需要开发一次。系统会自动在不同手机上选择最可靠的推送通道发送push消息,保障送达率。

UniPush即降低了开发成本、又提高了push送达率,并且免费,是当前推送的最佳解决方案。

技术架构

名词解释

名词解释
通知消息指定通知标题和内容后,由个推SDK自动处理在系统通知栏中展示通知栏消息,同时响铃或震动提醒用户(响铃和震动受手机系统的设置状态影响)。
透传消息即自定义消息,消息体格式客户可以自己定义,如纯文本、json 串等。透传消息个推只传递数据,不做任何处理,客户端接收到透传消息后需要自己去做后续动作处理,如通知栏展示、弹框等。
ClientId个推业务层中的对外用户标识,用于标识客户端身份,由第三方客户端获取并保存到第三方服务端,是个推 SDK 的唯一识别号,简称 CID。
在线推送app 在前台打开运行时,通过个推渠道下发消息。
离线推送app在后台、锁屏、进程关闭时,通过厂商渠道下发消息。若未集成 android 多厂商、未配置 ios 推送证书,则该机型无法使用离线推送。

更多名词解释参考:个推名词解释

消息推送流程

开通 UniPush 推送服务

UniPush内部封装好了个推及主流厂商 SDK,在使用前必须开通相关服务:点此查看如何开通UniPush推送服务

打开 DCloud开发者中心,登录后会进入我的应用列表。在左侧菜单点击uniPush,然后选择 1.0 或 2.0,进入Uni Push信息页,左上角显示为当前要操作的应用,点击可以切换应用。如下图所示:

用户首次使用UniPush功能时,需要向个推同步身份信息。已通过实名认证的用户,会直接将实名认证信息同步给个推。如下图所示:

未提交实名认证信息的用户,需要在页面中输入相关信息后提交,如下图所示:

应用开通UniPush功能时,需要提交应用相关信息,如下图所示:

注意:UniPush在申请开通时,需要确保输入的Android包名iOS Bundle ID必须与打包时配置的一致,否则可能会导致无法收到推送消息。

Android平台:
Android包名必须与HBuilderX中App云端打包时配置的Android包名一致;Android应用签名必须填入打包时使用证书的SHA1指纹
iOS平台:
iOS BundleId必须与HBuilderX中App云端打包时配置的Bundle ID(AppID)一致。

如果已经开通UniPush,会看到如下页面:

若需要支持主流Android厂商客户端接收离线推送,您需要完成 :Android 多厂商配置

iOS 平台还需要在 【配置管理】-【应用配置】页面上传推送证书,如何获取推送证书请参考个推官方文档教程:iOS证书配置指南

核心代码

unipush.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
// 监听push消息 以及 后台数据回复
import phoneInfo from '@/common/js/phone-info.js';
import store from '@/store'
let timer = null;
let numloop = 0;
import {
pushEscalation // 绑定别名的接口
} from "@/api/client-notice.js"

// 消息推送 应用配置(这些给后端用的)
const uniPushObj = {
cid: "",
AppID: "你的AppID",
AppKey: "你的AppKey",
AppSecret: "你的AppSecret",
MasterSecret: "你的MasterSecret",
}

export default {
getInfo() {
uni.getSystemInfo({
success: res => {
phoneInfo.systemInfo = res;
}
});
},
// 开启监听推送
pushListener() {
const token = uni.getStorageSync("token") || store.state.token;
const platform = phoneInfo.systemInfo.platform.toLowerCase();
// 点击推送信息
plus.push.addEventListener('click', res => {
// 其实在这里就可以根据你自己的业务去写了
if (token) {
if (platform == 'android') {
const msg_type = res.payload.msg_type // 0 在线 || 1 离线
// 做些什么 这里处理你的逻辑
if (msg_type == 0) {
console.log('安卓------在线');
} else {
console.log('安卓------离线');
}
} else {
// 在线
if (res.aps == null) {
console.log('苹果------在线');
} else {
// 离线
console.log('苹果------离线');
}
}
} else {
// 这里跳登录页了
uni.redirectTo({
url: `pages/Login-Reg/Login/email-login`
})
}
});
// 接收推送信息 在线
plus.push.addEventListener('receive', res => {
const messageTitle = res.title;
const messageContent = res.content;
if (platform == 'android') {
/***
安卓监听不到 因为安卓这个格式被封装了,做成了通知栏展示
换个格式就行(比如里面多个字段,或换个字段名)
*/
/***
此格式的透传消息由 unipush 做了特殊处理, 会自动展示通知栏
开发者也可自定义其它格式, 在客户端自己处理
*/
// "push_message": {
// "transmission": "{
// title:\"标题\",
// content:\"内容\",
// payload:\"自定义数据\"
// }"
// },
// Hbulidx 版本大于 ## 3.4.18,安卓不再通知栏展示, 需要自行创建通知
plus.push.createMessage(messageContent, res.payload, {
title: messageTitle
});
// 或者在 onlaunch 写入
// plus.push.setAutoNotification(true);
} else {
const type = res.type
//【APP离线】收到消息,但没有提醒(发生在一次收到多个离线消息时,只有一个有提醒,但其他的没有提醒)
//【APP在线】收到消息,不会触发系统消息,需要创建本地消息,但不能重复创建
// 必须加msg.type验证去除死循环
if (res.aps == null && type == "receive") {
//创建本地消息,发送的本地消息也会被receive方法接收到,但没有type属性,且aps是null
plus.push.createMessage(messageContent, res.payload, {
title: messageTitle
});
}
}
});
},
// 循环获取clientid信息,直到获取到为止
getClientInfoLoop() {
plus.push.getClientInfoAsync(info => {
// 如果info不存在,或者info存在,cid不存在则再次获取cid
if (!info || !info.clientid) {
console.log("cid为空=========================================");
let infoTimer = null;
infoTimer = setInterval(function() {
if (cid) {
clearInterval(infoTimer); //清定时器
uni.showModal({
content: cid
})
uni.setStorageSync('cid', cid);
uniPushObj.cid = cid
}
}, 50);
} else if (info && info.clientid) {
let cid = info.clientid;
uni.setStorageSync('cid', cid);
uniPushObj.cid = cid
}
}, function(e) {
console.log('Failed', JSON.stringify(e));
let pinf = plus.push.getClientInfo();
let cid = pinf.clientid; //客户端标识
if (cid) {
uni.setStorageSync('cid', cid);
uniPushObj.cid = cid
}
})
},
/**
* 向后台传送cid,绑定别名
*/
passCid() {
pushEscalation({
"appid": uniPushObj.AppID,
"cid": uniPushObj.cid
}).then(response => {
if (response.Code == 0) {
console.log('----------> cid 绑定别名成功', response);
}
})
},
}

phone-info.js

1
2
3
4
export default {
systemInfo: {}, // 系统设备信息
manifestInfo: "" || uni.getStorageSync("widgetInfo"), // manifest.json 应用信息
}

APP.vue

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<script>
import phoneInfo from '@/common/js/phone-info.js';
import uniPushListener from '@/common/js/unipush.js';
export default {
onLaunch: function() {
uniPushListener.getInfo();
// #ifdef APP-PLUS
plus.screen.lockOrientation('portrait-primary'); //锁定屏幕方向
uni.setStorageSync('cancelUpdate', 'false'); // 进来APP 重置更新弹窗
// 获取App 当前版本号
if (Object.keys(uni.getStorageSync('widgetInfo')).length == 0) {
plus.runtime.getProperty(plus.runtime.appid, widgetInfo => {
phoneInfo.manifestInfo = widgetInfo;
uni.setStorageSync('widgetInfo', widgetInfo);
});
}
uniPushListener.getClientInfoLoop(); // 循环获取cid
plus.runtime.setBadgeNumber(0); // 角标清空
uniPushListener.pushListener(); // 监听通知栏信息
//#endif
}
};
</script>