diff --git a/README.md b/README.md index c4f397420..35e569092 100644 --- a/README.md +++ b/README.md @@ -651,7 +651,12 @@ The Request body must have a notifications array. The following is a parameter t | mutable_content | bool | enable Notification Service app extension. | - | only iOS(10.0+). | | name | string | sets the name value on the aps sound dictionary. | - | only iOS | | volume | float32 | sets the volume value on the aps sound dictionary. | - | only iOS | -| interruption_level | string | defines the interruption level for the push notification. | - | only iOS(15.0+) | +| interruption_level | string | defines the interruption level for the push notification. | - | only iOS(15.0+) | +| content-state | string array | dynamic and custom content for live-activity notification. | - | only iOS(16.1+) | +| timestamp | int | the UNIX time when sending the remote notification that updates or ends a Live Activity | - | only iOS(16.1+) | +| event | string | describes whether you update or end an ongoing Live Activity | - | only iOS(16.1+) | +| stale-date | int | the date which a Live Activity becomes stale, or out of date | - | only iOS(16.1+) | +| dismissal-date | int | the UNIX time -timestamp- which a Live Activity will end and will be removed | - | only iOS(16.1+) | ### iOS alert payload diff --git a/notify/notification.go b/notify/notification.go index 109a2c25d..33a00ddb0 100644 --- a/notify/notification.go +++ b/notify/notification.go @@ -119,6 +119,14 @@ type PushNotification struct { // ref: https://github.com/sideshow/apns2/blob/54928d6193dfe300b6b88dad72b7e2ae138d4f0a/payload/builder.go#L7-L24 InterruptionLevel string `json:"interruption_level,omitempty"` + + // live-activity support + // ref: https://developer.apple.com/documentation/activitykit/updating-and-ending-your-live-activity-with-activitykit-push-notifications + ContentState D `json:"content-state,omitempty"` + StaleDate int64 `json:"stale-date,omitempty"` + DismissalDate int64 `json:"dismissal-date"` + Event string `json:"event,omitempty"` + Timestamp int64 `json:"timestamp,omitempty"` } // Bytes for queue message diff --git a/notify/notification_apns.go b/notify/notification_apns.go index 6f053e8b3..a2fda2066 100644 --- a/notify/notification_apns.go +++ b/notify/notification_apns.go @@ -294,6 +294,26 @@ func iosAlertDictionary(notificationPayload *payload.Payload, req *PushNotificat notificationPayload.AlertSummaryArgCount(req.Alert.SummaryArgCount) } + if len(req.ContentState) > 0 { + notificationPayload.ContentState(req.ContentState) + } + + if req.StaleDate > 0 { + notificationPayload.StaleDate(req.StaleDate) + } + + if req.DismissalDate > 0 { + notificationPayload.DismissalDate(req.DismissalDate) + } + + if len(req.Event) > 0 { + notificationPayload.Event(req.Event) + } + + if req.Timestamp > 0 { + notificationPayload.Timestamp(req.Timestamp) + } + return notificationPayload } diff --git a/notify/notification_apns_test.go b/notify/notification_apns_test.go index ea2c5b588..e8ba3f864 100644 --- a/notify/notification_apns_test.go +++ b/notify/notification_apns_test.go @@ -513,6 +513,11 @@ func TestMessageAndTitle(t *testing.T) { func TestIOSAlertNotificationStructure(t *testing.T) { var dat map[string]interface{} + unix := time.Now().Unix() + stale_date := time.Now().Unix() + dismissal_date := stale_date + 5 + timeStamp := time.Now().Unix() + itemId := float64(12345) req := &PushNotification{ Message: "Welcome", @@ -529,6 +534,14 @@ func TestIOSAlertNotificationStructure(t *testing.T) { TitleLocKey: testMessage, }, InterruptionLevel: testMessage, + StaleDate: stale_date, + DismissalDate: dismissal_date, + Event: testMessage, + Timestamp: timeStamp, + ContentState: D{ + "item_id": itemId, + "item_name": testMessage, + }, } notification := GetIOSNotification(req) @@ -550,10 +563,16 @@ func TestIOSAlertNotificationStructure(t *testing.T) { subtitle, _ := jsonparser.GetString(data, "aps", "alert", "subtitle") titleLocKey, _ := jsonparser.GetString(data, "aps", "alert", "title-loc-key") interruptionLevel, _ := jsonparser.GetString(data, "aps", "interruption-level") + staleDate, _ := jsonparser.GetInt(data, "aps", "stale-date") + event, _ := jsonparser.GetString(data, "aps", "event") + timestamp, _ := jsonparser.GetInt(data, "aps", "timestamp") aps := dat["aps"].(map[string]interface{}) alert := aps["alert"].(map[string]interface{}) titleLocArgs := alert["title-loc-args"].([]interface{}) locArgs := alert["loc-args"].([]interface{}) + contentState := aps["content-state"].(map[string]interface{}) + contentStateItemId := contentState["item_id"] + contentStateItemName := contentState["item_name"] assert.Equal(t, testMessage, action) assert.Equal(t, testMessage, actionLocKey) @@ -564,6 +583,16 @@ func TestIOSAlertNotificationStructure(t *testing.T) { assert.Equal(t, testMessage, subtitle) assert.Equal(t, testMessage, titleLocKey) assert.Equal(t, testMessage, interruptionLevel) + assert.Equal(t, testMessage, event) + assert.Equal(t, unix, staleDate) + assert.Equal(t, unix, timestamp) + + // dynamic contentState content + assert.Equal(t, contentStateItemId, itemId) + assert.Equal(t, contentStateItemName, testMessage) + assert.Contains(t, contentState, "item_id") + assert.Contains(t, contentState, "item_name") + assert.Contains(t, titleLocArgs, "a") assert.Contains(t, titleLocArgs, "b") assert.Contains(t, locArgs, "a")