先熟悉一下主要的几个接口或者类:
com.notnoop.apns.internal包:
- AbstractApnsService:一个抽象类,实现了ApnsService接口。主要包含三种表现形式:
-
ApnsServiceImpl:基础消息处理类。
-
BatchApnsService:批量消息处理类,默认每隔5秒钟,执行一次批量推送。
-
QueuedApnsService:队列消息处理类,即使用阻塞队列方式处理消息。
- ApnsConnection:作为应用连接到苹果APNS服务的接口。主要包含两种表现形式:
- ApnsConnectionImpl:基础连接类,实现了ApnsConnection接口。主要处理从消息发送到收到回执后的一系列过程。
- ApnsPooledConnection:以多线程的方式管理连接池。
- ReconnectPolicies:Socket的连接策略,分为三种:Never、Always、EveryHalfHour。
- Utilities:顾名思义,就是一个工具类,包含一些工具和常量。
com.notnoop.apns包:
- APNS:作为与APNS交互的主要类,用于构建Payload和ApnsService。
ApnsDelegate:委托接口,委托收到苹果服务器的状态通知后的处理。如果消息实际到达了客户端,则服务器不会收到任何的状态通知。
ApnsDelegateAdapter:代理适配器,继承了ApnsDelegate接口,但不做任何事。
ApnsNotification:通知信息接口,包含通知的所有信息。
ApnsService:APNS服务接口。
ApnsServiceBuilder:ApnsService的生成器。
DeliveryError:APNS可能返回的错误。
EnhancedApnsNotification:通知信息类,继承了ApnsNotification接口。
PayloadBuilder:Payload生成器。
ReconnectPolicy:重连策略接口,基于ReconnectPolicies。
示例:
package com.xxx.pushmsg.service.ios.impl; import com.xxx.common.constant.CacheConstant; import com.xxx.common.utils.RedisUtils; import com.xxx.common.utils.StringUtil; import com.xxx.pushmsg.service.ios.IosPushMsgService; import com.notnoop.apns.APNS; import com.notnoop.apns.ApnsDelegate; import com.notnoop.apns.ApnsService; import com.notnoop.apns.PayloadBuilder; import com.notnoop.exceptions.NetworkIOException; import javapns.notification.transmission.NotificationProgressListener; import javapns.notification.transmission.NotificationThread; import javapns.notification.transmission.NotificationThreads; import org.apache.commons.collections.MapUtils; import org.apache.commons.lang.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import javax.annotation.PostConstruct; import javax.annotation.Resource; import java.util.Date; import java.util.Iterator; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; @Service public class IosPushMsgServiceImpl implements IosPushMsgService { private static final Logger log = LoggerFactory.getLogger(IosPushMsgServiceImpl.class); private static final Logger logPush = LoggerFactory.getLogger("push_arrival_rate"); public static final ConcurrentHashMap<Long, Integer> msgStateMap = new ConcurrentHashMap<Long, Integer>(); @Value("${priest.pushmsg.production}")
//是否是生产环境 private boolean production; @Value("${priest.pushmsg.certificate.file.name}")
//证书文件地址 private String certificateName; ApnsService service = null; @Resource private RedisUtils redisUtils;
//连接池大小 private int capacity = 20; @Resource private ApnsDelegate delegate; @PostConstruct public void init() { String password = "123456"; // 证书密码 try {
//初始化服务类型为基本消息处理类型,并且连接设置为连接池 service = APNS.newService().withCert(certificateName, password) .asPool(capacity).withDelegate(delegate).withAppleDestination(production).build(); } catch (Exception e) { log.error("Init error Class::IosPushMsgServiceImpl Method::init", e); } } public void stopPush(Long msgId){ } public boolean pushOffLineMessageNotnoop(Map<String, String> tokenMessgae, Map<String, Object> mapCustom) { if (MapUtils.isEmpty(tokenMessgae)) { return true; }
//铃音,微信等应用实现语音呼叫时使用的方式是将此铃音设置为30秒的长铃音,最大限制为30秒。
String sound = "msg.wav"; try { this.send(tokenMessgae, null, sound, mapCustom); } catch (Exception ex) { log.error("OffLineMessageNotnoop Multi error Class::IosPushMsgServiceImpl Method::pushOffLineMessageNotnoop Param::message" + " Param::tokenMessgae:" + tokenMessgae + ",mapCustom:" + mapCustom, ex); } return true; }
//发送方法 private void send(Map<String, String> tokenMessage, String launchImage, String sound, Map<String, Object> mapCustom) { try { Long nowStart = System.currentTimeMillis(); Map<String, String> mapCount = this.redisUtils.hGetAll(CacheConstant.CACHE_PREFIX_IOS_GROUP_PUSHMSG_COUNT); //发送消息 Iterator<String> it = tokenMessage.keySet().iterator(); while (it.hasNext()) { Long nowStart111 = System.currentTimeMillis(); String token = it.next();
//因为标准的Token大小为64位,因此如果Token不符合规范则不推 if (token.length() < 64) { continue; } String alert = tokenMessage.get(token);
//构造Payload PayloadBuilder payloadBuilder = APNS.newPayload(); //拼装消息 payloadBuilder = payloadBuilder.alertBody(alert); if (!StringUtils.isEmpty(launchImage)) { payloadBuilder = payloadBuilder.launchImage(launchImage); } if (!StringUtils.isEmpty(sound)) { payloadBuilder = payloadBuilder.sound(sound); } //裁剪消息 if (payloadBuilder.isTooLong()) { payloadBuilder = payloadBuilder.shrinkBody(); } payloadBuilder = payloadBuilder.forNewsstand(); //增加额外的信息 if(null != mapCustom) payloadBuilder.customFields(mapCustom); Integer count = 1; if (mapCount.containsKey(token)) { String countStr = mapCount.get(token); count = StringUtil.isEmpty(countStr) ? 0 : Integer.valueOf(countStr); if (count < 99) { count = count + 1; } else { count = 99; } }
//设置小红圈上面的数字 payloadBuilder.badge(count); //组装成json String payload = payloadBuilder.build();
//发送消息 service.push(token, payload, new Date(System.currentTimeMillis() + 1000 * 1000)); Long nowEnd111 = System.currentTimeMillis();
//重组消息体,去除其中的Emoji,否则发送消息体会出现问题 String logContent = StringUtil.filterEmoji(alert).replaceAll("\r","").replaceAll("\n",""); this.redisUtils.hPut(CacheConstant.CACHE_PREFIX_IOS_GROUP_PUSHMSG_COUNT, token, count); StringBuffer sb = new StringBuffer(); sb.append("{\"token\":"); sb.append("\""); sb.append(token); sb.append("\""); sb.append(",\"content\":"); sb.append("{"); sb.append("\"content\":"); sb.append("\""); sb.append(logContent); sb.append("\""); sb.append(",\"createTime\":"); sb.append(nowEnd111); sb.append("}"); sb.append(",\"ret\":"); sb.append("{\"ret_code\":0}"); sb.append("}"); logPush.info(sb.toString()); } Long nowEnd = System.currentTimeMillis(); log.info("IOSPushMsgSend Cost:" + (nowEnd - nowStart)); } catch (NetworkIOException e) { log.error("Send Multi Error NetworkIOException At Class::IosPushMsgServiceImpl Method::send" + " Param::tokenMessage:" + tokenMessage, e); if (e.toString().contains("certificate")) { //shortMessageService.sendMessage(Long.MAX_VALUE, null, "15001257920", e.toString()); } } catch (Exception ex) { log.error("Send Multi Error Exception At Class::IosPushMsgServiceImpl Method::send" + " Param::tokenMessage:" + tokenMessage, ex); } finally { } } public static final NotificationProgressListener DEBUGGING_PROGRESS_LISTENER = new NotificationProgressListener() { public void eventThreadStarted(NotificationThread notificationThread) { log.info("EventThreadStarted [EVENT]: thread #" + notificationThread.getThreadNumber() + " started with " + " devices beginning at message id #" + notificationThread.getFirstMessageIdentifier() + " At Class::NotificationProgressListener Method::eventThreadStarted" + notificationThread.getFailedNotifications()); } public void eventThreadFinished(NotificationThread thread) { log.info("EventThreadFinished [EVENT]: thread #" + thread.getThreadNumber() + " finished: pushed messages #" + thread.getFirstMessageIdentifier() + " to " + thread.getLastMessageIdentifier() + " toward " + " devices" + " At Class::NotificationProgressListener Method::eventThreadFinished" + thread.getFailedNotifications()); } public void eventConnectionRestarted(NotificationThread thread) { log.info("EventConnectionRestarted [EVENT]: connection restarted in thread #" + thread.getThreadNumber() + " because it reached " + thread.getMaxNotificationsPerConnection() + " notifications per connection" + " At Class::NotificationProgressListener Method::eventConnectionRestarted" + thread.getFailedNotifications()); } public void eventAllThreadsStarted(NotificationThreads notificationThreads) { log.info("EventAllThreadsStarted [EVENT]: all threads started: " + notificationThreads.getThreads().size() + " At Class::NotificationProgressListener Method::eventAllThreadsStarted" + notificationThreads.getFailedNotifications()); } public void eventAllThreadsFinished(NotificationThreads notificationThreads) { log.info("EventAllThreadsFinished [EVENT]: all threads finished: " + notificationThreads.getThreads().size() + " At Class::NotificationProgressListener Method::eventAllThreadsFinished" + notificationThreads.getFailedNotifications()); } public void eventCriticalException(NotificationThread notificationThread, Exception exception) { log.info("EventCriticalException [EVENT]: critical exception occurred: " + exception + " At Class::NotificationProgressListener Method::eventCriticalException" + notificationThread.getFailedNotifications()); } }; public void setCapacity(int capacity) { this.capacity = capacity; } }