本文共 7395 字,大约阅读时间需要 24 分钟。
这里主要从代码层面展示下,如何整合APNS。并用该demo进行远程消息的发送
参考资料:
后台服务连接APNS有两种方式----------------连接方式主要是用于安全连接,以及告诉APNS你是哪个APP.cuiyaonan2000@163.com
.p8 文件生成:登录开发者账号,进入Certificates, Identifiers & Profiles 面板,左侧菜单栏选中Keys ,点击右侧 + 号按钮,生成如图文件创建页面,,输入文件名,勾选APNs,点击continue,直到生成.p8文件
.p12 文件生成 : 在系统软件keychain 中,找到你的推送证书(开发的或者生产的),然后双击证书,弹出如图窗口,选择Export(导出)证书,选择存放的位置,就生成的.p12 文件
当创建了一个APNSClient实例之后,你就可以连接上APNs网关服务器可。
这个连接过程是异步的;client实例将会马上返回一个Future对象,但在你发送任何推送通知之前,你需要等待这个连接过程完成之后才能进行。-----------------------(这个就是响应式编程,我们在微服务中也会用到cuiyaonan2000@163.com)
请注意,这个对象是Netty框架中的,它是Java中的接口的一个拓展,它允许调用者添加监听器或添加methods来检测Future
的状态。
Future
对象,但在货值推送消息是被APNS网关服务器接受还是拒绝之前,还需要等待Future
过程完成。-------响应式编程
Future
对象的执行结果会有以下三种情形:
Future
对象因为一些未知异常而执行失败,这通常是在某种特定情况下的暂时性的失败,调用者应该在问题解决之后对这个推送通知进行重新地投递发送。但如果是在这种情况下投递失败,调用者应该通过调用阻塞方法来返回一个Future
对象,这个过程其实是在连接断开之后进行自动重连。---------------------------该阻塞方法同时也用于异常出现的格式化返回,比如返回一个错误的自定义信息,以及详细的内容
在实际应用场景中,去等待对每个特定设备的阻塞推送,效率是极其低的。而在Future
中添加一个监听器,在推送完成之后回调这个监听器的方法,和阻塞等待每个推送完成这种方式相比起来,显然能够提供更高效的高并发服务。
APNs协议是基于的一套推送协议。HTTP/2是一套相对新的协议,以至于它的发展还没有延伸拓展到Java世界中。例如以下几点:
通常来说,原生的SSL provider是满足HTTP/2对系统性能增强要求的最好方法,因为安装是相当简单的,并且它运行在Java 7以上版本通常能够提供比JDK的SSL provider更好的SSL执行性能。
官方网址:
p12连接
final ApnsClient apnsClient = new ApnsClientBuilder() .setApnsServer(ApnsClientBuilder.DEVELOPMENT_APNS_HOST) .setClientCredentials(new File("/path/to/certificate.p12"), "p12-file-password") .build();
p8连接
final ApnsClient apnsClient = new ApnsClientBuilder() .setApnsServer(ApnsClientBuilder.DEVELOPMENT_APNS_HOST) .setSigningKey(ApnsSigningKey.loadFromPkcs8File(new File("/path/to/key.p8"), "TEAMID1234", "KEYID67890")) .build();
如下我们不用自己拼接json,可以使用pushy的工具,当然也可以自己拼接json
final SimpleApnsPushNotification pushNotification;{ final ApnsPayloadBuilder payloadBuilder = new SimpleApnsPayloadBuilder(); payloadBuilder.setAlertBody("Example!"); final String payload = payloadBuilder.build(); final String token = TokenUtil.sanitizeTokenString(""); pushNotification = new SimpleApnsPushNotification(token, "com.example.myApp", payload);}
如下两个合并着看,然后自己多试试
如下的代码示例包含,1发送消息 2获取future 3对future进行控制 4对future进行监听 很重要哦cuiyaonan2000@163.com
//发送消息回复返回值final PushNotificationFuture> sendNotificationFuture = apnsClient.sendNotification(pushNotification);//对返回值进行处理控制try { final PushNotificationResponse pushNotificationResponse = sendNotificationFuture.get(); if (pushNotificationResponse.isAccepted()) { System.out.println("Push notification accepted by APNs gateway."); } else { System.out.println("Notification rejected by the APNs gateway: " + pushNotificationResponse.getRejectionReason()); pushNotificationResponse.getTokenInvalidationTimestamp().ifPresent(timestamp -> { System.out.println("\t…and the token is invalid as of " + timestamp); }); }} catch (final ExecutionException e) { System.err.println("Failed to send push notification."); e.printStackTrace();}//监听--用以提高效率sendNotificationFuture.whenComplete((response, cause) -> { if (response != null) { // Handle the push notification response as before from here. } else { // Something went wrong when trying to send the notification to the // APNs server. Note that this is distinct from a rejection from // the server, and indicates that something went wrong when actually // sending the notification or waiting for a reply. cause.printStackTrace(); }});
package cui.yao.nan.apns;import java.io.File;import java.util.Date;import java.util.UUID;import com.turo.pushy.apns.ApnsClient;import com.turo.pushy.apns.ApnsClientBuilder;import com.turo.pushy.apns.DeliveryPriority;import com.turo.pushy.apns.PushNotificationResponse;import com.turo.pushy.apns.PushType;import com.turo.pushy.apns.util.SimpleApnsPushNotification;import com.turo.pushy.apns.util.concurrent.PushNotificationFuture;import io.netty.channel.EventLoopGroup;import io.netty.channel.nio.NioEventLoopGroup;public class APNsUtils { private static ApnsClient apnsClient = null; public static void main(String[] args) throws Exception { // IOS等终端设备注册后返回的DeviceToken String deviceToken = "5d7cf67dd6ab56c6d699f86806682e7d99e019216df734f4c57196b84790b718"; // 这是你的主题,大多数情况是bundleId,voip需要在bundleId加上.voip。对应文档中的apns-topic // 代表app签名的topic String topic = "com.voip.test.voip"; String payload = "{ \"aps\" : {\"alert\" : \"测试\", \"sound\" : \"default\", \"badge\" :1},\"cuiyaonan2000\":\"cuiyaonan2000\" }"; // 有效时间 Date invalidationTime = new Date(System.currentTimeMillis() + 60 * 60 * 1000L); // 发送策略 apns-priority 10为立即 5为省电 DeliveryPriority priority = DeliveryPriority.IMMEDIATE; // 推送方式,主要有alert,background,voip,complication,fileprovider,mdm PushType pushType = PushType.VOIP; // 推送的合并ID,相同的 apns-collapse-id会在App中合并 String collapseId = UUID.randomUUID().toString(); // apnsId 唯一标示,如果不传,APNs会给我们生成一个 UUID apnsId = UUID.randomUUID(); // 构造一个APNs的推送消息实体 SimpleApnsPushNotification msg = new SimpleApnsPushNotification(deviceToken, topic, payload, invalidationTime, priority, pushType, collapseId, apnsId); // 开始推送 PushNotificationFuture> future = getAPNSConnect() .sendNotification(msg); PushNotificationResponse response = future.get(); System.out.println(response.getRejectionReason()); // 如果返回的消息中success为true那么成功,否则失败! // 如果失败不必惊慌,rejectionReason字段中会有失败的原因。对应官网找到原因即可 // https://developer.apple.com/documentation/usernotifications/setting_up_a_remote_notification_server/handling_notification_responses_from_apns?language=objc System.out.println("------------->" + response); } public static ApnsClient getAPNSConnect() { if (apnsClient == null) { try { // 四个线程 EventLoopGroup eventLoopGroup = new NioEventLoopGroup(4); apnsClient = new ApnsClientBuilder().setApnsServer(ApnsClientBuilder.DEVELOPMENT_APNS_HOST) .setClientCredentials(new File("/Users/liguoxin/Desktop/p12/distri_push.p12"), "111111") //setConcurrentConnections用于设置服务器与苹果服务器建立几个链接通道,这里是建立了四个,链接通道并不是越多越好的,具体速度自己百度 .setConcurrentConnections(4) //setEventLoopGroup的作用是建立几个线程来处理,说白了就是多线程,我这里设置的都是4,相当于16个线程同时处理。 .setEventLoopGroup(eventLoopGroup).build(); } catch (Exception e) { e.printStackTrace(); } } return apnsClient; }}