I have a seemingly standard task of sending push notifications to Apple devices from a server written in Java. I have never done that in the past, so I went to tutorials and Apple documentation.
1) The APN Provider API claims that THE protocol to send push notifications from the server is HTTP/2. I failed to find any tutorials describing how to do so (I wanted those mostly as a sign that I'm not the first one to do that and maybe for references to the most popular tools/libraries). I found several tutorials (Ray Wenderlich tutorial probably being the most cited) that teach how to send push notifications using the binary protocol. Most GitHub projects use it as well (e.g. a "push notification simulator kit from a Ray Wenderlich tutorial", a popular "pushmeup" ruby gem, a very popular notnoop/java-apns library and so on). Now, the Apple docs have a section for binary provider API which states that
The legacy binary interface required your provider server to employ the binary API described in this appendix. All developers should migrate their remote notification provider servers to the more capable and more efficient HTTP/2-based API described in APNs Provider API.
This definitely sounds like I shouldn't be using the binary API for new development... Even more so since the binary API requires usage (periodic polling) of a separate Feedback service for "dead" device tokens (or else you might be blocked they say), while the new HTTP/2 API gives this information as a response to each individual request, which looks like less moving parts.
As for the HTTP/2, there is a Java library CleverTap/apns-http2 which is even relatively popular, but it uses Jetty HTTP/2 client, and for it to work one needs to start JVM with an ALPN jar on the boot classpath, and that jar corresponds approximately 1-to-1 with JDK versions (which means that if your development uses 1.8.0u92 and your production uses 1.8.0u91 then there should be different jars put). That looks like a very brittle configuration to me in general and hard to apply in my case (each developer has his own VM + common dev VM + test server + prod) -- I don't think it's worth the effort to freeze one version on all of the machines and that these won't diverge with time; all I know is that all of them use JDK 8, but minor versions are out of my control. This need for the ALPN jar will be the case until JDK 9 is out (and adopted widely) which means 1+ year, and it is the case for Jetty and Netty and okhttp3 and I guess any Java library.
2) As if this was not enough, there are also two authentication schemes described by the Apple docs: using a certificate ("old style") vs using JWT. The certificate approach is tried-and-true, but from the docs it looks like the certificate should be regenerated every year while JWTs don't (or to be more precise JWTs are regenerated every hour automatically and so that will be baked into the application and hopefully won't require any manual administrative actions that can be forgotten etc.). The only problem with JWT for me is that
After you create the token, you must sign it with a private key as described in Creating a Universal Provider Token Signing Key in App Distribution Guide.
The problem is that there is no such section or title or anything in that guide. Perhaps this step is very simple, but not having any hands-on experience with iOS security in particular and little experience with cryptography in general I'm afraid I'll miss something here. I can ask our iOS developers for help but I'm not even sure this approach is mature enough if I can find zero working tutorials.
So, my questions finally are (pick any):
- Am I missing something and there is a way to follow Apple's guidelines and have the solution be reasonably simple?
- How likely is it that the binary protocol will be terminated "soon"?
- Should I choose the binary protocol or HTTP/2?
- If it's the latter, should I pursue using JWT or is using a certificate more practical?
- Maybe the situation (mostly with HTTP/2) is much better in some other languages/server platforms? I might even think about having a separate service just for sending iOS pushes done in that if that means jumping through less hoops.
Thank you, sorry for the lengthy text.