-
Notifications
You must be signed in to change notification settings - Fork 335
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
2 changed files
with
373 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,230 @@ | ||
// Package payload is a helper package which contains a payload | ||
// builder to make constructing notification payloads easier. | ||
package payload | ||
|
||
import "encoding/json" | ||
|
||
type payload struct { | ||
content map[string]interface{} | ||
} | ||
|
||
type aps struct { | ||
Alert interface{} `json:"alert,omitempty"` | ||
Badge interface{} `json:"badge,omitempty"` | ||
Category string `json:"category,omitempty"` | ||
ContentAvailable int `json:"content-available,omitempty"` | ||
URLArgs []string `json:"url-args,omitempty"` | ||
Sound string `json:"sound,omitempty"` | ||
} | ||
|
||
type alert struct { | ||
Action string `json:"action,omitempty"` | ||
ActionLocKey string `json:"action-loc-key,omitempty"` | ||
Body string `json:"body,omitempty"` | ||
LaunchImage string `json:"launch-image,omitempty"` | ||
LocArgs []string `json:"loc-args,omitempty"` | ||
LocKey string `json:"loc-key,omitempty"` | ||
Title string `json:"title,omitempty"` | ||
TitleLocArgs []string `json:"title-loc-args,omitempty"` | ||
TitleLocKey string `json:"title-loc-key,omitempty"` | ||
} | ||
|
||
// NewPayload represents a notification payload. | ||
func NewPayload() *payload { | ||
return &payload{ | ||
map[string]interface{}{ | ||
"aps": &aps{}, | ||
}, | ||
} | ||
} | ||
|
||
// Sets the aps alert on the payload. | ||
// This will display a notification alert message to the user. | ||
// {"aps":{"alert":alert}} | ||
func (p *payload) Alert(alert interface{}) *payload { | ||
p.aps().Alert = alert | ||
return p | ||
} | ||
|
||
// Sets the aps badge on the payload. | ||
// This will display a numeric badge on the app icon. | ||
// {"aps":{"badge":b}} | ||
func (p *payload) Badge(b int) *payload { | ||
p.aps().Badge = b | ||
return p | ||
} | ||
|
||
// Sets the aps badge on the payload to 0. | ||
// This will clear the badge on the app icon. | ||
// {"aps":{"badge":0}} | ||
func (p *payload) ZeroBadge() *payload { | ||
p.aps().Badge = 0 | ||
return p | ||
} | ||
|
||
// Removes the badge attribute from the payload. | ||
// This will leave the badge on the app icon unchanged. | ||
// If you wish to clear the app icon badge, use ZeroBadge() instead. | ||
// {"aps":{}} | ||
func (p *payload) UnsetBadge() *payload { | ||
p.aps().Badge = nil | ||
return p | ||
} | ||
|
||
// Sets the aps sound on the payload. | ||
// This will play a sound from the app bundle, or the default sound otherwise. | ||
// {"aps":{"sound":sound}} | ||
func (p *payload) Sound(sound string) *payload { | ||
p.aps().Sound = sound | ||
return p | ||
} | ||
|
||
// Sets the aps content-available on the payload to 1. | ||
// This will indicate to the app that there is new content available to download | ||
// and launch the app in the background. | ||
// {"aps":{"content-available":1}} | ||
func (p *payload) ContentAvailable() *payload { | ||
p.aps().ContentAvailable = 1 | ||
return p | ||
} | ||
|
||
// Sets the aps content-available on the payload to 1. | ||
// This is an alias for ContentAvailable(). | ||
// {"aps":{"content-available":1}} | ||
func (p *payload) NewsstandAvailable() *payload { | ||
return p.ContentAvailable() | ||
} | ||
|
||
// Custom payload | ||
|
||
// Sets a custom key and value on the payload. | ||
// This will add custom key/value data to the notification payload at root level. | ||
// {"aps":{}, key:value} | ||
func (p *payload) Custom(key string, val interface{}) *payload { | ||
p.content[key] = val | ||
return p | ||
} | ||
|
||
// Alert dictionary | ||
|
||
// Sets the aps alert title on the payload. | ||
// This will display a short string describing the purpose of the notification. | ||
// Apple Watch & Safari display this string as part of the notification interface. | ||
// {"aps":{"alert":"title"}} | ||
func (p *payload) AlertTitle(title string) *payload { | ||
p.aps().alert().Title = title | ||
return p | ||
} | ||
|
||
// Sets the aps alert title localization key on the payload. | ||
// This is the key to a title string in the Localizable.strings file for the | ||
// current localization. See Localized Formatted Strings in Apple documentation | ||
// for more information. | ||
// {"aps":{"alert":{"title-loc-key":key}}} | ||
func (p *payload) AlertTitleLocKey(key string) *payload { | ||
p.aps().alert().TitleLocKey = key | ||
return p | ||
} | ||
|
||
// Sets the aps alert title localization args on the payload. | ||
// These are the variable string values to appear in place of the format | ||
// specifiers in title-loc-key. See Localized Formatted Strings in Apple | ||
// documentation for more information. | ||
// {"aps":{"alert":{"title-loc-args":args}}} | ||
func (p *payload) AlertTitleLocArgs(args []string) *payload { | ||
p.aps().alert().TitleLocArgs = args | ||
return p | ||
} | ||
|
||
// Sets the aps alert body on the payload. | ||
// This is the text of the alert message. | ||
// {"aps":{"alert":{"body":body}}} | ||
func (p *payload) AlertBody(body string) *payload { | ||
p.aps().alert().Body = body | ||
return p | ||
} | ||
|
||
// Sets the aps launch image on the payload. | ||
// This is the filename of an image file in the app bundle. The image is used | ||
// as the launch image when users tap the action button or move the action | ||
// slider. | ||
// {"aps":{"alert":{"launch-image":image}}} | ||
func (p *payload) AlertLaunchImage(image string) *payload { | ||
p.aps().alert().LaunchImage = image | ||
return p | ||
} | ||
|
||
// Sets the aps alert localization key on the payload. | ||
// This is the key to an alert-message string in the Localizable.strings file | ||
// for the current localization. See Localized Formatted Strings in Apple | ||
// documentation for more information. | ||
// {"aps":{"alert":{"loc-key":key}}} | ||
func (p *payload) AlertLocKey(key string) *payload { | ||
p.aps().alert().LocKey = key | ||
return p | ||
} | ||
|
||
// Sets the aps alert action on the payload. | ||
// This is the label of the action button, if the user sets the notifications | ||
// to appear as alerts. This label should be succinct, such as “Details” or | ||
// “Read more”. If omitted, the default value is “Show”. | ||
// {"aps":{"alert":{"action":action}}} | ||
func (p *payload) AlertAction(action string) *payload { | ||
p.aps().alert().Action = action | ||
return p | ||
} | ||
|
||
// Sets the aps alert action localization key on the payload. | ||
// This is the the string used as a key to get a localized string in the current | ||
// localization to use for the notfication right button’s title instead of | ||
// “View”. See Localized Formatted Strings in Apple documentation for more | ||
// information. | ||
// {"aps":{"alert":{"action-loc-key":key}}} | ||
func (p *payload) AlertActionLocKey(key string) *payload { | ||
p.aps().alert().ActionLocKey = key | ||
return p | ||
} | ||
|
||
// General | ||
|
||
// Sets the aps category on the payload. | ||
// This is a string value that represents the identifier property of the | ||
// UIMutableUserNotificationCategory object you created to define custom actions. | ||
// {"aps":{"alert":{"category":category}}} | ||
func (p *payload) Category(category string) *payload { | ||
p.aps().Category = category | ||
return p | ||
} | ||
|
||
// Sets the mdm on the payload. | ||
// This is for Apple Mobile Device Management (mdm) payloads. | ||
// {"aps":{}:"mdm":mdm} | ||
func (p *payload) Mdm(mdm string) *payload { | ||
p.content["mdm"] = mdm | ||
return p | ||
} | ||
|
||
// Sets the aps category on the payload. | ||
// This specifies an array of values that are paired with the placeholders | ||
// inside the urlFormatString value of your website.json file. | ||
// See Apple Notification Programming Guide for Websites. | ||
// {"aps":{"url-args":urlArgs}} | ||
func (p *payload) URLArgs(urlArgs []string) *payload { | ||
p.aps().URLArgs = urlArgs | ||
return p | ||
} | ||
|
||
func (p *payload) MarshalJSON() ([]byte, error) { | ||
return json.Marshal(p.content) | ||
} | ||
|
||
func (p *payload) aps() *aps { | ||
return p.content["aps"].(*aps) | ||
} | ||
|
||
func (a *aps) alert() *alert { | ||
if _, ok := a.Alert.(*alert); !ok { | ||
a.Alert = &alert{} | ||
} | ||
return a.Alert.(*alert) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,143 @@ | ||
package payload_test | ||
|
||
import ( | ||
"encoding/json" | ||
"testing" | ||
|
||
. "github.com/sideshow/apns2/payload" | ||
"github.com/stretchr/testify/assert" | ||
) | ||
|
||
func TestEmptyPayload(t *testing.T) { | ||
payload := NewPayload() | ||
b, _ := json.Marshal(payload) | ||
assert.Equal(t, `{"aps":{}}`, string(b)) | ||
} | ||
|
||
func TestAlert(t *testing.T) { | ||
payload := NewPayload().Alert("hello") | ||
b, _ := json.Marshal(payload) | ||
assert.Equal(t, `{"aps":{"alert":"hello"}}`, string(b)) | ||
} | ||
|
||
func TestBadge(t *testing.T) { | ||
payload := NewPayload().Badge(1) | ||
b, _ := json.Marshal(payload) | ||
assert.Equal(t, `{"aps":{"badge":1}}`, string(b)) | ||
} | ||
|
||
func TestZeroBadge(t *testing.T) { | ||
payload := NewPayload().ZeroBadge() | ||
b, _ := json.Marshal(payload) | ||
assert.Equal(t, `{"aps":{"badge":0}}`, string(b)) | ||
} | ||
|
||
func TestUnsetBadge(t *testing.T) { | ||
payload := NewPayload().Badge(1).UnsetBadge() | ||
b, _ := json.Marshal(payload) | ||
assert.Equal(t, `{"aps":{}}`, string(b)) | ||
} | ||
|
||
func TestSound(t *testing.T) { | ||
payload := NewPayload().Sound("Default.caf") | ||
b, _ := json.Marshal(payload) | ||
assert.Equal(t, `{"aps":{"sound":"Default.caf"}}`, string(b)) | ||
} | ||
|
||
func TestContentAvailable(t *testing.T) { | ||
payload := NewPayload().ContentAvailable() | ||
b, _ := json.Marshal(payload) | ||
assert.Equal(t, `{"aps":{"content-available":1}}`, string(b)) | ||
} | ||
|
||
func TestNewsstandAvailable(t *testing.T) { | ||
payload := NewPayload().NewsstandAvailable() | ||
b, _ := json.Marshal(payload) | ||
assert.Equal(t, `{"aps":{"content-available":1}}`, string(b)) | ||
} | ||
|
||
func TestCustom(t *testing.T) { | ||
payload := NewPayload().Custom("key", "val") | ||
b, _ := json.Marshal(payload) | ||
assert.Equal(t, `{"aps":{},"key":"val"}`, string(b)) | ||
} | ||
|
||
func TestCustomMap(t *testing.T) { | ||
payload := NewPayload().Custom("key", map[string]interface{}{ | ||
"map": 1, | ||
}) | ||
b, _ := json.Marshal(payload) | ||
assert.Equal(t, `{"aps":{},"key":{"map":1}}`, string(b)) | ||
} | ||
|
||
func TestAlertTitle(t *testing.T) { | ||
payload := NewPayload().AlertTitle("hello") | ||
b, _ := json.Marshal(payload) | ||
assert.Equal(t, `{"aps":{"alert":{"title":"hello"}}}`, string(b)) | ||
} | ||
|
||
func TestAlertTitleLocKey(t *testing.T) { | ||
payload := NewPayload().AlertTitleLocKey("GAME_PLAY_REQUEST_FORMAT") | ||
b, _ := json.Marshal(payload) | ||
assert.Equal(t, `{"aps":{"alert":{"title-loc-key":"GAME_PLAY_REQUEST_FORMAT"}}}`, string(b)) | ||
} | ||
|
||
func TestAlertTitleLocArgs(t *testing.T) { | ||
payload := NewPayload().AlertTitleLocArgs([]string{"Jenna", "Frank"}) | ||
b, _ := json.Marshal(payload) | ||
assert.Equal(t, `{"aps":{"alert":{"title-loc-args":["Jenna","Frank"]}}}`, string(b)) | ||
} | ||
|
||
func TestAlertBody(t *testing.T) { | ||
payload := NewPayload().AlertBody("body") | ||
b, _ := json.Marshal(payload) | ||
assert.Equal(t, `{"aps":{"alert":{"body":"body"}}}`, string(b)) | ||
} | ||
|
||
func TestAlertLaunchImage(t *testing.T) { | ||
payload := NewPayload().AlertLaunchImage("Default.png") | ||
b, _ := json.Marshal(payload) | ||
assert.Equal(t, `{"aps":{"alert":{"launch-image":"Default.png"}}}`, string(b)) | ||
} | ||
|
||
func TestAlertLocKey(t *testing.T) { | ||
payload := NewPayload().AlertLocKey("LOC") | ||
b, _ := json.Marshal(payload) | ||
assert.Equal(t, `{"aps":{"alert":{"loc-key":"LOC"}}}`, string(b)) | ||
} | ||
|
||
func TestAlertAction(t *testing.T) { | ||
payload := NewPayload().AlertAction("action") | ||
b, _ := json.Marshal(payload) | ||
assert.Equal(t, `{"aps":{"alert":{"action":"action"}}}`, string(b)) | ||
} | ||
|
||
func TestAlertActionLocKey(t *testing.T) { | ||
payload := NewPayload().AlertActionLocKey("PLAY") | ||
b, _ := json.Marshal(payload) | ||
assert.Equal(t, `{"aps":{"alert":{"action-loc-key":"PLAY"}}}`, string(b)) | ||
} | ||
|
||
func TestCategory(t *testing.T) { | ||
payload := NewPayload().Category("NEW_MESSAGE_CATEGORY") | ||
b, _ := json.Marshal(payload) | ||
assert.Equal(t, `{"aps":{"category":"NEW_MESSAGE_CATEGORY"}}`, string(b)) | ||
} | ||
|
||
func TestMdm(t *testing.T) { | ||
payload := NewPayload().Mdm("996ac527-9993-4a0a-8528-60b2b3c2f52b") | ||
b, _ := json.Marshal(payload) | ||
assert.Equal(t, `{"aps":{},"mdm":"996ac527-9993-4a0a-8528-60b2b3c2f52b"}`, string(b)) | ||
} | ||
|
||
func TestURLArgs(t *testing.T) { | ||
payload := NewPayload().URLArgs([]string{"a", "b"}) | ||
b, _ := json.Marshal(payload) | ||
assert.Equal(t, `{"aps":{"url-args":["a","b"]}}`, string(b)) | ||
} | ||
|
||
func TestCombined(t *testing.T) { | ||
payload := NewPayload().Alert("hello").Badge(1).Sound("Default.caf").Custom("key", "val") | ||
b, _ := json.Marshal(payload) | ||
assert.Equal(t, `{"aps":{"alert":"hello","badge":1,"sound":"Default.caf"},"key":"val"}`, string(b)) | ||
} |