APNs的学习和使用

APNs的学习和使用

    
APNs(英文全称:Apple Push Notification service),中文翻译为:苹果推送通知服务。 该技术由 苹果公司提供的APNs服务。
苹果推送通知服务的传输和路由的通知从一个给定的供应商给定的设备。通知是由两个主要部分组成的数据:设备令牌和有效载荷的短消息。设备令牌是类似于一个电话号码,它包含的信息,使的APN定位的设备上安装客户端应用程序。APN还用它来验证通知的 路由有效载荷是一个JSON定义的属性列表中指定的设备上的应用程序的用户将被提醒。

    APNs在java的使用,这篇文章非常有效

APNs入门学习和使用

https://www.jianshu.com/p/bcdf0c609f7d

作者:Coselding

基本对着这个就能写出基本的APNs实例,本文主要讨论代码编写过程中出现的问题

    1.java.lang.NoClassDefFoundError: sun/security/ssl/EllipticCurvesExtension

假如你已经加了java虚拟机参数


里面的alpn-boot-8.1.12.v20180117.jar是用来替换虚拟机中的jar包的,这时候出了异常,异常信息可能如下:


     
     
  1. [nioEventLoopGroup-2-1] WARN io.netty.handler.ssl.ApplicationProtocolNegotiationHandler - [id: 0x548cffb1, L://*你的ip*/:11364 - R:api.development.push.apple.com/17.188.166.29:443] Failed to select the application-level protocol:
  2. java.lang.NoClassDefFoundError: sun/security/ssl/EllipticCurvesExtension
  3. at sun.security.ssl.ClientHandshaker.getKickstartMessage(ClientHandshaker.java:1526)
  4. at sun.security.ssl.Handshaker.kickstart(Handshaker.java:1061)
  5. at sun.security.ssl.SSLEngineImpl.kickstartHandshake(SSLEngineImpl.java:734)
  6. at sun.security.ssl.SSLEngineImpl.beginHandshake(SSLEngineImpl.java:756)
  7. at io.netty.handler.ssl.JdkSslEngine.beginHandshake(JdkSslEngine.java:147)
  8. at io.netty.handler.ssl.SslHandler.handshake(SslHandler.java:1360)
  9. at io.netty.handler.ssl.SslHandler.channelActive(SslHandler.java:1399)
  10. at io.netty.channel.AbstractChannelHandlerContext.invokeChannelActive(AbstractChannelHandlerContext.java:223)
  11. at io.netty.channel.AbstractChannelHandlerContext.invokeChannelActive(AbstractChannelHandlerContext.java:209)
  12. at io.netty.channel.AbstractChannelHandlerContext.fireChannelActive(AbstractChannelHandlerContext.java:202)
  13. at io.netty.channel.DefaultChannelPipeline$HeadContext.channelActive(DefaultChannelPipeline.java:1322)
  14. at io.netty.channel.AbstractChannelHandlerContext.invokeChannelActive(AbstractChannelHandlerContext.java:223)
  15. at io.netty.channel.AbstractChannelHandlerContext.invokeChannelActive(AbstractChannelHandlerContext.java:209)
  16. at io.netty.channel.DefaultChannelPipeline.fireChannelActive(DefaultChannelPipeline.java:902)
  17. at io.netty.channel.nio.AbstractNioChannel$AbstractNioUnsafe.fulfillConnectPromise(AbstractNioChannel.java:311)
  18. at io.netty.channel.nio.AbstractNioChannel$AbstractNioUnsafe.finishConnect(AbstractNioChannel.java:341)
  19. at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:627)
  20. at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:551)
  21. at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:465)
  22. at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:437)
  23. at io.netty.util.concurrent.SingleThreadEventExecutor$5.run(SingleThreadEventExecutor.java:873)
  24. at io.netty.util.concurrent.DefaultThreadFactory$DefaultRunnableDecorator.run(DefaultThreadFactory.java:144)
  25. at java.lang.Thread.run(Thread.java:748)
  26. [nioEventLoopGroup-2-1] INFO com.relayrides.pushy.apns.ApnsClient - Failed to connect.
  27. java.lang.IllegalStateException: Channel closed before HTTP/2 preface completed.
  28. at com.relayrides.pushy.apns.ApnsClient$2.operationComplete(ApnsClient.java:412)
  29. at com.relayrides.pushy.apns.ApnsClient$2.operationComplete(ApnsClient.java:404)
  30. at io.netty.util.concurrent.DefaultPromise.notifyListener0(DefaultPromise.java:514)
  31. at io.netty.util.concurrent.DefaultPromise.notifyListenersNow(DefaultPromise.java:488)
  32. at io.netty.util.concurrent.DefaultPromise.notifyListeners(DefaultPromise.java:427)
  33. at io.netty.util.concurrent.DefaultPromise.trySuccess(DefaultPromise.java:111)
  34. at io.netty.channel.DefaultChannelPromise.trySuccess(DefaultChannelPromise.java:82)
  35. at io.netty.channel.AbstractChannel$CloseFuture.setClosed(AbstractChannel.java:1058)
  36. at io.netty.channel.AbstractChannel$AbstractUnsafe.doClose0(AbstractChannel.java:686)
  37. at io.netty.channel.AbstractChannel$AbstractUnsafe.close(AbstractChannel.java:664)
  38. at io.netty.channel.AbstractChannel$AbstractUnsafe.close(AbstractChannel.java:607)
  39. at io.netty.channel.DefaultChannelPipeline$HeadContext.close(DefaultChannelPipeline.java:1276)
  40. at io.netty.channel.AbstractChannelHandlerContext.invokeClose(AbstractChannelHandlerContext.java:634)
  41. at io.netty.channel.AbstractChannelHandlerContext.close(AbstractChannelHandlerContext.java:618)
  42. at io.netty.channel.ChannelOutboundHandlerAdapter.close(ChannelOutboundHandlerAdapter.java:71)
  43. at io.netty.channel.AbstractChannelHandlerContext.invokeClose(AbstractChannelHandlerContext.java:634)
  44. at io.netty.channel.AbstractChannelHandlerContext.close(AbstractChannelHandlerContext.java:618)
  45. at io.netty.handler.ssl.SslHandler$8.operationComplete(SslHandler.java:1437)
  46. at io.netty.handler.ssl.SslHandler$8.operationComplete(SslHandler.java:1428)
  47. at io.netty.util.concurrent.DefaultPromise.notifyListener0(DefaultPromise.java:514)
  48. at io.netty.util.concurrent.DefaultPromise.notifyListenersNow(DefaultPromise.java:488)
  49. at io.netty.util.concurrent.DefaultPromise.notifyListeners(DefaultPromise.java:427)
  50. at io.netty.util.concurrent.DefaultPromise.addListener(DefaultPromise.java:170)
  51. at io.netty.channel.DefaultChannelPromise.addListener(DefaultChannelPromise.java:93)
  52. at io.netty.channel.DefaultChannelPromise.addListener(DefaultChannelPromise.java:28)
  53. at io.netty.handler.ssl.SslHandler.safeClose(SslHandler.java:1428)
  54. at io.netty.handler.ssl.SslHandler.closeOutboundAndChannel(SslHandler.java:1259)
  55. at io.netty.handler.ssl.SslHandler.close(SslHandler.java:449)
  56. at io.netty.channel.AbstractChannelHandlerContext.invokeClose(AbstractChannelHandlerContext.java:634)
  57. at io.netty.channel.AbstractChannelHandlerContext.close(AbstractChannelHandlerContext.java:618)
  58. at io.netty.channel.AbstractChannelHandlerContext.close(AbstractChannelHandlerContext.java:475)
  59. at io.netty.handler.ssl.ApplicationProtocolNegotiationHandler.exceptionCaught(ApplicationProtocolNegotiationHandler.java:122)
  60. at io.netty.channel.AbstractChannelHandlerContext.invokeExceptionCaught(AbstractChannelHandlerContext.java:295)
  61. at io.netty.channel.AbstractChannelHandlerContext.invokeExceptionCaught(AbstractChannelHandlerContext.java:274)
  62. at io.netty.channel.AbstractChannelHandlerContext.fireExceptionCaught(AbstractChannelHandlerContext.java:266)
  63. at io.netty.handler.ssl.SslHandler.exceptionCaught(SslHandler.java:743)
  64. at io.netty.channel.AbstractChannelHandlerContext.invokeExceptionCaught(AbstractChannelHandlerContext.java:295)
  65. at io.netty.channel.AbstractChannelHandlerContext.notifyHandlerException(AbstractChannelHandlerContext.java:862)
  66. at io.netty.channel.AbstractChannelHandlerContext.invokeChannelActive(AbstractChannelHandlerContext.java:225)
  67. at io.netty.channel.AbstractChannelHandlerContext.invokeChannelActive(AbstractChannelHandlerContext.java:209)
  68. at io.netty.channel.AbstractChannelHandlerContext.fireChannelActive(AbstractChannelHandlerContext.java:202)
  69. at io.netty.channel.DefaultChannelPipeline$HeadContext.channelActive(DefaultChannelPipeline.java:1322)
  70. at io.netty.channel.AbstractChannelHandlerContext.invokeChannelActive(AbstractChannelHandlerContext.java:223)
  71. at io.netty.channel.AbstractChannelHandlerContext.invokeChannelActive(AbstractChannelHandlerContext.java:209)
  72. at io.netty.channel.DefaultChannelPipeline.fireChannelActive(DefaultChannelPipeline.java:902)
  73. at io.netty.channel.nio.AbstractNioChannel$AbstractNioUnsafe.fulfillConnectPromise(AbstractNioChannel.java:311)
  74. at io.netty.channel.nio.AbstractNioChannel$AbstractNioUnsafe.finishConnect(AbstractNioChannel.java:341)
  75. at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:627)
  76. at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:551)
  77. at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:465)
  78. at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:437)
  79. at io.netty.util.concurrent.SingleThreadEventExecutor$5.run(SingleThreadEventExecutor.java:873)
  80. at io.netty.util.concurrent.DefaultThreadFactory$DefaultRunnableDecorator.run(DefaultThreadFactory.java:144)
  81. at java.lang.Thread.run(Thread.java:748)
  82. [nioEventLoopGroup-2-1] WARN io.netty.handler.ssl.ApplicationProtocolNegotiationHandler - [id: 0x548cffb1, L:/192.168.2.71:11364 ! R:api.development.push.apple.com/17.188.166.29:443] TLS handshake failed:
  83. java.nio.channels.ClosedChannelException
  84. at io.netty.handler.ssl.SslHandler.channelInactive(...)(Unknown Source)

