最近公司需要用蘋果APNs實作類似微信視訊接電話的效果,檢視了蘋果官網有VOIP這個東西,于是進行了研究開發。
首先總結一下接入流程:
- 在開發者中心申請對應的證書(推送證書,VOIP證書)
- IOS 注冊推送到APNs(直接調用PushKit 的API即可),回掉中的DeviceToken發送到我們自己的服務端(服務端儲存)
- 伺服器通發送HTTP推送消息請求到APNs伺服器。(這一步就是伺服器發送推送消息)
- IOS接受推送并處理。
BiBi一句。研究任何一樣東西首先檢視官網資料,千萬别怕英文,不知道的單詞可以查,雖然我也是個英語小白。不懂的然後再網上搜尋資料,這樣有利于學習!
蘋果開發者中心推送PushKit文檔
進入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,推送成功。現在檢視手機已經收到消息了