這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。
原文在此:http://bravenewmethod.wordpress.com/2011/02/25/apple-push-notifications-with-go-language/
前兩天正巧看到 APNS 沒有 Go 的實現,還在琢磨怎麼實現一個試試,這下我又省心了。文章本身並不怎麼出色,代碼倒是有些用途。翻譯這篇東西純粹是為了給自己後面的工作留個資料。大家有用則用,無用就無視吧。
————–翻譯分割線————–
Go語言開發蘋果推播通知
我開始嘗試學習並熟悉 Go 語言,並且做了一些普通的常識,例如,發送蘋果推播通知(Apple Push Notifications)。這是我個人對一些開發環境的效能測試。迄今為止,已經有:
- 使用 Node.js 的推播通知(Push notifications with Node.js)
- 使用 Erlang 的推播通知(Push notifications with Erlang)
第一步 準備
擷取並編譯 Go。這裡的例子是在 Ubuntu 10.04 LTS x64 上,基於 Go 上手指南(Go getting started guide) 裡的介紹進行安裝。
- 關於蘋果推送和取得應用沙箱私密金鑰的 .pem 檔案的介紹在這裡。
- 當然,你必須從 iOS 應用擷取 32 位的推送令牌(push token)。
第二部 代碼
這裡是完整的代碼,複製並儲存為檔案 apn.go。
注意修改認證檔案(cert.pem 和 key-noenc.pem)為你自己的認證檔案。同時,替換推送令牌為你自己的推送令牌, 在這個例子裡為了更加清楚,使用十六進位字串書寫。
package mainimport ( "crypto/tls" "fmt" "net" "json" "os" "time" "bytes" "encoding/hex" "encoding/binary")func main() { // 載入認證和設定檔 cert, err := tls.LoadX509KeyPair("cert.pem", "key-noenc.pem") if err != nil { fmt.Printf("error: %s\n", err.String()) os.Exit(1) } conf := &tls.Config { Certificates: []tls.Certificate{cert}, } // 串連到 APNS 並且用 tls 用戶端加密 socket conn, err := net.Dial("tcp", "", "gateway.sandbox.push.apple.com:2195") if err != nil { fmt.Printf("tcp error: %s\n", err.String()) os.Exit(1) } tlsconn := tls.Client(conn, conf) // 強制握手,以驗證身份握手被處理,否則會在第一次讀寫的時候進行嘗試 err = tlsconn.Handshake() if err != nil { fmt.Printf("tls error: %s\n", err.String()) os.Exit(1) } // 調試資訊 state := tlsconn.ConnectionState() fmt.Printf("conn state %v\n", state) // 從 JSON 結構構造二進位的 payload payload := make(map[string]interface{}) payload["aps"] = map[string]string{"alert": "Hello Push"} bpayload, err := json.Marshal(payload) // 將十六進位的裝置令牌轉為二進位的位元組數組 btoken, _ := hex.DecodeString("6b4628de9317c80edd1c791640b58fdfc46d21d0d2d1351687239c44d8e30ab1") // 構造 pdu buffer := bytes.NewBuffer([]byte{}) // 命令 binary.Write(buffer, binary.BigEndian, uint8(1)) // 傳輸 id,optional binary.Write(buffer, binary.BigEndian, uint32(1)) // 到期時間,1小時 binary.Write(buffer, binary.BigEndian, uint32(time.Seconds() + 60*60)) // 推送裝置令牌 binary.Write(buffer, binary.BigEndian, uint16(len(btoken))) binary.Write(buffer, binary.BigEndian, btoken) // 推送 payload binary.Write(buffer, binary.BigEndian, uint16(len(bpayload))) binary.Write(buffer, binary.BigEndian, bpayload) pdu := buffer.Bytes() // 寫入 pdu _, err = tlsconn.Write(pdu) if err != nil { fmt.Printf("write error: %s\n", err.String()) os.Exit(1) } // 等待 5 秒,以便 pdu 從 socket 返回錯誤 tlsconn.SetReadTimeout(5*1E9) readb := [6]byte{} n, err := tlsconn.Read(readb[:]) if n > 0 { fmt.Printf("received: %s\n", hex.EncodeToString(readb[:n])) } tlsconn.Close()}
第三步 編譯和運行
簡單
$ 6g apn.go$ 6l apn.6$ ./6.outconn state {true 47}$
如果所有都沒有問題,程式會在幾秒鐘後退出,你會在你的 iPhone 上看到推播通知。