每个alpn-boot包都对应一个单独的jdk版本,并且严格对照版本,因此需要找到对应jdk版本的包,下面是包与jdk的对照表:


具体参照https://www.eclipse.org/jetty/documentation/current/alpn-chapter.html

看网上说用

jetty-alpn-agent-2.0.6.jar  
可以自动选择与jdk版本对应的包

2.slf4报错

pushy依赖于slf4j-api的包,但是并没有slf4j的具体实现,因此会出现如下错误:


     
     
  1. SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
  2. SLF4J: Defaulting to no-operation (NOP) logger implementation
  3. SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.

这时只需要添加slf4j-simple的依赖就可以了


     
     
  1. <dependency>
  2. <groupId>org.slf4j </groupId>
  3. <artifactId>slf4j-simple </artifactId>
  4. <version>1.7.25 </version>
  5. </dependency>

3.消息发送阻塞

	final Future<PushNotificationResponse<SimpleApnsPushNotification>> sendNotificationFuture = apnsClient.sendNotification(pushNotification);
     
     
final PushNotificationResponse<SimpleApnsPushNotification> pushNotificationResponse = future.get();

     
     

如果有多条消息发送,在下一条消息发送之前,只能等上一条消息发送之后得到响应才能发送下一条消息,这无疑是相当耗费时间的,如果想并行的发送消息,就是其他文章说的异步回调方式,可以用:

