最近公司需要用苹果APNs实现类似微信视频接电话的效果,查看了苹果官网有VOIP这个东西,于是进行了研究开发。
首先总结一下接入流程:
- 在开发者中心申请对应的证书(推送证书,VOIP证书)
- IOS 注册推送到APNs(直接调用PushKit 的API即可),回掉中的DeviceToken发送到我们自己的服务端(服务端保存)
- 服务器通发送HTTP推送消息请求到APNs服务器。(这一步就是服务器发送推送消息)
- IOS接受推送并处理。
BiBi一句。研究任何一样东西首先查看官网资料,千万别怕英文,不知道的单词可以查,虽然我也是个英语小白。不懂的然后再网上搜索资料,这样有利于学习!
进入Setting Up a Remote Notification Server
可以看到整个APNs的工作流程。
下面基于“服务器通发送HTTP推送消息请求到APNs服务器”这一步进行开发。
-
推送消息描述如下图。大概意思就是App注册,服务端构建消息发送到APNs。认证的方式有两种:
1、基于Token。使用开发者中心申请的.p8文件和Key ID进行Token认证
2、基于推送证书,使用.p12证书认证
此处由于公司要求我们使用.p12文件进行开发。 -
使用pushy进行开发。使用最新包!结合官网进行开发。
<dependency>
<groupId>com.turo</groupId>
<artifactId>pushy</artifactId>
<version>0.13.10</version>
</dependency>
下面是我写的一个APNs的一个推送Demo。
@Slf4j
public class APNsUtils {
private static ApnsClient apnsClient = null;
public static void main(String[] args) throws Exception {
//IOS等终端设备注册后返回的DeviceToken
String deviceToken ="5d7cf67dd6ab56c6d699f86806682e7d99e019216df734f4c57196b84790b718";
// String deviceToken = "74abd7d51c58a8db995fa53c3508a72481a9d4ad56e7ed1f7d12362f798a6906";
/**
* Use the voip push type for notifications that provide information about an incoming Voice-over-IP (VoIP)
* call. For more information, see Responding to VoIP Notifications from PushKit.
* If you set this push type, the apns-topic header field must use your app’s bundle ID with .voip
* appended to the end. If you’re using certificate-based authentication,
* you must also register the certificate for VoIP services.
* The topic is then part of the 1.2.840.113635.100.6.3.4 or 1.2.840.113635.100.6.3.6 extension.
*/
//这是你的主题,大多数情况是bundleId,voip需要在bundleId加上.voip。对应文档中的apns-topic
//此处可以参考https://developer.apple.com/documentation/usernotifications/setting_up_a_remote_notification_server/sending_notification_requests_to_apns?language=objc
String topic = "com.voip.test.voip";
String payload = "{ \"aps\" : {\"alert\" : \"测试\", \"sound\" : \"default\", \"badge\" :1},\"liguoxin\":\"liguoxin\" }";
//有效时间
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 = 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<SimpleApnsPushNotification,PushNotificationResponse<SimpleApnsPushNotification>> future = getAPNSConnect().sendNotification(msg);
PushNotificationResponse<SimpleApnsPushNotification> 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 {
/**
* Development server: api.sandbox.push.apple.com:443
* Production server: api.push.apple.com:443
*
* api.development.push.apple.com这个域名苹果官网现在找不到了
*/
String SANDBOX_APNS_HOST = "api.sandbox.push.apple.com";
// /Users/liguoxin/Desktop/p12/deve_push.p12
// /Users/liguoxin/Desktop/p12/distri_push.p12
//四个线程
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(4).setEventLoopGroup(eventLoopGroup).build();
// EventLoopGroup eventLoopGroup = new NioEventLoopGroup(4);
// apnsClient = new ApnsClientBuilder().setApnsServer(ApnsClientBuilder.DEVELOPMENT_APNS_HOST)
// .setSigningKey(ApnsSigningKey.loadFromPkcs8File(new File("/Users/liguoxin/Desktop/p12/deve_push.p8"),
// "我的temid", "我的keyid"))
// .setConcurrentConnections(4).setEventLoopGroup(eventLoopGroup).build();
} catch (Exception e) {
log.error("ios get pushy apns client failed!");
e.printStackTrace();
}
}
return apnsClient;
}
}
推送结果如下,返回success为true,推送成功。现在查看手机已经收到消息了