原文在此:http://bravenewmethod.wordpress.com/2011/02/25/apple-push-notifications-with-go-language/
前两天正巧看到 APNS 没有 Go 的实现,还在琢磨怎么实现一个试试,这下我又省心了。文章本身并不怎么出色,代码倒是有些用途。翻译这篇东西纯粹是为了给自己后面的工作留个资料。大家有用则用,无用就无视吧。
————–翻译分割线————–
Go语言开发苹果推送通知
我开始尝试学习并熟悉 Go 语言,并且做了一些普通的常识,例如,发送苹果推送通知(Apple Push Notifications)。这是我个人对一些开发环境的性能测试。迄今为止,已经有:
第一步 准备
获取并编译 Go。这里的例子是在 Ubuntu 10.04 LTS x64 上,基于 Go 上手指南(Go getting started guide) 里的介绍进行安装。
- 关于苹果推送和取得应用沙盒私钥的 .pem 文件的介绍在这里。
- 当然,你必须从 iOS 应用获取 32 位的推送令牌(push token)。
第二部 代码
这里是完整的代码,复制并保存为文件 apn.go。
注意修改证书文件(cert.pem 和 key-noenc.pem)为你自己的证书文件。同时,替换推送令牌为你自己的推送令牌, 在这个例子里为了更加清楚,使用十六进制字符串书写。
package main import ( "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.out conn state {true 47} $
如果所有都没有问题,程序会在几秒钟后退出,你会在你的 iPhone 上看到推送通知。
Leave a Reply