How to change iOS notification message upon receiving? - ios

When I push notification from OneSignal, I want to push something like
", you have received a message"
I want to replace $name in app with the username something like
notificationMessage = UserDefaults.standard.string(forKey: "username") + notificationMessage
Is it possible to override notification?

If you mean to change the alert that the System shows, then NO you can't change those. They are managed by the OS.
For foreground only:
If you have some internal alert that you'd like to pop—when the app is in foreground then you're free to do as you wish
For example you could do something like:
func userNotificationCenter(center: UNUserNotificationCenter, willPresentNotification notification: UNNotification, withCompletionHandler completionHandler: #escaping (UNNotificationPresentationOptions) -> Void) {
//1. extract notification data
let message = notification.request.content.body
let title = notification.request.content.title
// 2. use the message and title and change their values
// 3. use your new message and title and show your own custom alert.
// 4. I excluded the alert so you could show whatever you like yourself. But still I want to increase the badge and have sound when notification arrives...
completionHandler([.badge, .sound])
}
you can't change the request itself since it's a get only...
Having that said I don't suggest this. Your logic of this should be handled on the server you push these notifications. This should be unnecessary.

Related

iOS push notification sound stopped working using azure notification hub [ no sound at all ]

My ios app has stopped playing sound for push notification since quite long. We have azure notification hub as our backend for sending notifications.
As per our discussion with MS Azure team, they informed that in order to enable the sound, we would need to include "Sound" property as per new APIs. But using azure notification hub this API would become bad request as "Sound" property is not supported by them. There is nothing else can be performed from azure notification side and they suggested to reach out to APNS to seek any alternatives, if any.
They are still working to add support for Critical Alerts on APNS.
Is there any work around? Has anyone faced such issue? Any help would be greatly appreciaated.
Below is the code for registering for push notifications:
let center = UNUserNotificationCenter.current()
center.requestAuthorization(options: [.alert, .sound], completionHandler: {(_ granted: Bool, _ error: Error?) -> Void in
if error == nil {
DispatchQueue.main.async {
UIApplication.shared.registerForRemoteNotifications()
}
}
})
To play the default system sound, create your sound object using the default method.
By default, a notification contains an alert message that is displayed to the user without playing a sound. If you want to play a sound when a notification arrives, Apple provides one “default” sound that you can specify.
{"aps":{"sound":"default"}}
References:
https://developer.apple.com/documentation/usernotifications/unnotificationsound
There is an option to add sound to your remote notification locally, by this way no need to depend on server for adding sound property,
You can also use a notification service app extension to add a sound file to a notification shortly before delivery. In your extension, create a UNNotificationSound object and add it to your notification content in the same way that you’d for a local notification.
For this need to create a new target, you may need create cer for the notification extension's bundle ID same as main app.
Sample UNNotificationServiceExtension code for your reference,
import UserNotifications
class NotificationService: UNNotificationServiceExtension {
var contentHandler: ((UNNotificationContent) -> Void)?
var bestAttemptContent: UNMutableNotificationContent?
// MARK:- Notification lifecycle
override func didReceive(_ request: UNNotificationRequest, withContentHandler contentHandler: #escaping (UNNotificationContent) -> Void) {
self.contentHandler = contentHandler
bestAttemptContent = (request.content.mutableCopy() as? UNMutableNotificationContent)
// -------------
// To play default sound
let defaultSound = UNNotificationSound.default
bestAttemptContent?.sound = defaultSound
// -----OR------
// To play custom sound
let customSound = UNNotificationSound(named: UNNotificationSoundName(rawValue: "somelocalfile"))
bestAttemptContent?.sound = customSound
// --------------
contentHandler(bestAttemptContent!)
}
override func serviceExtensionTimeWillExpire() {
// Called just before the extension will be terminated by the system.
// Use this as an opportunity to deliver your “best attempt” at modified content, otherwise the original push payload will be used.
if let contentHandler = contentHandler, let bestAttemptContent = bestAttemptContent {
// If notification doesnt process in time, Increment badge counter. Default notification will be shown
let customSound = UNNotificationSound(named: UNNotificationSoundName(rawValue: "somelocalfile"))
bestAttemptContent.sound = customSound
contentHandler(bestAttemptContent)
}
}
}
NOTE:
According to this doc sound should be sent as default or any custom sound file path. There is no mentioning on behaviour of ignoring "Sound" in payload, considering this as Sound is mandatory!!.
EDIT:
#shaqir From Apple documentation here,
Include this key when you want the system to play a sound.
If the sound file cannot be found, or if you specify default for the value, the system plays the default alert sound.
Means if no sound key in payload, no sound will be played. It should be default or wrong audio path.

