原文在此: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