Parse iOS Swift Push Notification History - ios

I am using Parse Push Notifications with Swift (iOS 8). The problem is when app is closed and you recieve multiple notifications, they will show in notifications alert. When I touch one of the notification it will open my app......but it will clear all notifications in notification alert view (not sure what is called). So as result all of my push notifications are lost. And I need them since they have specific payload that my app needs.
So basicly, all I need is data from received notification (not just from the one I opened).
I am using this code that Parse recommends. When app is closed and is opened with push, this function is called. I use constant let = notificationPayload to get info of payloads from push notifications. But I only get data from one push.
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
// Enable storing and querying data from Local Datastore.
// Remove this line if you don't want to use Local Datastore features or want to use cachePolicy.
Parse.enableLocalDatastore()
// ****************************************************************************
// Uncomment this line if you want to enable Crash Reporting
// ParseCrashReporting.enable()
//
// Uncomment and fill in with your Parse credentials:
Parse.setApplicationId("+++++", clientKey: "++++++++")
//
// If you are using Facebook, uncomment and add your FacebookAppID to your bundle's plist as
// described here: https://developers.facebook.com/docs/getting-started/facebook-sdk-for-ios/
// Uncomment the line inside ParseStartProject-Bridging-Header and the following line here:
// PFFacebookUtils.initializeFacebook()
// ****************************************************************************
PFUser.enableAutomaticUser()
let defaultACL = PFACL();
// If you would like all objects to be private by default, remove this line.
defaultACL.setPublicReadAccess(true)
PFACL.setDefaultACL(defaultACL, withAccessForCurrentUser:true)
if application.applicationState != UIApplicationState.Background {
// Track an app open here if we launch with a push, unless
// "content_available" was used to trigger a background push (introduced in iOS 7).
// In that case, we skip tracking here to avoid double counting the app-open.
// Extract the notification data.
if let notificationPayload = launchOptions? [UIApplicationLaunchOptionsRemoteNotificationKey] as? NSDictionary {
// notificationPayload have payload of only one push notification.
}
let preBackgroundPush = !application.respondsToSelector("backgroundRefreshStatus")
let oldPushHandlerOnly = !self.respondsToSelector("application:didReceiveRemoteNotification:fetchCompletionHandler:")
var noPushPayload = false;
if let options = launchOptions {
noPushPayload = options[UIApplicationLaunchOptionsRemoteNotificationKey] != nil;
}
if (preBackgroundPush || oldPushHandlerOnly || noPushPayload) {
PFAnalytics.trackAppOpenedWithLaunchOptions(launchOptions)
}
}
if application.respondsToSelector("registerUserNotificationSettings:") {
let userNotificationTypes = UIUserNotificationType.Alert | UIUserNotificationType.Badge | UIUserNotificationType.Sound
let settings = UIUserNotificationSettings(forTypes: userNotificationTypes, categories: nil)
application.registerUserNotificationSettings(settings)
application.registerForRemoteNotifications()
} else {
let types = UIRemoteNotificationType.Badge | UIRemoteNotificationType.Alert | UIRemoteNotificationType.Sound
application.registerForRemoteNotificationTypes(types)
}
return true
}
Any goot info, webpage, tutorial for this? Parse.com documentation is useless since apparently people get only one notification when app is closed.

If your push notifications contain important payload, you will probably have to save that payload somewhere else (Parse cloud data, for instance).
This way, even if iOS ditches your push notifications (or if the user decided to discard them) - your payload will be always available.
When the application starts up - look up for that payload in the database and act accordingly.

I found what was causing my Notifications to disappeare. I had this code in which would erase notifications:
UIApplication.sharedApplication().applicationIconBadgeNumber = 1
UIApplication.sharedApplication().applicationIconBadgeNumber = 0
UIApplication.sharedApplication().cancelAllLocalNotifications()

Related

Push notification not determined

In ios 10 there is UNUserNotificationCenter class and method getNotificationSettingsWithCompletionHandler which gives you UNNotificationSettings object and you can check is user has been ever asked for push notifications permissions.Is there a way to achieve this for iOS 9 and iOS 8.
You can use something like this:
let notificationType = UIApplication.sharedApplication().currentUserNotificationSettings()!.types
if notificationType == UIUserNotificationType.None {
// Push notifications are disabled in setting by user.
} else {
// Push notifications are enabled in setting by user.
}
if notificationType != UIUserNotificationType.None {
// Push notifications are enabled in setting by user.
}
if notificationType == UIUserNotificationType.Badge {
// the application may badge its icon upon a notification being received
}
if notificationType == UIUserNotificationType.Sound {
// the application may play a sound upon a notification being received
}
if notificationType == UIUserNotificationType.Alert {
// the application may display an alert upon a notification being received
}
There is no way. That functionality is available starting from ios 10.

