I am trying to test my app and I noticed that handleActionWithIdentifier: forLocalNotification does not fire. While the app is in the foreground, this delegate method should fire after the user clicks on the action. I have read other posts about this, but most of them refer to the completionHandler() at the bottom of the method. I cannot seem to find a solution. If I put my app in the background, didReceiveLocalNotification does fire correctly. I am truly stumped. Here is my code...
import UIKit
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
let notificationActionOk = UIMutableUserNotificationAction()
notificationActionOk.identifier = "ALARM_IDENTIFIER"
notificationActionOk.title = "Ok"
notificationActionOk.destructive = false
notificationActionOk.authenticationRequired = false
notificationActionOk.activationMode = UIUserNotificationActivationMode.Background
let notificationCategory = UIMutableUserNotificationCategory()
notificationCategory.identifier = "ALARM_CATEGORY"
notificationCategory.setActions([notificationActionOk], forContext: UIUserNotificationActionContext.Default)
notificationCategory.setActions([notificationActionOk], forContext: UIUserNotificationActionContext.Minimal)
let settings = UIUserNotificationSettings(forTypes: [.Alert, .Sound], categories: [notificationCategory])
UIApplication.sharedApplication().registerUserNotificationSettings(settings)
return true
}
func application(application: UIApplication, handleActionWithIdentifier identifier: String?, forLocalNotification notification: UILocalNotification, completionHandler: () -> Void) {
print("Handle action \(identifier)")
completionHandler()
//I cannot get this method to fire.
}
func application(application: UIApplication, didReceiveLocalNotification notification: UILocalNotification) {
print("Received local notification")
//This method fires correctly
}
}
Related
In order to try out Push Notifications with Firebase I have been following these three documents:
One, Two, Three and Four.
I have one question, but before asking; here is what I can see:
When my app is in the foreground and a notification is sent, only this function is called:
userNotificationCenter(_:willPresent:withCompletionHandler:)
If I tap on the notification, then this one is also so called:
userNotificationCenter(_:didReceive:withCompletionHandler:)
When my app is in the background and a notification is sent, nothing is called.
If I tap on the notification, then this one is called:
userNotificationCenter(_:didReceive:withCompletionHandler:)
As a result of this situation, whithout having to react (by tapping on the notification); I can have the app perform some useful action when a notification is arriving while in the foreground, using the userNotificationCenter(_:willPresent:withCompletionHandler:) function.
On the other hand while in the background, I can only have the app perform some useful action when a notification is arriving if the user taps on the notification.
Is there a way for me to also have the app perform some useful action even if the user has no reaction?
Here is the relevant code I have at this point:
import UIKit
import Firebase
import UserNotifications
import FirebaseInstanceID
import FirebaseMessaging
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterDelegate, MessagingDelegate {
var window: UIWindow?
func application(_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
window = UIWindow(frame: UIScreen.main.bounds)
UNUserNotificationCenter.current().delegate = self
let authOptions: UNAuthorizationOptions = [.alert, .badge, .sound]
UNUserNotificationCenter.current().requestAuthorization(
options: authOptions,
completionHandler: {
granted, error in
if error != nil {print("Error: \(error!)")}
if granted {
DispatchQueue.main.async
{application.registerForRemoteNotifications()}
}
})
FirebaseApp.configure()
.......
return true
}
func application(_ application: UIApplication,
didReceiveRemoteNotification userInfo: [AnyHashable: Any]) {
print(#function)
if let messageID = userInfo[gcmMessageIDKey] {
print("Message ID: \(messageID)")
}
// Print full message.
print(userInfo)
}
func application(_ application: UIApplication,
didReceiveRemoteNotification userInfo: [AnyHashable: Any],
fetchCompletionHandler completionHandler: #escaping (UIBackgroundFetchResult) -> Void) {
print(#function)
if let messageID = userInfo[gcmMessageIDKey] {
print("Message ID: \(messageID)")
}
// Print full message.
print(userInfo)
completionHandler(UIBackgroundFetchResult.newData)
}
}
For information, I am using Xcode Version 10.1, iOS 12.1 and Swift 4.2.
swift 4.2, Xcode 10.0, IOS 12.0
import UIKit
import Firebase
import UserNotifications
import FirebaseInstanceID
import FirebaseMessaging
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterDelegate, MessagingDelegate {
var window: UIWindow?
func application(_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
window = UIWindow(frame: UIScreen.main.bounds)
if #available(iOS 10.0, *) {
let center = UNUserNotificationCenter.current()
center.requestAuthorization(options: [.badge, .alert , .sound]) { (granted, error) in
let type: UIUserNotificationType = [UIUserNotificationType.badge, UIUserNotificationType.alert, UIUserNotificationType.sound]
let setting = UIUserNotificationSettings(types: type, categories: nil)
UIApplication.shared.registerUserNotificationSettings(setting)
UIApplication.shared.registerForRemoteNotifications()
}
} else {
let type: UIUserNotificationType = [UIUserNotificationType.badge, UIUserNotificationType.alert, UIUserNotificationType.sound]
let setting = UIUserNotificationSettings(types: type, categories: nil)
UIApplication.shared.registerUserNotificationSettings(setting)
UIApplication.shared.registerForRemoteNotifications()
}
application.registerForRemoteNotifications()
if(FIRApp.defaultApp() == nil){
FIRApp.configure()
}
NotificationCenter.default.addObserver(self,
selector: #selector(self.tokenRefreshNotification(notification:)),
name: NSNotification.Name.firInstanceIDTokenRefresh,
object: nil)
return true
}
#available(iOS 10.0, *)
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: #escaping () -> Void) {
let userInfo = response.notification.request.content.userInfo as? NSDictionary
_ = UIStoryboard(name: "Main", bundle: nil)
let appdelegate = UIApplication.shared.delegate as! AppDelegate
let aps = userInfo?["aps"] as! NSDictionary
}
#available(iOS 10.0, *)
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: #escaping (UNNotificationPresentationOptions) -> Void) {
completionHandler([.alert, .badge, .sound])
}
}
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
// Convert token to string
let deviceTokenString = deviceToken.reduce("", {$0 + String(format: "%02X", $1)})
print("Device Token", deviceTokenString)
FIRInstanceID.instanceID().setAPNSToken(deviceToken, type: FIRInstanceIDAPNSTokenType.unknown)
}
func application(_ application: UIApplication, didReceiveRemoteNotification data: [AnyHashable : Any]) {
let appdelegate = UIApplication.shared.delegate as! AppDelegate
let aps = data["aps"] as! NSDictionary
let state = UIApplication.shared.applicationState
if state == .background {
}
if state == .active {
}
}
//MARK: Notification Center Call
func callNotificationCenter(){
NotificationCenter.default.post(name: NSNotification.Name(rawValue: "reloadData"), object: nil)
}
func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) {
}
// start firebase
#objc func tokenRefreshNotification(notification: NSNotification) {
let refreshedToken = FIRInstanceID.instanceID().token()
print(refreshedToken)
connectToFcm()
}
func connectToFcm() {
FIRMessaging.messaging().connect { (error) in
if (error != nil) {
print("Unable to connect with FCM. \(error?.localizedDescription ?? "")")
} else {
print("Connected to FCM")
}
}
}
IOS remote push notification (testflight?) not working IOS9 where it is full working IOS10. What can I do?
Note: also I am testing by apn tester both IOS9 and IOS10 it is working fine. My project in swift 2.
Full code here:
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
//ask for user to permited push notification
registerForPushNotifications(application)
//crate notification with sound alert, Badge , and sound
let notificationTypes: UIUserNotificationType = [UIUserNotificationType.Alert, UIUserNotificationType.Badge, UIUserNotificationType.Sound]
//add nofification type in system notification
let pushNotificationSettings = UIUserNotificationSettings(forTypes: notificationTypes, categories: nil)
application.registerUserNotificationSettings(pushNotificationSettings)
//register for remot notificaiton not local
return true
}
//MARK:- Push Notification configaratin
func application(application: UIApplication, didRegisterUserNotificationSettings notificationSettings: UIUserNotificationSettings) {
if notificationSettings.types != .None{
application.registerForRemoteNotifications()
}
}
func registerForPushNotifications(application: UIApplication)
{
let notificationSettings = UIUserNotificationSettings(forTypes: [.Badge, .Sound, .Alert], categories: nil)
application.registerUserNotificationSettings(notificationSettings)
}
func application(application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: NSData) {
//send Device Id
}
func application(application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: NSError)
{
print("Failed to register:", error)
}
func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject]) {
self.showingAlert("notification arived 3: \(userInfo)")
}
Push notification:
Background Mode:
I'm making this sweet app that requires Push notifications.
However when trying to grab the Push token not all required functions seem to get executed.
The user does get presented with this Alert:
When the user hits OK I step through my code and see that not everything gets executed:
override func viewDidLoad(){
let tapper = UITapGestureRecognizer(target: view, action:#selector(UIView.endEditing))
tapper.cancelsTouchesInView = false
view.addGestureRecognizer(tapper)
print("gets called")
registerForPushNotifications(UIApplication.sharedApplication())
}
func registerForPushNotifications(application: UIApplication) {
print("gets called")
let notificationSettings = UIUserNotificationSettings(
forTypes: [.Badge, .Sound, .Alert], categories: nil)
application.registerUserNotificationSettings(notificationSettings)
}
func application(application: UIApplication, didRegisterUserNotificationSettings notificationSettings: UIUserNotificationSettings) {
print("doesn't get called")
if notificationSettings.types != .None {
application.registerForRemoteNotifications()
}
}
func application(application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: NSData) {
print("doesn't get called")
let tokenChars = UnsafePointer<CChar>(deviceToken.bytes)
var apnsTokenString = ""
for i in 0..<deviceToken.length {
apnsTokenString += String(format: "%02.2hhx", arguments: [tokenChars[i]])
}
Constant.pushToken = apnsTokenString
print("Device Token:", Constant.pushToken)
}
func application(application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: NSError) {
debugPrint("Error Registering Remote Notification")
}
In my console the following gets printed:
gets called
gets called
Meaning that not all required functions get called. What am I doing wrong?
Assuming all of the code you posted in your question is in your view controller class, the problem is that you need to put the UIApplicationDelegate methods in your actual app delegate class, not the view controller class. Simply move those methods to the proper class and they will work.
Just use this code
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
print("gets called")
let settings = UIUserNotificationSettings(forTypes: [.Alert, .Badge, .Sound], categories: nil)
application.registerUserNotificationSettings(settings)
application.registerForRemoteNotifications()
}
func application(application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: NSData) {
let characterSet: NSCharacterSet = NSCharacterSet(charactersInString: "<>")
let deviceTokenString: String = (deviceToken.description as NSString)
.stringByTrimmingCharactersInSet(characterSet)
.stringByReplacingOccurrencesOfString( " ", withString: "") as String
print(deviceTokenString)
}
I am tired of doing this. Let me tell you whats happening. I am using iOS 9.0 & Xcode 7.3.1.
Situation 1 :
I have registered for local notification settings in didFinishLaunchingWithOptions like this.
let settings = UIUserNotificationSettings(forTypes: [UIUserNotificationType.Alert, UIUserNotificationType.Badge, UIUserNotificationType.Sound] , categories: nil)
application.registerUserNotificationSettings(settings)
I have several controllers in my project, user will be pressing one button in one of these and I will be scheduling a notification by calling a function in App Delegate. The function is given below.
func activatingUserLocalNotification(timeIntervalSinceNow : NSDate?, alertBody : String, userInfo : [NSObject : AnyObject], region : CLRegion?)
{
let localNotification = UILocalNotification()
localNotification.fireDate = timeIntervalSinceNow
localNotification.timeZone = NSTimeZone.defaultTimeZone()
localNotification.alertBody = alertBody
localNotification.region = region
localNotification.regionTriggersOnce = false
localNotification.soundName = UILocalNotificationDefaultSoundName
localNotification.userInfo = userInfo
localNotification.applicationIconBadgeNumber = UIApplication.sharedApplication().applicationIconBadgeNumber + 1
UIApplication.sharedApplication().scheduleLocalNotification(localNotification)
}
Now I have set a notification by pressing on a button, which called this above function it successfully scheduled the notification.
I have set breakpoints in all these methods.
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool
{
// Break Point
return true
}
func application(application: UIApplication, handleActionWithIdentifier identifier: String?, forLocalNotification notification: UILocalNotification, withResponseInfo responseInfo: [NSObject : AnyObject], completionHandler: () -> Void) {
// Break Point
}
func application(application: UIApplication, handleActionWithIdentifier identifier: String?, forLocalNotification notification: UILocalNotification, completionHandler: () -> Void) {
// Break Point
}
func application(application: UIApplication, didReceivelocalNotification notification: UILocalNotification)
{
// Break Point
}
And waited for sometime while the app is in Foreground, Waited some more time. Nothing happened. I thought the app would fire up the notification and one of the method would get called, so that I could present the notification inside the app. But nothing happened.
Situation 2 :
Now I have tried the same, now I minimised the app [ App is in Background state ] by going to an another app and using it for sometime. Now the notification fired up properly, just like I have told you I have set breakpoints in almost all methods but none of them called when I clicked on the notification. But it called applicationWillEnterForeground, What am gonna do with this method without the launchOptions.
It's been two days I am fighting with this, Don't have any idea about whats happening.
Push Notifications Works Fine Though [ Inside & Outside the App ].
Let me know your thoughts? Please.
How I call this function activatingUserLocalNotification from a controller.
func setLocalNotificationForDistance(id : String, name : String, location : CLLocationCoordinate2D, radius : Double)
{
let alertBody = "Hello \(name)"
let dict : [NSObject : AnyObject] = ["aps" : ["alert" : alertBody], “id” : id]
let region = CLCircularRegion(center: location, radius: radius, identifier: id)
let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
appDelegate.activatingUserLocalNotification(nil, alertBody: alertBody, userInfo: dict, region: region)
}
App Delegate
//
// AppDelegate.swift
//
//
import UIKit
import FBSDKCoreKit
import SVProgressHUD
import Alamofire
import GoogleMaps
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
//MARK: Local Variables
var window: UIWindow?
static let UpdateRootNotification = "UpdateRootNotification"
static let ShowMainUINotification = "ShowMainUINotification"
//MARK: Application Life Cycle
// Did Finish Launching
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool
{
let settings = UIUserNotificationSettings(forTypes: [UIUserNotificationType.Alert, UIUserNotificationType.Badge, UIUserNotificationType.Sound] , categories: nil)
application.registerUserNotificationSettings(settings)
return true
}
// Foreground
func applicationWillEnterForeground(application: UIApplication) {
}
// Did Become Active
func applicationDidBecomeActive(application: UIApplication) {
FBSDKAppEvents.activateApp()
application.applicationIconBadgeNumber = 0 // clear badge icon
}
// Did Enter Background
func applicationDidEnterBackground(application: UIApplication) {
}
// Opened Via Shortcut
func application(application: UIApplication, performActionForShortcutItem
shortcutItem: UIApplicationShortcutItem, completionHandler: (Bool) -> Void) {
}
// Continue User Activity
func application(application: UIApplication, continueUserActivity userActivity: NSUserActivity,
restorationHandler: ([AnyObject]?) -> Void) -> Bool {
return true
}
//MARK: Local Notification
func activatingUserLocalNotification(timeIntervalSinceNow : NSDate?, alertBody : String, userInfo : [NSObject : AnyObject], region : CLRegion?)
{
let localNotification = UILocalNotification()
localNotification.fireDate = timeIntervalSinceNow
localNotification.timeZone = NSTimeZone.defaultTimeZone()
localNotification.alertBody = alertBody
localNotification.region = region
localNotification.regionTriggersOnce = false
localNotification.soundName = UILocalNotificationDefaultSoundName
localNotification.userInfo = userInfo
localNotification.applicationIconBadgeNumber = UIApplication.sharedApplication().applicationIconBadgeNumber + 1
UIApplication.sharedApplication().scheduleLocalNotification(localNotification)
}
func application(application: UIApplication, handleActionWithIdentifier identifier: String?, forLocalNotification notification: UILocalNotification, withResponseInfo responseInfo: [NSObject : AnyObject], completionHandler: () -> Void) {
}
func application(application: UIApplication, handleActionWithIdentifier identifier: String?, forLocalNotification notification: UILocalNotification, completionHandler: () -> Void) {
}
func application(application: UIApplication, didReceivelocalNotification notification: UILocalNotification)
{
application.applicationIconBadgeNumber = 0
UIApplication.sharedApplication().presentLocalNotificationNow(notification)
}
// MARK: Push Notification
func application(application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: NSData) {
if API.sharedInstance.isLoggedIn() {
NSUserDefaults.standardUserDefaults().setObject(deviceToken, forKey: "push_token")
NSUserDefaults.standardUserDefaults().synchronize()
API.sharedInstance.registerDeviceToken(deviceToken)
}
}
func application(application: UIApplication, didRegisterUserNotificationSettings notificationSettings: UIUserNotificationSettings) {
application.registerForRemoteNotifications()
}
func application(application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: NSError) {
EventTracker.trackEventWithCategory("APN", action: "Registraion", label: "Failed")
}
func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject]) {
APNSManager.sharedInstance.handlePushNotification(userInfo)
}
//MARK: Open URL
func application(application: UIApplication, openURL url: NSURL, sourceApplication: String?, annotation: AnyObject) -> Bool {
return FBSDKApplicationDelegate.sharedInstance().application(application, openURL:url,sourceApplication:sourceApplication,annotation:annotation)
}
}
This is a bit funny, but change:
func application(application: UIApplication, didReceivelocalNotification notification: UILocalNotification)
To:
func application(application: UIApplication, didReceiveLocalNotification notification: UILocalNotification)
Note the capital L. From docs:
Also: expect this delegate method to be called only when your app is active. No notification should be visible in that situation as your app is active. You can handle it by using didReceiveLocalNotification delegate method.
I'm trying to receive voip(and regular) push notification work on my app for sinch calls.
The code its already receiving calls when the app is in foreground.
And background with local nofitications
And the certificate for push is working sending pushes with pusher app in mac, i follow the tutorials and dont know what i'm missing
My code:
class AppDelegate: UIResponder, UIApplicationDelegate, SINCallClientDelegate, SINCallDelegate, SINMessageClientDelegate, SINClientDelegate, SINManagedPushDelegate {
var msgClient:SINMessageClient!
var window: UIWindow?
var applicationKey:String!
var applicationSecret:String!
var environmentHost:String!
var voipClient:SINClient!
var push:SINManagedPush!
func requestUserNotificationPermission() {
if UIApplication.sharedApplication().respondsToSelector("registerUserNotificationSettings:") {
let settings = UIUserNotificationSettings(forTypes: [.Alert, .Badge, .Sound], categories: nil)
UIApplication.sharedApplication().registerUserNotificationSettings(settings)
UIApplication.sharedApplication().registerForRemoteNotifications()
}
}
func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject]) {
self.push.application(application, didReceiveRemoteNotification: userInfo)
}
func application(application: UIApplication, didReceiveLocalNotification notification: UILocalNotification) {
self.handleLocalNotification(notification)
}
func application(application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: NSData) {
self.push.application(application, didRegisterForRemoteNotificationsWithDeviceToken: deviceToken)
}
func startSinch() {
if self.voipClient == nil {
self.push.registerUserNotificationSettings()
let userID = "partner-4" //fixed for tests
self.voipClient = Sinch.clientWithApplicationKey(applicationKey, applicationSecret:applicationSecret,environmentHost:environmentHost,userId: userID)
self.voipClient.delegate = self;
//commented to test push but is working
//self.voipClient.setSupportActiveConnectionInBackground(true)
self.voipClient.enableManagedPushNotifications()
self.voipClient.setSupportCalling(true)
self.voipClient.setSupportMessaging(true);
self.voipClient.start()
self.voipClient.startListeningOnActiveConnection()
self.msgClient = self.voipClient.messageClient()
self.msgClient.delegate = self
}
}
func managedPush(managedPush: SINManagedPush!, didReceiveIncomingPushWithPayload payload: [NSObject : AnyObject]!, forType pushType: String!) {
self.handleRemoteNotification(payload)
}
func handleRemoteNotification(userInfo: NSDictionary){
if (self.voipClient == nil) {
self.startSinch()
}
self.voipClient.relayRemotePushNotification(userInfo as [NSObject : AnyObject])
}
func client(client: SINCallClient!, localNotificationForIncomingCall call: SINCall!) -> SINLocalNotification! {
let notification = SINLocalNotification()
notification.alertAction = "test"
notification.alertBody = "test"
notification.soundName = "notification-sound.caf"
return notification
}
func relayLocalNotification(notification: UILocalNotification) -> SINNotificationResult{
return self.voipClient.relayLocalNotification(notification)
}