Are remote notifications possible for free provisioning account? - ios

I'm slightly confused about the difference between "normal" push notifications vs. remote notifications, as well as which of them is possible with my free provisioning profile.
I'm able to send push notifications that appear on lock-screen with the following code:
AppDelegate.swift
func application(_ application: UIApplication, didFinishLaunchingWithOptions: [UIApplication.LaunchOptionsKey : Any]?) -> Bool {
...
registerForPushNotifications()
createNotification()
return true
}
func registerForPushNotifications() {
UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .sound, .badge]) { [weak self] granted, _ in
print("Permission granted: \(granted)")
guard granted else { return }
}
}
static func createNotification() {
let content = UNMutableNotificationContent()
content.title = "test-title"
// 2. create trigger
var components = DateComponents.init()
components.hour = 14
components.minute = 39
let trigger = UNCalendarNotificationTrigger(dateMatching: components, repeats: false)
content.badge = 1
content.sound = UNNotificationSound.default
// 4. create send request
let request = UNNotificationRequest(identifier: UUID().uuidString, content: content, trigger: trigger)
// add request to send center
UNUserNotificationCenter.current().add(request) { error in
if error == nil {
print("Time Interval Notification scheduled!")
}
}
}
However, what I really want is to create a daily notification that is based on some HTTP request.
In other words, I would like to send an HTTP request to some API (say it returns a boolean value) and create a notification based on that value.
I've done some research and I think that remote notifications are capable of doing so.
Unfortunately, when I try to register for remote notifications:
DispatchQueue.main.async {
UIApplication.shared.registerForRemoteNotifications()
}
I get an error: no valid “aps-environment” entitlement string found for application.
As I've stated - I do not have a paid Apple developer membership.
My questions are:
will remote notifications actually fulfill my needs?
Are remote notifications possible with free provisioning account?
I've found that "normal" push notifications are indeed possible.
Thanks!

It seems you have a misunderstanding about how remote push notifications work. Your server needs to schedule the remote notifications, not your app. You can schedule a daily remote notification on your server, which should suffice your needs, but as I've said, you'll need server-side logic to achieve this.
No - you need a paid developer membership to be able to use remote push notifications. Local notifications require no paid membership, but remote ones do.

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.

iOS app not receiving push notifications from Twilio programmable chat

I have started a new project to try out Twilio programable chat but I'm not able to get the push notifications to work.
I am using Firebase to handle the push notifications and notifications directly from Firebase are working fine.
Now here's how I've configured everything:
I am using a Twilio function for my chat to work. I've created an FCM push credential on Twilio dashboard and when asked for the FCM SECRET I've added the Server key that was inside the Cloud Messaging Settings on Firebase console.
I have updated the push notification configuration to enable notifications on a new message on the dashboard like this:
On the app I do have push notifications working, because I am able to receive notifications directly from Firebase.
I've registered for remote notifications on didFinishLaunchingWithOptions like this:
UNUserNotificationCenter.current().delegate = self
UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .badge, .sound]) { _, _ in }
application.registerForRemoteNotifications()
On AppDelegate I'm actually receiving the device token, storing it for later and setting it on my chat client
static var token: Data?
func application(_: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
AppDelegate.token = deviceToken
}
After that, when I'm creating my chat client, I set the device token and the callback's result is successful
func signIn(identity: String) {
self.identity = identity
tokenService.retrieveToken(identity: identity) { result in
if case let .success(token) = result {
TwilioChatClient.chatClient(withToken: token, properties: nil, delegate: self) { _, client in
self.client = client
if let pushToken = AppDelegate.token {
client?.register(withNotificationToken: pushToken) { result in
print(result.isSuccessful()) // this prints true
}
}
}
}
}
}
After all this setup I'm still not able to receive push notifications, so I'm not sure if I'm doing something wrong or if I'm missing something
I have had similar issue. My problem was that I was not able to receive push notifications on iOS 13.
For me the solution was to update the Twilio SDK within iOS Project.
Right now it is v.4.0.0

iOS : How to remove remote notifications if app is not active?

I want to clear remote notifications so they don't add up in the Notification Center (like when you get a video call in WhatsApp or Messenger, only the last notification is displayed).
I tried to call (in didReceiveRemoteNotification):
let center = UNUserNotificationCenter.current()
center.removeDeliveredNotifications(withIdentifiers: ["notification_identifier"])
But it gets called only if the app is active. How can I do this if the app is in another state?
Thanks for your help.
After some research and thanks to Paulw1's answer, I found out there are two ways of doing this:
Remote only
Notifications can be collapsed remotely, you only have to send the notification with apns-collapse-id as a request header. Please note that it's only supported in HTTP/2 though. More information here.
Silent remote + local notification
The other way consists in sending a silent remote notification, with this kind of payload:
{
"type": "notification_type",
"aps" : {
"content-available": 1
}
}
It will call didReceiveRemoteNotification even if the app's state is inactive or background. Then, I create a local notification request (needs using UserNotifications, available from iOS10) :
let content = UNMutableNotificationContent()
content.body = "Notification message"
let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 0.25, repeats: false)
let request = UNNotificationRequest(identifier: "identifierToUpdate", content: content, trigger: trigger)
self.center.add(request, withCompletionHandler: nil)
The key to update the previous notification is to use the same request identifier.

