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)
	}
}
  • このエントリーをはてなブックマークに追加