iOS Push notification client written in Golang
Sending push notification to iOS device is easy and simple using to APNs Provider API. We can create golang notification client which is only needed dozens of lines and it can send notification as a test.
Environment
- Golang 1.9
Create JWT
JWT(JSON Web Token) is token that contains URL Safe JSON structure and can digitally sign it. The APNs Provider API provides iOS Push notification service and its connection is using JWT. Thanks for very useful library jwt-go,
we can easily create JWT. It constructed by three parts Header
, Payload
and Signature
. Header consists of alg
which is hashing algorithm and kid
which is key ID of p8 file downloaded from Apple developer console. Payload has two value iat
, iss
. iat
is time of token created and format is UTC. iss
is team ID getted from Apple developer console. Signature
is the parts of combined encoded header and payload. Allowed hashing algorithm is only ES256 and sign heaer and payload using readed private key from readPrivateKey()
.
func readPrivateKey() (*ecdsa.PrivateKey, error) {
file, err := ioutil.ReadFile("YOUR p8 FILE PATH")
if err != nil {
return nil, err
}
block, _ := pem.Decode(file)
key, err := x509.ParsePKCS8PrivateKey(block.Bytes)
if err != nil {
return nil, err
}
if privateKey, ok := key.(*ecdsa.PrivateKey); ok {
return privateKey, nil
}
return nil, errors.New("")
}
func CreateJWT(privateKey *ecdsa.PrivateKey) (string, error) {
token := jwt.NewWithClaims(
jwt.SigningMethodES256,
jwt.MapClaims{
"iat": time.Now().Unix(),
"iss": "YOUR TEAM ID",
})
token.Header["alg"] = "ES256"
token.Header["kid"] = "YOUR KEY ID"
s, err := token.SignedString(privateKey)
if err != nil {
return "", err
}
return s, nil
}
Send request
After creating JWT, all we need is setup HTTP request conform to document of APNs. Setup payload, header and url correctly, we can send push notification to your device and if you failed to send it, there are wrong in configure. Please fix it base on the response.
func SampleRequest() {
jwtToken, err := CreateJWT()
if err != nil {
fmt.Println(err)
return
}
deviceToken := "YOUR DEVICE TOKEN"
header := map[string][]string{
"authorization": {fmt.Sprintf("bearer %s", jwtToken)},
"apns-topic": {"YOUR TOPIC"},
}
payload := []byte(`{"aps": {"alert": {"title": "title", "body": "body"}}}`)
// develop
urlString := "https://api.development.push.apple.com:443"
// production
//urlString = "https://api.push.apple.com:443"
URL := fmt.Sprintf("%s/3/device/%s", urlString, deviceToken)
req, err := http.NewRequest("POST", URL, bytes.NewReader(payload))
if err != nil {
fmt.Println(err)
return
}
req.Header = header
if err != nil {
fmt.Println(err)
return
}
tr := &http.Transport{}
if err := http2.ConfigureTransport(tr); err != nil {
fmt.Println(err)
return
}
client := &http.Client{
Transport: tr,
}
res, err := client.Do(req)
if err != nil {
fmt.Println(err)
return
}
fmt.Println(res.Status)
body, err := ioutil.ReadAll(res.Body)
if err != nil {
var r Response
if err := json.Unmarshal(body, &r); err != nil {
fmt.Println(err)
return
}
fmt.Println(r)
}
}