-
Notifications
You must be signed in to change notification settings - Fork 338
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add iOS 15 payload additions #185
Conversation
- Add interruption-level to payload interruption-level options: - passive - active (default if none is passed to apns) - time-sensitive - critical (requires Apple entitlement) - Add relevance-score to payload relevance-score is a number between 0 and 1 The highest score gets featured in the notification summary.
Hi @sideshow, this PR adds support for new iOS 15 payload features interruption-level & relevance-score. Includes new tests & updated readme. Hope it's useful, thanks. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for submitting this! I'm just an interested bystander who'll end up using it ;)
Note that at the time of writing [Apple docs](https://developer.apple.com/documentation/usernotifications/setting_up_a_remote_notification_server/generating_a_remote_notification#2943360) have a typo, showing `time-senstive` as opposed to `time-sensitive`. Testing has shown that the correct spelling `time-sensitive` does indeed work.
Alphabetically order keys in struct as per @Singwai suggestion.
payload/builder.go
Outdated
// InterruptionLevelPassive sets the aps interruption-level to "passive" on the payload. | ||
// This is to indicate the importance and delivery timing of a notification. | ||
// See: https://developer.apple.com/documentation/usernotifications/unnotificationinterruptionlevel/ | ||
// | ||
// {"aps":{"interruption-level":passive}} | ||
func (p *Payload) InterruptionLevelPassive() *Payload { | ||
p.aps().InterruptionLevel = "passive" | ||
return p | ||
} | ||
|
||
// InterruptionLevelActive sets the aps interruption-level to "active" on the payload. | ||
// This is to indicate the importance and delivery timing of a notification. | ||
// See: https://developer.apple.com/documentation/usernotifications/unnotificationinterruptionlevel/ | ||
// | ||
// {"aps":{"interruption-level":active}} | ||
func (p *Payload) InterruptionLevelActive() *Payload { | ||
p.aps().InterruptionLevel = "active" | ||
return p | ||
} | ||
|
||
// InterruptionLevelTimeSensitive sets the aps interruption-level to "time-sensitive" on the payload. | ||
// This is to indicate the importance and delivery timing of a notification. | ||
// See: https://developer.apple.com/documentation/usernotifications/unnotificationinterruptionlevel/ | ||
// | ||
// {"aps":{"interruption-level":time-sensitive}} | ||
func (p *Payload) InterruptionLevelTimeSensitive() *Payload { | ||
p.aps().InterruptionLevel = "time-sensitive" | ||
return p | ||
} | ||
|
||
// InterruptionLevelCritical sets the aps interruption-level to "critical" on the payload. | ||
// This is to indicate the importance and delivery timing of a notification. | ||
// This interruption level requires an approved entitlement from Apple. | ||
// See: https://developer.apple.com/documentation/usernotifications/unnotificationinterruptionlevel/ | ||
// | ||
// {"aps":{"interruption-level":critical}} | ||
func (p *Payload) InterruptionLevelCritical() *Payload { | ||
p.aps().InterruptionLevel = "critical" | ||
return p | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there a reason to use these four different functions for setting this value rather than a single setter (i.e. InterruptionLevel
) and define a custom string type ala EPushType
with the values as defined as constants?
Definitely appreciate the initiative in getting this out.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I used the four functions as I was following the way that individual functions were provided for badges eg. ZeroBadge
etc.
I am happy to swap to a single setter (which was my original thought tbh).
Welcome your thoughts @chrishaines?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure but it seems to be that this is partially due to typing (it allows Badge
to specifically take an int
as an argument with UnsetBadge
being used to set it to nil
to remove it from the payload. I'm not sure why there is a separate ZeroBadge
function rather than just using Badge(0)
🤷♂️ ).
I think that EPushType
seems to be the closest precedent to handling an enumerated value in the codebase.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am inclined to swap it out then as you suggest (I have working code for that implementation ready to go).
Before I do though, can I ask, what is the reason for the E
prefix in EPushType
? Is there some specific naming convention? (I don't do a huge lot in Go).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure where that came from either to be honest. Perhaps it's for Enum
? That's really a complete guess.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that seems a sensible guess!
Just wondering if I should employ the same E
prefix or not!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that sounds reasonable. I would go for it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have swapped out the InterruptionLevel into a single function. Thanks for your input @chrishaines. Please can you give it a once over?
payload/builder.go
Outdated
// InterruptionLevelPassive sets the aps interruption-level to "passive" on the payload. | ||
// This is to indicate the importance and delivery timing of a notification. | ||
// See: https://developer.apple.com/documentation/usernotifications/unnotificationinterruptionlevel/ | ||
// | ||
// {"aps":{"interruption-level":passive}} | ||
func (p *Payload) InterruptionLevelPassive() *Payload { | ||
p.aps().InterruptionLevel = "passive" | ||
return p | ||
} | ||
|
||
// InterruptionLevelActive sets the aps interruption-level to "active" on the payload. | ||
// This is to indicate the importance and delivery timing of a notification. | ||
// See: https://developer.apple.com/documentation/usernotifications/unnotificationinterruptionlevel/ | ||
// | ||
// {"aps":{"interruption-level":active}} | ||
func (p *Payload) InterruptionLevelActive() *Payload { | ||
p.aps().InterruptionLevel = "active" | ||
return p | ||
} | ||
|
||
// InterruptionLevelTimeSensitive sets the aps interruption-level to "time-sensitive" on the payload. | ||
// This is to indicate the importance and delivery timing of a notification. | ||
// See: https://developer.apple.com/documentation/usernotifications/unnotificationinterruptionlevel/ | ||
// | ||
// {"aps":{"interruption-level":time-sensitive}} | ||
func (p *Payload) InterruptionLevelTimeSensitive() *Payload { | ||
p.aps().InterruptionLevel = "time-sensitive" | ||
return p | ||
} | ||
|
||
// InterruptionLevelCritical sets the aps interruption-level to "critical" on the payload. | ||
// This is to indicate the importance and delivery timing of a notification. | ||
// This interruption level requires an approved entitlement from Apple. | ||
// See: https://developer.apple.com/documentation/usernotifications/unnotificationinterruptionlevel/ | ||
// | ||
// {"aps":{"interruption-level":critical}} | ||
func (p *Payload) InterruptionLevelCritical() *Payload { | ||
p.aps().InterruptionLevel = "critical" | ||
return p | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure but it seems to be that this is partially due to typing (it allows Badge
to specifically take an int
as an argument with UnsetBadge
being used to set it to nil
to remove it from the payload. I'm not sure why there is a separate ZeroBadge
function rather than just using Badge(0)
🤷♂️ ).
I think that EPushType
seems to be the closest precedent to handling an enumerated value in the codebase.
payload/builder.go
Outdated
func (p *Payload) RelevanceScore(b float32) *Payload { | ||
p.aps().RelevanceScore = b | ||
return p | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This doesn't appear to allow setting a relevance-score
of 0
because it will omitted when building the aps
JSON. This will result in Apple using their default of 0.5
. I think you can address this by either using the Badge
precedent above (preferred) or by changing the type to a pointer.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can make a PR for this if you'd like.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good catch @chrishaines on relevance-score.
Sure if you have time to do the PR for that, and I will try and get the other swapped out tomorrow or at the weekend.
Thanks.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here ya go!
neilmorton#1
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you @chrishaines! I have merged this.
Allow relevance-score to be set to zero.
f2d2856
to
5485b9d
Compare
Thank you @neilmorton @chrishaines , this is great |
need a new git tag |
Add iOS 15 payload additions (sideshow#185)
…0.23.0 * Add iOS 15 payload additions (sideshow#185) * Add iOS 15 payload additions - Add interruption-level to payload interruption-level options: - passive - active (default if none is passed to apns) - time-sensitive - critical (requires Apple entitlement) - Add relevance-score to payload relevance-score is a number between 0 and 1 The highest score gets featured in the notification summary. * Update readme re iOS 15 features * Fix documentation typo Note that at the time of writing [Apple docs](https://developer.apple.com/documentation/usernotifications/setting_up_a_remote_notification_server/generating_a_remote_notification#2943360) have a typo, showing `time-senstive` as opposed to `time-sensitive`. Testing has shown that the correct spelling `time-sensitive` does indeed work. * Update builder.go Alphabetically order keys in struct as per @Singwai suggestion. * Allow relevance-score to be set to zero. * Updated to single InterruptionLevel function Co-authored-by: Chris Haines <[email protected]> * Go modules support (sideshow#181) * Go Modules Support * Replace Travis with Github Actions (sideshow#190) * Replace Travis with Github Actions * Fix context timeout error * Add Github workflow badge * Add coverage to actions * Update jwt library (sideshow#191) - Resolves sideshow#186 - Resolves sideshow#187 - Resolves sideshow#189 * Use NewReader instead of NewBuffer (sideshow#193) * Add location push type (sideshow#194) * Add location push type * Fix Typo * Add InvalidPushType reason error code * Use type switch with assignment syntax (sideshow#196) * Use POST http constant (sideshow#203) * Use if type conditional (sideshow#198) In that case if type is much simpler and look better. * Simplify FromPemBytes conditional (sideshow#197) - Simplify logic. strings.HasSuffix can check both for suffix and for equality * Use NewRequestWithContext instead of nil checking (sideshow#200) * Use appropriate type cast functions (sideshow#199) * Use appropriate type cast functions * avoid fmt usage * Fix double pointer (sideshow#195) * Refactor request/response variable names (sideshow#205) r *Request is more consistent with n *Notification * Feature/updated http2 transport (sideshow#209) * Update http2 transport * Add ReadIdleTimeout for ping frames * Update defaults for TCP Keepalive * Revert "CF-153: Updating Log to print issuedAt (#7)" This reverts commit 69ea756. * Revert "CF-133: Adding PushTypeLocation (#6)" This reverts commit 3668879. * Reverting Using int64 for timestamp (8fac21d) * Changing module name * gitignore idea directory --------- Co-authored-by: Neil Morton <[email protected]> Co-authored-by: Chris Haines <[email protected]> Co-authored-by: jbendotnet <[email protected]> Co-authored-by: Adam Jones <[email protected]> Co-authored-by: Mikhail Faraponov <[email protected]>
Adds interruption-level to payload
interruption-level options:
Adds relevance-score to payload
Updates readme re iOS 15 features