How to increase notification badge number dynamically when local notification is delivered?

My App sets up multiple notifications via a loop based on a calendar date and time. While everything else is working correctly with this, I cannot seem to get the badge number to increment properly. I have tried using a counter and setting
content.badge = self.counter as NSNumber
... or using ...
content.badge = NSNumber(value: UIApplication.shared.applicationIconBadgeNumber + 1)
but what happens is something like the following:
User gets notification 1,2,3,4,5 and badge number gets set to 5 content.badge = self.counter
User then "clears" notifications 2 and 3 -> and badge number is now 3 via my code (UIApplication.shared.applicationIconBadgeNumber - 1)
When the next notification (number 6) pops up, the badge number SHOULD show 4. It doesn't. It shows 6 because that's what was set via content.badge
What is the proper way to increment the badge number? I've looked at various posts here but they're for push notifications. Mine is for a local notifications. Can I set/update badge number WHEN a notification is actually delivered? I thought about trying this in...
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: #escaping (UNNotificationPresentationOptions) -> Void) {
completionHandler([.alert, .badge, .sound])
}
...but that seems to only be for in-app notifications. Is there another function that I can do this in?

How do I make a UNUserNotification that's consistent through app states?

I make a UNUserNotification like this:
let content = UNMutableNotificationContent()
content.title = "a title"
content.body = "a body"
content.sound = .default
content.categoryIdentifier = "\(type(of: self))"
let request = UNNotificationRequest(
identifier: UUID().uuidString,
content: content,
trigger: UNTimeIntervalNotificationTrigger(timeInterval: 0.01, repeats: false)
)
let category = UNNotificationCategory(
identifier: content.categoryIdentifier,
actions: [
UNNotificationAction(identifier: Strings.accept.id, title: Strings.accept.title, options: [.authenticationRequired, .foreground]),
UNNotificationAction(identifier: Strings.reject.id, title: Strings.reject.title, options: [.authenticationRequired, .destructive])
],
intentIdentifiers: [],
options: .customDismissAction
)
It will show a notification with a title and body, and two custom action buttons (accept and reject, it's an incoming call). It plays a sound too, but for some reason not if the app is foregrounded.
I also try to fake a persistent notification with it, like the way Whatsapp does it by repeating a local notification every ~4 seconds, but the second time it shows the notification the sound is cut off a bit. It's not the sound of the first one, the second one shows with its own sound playing but this time it doesn't fully play out. The sound is only ~1-2 seconds.
I don't understand why there are these differences, how do I make it always play a sound (foreground, background, not running) and how do I make sure the sound is not cut off the second time the notification is shown?
When notifications are received whilst the app is running the notifications are normally silenced so that the app can handle them in a more native way.
If I remember rightly, receiving the notification will call:
func userNotificationCenter(_ center: UNUserNotificationCenter,
willPresent notification: UNNotification,
withCompletionHandler completionHandler:
#escaping (UNNotificationPresentationOptions) -> Void) {
if someCondition {
completionHandler(.alert)
} else {
completionHandler(.init(rawValue: 0))
}
}
This method is called when the notification is received and if the app is running in the foreground, it will normally be silenced. The completion handler determines what action should be taken and whether or not a notification should show or a sound made etc.
In this case if someCondition is true then it should show the notification natively as it normally would, otherwise dont do anything.
Try calling completionHandler(.alert) in this method in your app and your notifications should show
Checkout the documentation here

iOS push notification banner clear action button [duplicate]

This question already has answers here:
How to detect "clear" notifications
(3 answers)
Closed 4 years ago.
i want to do something when user clear notification from home screen is it possible to get trigger when user tap on clear button on push notification banner, i ended up with adding custom button on view but thats not feasible.
image is attached i want trigger when user tap on this clear action any idea ???
{
“aps” : {
“category” : “MEETING_INVITATION”
“alert” : {
“title” : “Weekly Staff Meeting”
“body” : “Every Tuesday at 2pm”
},
},
“MEETING_ID” : “123456789”,
“USER_ID” : “ABCD1234”
}
i have done this but its adding button on view like popup
func userNotificationCenter(_ center: UNUserNotificationCenter,
didReceive response: UNNotificationResponse,
withCompletionHandler completionHandler:
#escaping () -> Void) {
// Get the meeting ID from the original notification.
let userInfo = response.notification.request.content.userInfo
let meetingID = userInfo["MEETING_ID"] as! String
let userID = userInfo["USER_ID"] as! String
// Perform the task associated with the action.
switch response.actionIdentifier {
case "ACCEPT_ACTION":
sharedMeetingManager.acceptMeeting(user: userID,
meetingID: meetingID)
break
case "DECLINE_ACTION":
sharedMeetingManager.declineMeeting(user: userID,
meetingID: meetingID)
break
// Handle other actions…
default:
break
}
// Always call the completion handler when done.
completionHandler()
}
From docs about actionIdentifier:
This parameter may contain one the identifier of one of your UNNotificationAction objects or it may contain a system-defined identifier. The system defined identifiers are UNNotificationDefaultActionIdentifier and UNNotificationDismissActionIdentifier, which indicate that the user opened the app or dismissed the notification without any further actions.
So you don’t have to use your own identifiers, use system’s.
Instead of
"ACCEPT_ACTION"
use
UNNotificationDefaultActionIdentifier
and instead of
"DECLINE_ACTION"
use
UNNotificationDismissActionIdentifier

How to handle UNNotificationAction when app is closed?

How to handle new iOS10 Notification Action when app is closed (not in background) ?
when app is minimalized everything works fine with:
UNUserNotificationCenter.current().delegate = x
and handling it in
class x: UNUserNotificationCenterDelegate {
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: #escaping () -> Swift.Void) {
}
}
but nothing is called when app is closed and user tap action in notification... maybe i can't handle background task and i always have to launch app?
The notification action buttons handling can be done in both Extension as well as in Containing App.
When the action button is tapped, the handle first goes to the Extension and then to the Containing App if required. If Extension does not handle the notification action, the handle is passed on to the containing app.
Tapping a button launches your app (either in the foreground or
background) and gives you a chance to perform the indicated action.
Handling in extension:
func didReceive(_ response: UNNotificationResponse, completionHandler completion: #escaping (UNNotificationContentExtensionResponseOption) -> Void)
{
//You need to handle all the actions that appear with notification..
completion(.dismissAndForwardAction)
}
The completion closure takes a value of type UNNotificationContentExtensionResponseOption:
enum UNNotificationContentExtensionResponseOption : UInt
{
case doNotDismiss //the custom UI is not dismissed after handling the action
case dismiss //the custom UI is dismissed after handling the action
case dismissAndForwardAction //the custom UI is dismissed after handling the action and the control is then passed to containing app for any additional handling
}
Handling in Containing App:
extension AppDelegate : UNUserNotificationCenterDelegate
{
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: #escaping () -> Void)
{
// Action handling - handling for all actions is not required
completionHandler()
}
}
For more you can refer to this(https://github.com/pgpt10/RichNotificationSample) tutorial.
Yes, it always launch the app, when user tap action in notification, button launches your app.
Some lines from apple doc:
Tapping a button launches your app (either in the foreground or background) and gives you a chance to perform the indicated action. You use this class to specify the text that is displayed in the button and the information your app needs to perform the corresponding action.
"Tapping a button launches your app (either in the foreground or background) and gives you a chance ... "
These lines appear in the doc for UIUserNotificationAction, which has been deprecated in iOS10.
The original question refers to the UNUserNotificationCenterDelegate in iOS 11.
Relevant doc: Declaring Your Actionable Notification Types
Quote from the doc:
When the user selects an action, the system launches your app in the
background and notifies the shared UNUserNotificationCenter object,
which notifies its delegate. Use your delegate object's
userNotificationCenter:didReceiveNotificationResponse:withCompletionHandler:
method to identify the selected action and provide an appropriate
response.

Resources