How to get unique device id in iOS

I am working on iOS app for push notification feature i need to send unique device id of iOS device to server ,in android secure androd id getting for every device,is there any way to get unique device id of iOS.
I found some answers vendor id and ad id are they unique
code:
Secure.getString(getContext().getContentResolver(),Secure.ANDROID_ID);
For get UUID you can use this code
UIDevice *currentDevice = [UIDevice currentDevice];
NSString *deviceId = [[currentDevice identifierForVendor] UUIDString];
But for push notifications you need device token and it will create after user will accept permission and UIApplication delegate method will call
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken
There is no legal way to uniquely identify an iOS device. Period.
You can get only compromise solutions: IDFA, Vendor ID or APNS Device Token.
Every above-mentioned ID can change during the device lifecycle, thus they cannot be used as unique device identifiers.
for Step by step by Step Integration of APNS in your application , you can get the steps in here
iOS9 Apple says that Device Token might change each time your app is installed. So the best way is to reregister the Device token on each launch.
Step-1
There are two steps to register for push notifications. First, you must obtain the user’s permission to show any kind of notification, after which you can register for remote notifications. If all goes well, the system will then provide you with a device token, which you can think of as an “address” to this device.
This method creates an instance of UIUserNotificationSettings and passes it to registerUserNotificationSettings(_:).
UIUserNotificationSettings stores settings for the type of notification your app will use. For the UIUserNotificationTypes, you can use any combination of the following:
.Badge allows the app to display a number on the corner of the app’s icon.
.Sound allows the app to play a sound.
.Alert allows the app to display text.
The set of UIUserNotificationCategorys that you currently pass nil to allows you to specify different categories of notifications your app can handle. This becomes necessary when you want to implement actionable notifications, which you will use later
- (void)applicationDidFinishLaunching:(UIApplication *)app {
// other setup tasks here....
// Register the supported interaction types.
UIUserNotificationType types = UIUserNotificationTypeBadge |
UIUserNotificationTypeSound | UIUserNotificationTypeAlert;
UIUserNotificationSettings *mySettings =
[UIUserNotificationSettings settingsForTypes:types categories:nil];
[[UIApplication sharedApplication] registerUserNotificationSettings:mySettings];
// Register for remote notifications.
[[UIApplication sharedApplication] registerForRemoteNotifications];
}
Build and run. When the app launches, you should receive a prompt that asks for permission to send you notifications:
Tap OK and poof! The app can now display notifications.
- (void)application:(UIApplication *)application didRegisterUserNotificationSettings:(UIUserNotificationSettings *)notificationSettings
{
if (notificationSettings.types != UIUserNotificationTypeNone) {
//register to receive notifications
[application registerForRemoteNotifications];
}
}
Here, you first check whether the user has granted you any notification permissions; if they have, you directly call registerForRemoteNotifications().
Again, methods in UIApplicationDelegate are called to inform you about the status of registerForRemoteNotifications().
// Handle remote notification registration.
- (void)application:(UIApplication *)app
didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)devToken {
const void *devTokenBytes = [devToken bytes];
self.registered = YES;
// send your Device Token to server
}
As the names suggest, the system calls application(:didRegisterForRemoteNotificationsWithDeviceToken:) when the registration is successful, and otherwise calls application(:didFailToRegisterForRemoteNotificationsWithError:).
- (void)application:(UIApplication *)app
didFailToRegisterForRemoteNotificationsWithError:(NSError *)err {
NSLog(#"Error in registration. Error: %#", err);
}
Swift
let defaults = NSUserDefaults.standardUserDefaults()
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
// Override point for customization after application launch.
// PUSH NOTIFICATION
let deviceToken = defaults.objectForKey(UserDefaultsContracts.KEY_DEVICE_TOKEN) as String?
if (deviceToken == nil) {
print("There is no deviceToken saved yet.")
var types: UIUserNotificationType = UIUserNotificationType.Badge |
UIUserNotificationType.Alert |
UIUserNotificationType.Sound
var settings: UIUserNotificationSettings = UIUserNotificationSettings( forTypes: types, categories: nil )
application.registerUserNotificationSettings( settings )
application.registerForRemoteNotifications()
}
return true
}
func application(application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: NSData!) {
print("Got token data! (deviceToken)")
var characterSet: NSCharacterSet = NSCharacterSet( charactersInString: "<>" )
var deviceTokenString: String = ( deviceToken.description as NSString )
.stringByTrimmingCharactersInSet( characterSet )
.stringByReplacingOccurrencesOfString( " ", withString: "" ) as String
print( deviceTokenString )
defaults.setObject(deviceTokenString, forKey: UserDefaultsContracts.KEY_DEVICE_TOKEN)
}
func application(application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: NSError!) {
print("Couldn’t register: (error)")
}
}
for more information you get in Apple Documents
For Objectice-C:
UIDevice *device = [UIDevice currentDevice];
NSString *currentDeviceId = [[device identifierForVendor]UUIDString];
For Swift:
let device_id = UIDevice.currentDevice().identifierForVendor?.UUIDString
As per the Apple Documentation,
Device tokens can change, so your app needs to reregister every time
it is launched and pass the received token back to your server. If you
fail to update the device token, remote notifications might not make
their way to the user’s device. Device tokens always change when the
user restores backup data to a new device or computer or reinstalls
the operating system. When migrating data to a new device or computer,
the user must launch your app once before remote notifications can be
delivered to that device.
Never cache a device token; always get the token from the system
whenever you need it. If your app previously registered for remote
notifications, calling the registerForRemoteNotifications method again
does not incur any additional overhead, and iOS returns the existing
device token to your app delegate immediately. In addition, iOS calls
your delegate method any time the device token changes, not just in
response to your app registering or re-registering.
So the best way is to re-register for the token on each launch. For that you can call registerForPushNotifications(application) in applicationDidFinishLaunching() method.
The delegate method for the above method is didRegisterForRemoteNotificationsWithDeviceToken in which you can the deviceToken and send it to server.
func application(application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: NSData) {
let tokenChars = UnsafePointer<CChar>(deviceToken.bytes)
var tokenString = ""
for i in 0..<deviceToken.length {
tokenString += String(format: "%02.2hhx", arguments: [tokenChars[i]])
}
print("Device Token:", tokenString)
}
You should receiver in
func application(application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: NSData) {
var deviceTokenStr = String(format: "%#", deviceToken)
deviceTokenStr = deviceTokenStr.stringByReplacingOccurrencesOfString("<", withString: "")
deviceTokenStr = deviceTokenStr.stringByReplacingOccurrencesOfString(">", withString: "")
deviceTokenStr = deviceTokenStr.stringByReplacingOccurrencesOfString(" ", withString: "")
}
Or if you want to get unique device id , you can use
let UUID = NSUUID().UUIDString
as I did in my app, you can use first generated uuid and save it in Keychain file to use it as unique device id (because uuid is changed in every running for ur app and also device token) so u can save a uuid or any custom id u generate in keychain it will remain forever even user uninstall and in install the app many times

