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

1. 引入依赖



   cn.jpush.api
   jpush-client
   3.3.10


   cn.jpush.api
   jiguang-common
   1.1.4


   com.notnoop.apns
   apns
   1.0.0.Beta6


   com.huawei.android
   huawei-push
   1.1.1


   com.xiaomi
   mipush
   2.2.20



   com.vivo
   vpush
   1.1.0

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; //应用id
    
    private String appKey; //应用key
    
    private String masterSecret; //秘钥
    
    private String target; //推送目标
    
    private String platform; //推送平台
    

}

3.  实现类

//苹果都是透传推送
@Component
public class ApplePushMessage implements PushMessage {

   @Override
   public int pushNcMsg(PushMessageDTO pushMessageDTO, String content, String title) throws Exception {
      // TODO Auto-generated method stub
      return 0;
   }

   //苹果的appKey是voippush.p12文件路径, masterSecret是密码
   @Override
   public 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 = "https://login.cloud.huawei.com/oauth2/v2/token"; // 获取认证Token的URL
   private static String apiUrl = "https://api.push.hicloud.com/pushsend.do"; // 应用级消息下发API
   private static String accessToken;// 下发通知消息的认证Token
   private static long tokenExpiredTime; // accessToken的过期时间

   @Override
   public 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();// 目标设备Token
      deviceTokens.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());// 定义需要打开的appPkgName

      JSONObject 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;
   }

   @Override
   public 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();// 目标设备Token
      deviceTokens.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;
   }

   // 获取下发通知消息的认证Token
   private 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 data
         outPut = urlConnection.getOutputStream();
         outPut.write(data.getBytes("UTF-8"));
         outPut.flush();

         // read response
         if (urlConnection.getResponseCode() < 400) {
            in = urlConnection.getInputStream();
         } else {
            in = urlConnection.getErrorStream();
         }

         List 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 {

   @Override
   public 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;
   }

   @Override
   public 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 {
   
   @Override
   public int pushNcMsg(PushMessageDTO pushMessageDTO, String content, String title) throws Exception {
      Sender sender = new Sender(pushMessageDTO.getMasterSecret());//注册登录开发平台网站获取到的appSecret
       Result result = sender.getToken(Integer.valueOf(pushMessageDTO.getAppId()), pushMessageDTO.getAppKey());//注册登录开发平台网站获取到的appId和appKey
       Sender 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("http://www.vivo.com")
               .networkType(-1)
               .requestId("1234567890123456")
               .build();
       Result resultMessage = senderMessage.sendSingle(singleMessage);
      return 1;
   }

   @Override
   public int pushTransMsg(PushMessageDTO pushMessageDTO, String content) throws Exception {
      
      return 1;
   }

}

4 .  统一消息推送接口

public void pushMessageToAllPlatform(PushMessageVO pushMessageVO) {
    String[] sipCodeList = pushMessageVO.getSipCode().split(",");
    // 查询推送信息,在数据库构建的表(见文章末尾)
    List 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

 

 

 

 

 

 

你可能感兴趣的:(java服务端统一消息推送(苹果, 华为, 小米, 极光,vivo))