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.
Related
I've used apple push notification service in my app and I received certificates and it works well But now my problem is that when I use Firebase rest API for sending message as notification I won’t receive any notification in my iPhone until I run the app But when I use Firebase it will be working, well here is my codes:
import UIKit
import Firebase
import FirebaseMessaging
import FirebaseInstanceID
import UserNotifications
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
NotificationCenter.default.addObserver(self, selector: #selector(self.refreshToken(notification:)), name: NSNotification.Name.InstanceIDTokenRefresh, object: nil)
Messaging.messaging().isAutoInitEnabled = true
FirebaseApp.configure()
if #available(iOS 10.0, *) {
UNUserNotificationCenter.current().requestAuthorization(options: [.alert , .badge , .sound]) { (success, error) in
}
} else {
UIApplication.shared.registerUserNotificationSettings(UIUserNotificationSettings(types: [.badge, .sound, .alert], categories: nil))
UIApplication.shared.registerForRemoteNotifications()
// Fallback on earlier versions
}
application.registerForRemoteNotifications()
return true
}
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
#if PROD_BUILD
FIRInstanceID.instanceID().setAPNSToken(deviceToken, type: .prod)
#else
InstanceID.instanceID().setAPNSToken(deviceToken, type: .sandbox)
#endif
Messaging.messaging().subscribe(toTopic: "global")
}
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any]) {
Messaging.messaging().subscribe(toTopic: "global")
print(userInfo)
}
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any], fetchCompletionHandler completionHandler: #escaping (UIBackgroundFetchResult) -> Void) {
Messaging.messaging().appDidReceiveMessage(userInfo)
if Messaging.messaging().fcmToken != nil {
Messaging.messaging().subscribe(toTopic: "global")
}
// Print full message.
print(userInfo)
completionHandler(UIBackgroundFetchResult.newData)
}
func applicationDidEnterBackground(_ application: UIApplication) {
Messaging.messaging().shouldEstablishDirectChannel = false
}
func applicationDidBecomeActive(_ application: UIApplication) {
FBHandler()
}
#objc func refreshToken(notification : NSNotification) {
let refreshToken = InstanceID.instanceID().token()!
print("***\(refreshToken)")
FBHandler()
}
func FBHandler() {
Messaging.messaging().shouldEstablishDirectChannel = true
}
}
For APNS to work in background you need to enable background modes in capabilities section and tick remote notification.
Once you done add/check this delegate method in AppDelegate class
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any]) {
print("APNS USER INFO: \(userInfo)")
}
This method fires when app is in background and APNS comes.
More Info: How to handle push notification in background in ios 10?
UPDATE:
Add this one also and let see if it works
func userNotificationCenter(_ center: UNUserNotificationCenter,
didReceive response: UNNotificationResponse,
withCompletionHandler completionHandler: #escaping () -> Void) {
print("APNS: \(response.notification.request.content.userInfo)")
}
import UIKit
import UserNotifications
class SLPushNotificationManager: NSObject, UIApplicationDelegate {
class var currentManager : SLPushNotificationManager {
struct Static {
static let instance : SLPushNotificationManager = SLPushNotificationManager()
}
return Static.instance
}
override init() {
super.init()
NSNotificationCenter.defaultCenter().addObserverForName(UserLoggedInNotification, object: nil, queue: NSOperationQueue.mainQueue()) {[unowned self] (notification) -> Void in
self.registerForRemoteNotifications()
}
}
func registerForRemoteNotifications(){
if #available(iOS 10, *) {
let center = UNUserNotificationCenter.currentNotificationCenter()
center.requestAuthorizationWithOptions([.Alert, .Badge, .Sound], completionHandler: { (granted, error) in
if error == nil {
UIApplication.sharedApplication().registerForRemoteNotifications()
}
})
}else {
let notificationType: UIUserNotificationType = [UIUserNotificationType.Alert, UIUserNotificationType.Badge, UIUserNotificationType.Sound]
let settings = UIUserNotificationSettings(forTypes: notificationType, categories: nil)
UIApplication.sharedApplication().registerUserNotificationSettings(settings)
}// end else
}// end func
In the app delegate:
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
SLPushNotificationManager.currentManager //init push notification manager
}
func application(application: UIApplication, didRegisterUserNotificationSettings notificationSettings: UIUserNotificationSettings) {
application.registerForRemoteNotifications()
}
func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject]) {
SLPushNotificationManager.currentManager.handleNotification(userInfo)
}
func application(application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: NSData) {
SLPushNotificationManager.currentManager.registerDeviceToken(deviceToken)
}
func application(application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: NSError) {
print("Error: \(error.localizedDescription)", terminator: "")
}
#available(iOS 10.0, *)
func userNotificationCenter(center: UNUserNotificationCenter, willPresentNotification notification: UNNotification, withCompletionHandler completionHandler: (UNNotificationPresentationOptions) -> Void){
completionHandler(.Alert)
}
#available(iOS 10.0, *)
func userNotificationCenter(center: UNUserNotificationCenter, didReceiveNotificationResponse response: UNNotificationResponse, withCompletionHandler completionHandler: () -> Void){
print(response.notification.request.content.userInfo)
}
Now for the first time after downloading the app the user can register for APN! and the methode: func application(application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: NSData)
is called but after I unregistere for APN later then I try to register again the method: func application(application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: NSData)
is not called again... Any Ideas y this happens??
Why are you deregistering? Have you read what the documentation says about this:
You should call this method in rare circumstances only, such as when a
new version of the app removes support for all types of remote
notifications
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
}
}
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)
}
For some reason my didReceiveRemoteNotification is never called. I have done the following:
checklist of APNS:
Create AppId allowed with Push Notification
Create SSL certificate with valid certificate and app id
Create Provisioning profile with same certificate and make sure to add device
With Code:
Register app for push notification
Handle didRegisterForRemoteNotificationsWithDeviceToken method
Set targets> Capability> background modes> Remote Notification
Handle didReceiveRemoteNotification
Yet my function does not seem to get called. My code looks like this:
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
// Override point for customization after application launch.
if (application.respondsToSelector("isRegisteredForRemoteNotifications"))
{
// iOS 8 Notifications
application.registerUserNotificationSettings(UIUserNotificationSettings(forTypes: (.Badge | .Sound | .Alert), categories: nil));
application.registerForRemoteNotifications()
}
else
{
// iOS < 8 Notifications
application.registerForRemoteNotificationTypes(.Badge | .Sound | .Alert)
}
return true
}
func application(application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: NSData) {
let tokenChars = UnsafePointer<CChar>(deviceToken.bytes)
var tokenString = ""
for var i = 0; i < deviceToken.length; i++ {
tokenString += String(format: "%02.2hhx", arguments: [tokenChars[i]])
}
apnsID = tokenString
println("******apnsID is \(apnsID)")
dToken = deviceToken
println("******dToken is \(dToken)")
NSUserDefaults.standardUserDefaults().setObject(deviceToken, forKey: "deviceToken")
}
func application(application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: NSError) {
println("***********didFailToRegisterForRemoteNotificationsWithError")
println(error)
}
func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject], fetchCompletionHandler completionHandler: (UIBackgroundFetchResult) -> Void) {
println("Getting notification")
var message: NSString = ""
var alert: AnyObject? = userInfo["aps"]
println(userInfo["aps"])
if((alert) != nil){
var alert = UIAlertView()
alert.title = "Title"
alert.message = "Message"
alert.addButtonWithTitle("OK")
alert.show()
}
}
add content_available:true in your request . for iOS payload data.You will get notification in didReceiveRemoteNotification. Now handle it.
As I found out having the same problem myself, in order for didReceiveRemoteNotificationto be called, the incoming notification music carry an "available_content" : true parameter with the notification payload. So in case of you sending the notification in a dictionary form , as was my case in device to device pushes, you just have to add it in the dictionary as you would specify other parameters as you would for sound or badge, also needed if you're using some sort of push service as Postman
Three steps:
Add logic here to handle incoming notification:
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any],
fetchCompletionHandler completionHandler: #escaping (UIBackgroundFetchResult) -> Void) {
// Add your logic here
completionHandler(.newData)
}
Add Background mode to capabilities in target, and ensure to check 'Remote notifications'
While sending a push notification, add "content_available" : true
This worked for me in iOS 14/Xcode 12.3.