CLCircularRegion and wake up app

In application we have mechanism like native Reminder app in iOS with firing notifications when user enter or exit in some region.
But two devices behave differently (5 and 5s) in same time. All devices have enable notifications, and allow use locations.
Two devices have a some "travel" and in the route created 10 points. First device (5) when came to finish received only 6 notifications, (5s) don't receive any notification.
But my question is how I can know when my app is restart in background or continue working. Because, all log in app I redirect into a file, and after download container and analyze what happened in app in travel time.
I noticed app restart in same times when device is enter to region and my log marks fired in the file but notifications don't receive. This is happended when app try to get some information from web service in didFinishLaunchingWithOptions
And maybe this is problem. How to know distinguish restart app or continue working. Thx.
Are you checking UIApplicationLaunchOptionsLocationKey in didFinishLaunchingWithOptions similar to (sorry, Swift is what I have now):
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
if launchOptions?[UIApplicationLaunchOptionsLocationKey] != nil {
// app was launched in response to incoming location event
}
}
Additionally, if you're not already doing this you may need to create notifications differently if app is in background:
// Show an alert if application is active
if UIApplication.sharedApplication().applicationState == .Active {
if let message = notefromRegionIdentifier(region.identifier) {
if let viewController = window?.rootViewController {
showSimpleAlertWithTitle(nil, message: message, viewController: viewController)
}
}
}
else {
// Otherwise present a local notification:
let notification = UILocalNotification()
notification.alertBody = notefromRegionIdentifier(region.identifier)
notification.soundName = "Default";
UIApplication.sharedApplication().presentLocalNotificationNow(notification)
}

