Apple news push Apns is a barrier that every apple app must face. At present, small projects need to push messages to all users regularly. Previously, we used pyapns, a third-party library of python, to implement it. As a result, we found that the memory consumption was very high and the push was not stable. Often, the mobile phone could not receive messages.
So I try to write a loop push program in GO language. The main process is: regularly (every 2-4 minutes), traverse all users' apple token s, and push messages.
Here is the code:
1. Query out the apple token of all users in the database
Query out the apple token in all user tables
Package used:
import ( "os" "strconv" "math/rand" "time" "github.com/gohouse/gorose" _ "github.com/go-sql-driver/mysql" "log" "fmt" "github.com/sideshow/apns2" "github.com/sideshow/apns2/certificate" "github.com/sideshow/apns2/payload" )
Initialize database:
//Initialize database func init_db(){ var dbConfig = map[string]interface{} { "Default": "mysql_dev",// Default database configuration "SetMaxOpenConns": 0, // (connection pool) the maximum number of open connections. The default value is 0, indicating no limit "SetMaxIdleConns": 1, // Number of idle connections (connection pool), default 1 "Connections":map[string]map[string]string{ "mysql_dev": {// Define the database configuration named MySQL? Dev "host": "127.0.0.1", // Database address "username": "root", // Database user name "password": "123456", // Database password "port": "3306", // port "database": "xxx", // Linked database name "charset": "utf8", // character set "protocol": "tcp", // Link protocol "prefix": "", // Table prefix "driver": "mysql", // Database driver (mysql,sqlite,postgres,oracle,mssql) }, }, } connection, err := gorose.Open(dbConfig) if err != nil { fmt.Println(err) return } // close DB //defer connection.Close() Db = connection.GetInstance() }
Take the user token from the database:
users,err := Db.Table("users_userprofile").Fields("apple_token").Where("apple_token","!=","").Get() fmt.Println("get all tokens end") if err!=nil{ fmt.Println(err) return }
2. Initialize APNs
Third party packages used:
"github.com/sideshow/apns2" "github.com/sideshow/apns2/certificate" "github.com/sideshow/apns2/payload"
Initialization:
//Initialize APNSs func initApns(){ Info = log.New(os.Stdout,"Info:",log.Ldate | log.Ltime | log.Lshortfile) cert, err := certificate.FromP12File("./cert.p12", "123456") if err != nil { log.Fatal("Cert Error:", err) } Client = apns2.NewClient(cert).Production() }
3. Define two channel s:
var ( NotiChan chan *apns2.Notification responses chan *apns2.Response )
4. Traverse the queried user token, build notification, and pass it into NotiChan
for _,item := range users{ token:=item["apple_token"] fmt.Println("token",token) //Generate a job and put it into the Job channel for later worker s to send notification := &apns2.Notification{} notification.DeviceToken = token.(string) notification.Topic = "com.xxx.xxx" timeTamp:=time.Now().Unix() tm := time.Unix(timeTamp, 0) extras:=make(map[string]string) extras["command"]="wakeup" extras["msgId"]=strconv.FormatInt(timeTamp,10) extras["time"]=tm.Format("2006-01-02 03:04:05 PM") extras["counter"]=strconv.FormatInt(counter,10) payload := payload.NewPayload().Alert("").ContentAvailable() for k, v := range extras { payload.Custom(k, v) } notification.Payload = payload NotiChan <- notification //go sendApns(token.(string)) }
5. Create a worker process to accept the notification sent from NotiChan and send it to the user
//The worker takes the job from JobChan and sends the notification with apns2.client func worker_send(){ for{ n:= <- NotiChan fmt.Println("start sending notification") res, err := Client.Push(n) if err != nil { log.Fatal("Push Error:", err) } responses <- res } }
6. Create a process and handle the response
func work_response(){ for{ res := <- responses fmt.Println("%v %v %v\n", res.StatusCode, res.ApnsID, res.Reason) } }
7. Main thread logic, timing cycle
//Loop timer thread func startLoop(){ fmt.Println("start main loop") NotiChan=make(chan *apns2.Notification, 3000) responses = make(chan *apns2.Response, 3000) counter=0 for{ fmt.Println("start get all tokens") users,err := Db.Table("users_userprofile").Fields("apple_token").Where("apple_token","!=","").Get() fmt.Println("get all tokens end") if err!=nil{ fmt.Println(err) return } for _,item := range users{ token:=item["apple_token"] fmt.Println("token",token) //Generate a job and put it into the Job channel for later worker s to send notification := &apns2.Notification{} notification.DeviceToken = token.(string) notification.Topic = "com.xx.xxx" timeTamp:=time.Now().Unix() tm := time.Unix(timeTamp, 0) extras:=make(map[string]string) extras["command"]="wakeup" extras["msgId"]=strconv.FormatInt(timeTamp,10) extras["time"]=tm.Format("2006-01-02 03:04:05 PM") extras["counter"]=strconv.FormatInt(counter,10) payload := payload.NewPayload().Alert("").ContentAvailable() for k, v := range extras { payload.Custom(k, v) } notification.Payload = payload NotiChan <- notification //go sendApns(token.(string)) } waitTime:=rand.Intn(120) fmt.Println("wait:",waitTime," seconds") time.Sleep(time.Duration(waitTime+120)*time.Second) counter=counter+1 } }
8. In the main function:
func main() { //Start 10 work, process and send notification for i:=0;i<10;i++{ go worker_send() } for i:=0;i<10;i++{ go work_response() } startLoop() }