admin 管理员组

文章数量: 887021

java服务端统一消息推送(苹果, 华为, 小米, 极光,vivo)

1. 引入依赖

<!-- 极光 -->
<dependency><groupId>cn.jpush.api</groupId><artifactId>jpush-client</artifactId><version>3.3.10</version>
</dependency>
<dependency><groupId>cn.jpush.api</groupId><artifactId>jiguang-common</artifactId><version>1.1.4</version>
</dependency>
<!-- 苹果 -->
<dependency><groupId>com.notnoop.apns</groupId><artifactId>apns</artifactId><version>1.0.0.Beta6</version>
</dependency>
<!-- 华为 -->
<dependency><groupId>com.huawei.android</groupId><artifactId>huawei-push</artifactId><version>1.1.1</version>
</dependency>
<!-- 小米,vivo 请去官网下载, 然后配置到maven私服仓库nexus -->
<dependency><groupId>com.xiaomi</groupId><artifactId>mipush</artifactId><version>2.2.20</version>
</dependency><dependency><groupId>com.vivo</groupId><artifactId>vpush</artifactId><version>1.1.0</version>
</dependency>

2.  定义推送接口

public interface PushMessage {/*** 通知栏消息推送*/public int pushNcMsg(PushMessageDTO pushMessageDTO, String content, String title) throws Exception ;/*** 透传推送*/public int pushTransMsg(PushMessageDTO pushMessageDTO, String content) throws Exception ;}
//辅助类 appName, appId, appKey ,masterSecret请去官网注册账号,添加app应用获取
@Getter
@Setter
@ToString
public class PushMessageDTO implements Serializable {private static final long serialVersionUID = 1L;private String appName; //应用名称private String appId; //应用idprivate String appKey; //应用keyprivate String masterSecret; //秘钥private String target; //推送目标private String platform; //推送平台}

3.  实现类

//苹果都是透传推送
@Component
public class ApplePushMessage implements PushMessage {@Overridepublic int pushNcMsg(PushMessageDTO pushMessageDTO, String content, String title) throws Exception {// TODO Auto-generated method stubreturn 0;}//苹果的appKey是voippush.p12文件路径, masterSecret是密码@Overridepublic int pushTransMsg(PushMessageDTO pushMessageDTO, String content) throws Exception {ApnsService service = APNS.newService().withCert(pushMessageDTO.getAppKey(), pushMessageDTO.getMasterSecret()).withSandboxDestination().withAppleDestination(true).build();String payloadApple = APNS.newPayload().alertBody(content).build();String token = pushMessageDTO.getTarget();service.push(token, payloadApple);return 1;}
}
//华为
@Component
public class HuaWeiPushMessage implements PushMessage {private static String tokenUrl = ""; // 获取认证Token的URLprivate static String apiUrl = ".do"; // 应用级消息下发APIprivate static String accessToken;// 下发通知消息的认证Tokenprivate static long tokenExpiredTime; // accessToken的过期时间@Overridepublic int pushNcMsg(PushMessageDTO pushMessageDTO, String content, String title) throws Exception {if (tokenExpiredTime <= System.currentTimeMillis()) {refreshToken(pushMessageDTO.getMasterSecret(), pushMessageDTO.getAppKey());}/* PushManager.requestToken为客户端申请token的方法,可以调用多次以防止申请token失败 *//* PushToken不支持手动编写,需使用客户端的onToken方法获取 */JSONArray deviceTokens = new JSONArray();// 目标设备TokendeviceTokens.add(pushMessageDTO.getTarget());JSONObject body = new JSONObject();// 仅通知栏消息需要设置标题和内容,透传消息key和value为用户自定义body.put("title", title);// 消息标题body.put("content", content);// 消息内容体JSONObject param = new JSONObject();param.put("appPkgName", pushMessageDTO.getAppName());// 定义需要打开的appPkgNameJSONObject action = new JSONObject();action.put("type", 3);// 类型3为打开APP,其他行为请参考接口文档设置action.put("param", param);// 消息点击动作参数JSONObject msg = new JSONObject();msg.put("type", 3);// 3: 通知栏消息,异步透传消息请根据接口文档设置msg.put("action", action);// 消息点击动作msg.put("body", body);// 通知栏消息body内容JSONObject hps = new JSONObject();// 华为PUSH消息总结构体hps.put("msg", msg);JSONObject payload = new JSONObject();payload.put("hps", hps);String postBody = MessageFormat.format("access_token={0}&nsp_svc={1}&nsp_ts={2}&device_token_list={3}&payload={4}",URLEncoder.encode(accessToken, "UTF-8"), URLEncoder.encode("openpush.message.api.send", "UTF-8"),URLEncoder.encode(String.valueOf(System.currentTimeMillis() / 1000), "UTF-8"), URLEncoder.encode(deviceTokens.toString(), "UTF-8"),URLEncoder.encode(payload.toString(), "UTF-8"));String postUrl = apiUrl + "?nsp_ctx=" + URLEncoder.encode("{\"ver\":\"1\", \"appId\":\"" + pushMessageDTO.getAppKey() + "\"}", "UTF-8");httpPost(postUrl, postBody, 5000, 5000);return 1;}@Overridepublic int pushTransMsg(PushMessageDTO pushMessageDTO, String context) throws Exception {if (tokenExpiredTime <= System.currentTimeMillis()) {refreshToken(pushMessageDTO.getMasterSecret(),pushMessageDTO.getAppKey());}/* PushManager.requestToken为客户端申请token的方法,可以调用多次以防止申请token失败 *//* PushToken不支持手动编写,需使用客户端的onToken方法获取 */JSONArray deviceTokens = new JSONArray();// 目标设备TokendeviceTokens.add(pushMessageDTO.getTarget());JSONObject body = new JSONObject();body.put("online", 1);JSONObject param = new JSONObject();param.put("appPkgName", pushMessageDTO.getAppName());JSONObject action = new JSONObject();action.put("type", 3);// 类型3为打开APP,其他行为请参考接口文档设置action.put("param", param);// 消息点击动作参数JSONObject msg = new JSONObject();msg.put("type", 1);// 1: 透传异步消息,通知栏消息请根据接口文档设置msg.put("body", body.toString());// body内容不一定是JSON,可以是String,若为JSON需要转化为String发送msg.put("action", action);// 消息点击动作JSONObject hps = new JSONObject();// 华为PUSH消息总结构体hps.put("msg", msg);JSONObject payload = new JSONObject();payload.put("hps", hps);String postBody = MessageFormat.format("access_token={0}&nsp_svc={1}&nsp_ts={2}&device_token_list={3}&payload={4}",URLEncoder.encode(accessToken, "UTF-8"), URLEncoder.encode("openpush.message.api.send", "UTF-8"),URLEncoder.encode(String.valueOf(System.currentTimeMillis() / 1000), "UTF-8"), URLEncoder.encode(deviceTokens.toString(), "UTF-8"),URLEncoder.encode(payload.toString(), "UTF-8"));String postUrl = apiUrl + "?nsp_ctx=" + URLEncoder.encode("{\"ver\":\"1\", \"appId\":\"" + pushMessageDTO.getAppKey() + "\"}", "UTF-8");httpPost(postUrl, postBody, 5000, 5000);return 1;}// 获取下发通知消息的认证Tokenprivate void refreshToken(String appSecret, String appId) throws IOException {String msgBody = MessageFormat.format("grant_type=client_credentials&client_secret={0}&client_id={1}", URLEncoder.encode(appSecret, "UTF-8"), appId);String response = httpPost(tokenUrl, msgBody, 5000, 5000);JSONObject obj = JSONObject.parseObject(response);accessToken = obj.getString("access_token");tokenExpiredTime = System.currentTimeMillis() + (obj.getLong("expires_in") - 5 * 60) * 1000;}//httpPost请求private String httpPost(String httpUrl, String data, int connectTimeout, int readTimeout) throws IOException {OutputStream outPut = null;HttpURLConnection urlConnection = null;InputStream in = null;try {URL url = new URL(httpUrl);urlConnection = (HttpURLConnection) url.openConnection();urlConnection.setRequestMethod("POST");urlConnection.setDoOutput(true);urlConnection.setDoInput(true);urlConnection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");urlConnection.setConnectTimeout(connectTimeout);urlConnection.setReadTimeout(readTimeout);urlConnection.connect();// POST dataoutPut = urlConnection.getOutputStream();outPut.write(data.getBytes("UTF-8"));outPut.flush();// read responseif (urlConnection.getResponseCode() < 400) {in = urlConnection.getInputStream();} else {in = urlConnection.getErrorStream();}List<String> lines = IOUtils.readLines(in, urlConnection.getContentEncoding());StringBuffer strBuf = new StringBuffer();for (String line : lines) {strBuf.append(line);}System.out.println(strBuf.toString());return strBuf.toString();} finally {IOUtils.closeQuietly(outPut);IOUtils.closeQuietly(in);if (urlConnection != null) {urlConnection.disconnect();}}}}

//小米

@Component
public class XiaoMiPushMessage implements PushMessage {@Overridepublic int pushNcMsg(PushMessageDTO pushMessageDTO, String content, String title) throws Exception {Constants.useOfficial();Sender sender = new Sender(pushMessageDTO.getMasterSecret());String messagePayload = "{\"online\":\"1\"}";Message message = new Message.Builder().title(title).description(content).payload(messagePayload).restrictedPackageName(pushMessageDTO.getAppName()).passThrough(0).extra(Constants.EXTRA_PARAM_NOTIFY_EFFECT, Constants.NOTIFY_LAUNCHER_ACTIVITY).notifyType(-1).build();sender.sendToAlias(message, pushMessageDTO.getTarget(), 1);return 1;}@Overridepublic int pushTransMsg(PushMessageDTO pushMessageDTO, String content) throws Exception {Constants.useOfficial();Sender sender = new Sender(pushMessageDTO.getMasterSecret());String messagePayload = "{\"online\":\"1\"}";Message message = new Message.Builder().description(content).payload(messagePayload).restrictedPackageName(pushMessageDTO.getAppName()).passThrough(1).notifyType(-1).build();sender.sendToAlias(message, pushMessageDTO.getTarget(), 1);return 1;}}

//vivo暂时只有通知栏消息推送

@Component
public class VivoPushMessage implements PushMessage {@Overridepublic int pushNcMsg(PushMessageDTO pushMessageDTO, String content, String title) throws Exception {Sender sender = new Sender(pushMessageDTO.getMasterSecret());//注册登录开发平台网站获取到的appSecretResult result = sender.getToken(Integer.valueOf(pushMessageDTO.getAppId()), pushMessageDTO.getAppKey());//注册登录开发平台网站获取到的appId和appKeySender senderMessage = new Sender(pushMessageDTO.getMasterSecret(),result.getAuthToken());Message singleMessage = new Message.Builder().regId(pushMessageDTO.getTarget())//该测试手机设备订阅推送后生成的regId.notifyType(3).title(title).content(content).timeToLive(1000).skipType(2).skipContent("")workType(-1).requestId("1234567890123456").build();Result resultMessage = senderMessage.sendSingle(singleMessage);return 1;}@Overridepublic int pushTransMsg(PushMessageDTO pushMessageDTO, String content) throws Exception {return 1;}}

4 .  统一消息推送接口

public void pushMessageToAllPlatform(PushMessageVO pushMessageVO) {String[] sipCodeList = pushMessageVO.getSipCode().split(",");// 查询推送信息,在数据库构建的表(见文章末尾)List<PushMessageDTO> pushMessageDTOList = rxSipPlatformTargetMapper.selectPushMessage(pushMessageVO.getAppName(), sipCodeList);// 推送消息if (null != pushMessageDTOList && !pushMessageDTOList.isEmpty()) {for (PushMessageDTO pushMessageDTO : pushMessageDTOList) {pushMessageToApp(pushMessageDTO,  pushMessageVO.getPushType(), pushMessageVO.getContent(), pushMessageVO.getTitle());}}
}private int pushMessageToApp(PushMessageDTO pushMessageDTO, String pushType,String content, String title) {try {PushMessage pushMessage = (PushMessage) SpringUtil.getBean(PlatformEnum.getNameByType(pushMessageDTO.getPlatform()));if (StringUtils.isBlank(pushType) || "NC".equals(pushType)) {pushMessage.pushNcMsg(pushMessageDTO, content, title);}if (StringUtils.isBlank(pushType) || "TS".equals(pushType)) {pushMessage.pushTransMsg(pushMessageDTO, content);}} catch (Exception e) {log.error(e.toString());return 0;}return 1;}

//辅助参数类

public enum PlatformEnum {