Local notifications sent to background works in simulator but not on device

In the simulator I'm able to get the exact result I want: When I trigger a notification and my simulator phone is locked, then the notification gets pushed to the watch.
This used to work on device (my iPhone 6 on iOS 9.1 and Watch on watchOS 2.0). For some reason it stopped working and I don't know how to debug the problem.
So on device, I make sure that the app is in background by going to home screen and locking the phone and making sure my watch is asleep. When the notification is triggered, nothing happens. When I open up the app, that's when the notifications finally gets triggered. I.E. if I trigger 3 notifications, none of them register until I open the app back into foreground. This is not how it works in simulator (simulator has correct behavior described above).
The notification is triggered by me changing a text object that is stored in my Firebase db. The change calls the sendNotification function. Again, this works perfectly fine in the simulator and used to work on device but for some reason doesn't work anymore.
In app delegate I have:
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
UIApplication.sharedApplication().registerUserNotificationSettings(UIUserNotificationSettings(forTypes: .Alert, categories: nil))
// Setting up Local Notification
let assistAction = UIMutableUserNotificationAction()
assistAction.activationMode = UIUserNotificationActivationMode.Background
assistAction.identifier = categoryID
assistAction.title = "Assist"
assistAction.authenticationRequired = false
assistAction.destructive = false
// Category
let assistCategory = UIMutableUserNotificationCategory()
assistCategory.identifier = categoryID
assistCategory.setActions([assistAction], forContext: UIUserNotificationActionContext.Default)
// Only way to get this to work with parameter
let categories = NSSet(object: assistCategory)
// Settings
let settings = UIUserNotificationSettings(forTypes: [.Alert, .Badge, .Sound], categories: categories as? Set<UIUserNotificationCategory>)
UIApplication.sharedApplication().registerUserNotificationSettings(settings)
// UIApplication.sharedApplication().registerForRemoteNotifications()
return true
}
Then in my view controller I have:
func sendNotification(customerName: String, helpText: String) {
// Local Notification
let notification = UILocalNotification()
notification.alertBody = "\(customerName) \(helpText)"
notification.soundName = UILocalNotificationDefaultSoundName
notification.fireDate = NSDate()
notification.category = categoryID
UIApplication.sharedApplication().presentLocalNotificationNow(notification)
print("Sent notification");
}
Simulator seems to work differently than device. It's weird that simulator local notifications was acting like remote push notifications.
I ended up giving up on trying to make local notifications show up while app is in background on device because I've learned that that is not the expected behavior.
The correct solution is to just set up remote push notification, which I used Parse to do. And now it's working as expected. I have a web server that uses the Parse REST API to send a POST request to Parse and my iOS app is then set up to receive remote push notifications which now show up on my watch when my phone is locked.

UILocalNotification wants permission to show, but it is already granted

I am allowing remote and local notifications in my app, it works perfectly fine for remote notifications but when trying to use local notifications it then does not show the notification, but it is running the code.
Remote notifications work when I am out of the app, but local notifications don't want to show when I am in the app?
Here is the code:
In the didFinishLaunchingWithOptions method:
let notificationTypes:UIUserNotificationType = UIUserNotificationType.Badge | UIUserNotificationType.Sound | UIUserNotificationType.Alert
let notificationSettings:UIUserNotificationSettings = UIUserNotificationSettings(forTypes: notificationTypes, categories: nil)
UIApplication.sharedApplication().registerUserNotificationSettings(notificationSettings)
UIApplication.sharedApplication().registerForRemoteNotifications()
and the receiving of the notification:
if(application.applicationState == UIApplicationState.Active) {
var ln: UILocalNotification = UILocalNotification()
ln.userInfo = userInfo
ln.soundName = UILocalNotificationDefaultSoundName
ln.alertBody = notification["alert"] as NSString
ln.fireDate = NSDate()
application.scheduleLocalNotification(ln)
println("local")
} else {
PFPush.handlePush(userInfo)
}
When in the app, it is printing out local.
Any ideas?
It sounds like you don't quite get what a local notification is. The whole point of a local notification is that it is a way for the system to notify the user on your behalf when your app isn't frontmost. If your app is frontmost, there is nothing more for the system to do. Local notifications, therefore, do not fire any alert to the user when the app is frontmost. Instead, if your app is frontmost when a local notification fires, your app is notified and you can alert the user if you like.

Resources