Install apns2
masterTo install the apns2 package, ensure you have Go installed and your GOPATH set, then run:
go get -u github.com/sideshow/apns2repository·master·Indexed 25 days ago
https://github.com/sideshow/apns2A Go package for sending Apple Push Notifications (iOS, OSX, Safari) using the HTTP/2 protocol. It supports certificate-based (.p12, .pem) and JWT token-based (.p8) authentication, providing a ClientManager for connection pooling and a payload builder for structured notifications. The library supports various push types including alert, background, location, VoIP, and Live Activities.
To install the apns2 package, ensure you have Go installed and your GOPATH set, then run:
go get -u github.com/sideshow/apns2To achieve high throughput:
apns2.Client for every push. The TLS handshake is expensive. Hold onto a single client instance to leverage the underlying connection pool.You can create an APNs client using two different authentication methods:
NewClient(certificate tls.Certificate) when you have a .p12 or .pem certificate.NewTokenClient(token *token.Token) when using a JWT token.Important: As per Apple's API guidelines, you should keep a single handle on the Client and reuse it across multiple notifications. Do not repeatedly open and close connections, as APNs may treat rapid connection/disconnection as a DoS attack.
You can authenticate with Apple using a .p12 or .pem certificate. Use certificate.FromP12File to load your certificate and apns2.NewClient(cert) to create a client. You must specify whether to use .Development() or .Production() environments.
package main
import (
"log"
"fmt"
"github.com/sideshow/apns2"
"github.com/sideshow/apns2/certificate"
)
func main() {
cert, err := certificate.FromP12File("../cert.p12", "")
if err != nil {
log.Fatal("Cert Error:", err)
}
notification := &apns2.Notification{}
notification.DeviceToken = "11aa01229f15f0f0c52029d8cf8cd0aeaf2365fe4cebc4af26cd6d76b7919ef7"
notification.Topic = "com.sideshow.Apns2"
notification.Payload = []byte(`{"aps":{"alert":"Hello!"}}`)
// Use .Development() for Xcode builds, .Production() for App Store/Ad-hoc
client := apns2.NewClient(cert).Production()
res, err := client.Push(notification)
if err != nil {
log.Fatal("Error:", err)
}
fmt.Printf("%v %v %v\n", res.StatusCode, res.ApnsID, res.Reason)
}Instead of certificates, you can use Apple's Token Based Authentication (JWT). This requires a .p8 signing key, a KeyID, and a TeamID from your Apple developer account. Use apns2.NewTokenClient(token) to create the client. JWT keys work for both development and production environments and do not expire.
authKey, err := token.AuthKeyFromFile("../AuthKey_XXX.p8")
if err != nil {
log.Fatal("token error:", err)
}
token := &token.Token{
AuthKey: authKey,
// KeyID from developer account
KeyID: "ABC123DEFG",
// TeamID from developer account
TeamID: "DEF123GHIJ",
}
client := apns2.NewTokenClient(token)
res, err := client.Push(notification)While you can use raw bytes for notification.Payload, you can also use the payload package to build structured APNs payloads easily.
// Result: {"aps":{"alert":"hello","badge":1},"key":"val"}
payload := payload.NewPayload().Alert("hello").Badge(1).Custom("key", "val")
notification.Payload = payload
client.Push(notification)The Push method returns both a Response and an error.
error: Returned for unrecoverable issues (e.g., connection problems, certificate errors, or if the payload was never sent).Response: Returned if the payload was successfully sent to Apple. Use res.Sent() to check if the notification was accepted by Apple.res, err := client.Push(notification)
if err != nil {
log.Println("There was an error", err)
return
}
if res.Sent() {
log.Println("Sent:", res.ApnsID)
} else {
fmt.Printf("Not Sent: %v %v %v\n", res.StatusCode, res.ApnsID, res.Reason)
}A Notification requires three minimum fields: DeviceToken, Topic, and Payload.
Optional fields include:
ApnsID: A unique identifier.Expiration: A time.Time value.Priority: Set using apns2.PriorityLow or other priority constants.notification := &apns2.Notification{
DeviceToken: "11aa01229f15f0f0c52029d8cf8cd0aeaf2365fe4cebc4af26cd6d76b7919ef7",
Topic: "com.sideshow.Apns2",
Payload: []byte(`{"aps":{"alert":"Hello!"}}`),
}
notification.ApnsID = "40636A2C-C093-493E-936A-2A4333C06DEA"
notification.Expiration = time.Now()
notification.Priority = apns2.PriorityLowTo control request cancellations and timeouts, use PushWithContext(ctx, notification) instead of Push. This allows you to cancel all pushes when a parent process is cancelled or to set fine-grained timeouts for individual pushes.
ctx, cancel = context.WithTimeout(context.Background(), 10 * time.Second)
res, err := client.PushWithContext(ctx, notification)
defer cancel()You can customize the behavior of the ClientManager by setting the following fields:
MaxSize: The maximum number of clients allowed. When this limit is reached, the least recently used client is evicted. Set to 0 for no limit.MaxAge: The maximum duration a client can remain unused in the manager. If a client is retrieved after this duration, it is evicted and a new one is created via the Factory. Set to 0 to disable age-based eviction.Factory: A function used to construct clients if they are not found in the manager. It must accept a tls.Certificate and return a *Client.The apns2 CLI tool allows you to send notifications via STDIN.
Installation:
go get github.com/sideshow/apns2/apns2Usage:
apns2 --certificate-path=CERTIFICATE-PATH --topic=TOPIC [<flags>]
Input Format:
<DeviceToken> <APNS Payload>
Example:
aff0c63d9eaa63ad161bafee732d5bc2c31f66d552054718ff19ce314371e5d0 {"aps": {"alert": "hi"}}
Flags:
-c, --certificate-path=CERTIFICATE-PATH: Path to certificate file.-t, --topic=TOPIC: The topic (usually the app bundle ID).-m, --mode="production": APNS server (production or development). Defaults to production.--help: Show help.To send a notification to a device, use the Push or PushWithContext methods.
Push(n *Notification): Sends a notification using context.Background().PushWithContext(ctx Context, n *Notification): Sends a notification with a specific context, allowing for custom timeouts or cancellation signals.Both methods return a *Response indicating if the notification was accepted or rejected, or an error if the request failed.