    JIGUANG ("JIGUANG","jiGuangPushMessage"),
    HUAWEI  ("HUAWEI","huaWeiPushMessage"),
    APPLE   ("APPLE","applePushMessage"),
    XIAOMI  ("XIAOMI","xiaoMiPushMessage"),
    OPPO    ("OPPO","oppoPushMessage"),
    VIVO    ("VIVO","vivoPushMessage");


    private String platformType;

    private String platformName;

    private PlatformEnum(String platformType, String platformName) {
        this.platformType = platformType;
        this.platformName = platformName;
    }

    public String getPlatformType() {
        return platformType;
    }

    public void setPlatformType(String platformType) {
        this.platformType = platformType;
    }

    public String getPlatformName() {
        return platformName;
    }

    public void setPlatformName(String platformName) {
        this.platformName = platformName;
    }


    public static String getNameByType(String platformType) {
        for (PlatformEnum e : PlatformEnum.values()) {
            if (e.getPlatformType().equals(platformType)) {
                return e.getPlatformName();
            }
        }
        return null;
    }
}

public class PushMessageVO implements Serializable {private static final long serialVersionUID = 1L;@ApiModelProperty(value="app名称" ,required=true)private String appName;@ApiModelProperty(value="设备编号(多个用逗号隔开)" ,required=true)private String sipCode;@ApiModelProperty(value="消息推送模式(NC-通知栏消息, TS-透传消息)" ,required=true)private String pushType;@ApiModelProperty(value="消息内容" ,required=true)private String content;@ApiModelProperty(value="消息标题")private String title;}

数据库表:

CREATE TABLE `rx_sip_platform_target` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `sip_code` varchar(255) DEFAULT NULL COMMENT '设备编号',
  `platform` varchar(255) DEFAULT '0' COMMENT '推送平台',
  `target` varchar(255) DEFAULT NULL COMMENT '推送目标',
  `update_time` timestamp NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
)  COMMENT='设备登录推送目标表';

CREATE TABLE `rx_app_config` (
  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT 'id',
  `app_name` varchar(64) NOT NULL COMMENT '应用名称',
  `app_id` varchar(20) DEFAULT NULL COMMENT '应用ID',
  `app_key` varchar(128) NOT NULL COMMENT 'appKey',
  `master_secret` varchar(64) NOT NULL COMMENT 'masterSecret',
  `create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `update_time` timestamp NULL DEFAULT NULL,
  `platform` varchar(255) DEFAULT '0' COMMENT '推送平台',
  PRIMARY KEY (`id`)
)   COMMENT='应用推送平台配置信息';

//苹果的appKey是voippush.p12文件路径, masterSecret是密码

//查询推送集sql

<select id="selectPushMessage" resultMap="PushMessageDTOMap">SELECTc.app_name,c.app_id,c.app_key,c.master_secret,c.platform,p.targetFROMrx_sip_platform_target pINNER JOIN rx_app_config c ON c.platform = p.platformWHEREc.app_name =#{appName,jdbcType=VARCHAR}AND p.sip_code IN<foreach collection="sipCodeList" item="sipCode" open="(" close=")" separator=",">#{sipCode,jdbcType=VARCHAR}</foreach>
</select>

 

 

 

 

 

 

本文标签: java服务端统一消息推送(苹果 华为 小米 极光 vivo)