ios apns java codec 防止粘包
public Bootstrap newBootstrap(Bootstrap bootstrap, final PushHandler phandler) { bootstrap.handler(new ChannelInitializer<SocketChannel>() { @Override protected void initChannel(SocketChannel ch) throws Exception { ChannelPipeline pipeline = ch.pipeline(); if (isSsl) { SSLContext sslContext = SSLUtil.initSSLContext(credentials.getCertification(), credentials.getPassword()); SSLEngine sslEngine = sslContext.createSSLEngine(); sslEngine.setUseClientMode(true); pipeline.addLast("ssl", new SslHandler(sslEngine)); } if (Constant.debug) { pipeline.addLast("log", new LoggingHandler(LogLevel.DEBUG)); } pipeline.addLast("encoder", new Encoder()); pipeline.addLast("decoder", new Decoder()); pipeline.addLast("pushHandler", phandler); } }); return bootstrap; }
package com.couriusby.apns.codec; import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; import io.netty.handler.codec.ByteToMessageDecoder; import java.util.List; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.curiousby.apns.message.ErrorResponse; public class Decoder extends ByteToMessageDecoder { static final Logger logger = LoggerFactory.getLogger(Decoder.class); // 据文档: command + status + identifier = 1 + 1 + 4 static final int responseSize = 6; @Override protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception { // logger.debug("readableBytes:" + in.readableBytes()); if (in.readableBytes() >= responseSize) { ErrorResponse errorResponse = new ErrorResponse(); errorResponse.setCommond(in.readByte()); errorResponse.setStatus(in.readByte()); errorResponse.setIdentifier(in.readInt()); errorResponse.setErrorMsg(ErrorResponse.getErrorMsgByStatus(errorResponse.getStatus())); out.add(errorResponse); } logger.debug("decoder:" + out); } }
package com.curiousby.apns.codec; import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; import io.netty.handler.codec.MessageToByteEncoder; import java.nio.charset.Charset; import java.util.Date; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.curiousby.apns.message.Item; import com.curiousby.apns.message.Notification; /** * <pre> * 1 byte 4 byte * command + frameLength + item + item + ... + item * * 1 byte 2 byte * item = itemId + itemLength + itemData * * itemData据不同的类型有不同的长度: * * </pre> * * 采用组发送的方式,一次发送一系列的消息,然后每个消息的notificationIdentifier都是连续的, * 这样,如果apple的服务器返回错误,那么可以从错误里的Identifier知道是哪个出错了,然后重发下面的消息。 */ public class Encoder extends MessageToByteEncoder<Notification> { static final Logger logger = LoggerFactory.getLogger(Encoder.class); // TODO 这个到底要不要做成static的,static的可能容易调试点,不然每个线程都有一个计数的话,可能会比较乱 // TODO 处理超出int范围,再重新从0开始的逻辑 int identifier = 0; static final Charset utf8 = Charset.forName("UTF-8"); // 据apple的文档,这个值就是2,据其它地方看到的资料,有0和1的版本。 static final int COMMAND = 2; static final int defaultExpirationDate = 0; @Override protected void encode(ChannelHandlerContext ctx, Notification notification, ByteBuf out) throws Exception { // logger.debug("NotificationEncoder:" + notification); // String data = // "02000000770100205CA6A718250E1868A8EB7D8964D3E8A051B009268A3D710D0D8CC6591572890802003F7B22617073223A7B22736F756E64223A2264656661756C74222C22616C657274223A2252696E672072696E672C204E656F2E222C226261646765223A317D7D030004000000650400047FFFFFFF0500010A"; // out.writeBytes(Hex.decodeHex(data.toCharArray())); out.writeByte(COMMAND); out.writeInt(0); // 预先写入frameLen int frameLenIndex = out.writerIndex(); // 这里不检验数据格式的正确性,上层要检查 // 开始写入items // 开始写入Device token out.writeByte(Item.DEVICE_TOKEN); out.writeShort(32); out.writeBytes(notification.getToken()); // 写入Payload out.writeByte(Item.PAYLOAD); out.writeShort(notification.getPayload().length); out.writeBytes(notification.getPayload()); // 写入Notification identifier out.writeByte(Item.NOTIFICATION_IDENTIFIER); out.writeShort(4); out.writeInt(notification.getId()); // 写入Expiration date out.writeByte(Item.EXPIRATION_DATE); out.writeShort(4); Date expirationDate = notification.getExpirationDate(); if (expirationDate == null) { out.writeInt(0); } else { out.writeInt((int) (expirationDate.getTime() / 1000)); } // 写入Priority out.writeByte(Item.PRIORITY); out.writeShort(1); out.writeByte(notification.getPriority()); // 回退到该写入frameLen的位置,写入frameLen,再重新设置write index int currentWriteIndex = out.writerIndex(); out.writerIndex(1); // 因为command后面就是len,而command是1 byte。 out.writeInt(currentWriteIndex - frameLenIndex); out.writerIndex(currentWriteIndex); } }
捐助开发者
在兴趣的驱动下,写一个免费
的东西,有欣喜,也还有汗水,希望你喜欢我的作品,同时也能支持一下。 当然,有钱捧个钱场(支持支付宝和微信捐助,加入it技术扣扣群),没钱捧个人场,谢谢各位。
谢谢您的赞助,我会做的更好!
相关推荐
IOS APNS 官方开发文档 英文版本
Java APNS推送消息 HTTP/2协议, 基于JDK 11及以上
ios APNS推送服务器php核心代码pushMe
关于IOS_APNS推送消息(iphone端+服务端)。关于IOS_APNS推送消息(iphone端+服务端)。
java依赖+整合代码工具类示例
iOS创建apns证书步骤
APNS推送php推送服务器代码 iOS
Apple APNs java client, based on netty4. 基于netty4实现的苹果通知推送服务Java客户端。 特点: 支持第三版通知推送,即command = 2。目前的绝大部分Java客户端都只支持command = 1,即第二版。 ...
使用Nodejs调试iOS的APNS通知推送,如此简单。Use Node.js language test iOS apns pusn
服务端为Java时编写发送Push通知的示例,引用第三方库javapns
java(后台) ios 推送(APNS) 源码+支持jar包,代码经测试没问题,包含4个jar包:javaAPNS2.2、log4j、org.bouncycastle.jce1.39.0、apache.common.lang所属包
自己用java实现苹果的apns推送,调用压缩包的text文件里面的方法即可
java apns推送示例,基于http/2亲测有效
Java Apns 服务器演示
iOS苹果推送apns测试工具
最新的生成ios推送pem文件的步骤 如果有需求的可以下载看看,只要按照步骤写一定没有问题。
IOS推送APNS必须的三个包 做服务器必备,使用教程http://blog.csdn.net/maple1320/article/details/24260513
java实现苹果推送 里面有两个方法实现推送
java-apns是Apple推送通知服务(APN)的Java客户端。 该库旨在为Apple服务器提供高度可扩展的界面,同时仍保持简单和模块化。 该接口旨在仅需很少的代码即可实现最常见的情况,但可对其进行重新配置,因此如有必要...
IOS开发消息推送 APNS python 源码, 纯自己实现协议, 无需安装额外库 代码简洁, 用户可以自己随意修改使用, 无需安装其他库, 直接发消息, 指定自己的证书即可. 找了很多代码,都不好使, 自己写的