I have implemented the VoIP Push. everything works fine but when app recieves push, mobile starts ringing and just after 1-2 sec(the length of my .wav file) it stops.
I want: Sound should ring until user accept/reject the call.
My solutions
I should place the lengthy sound so it keeps on
ringing?
Or i should send the Voip Push Again and again untill user cancels/attend call?
After recieving push I should localy fire the push again and again.
I hope once you receive pushkit payload, then you are scheduling local notification and local notification is having sound file.
Sound file plays on 2 things, length of sound file ( 5 / 10 / 15 Seconds ) or max upto 30 seconds.
So if your sound file is less then 30 seconds, then edit your sound file and make repetitive till 30 seconds.
If you want to play sound file for more than 30 seconds then either you have reschedule local notification with sound file at each 30 seconds till user accept call or resend push kit payload from back end.
After all this things still your sound file stops in 1/2 seconds, then do check may be your app is crashing in background or terminated state.
Code
#available(iOS 8.0, *)
func pushRegistry(registry: PKPushRegistry!, didReceiveIncomingPushWithPayload payload: PKPushPayload!, forType type: String!) {
// Process the received push
var arrTemp = [NSObject : AnyObject]()
arrTemp = payload.dictionaryPayload
let dict : Dictionary <String, AnyObject> = arrTemp["aps"] as! Dictionary<String, AnyObject>
if "IfUserHasLoggedInWithApp" // Check this flag then only proceed
{
if UIApplication.sharedApplication().applicationState == UIApplicationState.Background || UIApplication.sharedApplication().applicationState == UIApplicationState.Inactive
{
if "CheckForIncomingCall" // Check this flag to know incoming call or something else
{
var strTitle : String = dict["alertTitle"] as? String ?? ""
let strBody : String = dict["alertBody"] as? String ?? ""
strTitle = strTitle + "\n" + strBody
let notificationIncomingCall = UILocalNotification()
notificationIncomingCall.fireDate = NSDate(timeIntervalSinceNow: 1)
notificationIncomingCall.alertBody = strTitle
notificationIncomingCall.alertAction = "Open"
notificationIncomingCall.soundName = "SoundFile.mp3"
notificationIncomingCall.category = dict["category"] as? String ?? ""
notificationIncomingCall.userInfo = "As per payload you receive"
UIApplication.sharedApplication().scheduleLocalNotification(notificationIncomingCall)
}
else
{
// something else
}
}
}
}
Debug pushkit notification in terminated state
Put debug pointer on delegate methods
Go to edit scheme
Select run option then Launch -> Wait for executable to be launched
Send push kit payload from back end
Once you get payload on device
it will automatically invoke and debug pointer will invoke at delegate methods.
You can refer some details here.
https://github.com/hasyapanchasara/PushKit_SilentPushNotification
Related
I am working on alarm application, i need to schedule alarm on specific time, I use scheduleLocalNotification for scheduling alarms and it's working fine as i want. BUT I need to run to a request to my API server before triggering alarm. In that request I want to check some parameters returning from API server, If that satisfies some condition.
If any one have a method that run on a particular date - time in swift
Please help me for that
func addAlarm (newAlarm: Alarm) {
// Create persistent dictionary of data
var alarmDictionary = NSUserDefaults.standardUserDefaults().dictionaryForKey(ALARMS_KEY) ?? Dictionary()
// Copy alarm object into persistent data
alarmDictionary[newAlarm.UUID] = newAlarm.toDictionary()
// Save or overwrite data
NSUserDefaults.standardUserDefaults().setObject(alarmDictionary, forKey: ALARMS_KEY)
scheduleNotification(newAlarm, category: "ALARM_CATEGORY")
scheduleNotification(newAlarm, category: "FOLLOWUP_CATEGORY")
}
/* NOTIFICATION FUNCTIONS */
func scheduleNotification (alarm: Alarm, category: String) {
let notification = UILocalNotification()
notification.category = category
notification.repeatInterval = NSCalendarUnit.Day
switch category {
case "ALARM_CATEGORY":
notification.userInfo = ["UUID": alarm.UUID]
notification.alertBody = "Time to wake up!"
notification.fireDate = alarm.wakeup
notification.timeZone = NSTimeZone.localTimeZone()
notification.soundName = "loud_alarm.caf"
break
case "FOLLOWUP_CATEGORY":
notification.userInfo = ["UUID": alarm.followupID]
notification.alertBody = "Did you arrive yet?"
notification.fireDate = alarm.arrival
notification.timeZone = NSTimeZone.localTimeZone()
notification.soundName = UILocalNotificationDefaultSoundName
break
default:
print("ERROR SCHEDULING NOTIFICATION")
return
}
print("Notification=\(notification)")
// For debugging purposes
if alarm.isActive {
UIApplication.sharedApplication().scheduleLocalNotification(notification)
}
}
Waking up an app through a local notification is not possible, this is available only for remote notifications. According to the Notification Programming Guide:
When a remote notification arrives, the system handles user
interactions normally when the app is in the background. It also
delivers the notification payload to the
application:didReceiveRemoteNotification:fetchCompletionHandler:
method of the app delegate in iOS and tvOS
But there is still a catch; even then it is not guaranteed that the app will be launched since, according to didReceiveRemoteNotification:fetchCompletionHandler: documentation:
However, the system does not automatically launch your app if the user
has force-quit it. In that situation, the user must relaunch your app
or restart the device before the system attempts to launch your app
automatically again.
I don't think there is a guaranteed way to schedule a block for execution in some later moment, independently from the state of the app at that time. Depending on your specific requirements and frequency, you could perhaps register for the fetch background mode and implement application:performFetchWithCompletionHandler: to opportunistically fetch and validate server data. Last note: make sure that you are a responsible background app (from my experience Apple takes this requirement seriously)
I've been working on one of my project where I allow users to schedule multiple notifications at their desired time.
iOS 10 gave us the ability to use a DateComponents as the fire date for our notification but I'm kind of lost as to how I'm supposed to schedule and handle multiple notifications.
Each notification needs its own request which then in turn needs its own identifier else you cannot create multiple notifications.
I figured I had to work with the identifier to schedule and handle notifications, but now my code is such a mess that I've been seriously asking myself if there hasn't been an easier way of doing this.
According to my data model the notification unique identifier is composed of :
The id of my model
A number that increments each time a new notification is created
The above is separated by an underscore
So for example if I had to schedule 10 notifications for the object with the id 3 it would look like this : 3_1, 3_2, 3_3...
Every time I receive a notification I loop trough the received notifications to update my UI. And when the user desires to delete the received notifications for a specific model, I loop through the received notification's unique identifiers by checking the identifiers that starts with the same ID.
I don't really see how I could manage to do it otherwise because according to the documentation, the only way of deleting a delivered notification is by using the identifier : UNUserNotificationCenter.current().removeDeliveredNotifications(withIdentifiers:)
The thing is, it's creating all sort of problems and while I could easily correct them it looks very hacky. I'm not really proud of what I've done and I am looking for more clever ways of getting around it. I intentionally did not post any code because that's not the problem. The approach is the real problem.
I'm asking here because the UserNotifications framework is pretty new and I haven't been able to find ressources taking about this subject.
Any idea ? Thanks in advance.
Edit : Here's some code.
#available(iOS 10.0, *)
func checkDeliveredAndPendingNotifications(completionHandler: #escaping (_ identifierDictionary: Dictionary<String, Int>) -> ()) {
var identifierDictionary:[String: Int] = [:]
UNUserNotificationCenter.current().getDeliveredNotifications { (notifications) in
for notification in notifications {
let identifierArraySplit = notification.request.identifier.components(separatedBy: "_")
if identifierDictionary[identifierArraySplit[0]] == nil || identifierDictionary[identifierArraySplit[0]]! < Int(identifierArraySplit[1])! {
identifierDictionary[identifierArraySplit[0]] = Int(identifierArraySplit[1])
}
}
UNUserNotificationCenter.current().getPendingNotificationRequests(completionHandler: { (requests) in
for request in requests {
let identifierArraySplit = request.identifier.components(separatedBy: "_")
if identifierDictionary[identifierArraySplit[0]] == nil || Int(identifierArraySplit[1])! > identifierDictionary[identifierArraySplit[0]]! {
identifierDictionary[identifierArraySplit[0]] = Int(identifierArraySplit[1])
}
}
completionHandler(identifierDictionary)
})
}
}
#available(iOS 10.0, *)
func generateNotifications() {
for medecine in medecines {
self.checkDeliveredAndPendingNotifications(completionHandler: { (identifierDictionary) in
DispatchQueue.main.async {
self.createNotification(medecineName: medecine.name, medecineId: medecine.id, identifierDictionary: identifierDictionary)
}
})
}
}
#available(iOS 10.0, *)
func createNotification(medecineName: String, medecineId: Int identifierDictionary: Dictionary<String, Int>) {
let takeMedecineAction = UNNotificationAction(identifier: "TAKE", title: "Take your medecine", options: [.destructive])
let category = UNNotificationCategory(identifier: "message", actions: [takeMedecineAction], intentIdentifiers:[], options: [])
UNUserNotificationCenter.current().setNotificationCategories([category])
let takeMedecineContent = UNMutableNotificationContent()
takeMedecineContent.userInfo = ["id": medecineId]
takeMedecineContent.categoryIdentifier = "message"
takeMedecineContent.title = medecineName
takeMedecineContent.body = "It's time for your medecine"
takeMedecineContent.badge = 1
takeMedecineContent.sound = UNNotificationSound.default()
let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 60, repeats: false)
var takeMedecineIdentifier = ""
for identifier in identifierDictionary {
if Int(identifier.key) == medecineId {
let nextIdentifierValue = identifier.value + 1
takeMedecineIdentifier = String(medecineId) + "_" + String(nextIdentifierValue)
}
}
let takeMedecineRequest = UNNotificationRequest(identifier: takeMedecineIdentifier, content: takeMedecineContent, trigger: trigger)
UNUserNotificationCenter.current().add(takeMedecineRequest, withCompletionHandler: { (error) in
if let _ = error {
print("There was an error : \(error)")
}
})
}
In the checkDeliveredAndPendingNotifications method, I loop through all the pending and delivered notifications, so later on I can create an identifier that does not exist already. I haven't found another way to generate unique identifiers for each notification.
As most of the work is done on another async queue, I've also created a completion handler when he has finished its job. I then call the createNotification method on the main thread (because I'm using Realm, and I'm obliged too do this) which should create a notification.
The problem here is the func add(UNNotificationRequest, withCompletionHandler: (Error?) -> Void)? = nil) method which is also doing work asynchronously. So when I go back to my loop in generateNotifications the checkDeliveredAndPendingNotifications return incorrect data. Well not incorrect it's just that the notification hasn't been created yet...
I'm a total noob with threading and I'm stuck with these kind of operations and I don't know where to go. I'm not sure I'm approaching the problem the right way.
You can get all notification and set/Delete as you need. Have a look on this accepted answer for both Objc c and swift.
How to schedule a local notification in iOS 10 (objective-c)
Hi I want to fetch some data using Alamofire and a NSTimer
The app works fine on foreground, the timer is set to call the GetEstado function each 30 seconds but when the app enters background the timer is paused and if my server updates something it does not actually updates on the app
Here's my code
func GetEstado(){
Alamofire.request(.POST, "https://myurl/getestado.php", parameters: ["id": id])
.responseString { rta in
if let dataFromString = rta.result.value!.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false) {
let json = JSON(data: dataFromString)
for (key,subJson):(String, JSON) in json {
if(key=="e"){
if(subJson.stringValue=="1"){
self.Timer.invalidate()
print("ACTUALIZACION")
let notification = UILocalNotification()
notification.fireDate = NSDate(timeIntervalSinceNow: 5)
notification.alertBody = "UPDATED"
notification.soundName = UILocalNotificationDefaultSoundName
UIApplication.sharedApplication().scheduleLocalNotification(notification)
self.performSegueWithIdentifier("UPDATED", sender: self)
}
else{
print("UPS")
}
}
}
}
}
}
Thanks
I think #Paulw11 answer your question in his comment, you can't use NSTimer in background, Apple has a known list of the task that can be produced in background, you can read more here.
But let think for a moment what you're trying to achieve, let suppose you can do it using NSTimer, then you have your app in background consuming memory and battery in your device constantly to try to get the updates from your server, this is not recommended at all.
It's for this that Apple/Google introduced Apple Push Notifications (Google: Android Push Notifications) to handle that the server notifies the app when it's in background or inactive regarding any task that is programmed in the server, lets say a new mail, a new message in the case of messaging apps, etc.
Then, the option you have is use the service proposed by Apple, you can read more in the following docs:
Notifications
Apple Push Notification Service
I hope this help you.
I am having troubles increasing the badge number using the Parse iOS Framework.
When I call this code, the other user gets the Push notification, but his badge number is not increasing on the icon.
let push = PFPush()
let data = ["badge": "Increment"]
push.setData(data)
push.setChannel("channel_\(userId)")
push.setMessage(message)
var err: NSError?
do {
try push.sendPush()
} catch var error as NSError {
err = error
} catch {
fatalError()
}
Thanks!
Try with this in swift for increase
let currentCountStr = UIApplication.sharedApplication().applicationIconBadgeNumber.description
let currentCount = Int(currentCountStr)
if(currentCount > 0) {
UIApplication.sharedApplication().applicationIconBadgeNumber = currentCount! + 1
} else {
UIApplication.sharedApplication().applicationIconBadgeNumber = 1
}
You should check your database and/or code if you successfully updated 'Installation' table. The way it works is, that they store badge number in that table (perhaps refresh after each application is awaken) so later server can send incremented number inside notification payload.
Parse had a blog entry on this : http://blog.parse.com/announcements/badge-management-for-ios/
Just to add note how it works in more generic environment :
You should send actual new badge number from the server, it is not just incremented for you.
There is good deal of information on another question :
Increment the Push notification Badge iPhone
I believe I am using cancelLocalNotification improperly.
I have a recurring notification that runs conditionally, which was created using the following code:
let localNotification: UILocalNotification = UILocalNotification()
localNotification.alertAction = "Inactive Membership"
localNotification.alertBody = "Our system has detected that your membership is inactive..."
localNotification.fireDate = NSDate(timeIntervalSinceNow: 5)
localNotification.repeatInterval = .Minute
UIApplication.sharedApplication().scheduleLocalNotification(localNotification)
This notification successfully runs every single minute (for testing purposes). Obviously, I'd like a way to conditionally remove these notifications, so I've tried to use cancelLocalNotification to do so.
How I think cancelLocalNotification works
My intuition is that cancelLocalNotification will remove all the notifications for that specific notification object. Here's how I'm using it.
UIApplication.sharedApplication().cancelLocalNotification(localNotification)
What actually happens
I've stepped through my function and verified that the cancelLocalNotification code does get called. However, I keep getting my notification every minute.
My Question
How do I properly cancel a UILocalNotification that has been scheduled?
Full code:
static func evaluateMemberStatusNotifications() {
let userDefaults = Global.app.userDefaults
let localNotification: UILocalNotification = UILocalNotification()
print("evaluating profile notifications")
// is the user active? if so no notification
let isActive : Bool = userDefaults.valueForKey("ActiveMember") as! Bool // false == inactive
print("is the user active?")
if !isActive {
print("user is not active, checking if notification code has run")
// if userDefaults is nil for this value, we'll set it to false
if (userDefaults.valueForKey("ProfileNotificationHasRun") == nil) {
print("nil! setting ProfileNotificationHasRun to 'false'")
userDefaults.setValue(false, forKey: "ProfileNotificationHasRun")
}
let statusNotification = userDefaults.valueForKey("ProfileNotificationHasRun") as! Bool
// has this code been run? If not run it
if !statusNotification {
print("running notification code")
// we schedule a notification
localNotification.alertAction = "Inactive Membership"
localNotification.alertBody = "Our system has detected that your membership is inactive."
localNotification.fireDate = NSDate(timeIntervalSinceNow: 5)
localNotification.category = "status"
localNotification.repeatInterval = .Day
UIApplication.sharedApplication().scheduleLocalNotification(localNotification)
userDefaults.setValue(true, forKey: "ProfileNotificationHasRun")
} else {
print("notification code has already run, time interval has been set")
}
} else {
print("member is active, remove Inactive notification")
// if the member is active, we remove the notification so the user doesn't
// keep getting notified
UIApplication.sharedApplication().cancelLocalNotification(localNotification)
userDefaults.setValue(false, forKey: "ProfileNotificationHasRun")
}
}
You're creating a new UILocalNotification (line 3 of your gist) and then cancelling it. That new notification was never scheduled. You need to get the existing, scheduled notification object and cancel that.
You can access your existing, scheduled notifications through the UIApplication.sharedApplication().scheduledLocalNotifications array.
Or you could just cancel all scheduled local notifications by calling UIApplication.sharedApplication().cancelAllLocalNotifications().
UPDATE
Each call to evaluateMemberStatusNotifications creates a new instance of UILocalNotification, then (depending on the ActiveMember value) either configures and schedules that new notification, or tries to delete the new (unscheduled) notification.
Instead, you should just create a new notification in the !isActive branch where you want to schedule it.
In the other branch, you need to find the existing notification in the scheduledLocalNotifications array and (if you find it) cancel that existing notification.
Since you say you have other notifications that you don't want to mess with, you should use the userInfo property of the notification to identify it. For example, when configuring the notification before scheduling it:
localNotification.alertAction = "Inactive Membership"
localNotification.alertBody = "Our system has detected that your membership is inactive. You may continue using this application though some features may not be available to you until your membership is reinstated."
localNotification.fireDate = NSDate(timeIntervalSinceNow: 5)
localNotification.category = "status"
localNotification.repeatInterval = .Day
// *** NEW
localNotification.userInfo = [ "cause": "inactiveMembership"]
And when you want to cancel the existing notification:
let maybeNotification = UIApplication.sharedApplication().scheduledLocalNotifications?.filter({ (notification: UILocalNotification) -> Bool in
notification.userInfo?["cause"] as? String == "inactiveMembership"
}).first
if let notification = maybeNotification {
UIApplication.sharedApplication().cancelLocalNotification(notification)
}