golang实现iOS设备消息推送通知服务插件库Chanify的使用
Golang实现iOS设备消息推送通知服务插件库Chanify的使用
Chanify是一个安全简单的通知工具,开发者、系统管理员等任何人都可以通过API推送通知。
主要特性
- 为通知自定义频道
- 部署自己的节点服务器
- 分布式架构设计
- 隐私保护设计
- 支持文本/图片/音频/文件消息格式
安装Chanify
预编译二进制文件
从发布页面下载预编译的二进制文件。
Docker安装
$ docker pull wizjin/chanify:latest
从源码安装
$ git clone https://github.com/chanify/chanify.git
$ cd chanify
$ make install
使用示例
作为发送客户端
package main
import (
"fmt"
"net/http"
"net/url"
"strings"
)
func main() {
// 发送文本消息
endpoint := "http://<address>:<port>"
token := "<your_token>"
message := "Hello from Golang!"
// 使用form表单方式发送
data := url.Values{}
data.Set("text", message)
resp, err := http.PostForm(
fmt.Sprintf("%s/v1/sender/%s", endpoint, token),
data,
)
if err != nil {
fmt.Println("发送失败:", err)
return
}
defer resp.Body.Close()
fmt.Println("发送成功,状态码:", resp.StatusCode)
}
作为无状态节点(Serverless)
package main
import (
"fmt"
"net/http"
)
func main() {
// 启动Chanify无状态节点
http.HandleFunc("/v1/sender/", func(w http.ResponseWriter, r *http.Request) {
// 处理发送请求
token := strings.TrimPrefix(r.URL.Path, "/v1/sender/")
fmt.Println("收到发送请求,token:", token)
// 这里添加转发到api.chanify.net的逻辑
w.WriteHeader(http.StatusOK)
w.Write([]byte("消息已接收"))
})
fmt.Println("启动服务器在 :8080")
http.ListenAndServe(":8080", nil)
}
作为有状态节点(Serverful)
package main
import (
"database/sql"
"fmt"
"net/http"
"strings"
_ "github.com/go-sql-driver/mysql"
)
var db *sql.DB
func main() {
// 初始化MySQL连接
var err error
db, err = sql.Open("mysql", "user:password@tcp(127.0.0.1:3306)/chanify?charset=utf8mb4&parseTime=true&loc=Local")
if err != nil {
panic(err)
}
defer db.Close()
// 启动Chanify有状态节点
http.HandleFunc("/v1/sender/", func(w http.ResponseWriter, r *http.Request) {
token := strings.TrimPrefix(r.URL.Path, "/v1/sender/")
// 查询设备token
var deviceToken string
err := db.QueryRow("SELECT device_token FROM devices WHERE user_token = ?", token).Scan(&deviceToken)
if err != nil {
http.Error(w, "无效token", http.StatusBadRequest)
return
}
// 这里添加发送到APNS的逻辑
fmt.Println("发送消息到设备:", deviceToken)
w.WriteHeader(http.StatusOK)
w.Write([]byte("消息已发送"))
})
fmt.Println("启动服务器在 :8080")
http.ListenAndServe(":8080", nil)
}
HTTP API示例
发送文本消息
func sendTextMessage() {
client := &http.Client{}
// 准备请求数据
data := url.Values{}
data.Set("text", "Hello from Golang!")
data.Set("title", "通知标题")
data.Set("sound", "1")
data.Set("priority", "10")
// 创建请求
req, err := http.NewRequest(
"POST",
"http://<address>:<port>/v1/sender/<token>",
strings.NewReader(data.Encode()),
)
if err != nil {
fmt.Println("创建请求失败:", err)
return
}
// 设置Content-Type
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
// 发送请求
resp, err := client.Do(req)
if err != nil {
fmt.Println("发送请求失败:", err)
return
}
defer resp.Body.Close()
fmt.Println("响应状态码:", resp.StatusCode)
}
发送图片消息
func sendImageMessage() {
// 打开图片文件
file, err := os.Open("image.jpg")
if err != nil {
fmt.Println("打开图片失败:", err)
return
}
defer file.Close()
// 准备multipart表单
body := &bytes.Buffer{}
writer := multipart.NewWriter(body)
part, err := writer.CreateFormFile("image", "image.jpg")
if err != nil {
fmt.Println("创建表单文件失败:", err)
return
}
_, err = io.Copy(part, file)
if err != nil {
fmt.Println("复制文件内容失败:", err)
return
}
err = writer.Close()
if err != nil {
fmt.Println("关闭writer失败:", err)
return
}
// 创建请求
req, err := http.NewRequest(
"POST",
"http://<address>:<port>/v1/sender/<token>",
body,
)
if err != nil {
fmt.Println("创建请求失败:", err)
return
}
// 设置Content-Type
req.Header.Set("Content-Type", writer.FormDataContentType())
// 发送请求
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
fmt.Println("发送请求失败:", err)
return
}
defer resp.Body.Close()
fmt.Println("响应状态码:", resp.StatusCode)
}
配置示例
创建配置文件 ~/.chanify.yml
:
server:
host: 0.0.0.0 # 监听IP地址
port: 8080 # 监听端口
endpoint: http://my.server/path # 端点URL
name: 我的节点 # 节点服务器名称
secret: <secret code> # 无状态节点服务器的密钥
datapath: ~/.chanify # 有状态节点服务器的数据存储路径
dburl: mysql://root:password@tcp(127.0.0.1:3306)/chanify?charset=utf8mb4&parseTime=true&loc=Local
http:
- readtimeout: 10s # HTTP读取超时
- writetimeout: 10s # HTTP写入超时
register:
enable: false # 禁用用户注册
whitelist: # 白名单
- <user id 1>
- <user id 2>
client: # 发送客户端配置
sound: 1 # 启用声音
endpoint: http://default.node.server
token: <default token>
interruption-level: active
安全配置
禁用注册并设置白名单
package main
import (
"fmt"
"net/http"
"strings"
)
var whitelist = map[string]bool{
"user1_id": true,
"user2_id": true,
}
func main() {
http.HandleFunc("/v1/register", func(w http.ResponseWriter, r *http.Request) {
// 检查用户ID是否在白名单中
userID := r.URL.Query().Get("user_id")
if !whitelist[userID] {
http.Error(w, "注册已禁用", http.StatusForbidden)
return
}
// 处理注册逻辑...
fmt.Fprintf(w, "用户 %s 注册成功", userID)
})
fmt.Println("启动服务器在 :8080")
http.ListenAndServe(":8080", nil)
}
完整示例
以下是一个完整的Golang示例,演示如何使用Chanify发送各种类型的通知:
package main
import (
"bytes"
"encoding/json"
"fmt"
"io"
"mime/multipart"
"net/http"
"net/url"
"os"
)
type ChanifyClient struct {
Endpoint string
Token string
}
func NewChanifyClient(endpoint, token string) *ChanifyClient {
return &ChanifyClient{
Endpoint: endpoint,
Token: token,
}
}
// SendText 发送文本消息
func (c *ChanifyClient) SendText(text, title string, sound bool, priority int) error {
data := url.Values{}
data.Set("text", text)
if title != "" {
data.Set("title", title)
}
if sound {
data.Set("sound", "1")
}
if priority > 0 {
data.Set("priority", fmt.Sprintf("%d", priority))
}
resp, err := http.PostForm(
fmt.Sprintf("%s/v1/sender/%s", c.Endpoint, c.Token),
data,
)
if err != nil {
return err
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return fmt.Errorf("请求失败,状态码: %d", resp.StatusCode)
}
return nil
}
// SendImage 发送图片消息
func (c *ChanifyClient) SendImage(imagePath string) error {
file, err := os.Open(imagePath)
if err != nil {
return err
}
defer file.Close()
body := &bytes.Buffer{}
writer := multipart.NewWriter(body)
part, err := writer.CreateFormFile("image", "image.jpg")
if err != nil {
return err
}
_, err = io.Copy(part, file)
if err != nil {
return err
}
err = writer.Close()
if err != nil {
return err
}
req, err := http.NewRequest(
"POST",
fmt.Sprintf("%s/v1/sender/%s", c.Endpoint, c.Token),
body,
)
if err != nil {
return err
}
req.Header.Set("Content-Type", writer.FormDataContentType())
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
return err
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return fmt.Errorf("请求失败,状态码: %d", resp.StatusCode)
}
return nil
}
// SendJSON 发送JSON格式的复杂消息
func (c *ChanifyClient) SendJSON(message map[string]interface{}) error {
jsonData, err := json.Marshal(message)
if err != nil {
return err
}
req, err := http.NewRequest(
"POST",
fmt.Sprintf("%s/v1/sender/%s", c.Endpoint, c.Token),
bytes.NewBuffer(jsonData),
)
if err != nil {
return err
}
req.Header.Set("Content-Type", "application/json")
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
return err
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return fmt.Errorf("请求失败,状态码: %d", resp.StatusCode)
}
return nil
}
func main() {
// 初始化客户端
client := NewChanifyClient("http://your.chanify.server:8080", "your_token_here")
// 示例1: 发送简单文本消息
err := client.SendText("这是一条测试消息", "测试标题", true, 10)
if err != nil {
fmt.Println("发送文本消息失败:", err)
} else {
fmt.Println("文本消息发送成功")
}
// 示例2: 发送图片消息
err = client.SendImage("test.jpg")
if err != nil {
fmt.Println("发送图片消息失败:", err)
} else {
fmt.Println("图片消息发送成功")
}
// 示例3: 发送复杂JSON消息
message := map[string]interface{}{
"text": "这是一条复杂消息",
"title": "复杂通知",
"sound": true,
"priority": 10,
"actions": []string{
"查看详情|http://example.com/details",
"忽略|chanify://action/ignore",
},
"timeline": map[string]interface{}{
"code": "timeline123",
"items": map[string]string{
"key1": "value1",
"key2": "value2",
},
},
}
err = client.SendJSON(message)
if err != nil {
fmt.Println("发送JSON消息失败:", err)
} else {
fmt.Println("JSON消息发送成功")
}
}
这个示例展示了如何使用Golang与Chanify集成,包括发送文本、图片和复杂JSON格式的消息。你可以根据自己的需求扩展这个客户端,添加更多功能如发送音频、文件等。
更多关于golang实现iOS设备消息推送通知服务插件库Chanify的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html
更多关于golang实现iOS设备消息推送通知服务插件库Chanify的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
使用Golang实现iOS设备消息推送通知服务(Chanify)
Chanify是一个开源的iOS消息推送服务,它允许开发者通过简单的API向iOS设备发送推送通知。下面我将介绍如何在Golang中使用Chanify实现iOS设备消息推送。
1. 准备工作
首先,你需要在iOS设备上安装Chanify应用,并获取你的设备token。
- 从App Store安装Chanify应用
- 打开应用,获取你的设备token(形如:
CTxxxx...
)
2. Golang实现Chanify推送
基本实现
package main
import (
"bytes"
"encoding/json"
"fmt"
"net/http"
)
// ChanifyNotification 定义Chanify通知结构
type ChanifyNotification struct {
Title string `json:"title"`
Text string `json:"text"`
Sound bool `json:"sound,omitempty"`
Actions string `json:"actions,omitempty"`
Copy string `json:"copy,omitempty"`
}
// SendChanifyNotification 发送Chanify通知
func SendChanifyNotification(token string, notification ChanifyNotification) error {
url := fmt.Sprintf("https://api.chanify.net/v1/sender/%s", token)
payload, err := json.Marshal(notification)
if err != nil {
return fmt.Errorf("failed to marshal notification: %v", err)
}
resp, err := http.Post(url, "application/json", bytes.NewBuffer(payload))
if err != nil {
return fmt.Errorf("failed to send request: %v", err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return fmt.Errorf("unexpected status code: %d", resp.StatusCode)
}
return nil
}
func main() {
// 替换为你的Chanify设备token
deviceToken := "CTxxxx...your_token_here"
notification := ChanifyNotification{
Title: "重要通知",
Text: "这是一条来自Golang的测试消息",
Sound: true,
}
err := SendChanifyNotification(deviceToken, notification)
if err != nil {
fmt.Printf("发送通知失败: %v\n", err)
return
}
fmt.Println("通知发送成功!")
}
高级功能实现
Chanify还支持更多高级功能,如自定义声音、动作按钮等:
package main
import (
"bytes"
"encoding/json"
"fmt"
"net/http"
"time"
)
// AdvancedChanifyNotification 高级Chanify通知结构
type AdvancedChanifyNotification struct {
Title string `json:"title"`
Text string `json:"text"`
Sound int `json:"sound,omitempty"` // 0-系统声音,1-铃音,2-警报
Priority int `json:"priority,omitempty"` // 0-默认,1-被动,5-低,10-高
Actions string `json:"actions,omitempty"` // 动作按钮,格式:"action1|http://url1,action2|http://url2"
Copy string `json:"copy,omitempty"` // 点击后复制的内容
AutoCopy int `json:"autocopy,omitempty"` // 0-不自动复制,1-自动复制
Timestamp int64 `json:"timestamps,omitempty"` // 时间戳
}
// SendAdvancedChanifyNotification 发送高级Chanify通知
func SendAdvancedChanifyNotification(token string, notification AdvancedChanifyNotification) error {
url := fmt.Sprintf("https://api.chanify.net/v1/sender/%s", token)
// 如果没有设置时间戳,使用当前时间
if notification.Timestamp == 0 {
notification.Timestamp = time.Now().Unix()
}
payload, err := json.Marshal(notification)
if err != nil {
return fmt.Errorf("failed to marshal notification: %v", err)
}
client := &http.Client{Timeout: 10 * time.Second}
req, err := http.NewRequest("POST", url, bytes.NewBuffer(payload))
if err != nil {
return fmt.Errorf("failed to create request: %v", err)
}
req.Header.Set("Content-Type", "application/json")
resp, err := client.Do(req)
if err != nil {
return fmt.Errorf("failed to send request: %v", err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return fmt.Errorf("unexpected status code: %d", resp.StatusCode)
}
return nil
}
func main() {
// 替换为你的Chanify设备token
deviceToken := "CTxxxx...your_token_here"
notification := AdvancedChanifyNotification{
Title: "高级通知",
Text: "这是一条包含高级功能的消息",
Sound: 1, // 使用铃音
Priority: 10, // 高优先级
Actions: "查看详情|https://example.com,忽略|",
Copy: "复制这段文本",
AutoCopy: 1,
}
err := SendAdvancedChanifyNotification(deviceToken, notification)
if err != nil {
fmt.Printf("发送通知失败: %v\n", err)
return
}
fmt.Println("高级通知发送成功!")
}
3. 使用自建Chanify服务器
如果你有自己的Chanify服务器,可以修改API端点:
func SendChanifyNotification(token string, notification ChanifyNotification, endpoint string) error {
if endpoint == "" {
endpoint = "https://api.chanify.net"
}
url := fmt.Sprintf("%s/v1/sender/%s", endpoint, token)
// 其余代码相同...
}
4. 错误处理和重试机制
为了更健壮的实现,可以添加错误处理和重试:
func SendWithRetry(token string, notification ChanifyNotification, retries int) error {
var lastErr error
for i := 0; i < retries; i++ {
err := SendChanifyNotification(token, notification)
if err == nil {
return nil
}
lastErr = err
time.Sleep(time.Second * time.Duration(i+1)) // 指数退避
}
return fmt.Errorf("after %d retries, last error: %v", retries, lastErr)
}
5. 总结
通过上述代码,你可以轻松地在Golang中集成Chanify推送服务,实现向iOS设备发送通知的功能。Chanify的优势在于:
- 开源且免费
- 不需要Apple开发者账号
- 支持自建服务器
- 提供丰富的通知定制选项
你可以根据实际需求扩展这些基础功能,构建更复杂的通知系统。