Skip to content

Commit 53f360a

Browse files
committed
Merge branch 'empty_alert' into safari
Conflicts: notification.go
2 parents 587351c + 15f1ca0 commit 53f360a

File tree

5 files changed

+88
-32
lines changed

5 files changed

+88
-32
lines changed

README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,10 @@ for ft := range f.Receive() {
8585
}
8686
```
8787

88+
Note that the channel returned from `Receive` will close after the
89+
[feedback service](https://developer.apple.com/library/ios/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/Chapters/CommunicatingWIthAPS.html#//apple_ref/doc/uid/TP40008194-CH101-SW3)
90+
has no more data to send.
91+
8892
## Running the tests
8993

9094
We use [Ginkgo](https://onsi.github.io/ginkgo) for our testing framework and

example/example.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ func main() {
2828

2929
p := apns.NewPayload()
3030
p.APS.Alert.Body = body
31-
p.APS.Badge = badge
31+
p.APS.Badge = &badge
3232

3333
p.SetCustomValue("link", "yourapp://precache/20140718")
3434

feedback.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,8 @@ func NewFeedbackWithFiles(gw string, certFile string, keyFile string) (Feedback,
6161
return Feedback{Conn: &conn}, nil
6262
}
6363

64+
// Receive returns a read only channel for APNs feedback. The returned channel
65+
// will close when there is no more data to be read.
6466
func (f Feedback) Receive() <-chan FeedbackTuple {
6567
fc := make(chan FeedbackTuple)
6668
go f.receive(fc)

notification.go

Lines changed: 56 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ type NotificationResult struct {
3838
}
3939

4040
type Alert struct {
41+
// Do not add fields without updating the implementation of isZero.
4142
Body string `json:"body,omitempty"`
4243
Title string `json:"title,omitempty"`
4344
Action string `json:"action,omitempty"`
@@ -47,12 +48,42 @@ type Alert struct {
4748
LaunchImage string `json:"launch-image,omitempty"`
4849
}
4950

51+
func (a *Alert) isZero() bool {
52+
return len(a.Body) == 0 && len(a.LocKey) == 0 && len(a.LocArgs) == 0 && len(a.ActionLocKey) == 0 && len(a.LaunchImage) == 0
53+
}
54+
5055
type APS struct {
51-
Alert Alert `json:"alert,omitempty"`
52-
Badge *int `json:"badge,omitempty"`
53-
Sound string `json:"sound,omitempty"`
54-
ContentAvailable int `json:"content-available,omitempty"`
55-
URLArgs []string `json:"url-args,omitempty"`
56+
Alert Alert
57+
Badge *int // 0 to clear notifications, nil to leave as is.
58+
Sound string
59+
ContentAvailable int
60+
URLArgs []string
61+
Category string // requires iOS 8+
62+
}
63+
64+
func (aps APS) MarshalJSON() ([]byte, error) {
65+
data := make(map[string]interface{})
66+
67+
if !aps.Alert.isZero() {
68+
data["alert"] = aps.Alert
69+
}
70+
if aps.Badge != nil {
71+
data["badge"] = aps.Badge
72+
}
73+
if aps.Sound != "" {
74+
data["sound"] = aps.Sound
75+
}
76+
if aps.ContentAvailable != 0 {
77+
data["content-available"] = aps.ContentAvailable
78+
}
79+
if aps.Category != "" {
80+
data["category"] = aps.Category
81+
}
82+
if aps.URLArgs != nil && len(aps.URLArgs) != 0 {
83+
data["url-args"] = aps.URLArgs
84+
}
85+
86+
return json.Marshal(data)
5687
}
5788

5889
type Payload struct {
@@ -62,6 +93,26 @@ type Payload struct {
6293
customValues map[string]interface{}
6394
}
6495

96+
func (p *Payload) MarshalJSON() ([]byte, error) {
97+
if len(p.MDM) != 0 {
98+
p.customValues["mdm"] = p.MDM
99+
} else {
100+
p.customValues["aps"] = p.APS
101+
}
102+
103+
return json.Marshal(p.customValues)
104+
}
105+
106+
func (p *Payload) SetCustomValue(key string, value interface{}) error {
107+
if key == "aps" {
108+
return errors.New("cannot assign a custom APS value in payload")
109+
}
110+
111+
p.customValues[key] = value
112+
113+
return nil
114+
}
115+
65116
type Notification struct {
66117
ID string
67118
DeviceToken string
@@ -79,26 +130,6 @@ func NewPayload() *Payload {
79130
return &Payload{customValues: map[string]interface{}{}}
80131
}
81132

82-
func (p *Payload) SetCustomValue(key string, value interface{}) error {
83-
if key == "aps" {
84-
return errors.New("cannot assign a custom APS value in payload")
85-
}
86-
87-
p.customValues[key] = value
88-
89-
return nil
90-
}
91-
92-
func (p *Payload) MarshalJSON() ([]byte, error) {
93-
if len(p.MDM) != 0 {
94-
p.customValues["mdm"] = p.MDM
95-
} else {
96-
p.customValues["aps"] = p.APS
97-
}
98-
99-
return json.Marshal(p.customValues)
100-
}
101-
102133
func (n Notification) ToBinary() ([]byte, error) {
103134
b := []byte{}
104135

notification_test.go

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,25 @@ var _ = Describe("Notifications", func() {
104104

105105
Describe("Payload", func() {
106106
Describe("#MarshalJSON", func() {
107+
Context("no alert (as with Passbook)", func() {
108+
It("should not contain the alert struct", func() {
109+
p := apns.NewPayload()
110+
b, err := json.Marshal(p)
111+
112+
Expect(err).To(BeNil())
113+
Expect(b).To(Equal([]byte(`{"aps":{}}`)))
114+
})
115+
})
116+
Context("no alert with content available (as with Newsstand)", func() {
117+
It("should not contain the alert struct", func() {
118+
p := apns.NewPayload()
119+
p.APS.ContentAvailable = 1
120+
b, err := json.Marshal(p)
121+
122+
Expect(err).To(BeNil())
123+
Expect(b).To(Equal([]byte(`{"aps":{"content-available":1}}`)))
124+
})
125+
})
107126
Context("with only APS", func() {
108127
It("should marshal APS", func() {
109128
p := apns.NewPayload()
@@ -155,7 +174,7 @@ var _ = Describe("Notifications", func() {
155174
j, err := json.Marshal(a)
156175

157176
Expect(err).To(BeNil())
158-
Expect(j).To(Equal([]byte(`{"alert":{},"badge":0}`)))
177+
Expect(j).To(Equal([]byte(`{"badge":0}`)))
159178
})
160179
})
161180
Context("no badge specified (do nothing)", func() {
@@ -165,7 +184,7 @@ var _ = Describe("Notifications", func() {
165184
j, err := json.Marshal(a)
166185

167186
Expect(err).To(BeNil())
168-
Expect(j).To(Equal([]byte(`{"alert":{}}`)))
187+
Expect(j).To(Equal([]byte(`{}`)))
169188
})
170189
})
171190
})
@@ -223,7 +242,7 @@ var _ = Describe("Notifications", func() {
223242
var frameLen, identifier, expiry uint32
224243
var priority byte
225244
var tok [32]byte
226-
var payload [20]byte
245+
var payload [10]byte
227246

228247
binary.Read(buf, binary.BigEndian, &command)
229248
binary.Read(buf, binary.BigEndian, &frameLen)
@@ -254,7 +273,7 @@ var _ = Describe("Notifications", func() {
254273
binary.Read(buf, binary.BigEndian, &priority)
255274

256275
Expect(command).To(Equal(uint8(2)))
257-
Expect(frameLen).To(Equal(uint32(76)))
276+
Expect(frameLen).To(Equal(uint32(66)))
258277

259278
// Token
260279
Expect(tokID).To(Equal(uint8(1)))
@@ -263,8 +282,8 @@ var _ = Describe("Notifications", func() {
263282

264283
// Payload
265284
Expect(payloadID).To(Equal(uint8(2)))
266-
Expect(payloadLen).To(Equal(uint16(20)))
267-
Expect(payload).To(Equal([20]byte{123, 34, 97, 112, 115, 34, 58, 123, 34, 97, 108, 101, 114, 116, 34, 58, 123, 125, 125, 125}))
285+
Expect(payloadLen).To(Equal(uint16(10)))
286+
Expect(payload).To(Equal([10]byte{123, 34, 97, 112, 115, 34, 58, 123, 125, 125}))
268287

269288
// Identifier
270289
Expect(identifierID).To(Equal(uint8(3)))

0 commit comments

Comments
 (0)