golang实现Google云消息推送服务插件库gcm的使用
golang实现Google云消息推送服务插件库gcm的使用
概述
Android SDK提供了一个方便的库(com.google.android.gcm.server),它极大地简化了基于Java的应用服务器与Google GCM服务器之间的交互。然而,Google没有为Java以外的语言(特别是Go语言)实现的应用服务器提供太多支持。gcm
包有助于填补这一空白,提供了一个简单的接口来发送GCM消息,并在服务不可用时自动重试请求。
安装
要安装gcm,使用go get
命令:
go get github.com/Aorioli/gcm
导入gcm包:
import "github.com/Aorioli/gcm"
使用示例
以下是一个快速示例,展示如何向GCM服务器发送消息:
package main
import (
"fmt"
"net/http"
"time"
"github.com/Aorioli/gcm"
)
func main() {
// 创建要发送的消息
data := map[string]interface{}{"score": "5x1", "time": "15:10"}
regIDs := []string{"4", "8", "15", "16", "23", "42"}
m := new(gcm.Message)
m.RegistrationIDs = regIDs
m.Data = data
// 创建一个Sender来发送消息
sender := gcm.NewSender("sample_api_key", 2, time.Minute)
// 发送消息并最多重试两次接收响应
response, err := sender.Send(m)
if err != nil {
fmt.Println("Failed to send message:", err)
return
}
/* ... */
}
代码说明
-
创建消息:
data
变量定义了要发送的数据内容regIDs
是目标设备的注册ID数组gcm.Message
结构体用于封装消息内容
-
创建Sender:
gcm.NewSender
创建一个新的发送者实例- 参数说明:
sample_api_key
: 你的GCM API密钥2
: 最大重试次数time.Minute
: 重试间隔时间
-
发送消息:
sender.Send(m)
发送消息并返回响应- 错误处理检查发送是否成功
贡献
欢迎贡献代码:
- 创建一个issue描述bug、增强功能或其他问题
- Fork仓库,在master以外的分支上进行更改
- 创建pull请求
更多关于golang实现Google云消息推送服务插件库gcm的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html
更多关于golang实现Google云消息推送服务插件库gcm的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
Golang实现Google云消息推送服务(GCM)插件库
Google云消息推送服务(GCM)是Google提供的移动消息推送服务,后来被Firebase Cloud Messaging(FCM)取代。不过对于仍需要与GCM交互的系统,我们可以使用Go语言实现相关功能。
GCM基本概念
GCM(Google Cloud Messaging)允许服务器向Android设备发送消息,主要特点包括:
- 支持向单个设备或设备组发送消息
- 消息大小限制为4KB
- 支持下游消息(服务器到设备)和上游消息(设备到服务器)
Go实现GCM客户端
下面是一个完整的GCM客户端实现示例:
package gcm
import (
"bytes"
"encoding/json"
"fmt"
"net/http"
)
const (
gcmSendEndpoint = "https://android.googleapis.com/gcm/send"
)
// Message represents a GCM message.
type Message struct {
RegistrationIDs []string `json:"registration_ids"`
CollapseKey string `json:"collapse_key,omitempty"`
Priority string `json:"priority,omitempty"` // "normal" or "high"
ContentAvailable bool `json:"content_available,omitempty"`
DelayWhileIdle bool `json:"delay_while_idle,omitempty"`
TimeToLive int `json:"time_to_live,omitempty"`
RestrictedPackageName string `json:"restricted_package_name,omitempty"`
DryRun bool `json:"dry_run,omitempty"`
Data map[string]interface{} `json:"data,omitempty"`
Notification *Notification `json:"notification,omitempty"`
}
// Notification represents a GCM notification payload.
type Notification struct {
Title string `json:"title,omitempty"`
Body string `json:"body,omitempty"`
Icon string `json:"icon,omitempty"`
Sound string `json:"sound,omitempty"`
Badge string `json:"badge,omitempty"`
Tag string `json:"tag,omitempty"`
Color string `json:"color,omitempty"`
ClickAction string `json:"click_action,omitempty"`
BodyLocKey string `json:"body_loc_key,omitempty"`
BodyLocArgs string `json:"body_loc_args,omitempty"`
TitleLocKey string `json:"title_loc_key,omitempty"`
TitleLocArgs string `json:"title_loc_args,omitempty"`
}
// Response represents a GCM response.
type Response struct {
MulticastID int64 `json:"multicast_id"`
Success int `json:"success"`
Failure int `json:"failure"`
CanonicalIDs int `json:"canonical_ids"`
Results []Result `json:"results"`
}
// Result represents a GCM message result for a single device.
type Result struct {
MessageID string `json:"message_id"`
RegistrationID string `json:"registration_id"`
Error string `json:"error"`
}
// Client represents a GCM client.
type Client struct {
apiKey string
client *http.Client
}
// NewClient creates a new GCM client.
func NewClient(apiKey string, httpClient *http.Client) *Client {
if httpClient == nil {
httpClient = http.DefaultClient
}
return &Client{
apiKey: apiKey,
client: httpClient,
}
}
// Send sends a GCM message.
func (c *Client) Send(msg *Message) (*Response, error) {
data, err := json.Marshal(msg)
if err != nil {
return nil, fmt.Errorf("failed to marshal message: %v", err)
}
req, err := http.NewRequest("POST", gcmSendEndpoint, bytes.NewBuffer(data))
if err != nil {
return nil, fmt.Errorf("failed to create request: %v", err)
}
req.Header.Set("Authorization", "key="+c.apiKey)
req.Header.Set("Content-Type", "application/json")
resp, err := c.client.Do(req)
if err != nil {
return nil, fmt.Errorf("failed to send request: %v", err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("unexpected status code: %d", resp.StatusCode)
}
var response Response
if err := json.NewDecoder(resp.Body).Decode(&response); err != nil {
return nil, fmt.Errorf("failed to decode response: %v", err)
}
return &response, nil
}
使用示例
package main
import (
"fmt"
"log"
"./gcm" // 替换为你的实际包路径
)
func main() {
// 初始化GCM客户端
apiKey := "YOUR_GCM_API_KEY" // 从Google开发者控制台获取
client := gcm.NewClient(apiKey, nil)
// 准备消息
msg := &gcm.Message{
RegistrationIDs: []string{"device_registration_id_1", "device_registration_id_2"},
Priority: "high",
Notification: &gcm.Notification{
Title: "Hello GCM",
Body: "This is a test message from GCM",
},
Data: map[string]interface{}{
"key1": "value1",
"key2": "value2",
},
}
// 发送消息
response, err := client.Send(msg)
if err != nil {
log.Fatalf("Failed to send message: %v", err)
}
// 处理响应
fmt.Printf("Success: %d, Failure: %d\n", response.Success, response.Failure)
for i, result := range response.Results {
if result.Error != "" {
fmt.Printf("Error for device %d: %s\n", i, result.Error)
} else {
fmt.Printf("Message sent to device %d: %s\n", i, result.MessageID)
if result.RegistrationID != "" {
fmt.Printf("New registration ID: %s\n", result.RegistrationID)
}
}
}
}
注意事项
- API密钥:需要从Google开发者控制台获取GCM API密钥
- 设备注册ID:每个Android设备在安装应用并注册GCM服务后会获得唯一的注册ID
- 响应处理:需要检查响应中的CanonicalIDs,如果有新的注册ID,应该更新服务器上的记录
- 错误处理:常见的错误包括:
- “InvalidRegistration” - 注册ID无效
- “NotRegistered” - 设备已取消注册
- “MessageTooBig” - 消息超过4KB限制
- 迁移到FCM:Google推荐新项目使用FCM而不是GCM
高级功能
如果需要更复杂的功能,可以考虑:
- 重试机制:对于暂时性错误实现指数退避重试
- 批量发送:将大量设备分批发送以避免超时
- 结果持久化:将发送结果存储到数据库供后续分析
- 设备组管理:实现设备组的创建、添加和删除功能
虽然GCM已被FCM取代,但对于维护旧系统或需要与遗留代码交互的场景,这个Go实现仍然非常有用。