How make iOS app running on background forever in Swift?

I want to make an app that makes HTTP request to a website periodically. The app has to run in the background, but can wake up or show a notification, depending on a response of request. Like a message of WhatsApp, but I don't have a webserver, only the device check values of the http get request.
This can be done with the fetch capability mentioned in the iOS Background Execution guide. You need to include the 'Background fetch' option in your app's capabilities, and then implement the application(_:performFetchWithCompletionHandler:) method in your application delegate. Then, this method will be called when iOS think's it is a good time to download some content. You can use URLSession and the associated methods to download whatever you want, and then call the provided completion handler, indicating whether content was available.
Note that this does not allow you to schedule such downloads, or have any control over when (or even if) they happen. The operating system will call the above method only when it decides that it is a good time. Apple's docs explain:
Enabling this mode is not a guarantee that the system will give your app any time to perform background fetches. The system must balance your app’s need to fetch content with the needs of other apps and the system itself. After assessing that information, the system gives time to apps when there are good opportunities to do so.
As an example, here is a basic implementation which initiates a download and then schedules a local notification for ten seconds from now if we get a good response:
func application(_ application: UIApplication, performFetchWithCompletionHandler completionHandler: #escaping (UIBackgroundFetchResult) -> Void) {
URLSession.shared.dataTask(with: URL(string: "http://example.com/backgroundfetch")!) { data, response, error in
guard let data = data else {
completionHandler(.noData)
return
}
guard let info = String(data: data, encoding: .utf8) else {
completionHandler(.failed)
return
}
let content = UNMutableNotificationContent()
content.title = "Update!"
content.body = info
let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 10, repeats: false)
let request = UNNotificationRequest(identifier: "UpdateNotification", content: content, trigger: trigger)
let center = UNUserNotificationCenter.current()
center.add(request) { (error : Error?) in
if let error = error {
print(error.localizedDescription)
}
}
completionHandler(.newData)
}
}
The Local and Remote Notification Programming Guide should be used as the reference for implementing notifications.

iOS Swift Twilio Programmable Chat Push Notifications

Using the TwilioChatClient pod, I have successfully registered my app to Twilio Programmable Chat to receive APN notifications.
However, from what I can tell, these notifications are being created after calling client.register(withToken: deviceToken) on an instantiated TwilioChatClient client, and NOT through the application's AppDelegate didReceiveRemoteNotification method. Stranger yet, didReceiveRemoteNotification is called, but only when the application is in the active state, and not the background state, where I would like to perform some operations.
Does anyone know where and how these notifications are being created, or why didReceiveRemoteNotification is only called during the active state? Amongst other things, I would like to increment the application icon badge number with each notification sent out by the client.
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
print("Registered for notifications");
if UserUtils.client?.userInfo != nil {
print("Has info");
UserUtils.deviceToken = deviceToken;
UserUtils.client?.register(withToken: deviceToken)
} else {
print("No info");
updatedPushToken = deviceToken as NSData?
}
}
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: #escaping (UIBackgroundFetchResult) -> Void) {
print("Received a notification");
if UIApplication.shared.applicationState != .active {
print(userInfo);
UserUtils.client?.handleNotification(userInfo);
UIApplication.shared.applicationIconBadgeNumber += 1;
if UserUtils.client?.userInfo != nil {
print(userInfo);
let jsonNotification = JSON(userInfo["aps"])
let alert = jsonNotification["alert"].stringValue + "\"}";
print(JSON.init(parseJSON: alert)["body"]);
} else {
print(userInfo);
let jsonNotification = JSON(userInfo["aps"])
let alert = jsonNotification["alert"].stringValue + "\"}";
print(JSON.init(parseJSON: alert)["body"]);
}
} else {
}
}
where the client.register(withToken: deviceToken) works as intended.
Twilio developer evangelist here.
I've spoken with the Programmable Chat team and this is what I've found out:
application(_:didReceiveRemoteNotification:fetchCompletionHandler:) is for silent notifications in the background that perform background processing only (that is, with "content-available": 1 set in the APNS notification). Programmable Chat sends notifications that show information to the user, so it won't be fired in background mode
Notifications can update the badge count for you though, so this is processing you don't have to do, this requires a different setting in the notification that we currently do not support, however work is being done to add that support now
If you want to both show a notification and do further background processing, this is not supported in regular notifications, however this is supported with iOS 10's service extensions. Programmable Chat doesn't support those either, but again, it is being worked on, so you may see that soon
Keep an eye on the Programmable Chat Changelog for these additions.
Let me know if that helps at all.

Resources