final PushNotificationResponse<SimpleApnsPushNotification> pushNotificationResponse = future.getNow();
     
     
这样的话不用等消息发送后得到响应才发送下一条消息了


贴一下项目代码


     
     
  1. import java.io.File;
  2. import java.io.IOException;
  3. import java.util.ArrayList;
  4. import java.util.List;
  5. import java.util.concurrent.TimeUnit;
  6. import javax.net.ssl.SSLException;
  7. import com.relayrides.pushy.apns.ApnsClient;
  8. import com.relayrides.pushy.apns.ApnsClientBuilder;
  9. import com.relayrides.pushy.apns.PushNotificationResponse;
  10. import com.relayrides.pushy.apns.util.ApnsPayloadBuilder;
  11. import com.relayrides.pushy.apns.util.SimpleApnsPushNotification;
  12. import com.relayrides.pushy.apns.util.TokenUtil;
  13. import io.netty.channel.EventLoopGroup;
  14. import io.netty.channel.nio.NioEventLoopGroup;
  15. import io.netty.util.concurrent.Future;
  16. import io.netty.util.concurrent.GenericFutureListener;
  17. public class MyApnsClient {
  18. static ApnsClient apnsClient;
  19. /*
  20. * static URL url = MyApnsClient.class.getClassLoader().getResource("dev.p12");
  21. * static File file = new File(url.getFile());
  22. */
  23. public static void main(String[] args) {
  24. try {
  25. //并行线程数
  26. EventLoopGroup loopGroup = new NioEventLoopGroup(4);
  27. //建立apns的客户端,可添加自己写的监听类,实现ApnsClientMetricsListener接口
  28. apnsClient = new ApnsClientBuilder().setEventLoopGroup(loopGroup)
  29. .setMetricsListener(new MyApnsClientListener())
  30. .setClientCredentials(new File("G:\\path\\test.p12"), "123456").build();
  31. //设置apns服务器host
  32. final Future <Void> connectFuture = apnsClient.connect(ApnsClient.DEVELOPMENT_APNS_HOST);
  33. // 设置等待时间,可抛出中断异常
  34. connectFuture.await();
  35. //connectFuture.await(10, TimeUnit.MINUTES);
  36. List <SimpleApnsPushNotification> pushNotifications=new ArrayList <SimpleApnsPushNotification>();
  37. for(int i=0;i <10;i++) {
  38. final SimpleApnsPushNotification pushNotification;
  39. {
  40. //消息的载体
  41. final ApnsPayloadBuilder payloadBuilder = new ApnsPayloadBuilder();
  42. payloadBuilder.setAlertBody("hello world");
  43. payloadBuilder.setSoundFileName("system_sing.mp3");
  44. payloadBuilder.setBadgeNumber(1);
  45. payloadBuilder.setContentAvailable(true);
  46. final String payload = payloadBuilder.buildWithDefaultMaximumLength();
  47. //设备的唯一标识号devicetoken
  48. final String token = TokenUtil
  49. .sanitizeTokenString("your device token");
  50. pushNotification = new SimpleApnsPushNotification(token, null, payload);
  51. }
  52. pushNotifications.add(pushNotification);
  53. }
  54. for(SimpleApnsPushNotification pushNotification:pushNotifications) {
  55. //发送信息得到回应的实例,是异步的,会立马创建一个实例,但可能是发送未成功的状态
  56. final Future<PushNotificationResponse<SimpleApnsPushNotification>> sendNotificationFuture = apnsClient
  57. .sendNotification(pushNotification);
  58. sendNotificationFuture.addListener(
  59. new GenericFutureListener <Future<PushNotificationResponse<SimpleApnsPushNotification>>>() {
  60. @Override
  61. public void operationComplete(
  62. Future <PushNotificationResponse<SimpleApnsPushNotification>> future) throws Exception {
  63. final PushNotificationResponse <SimpleApnsPushNotification> pushNotificationResponse = future
  64. .getNow();
  65. if (pushNotificationResponse.isAccepted()) {
  66. System.out.println("Push notification accepted by APNs gateway.");
  67. } else {
  68. System.out.println("Notification rejected by the APNs gateway: "
  69. + pushNotificationResponse.getRejectionReason());
  70. if (pushNotificationResponse.getTokenInvalidationTimestamp() != null) {
  71. System.out.println("\t…and the token is invalid as of "
  72. + pushNotificationResponse.getTokenInvalidationTimestamp());
  73. }
  74. }
  75. }
  76. });
  77. }
  78. final Future <Void> disconnectFuture = apnsClient.disconnect();
  79. try {
  80. disconnectFuture.await();
  81. if (disconnectFuture.isSuccess()) {
  82. System.out.println("连接关闭");
  83. }
  84. } catch (InterruptedException e) {
  85. System.out.println("Failed to disconnect APNs , timeout");
  86. e.printStackTrace();
  87. }
  88. } catch (SSLException e) {
  89. e.printStackTrace();
  90. } catch (IOException e) {
  91. e.printStackTrace();
  92. } catch (InterruptedException e) {
  93. System.out.println("Failed to connect APNs , timeout");
  94. e.printStackTrace();
  95. } /*
  96. * catch (ExecutionException e) {
  97. * System.err.println("Failed to send push notification."); if (e.getCause()
  98. * instanceof ClientNotConnectedException) {
  99. * System.out.println("Waiting for client to reconnect…"); try {
  100. * apnsClient.getReconnectionFuture().await(); } catch (InterruptedException e1)
  101. * { System.out.println("Failed to connect APNs , timeout");
  102. * e1.printStackTrace(); } System.out.println("Reconnected."); }
  103. * e.printStackTrace(); }
  104. */
  105. }
  106. }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值