Push Notifications with NodeJS backend - ios

I currently am looking to do push notifications for an iOS app. I use PostgresSQL and NodeJS for the backend and as I look online, there doesnt seem to be a direct way to implement PEER TO PEER push notifications, between two devices. Any help from people with experience would be very helpful.

You can segment users you wish to send individual messages to using the Parse SDK. Their service is retiring in January, but you can still host your own MongoDB instance and retain the full functionality of their platform.
Register your logged in user to receive push notifications:
UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:types categories:nil];
[[UIApplication sharedApplication] registerUserNotificationSettings:settings];
Implement the didRegisterForRemoteNotificationsWithDeviceToken method in your AppDelegate
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)newDeviceToken {
NSLog(#"didRegisterForRemoteNotifications");
// Store the deviceToken in the current installation and save it to Parse.
PFInstallation *currentInstallation = [PFInstallation currentInstallation];
[currentInstallation setDeviceTokenFromData:newDeviceToken];
if ([PFUser currentUser]) {
[currentInstallation setObject:[PFUser currentUser] forKey:#"user"];
}
[currentInstallation saveInBackground];
}
This creates a pointer to the User's account which we'll use to segment the user with this:
NSString *toUserObjectId = someUser.objectId; //someUser is a 'PFUser' object
// segment the user
PFQuery *innerQuery = [PFUser query];
[innerQuery whereKey:#"objectId" equalTo:toUserObjectId];
PFQuery *query = [PFInstallation query];
[query whereKey:#"user" matchesQuery:innerQuery];
NSDictionary *pushData = #{
#"alert": #"some message",
// #"p": someStringPayload,
#"badge": #"Increment",
#"sound": #"cheering.caf",
};
PFPush *push = [[PFPush alloc] init];
[push setData:pushData];
//[push expireAfterTimeInterval:interval];
[push setQuery:query];
[push sendPushInBackground];
If you're going this route, I'd start a new app on their existing service, then migrate somewhere else. Hope this helps.

Related

resigter for remote notifications causing crash in appDelegate iOS Parse.com [duplicate]

I'm trying to enable push notifications through parse. The parse notification code works if there is already a user cached and signed into the app. If I logout and try to signup a new user, however, the app crashes and I get an error that states: 'NSInvalidArgumentException', reason: 'Can't use nil for keys or values on PFObject. Use NSNull for values.'...I believe the issue is with the didRegisterForRemoteNotificationsWithDeviceToken method within the app delegate. Because there isn't a currentUser logged in, when the app tries creating a PFInstallation, all of the associating fields are returning nil. I have tried an if statement checking for a currentUser before running the PFInstallation code, but the app still crashes. I need to register for notifications after signup occurs, but I can't figure out how to do that seeing as didRegisterForRemoteNotificationsWithDeviceToken needs to occur in the app delegate. Any advice or solutions are appreciate. My code snippet is below. Thanks!
EDIT: This code works now!
- (void)application:(UIApplication *)application
didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)newDeviceToken
{
PFInstallation *currentInstallation = [PFInstallation currentInstallation];
if ([PFUser currentUser] != nil)
{
currentInstallation[#"currentUser"]=[PFUser currentUser];
}
else
{
[currentInstallation removeObjectForKey:#"currentUser"];
}
[currentInstallation setDeviceTokenFromData:newDeviceToken];
[currentInstallation saveInBackground];
}
For Sending Push Notifications
- (IBAction)send:(id)sender
{
PFQuery *userQuery = [PFUser query];
[userQuery whereKey:#"objectId" equalTo:self.recipient.objectId];
PFQuery *query = [PFInstallation query];
[query whereKey:#"user" matchesQuery:userQuery];
NSString *sendingUser = self.currentUser.username;
NSString *message = [NSString stringWithFormat:#"from %#: \n %#", sendingUser,self.message.text];
PFPush *push= [[PFPush alloc]init];
[push setQuery:query];
[push setMessage:message];
[push sendPushInBackground];
NSLog(#"Message sent!");
[self dismissViewControllerAnimated:NO completion:nil];
}
You can still register an installation without a current user, but you have to make sure that the user is removed from the registration -
- (void)application:(UIApplication *)application
didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken
{
// Store the deviceToken in the current installation and save it to Parse.
PFInstallation *currentInstallation = [PFInstallation currentInstallation];
if ([PFUser currentUser] != nil)
{
currentInstallation[#"currentUser"]=[PFUser currentUser];
}
else {
[currentInstallation removeObjectForKey:#"currentUser"];
}
[currentInstallation setDeviceTokenFromData:deviceToken];
[currentInstallation saveInBackground];
}
Then, wherever you handle login/logout events you can update the current installation record. For example -
-(void) loggedIn
{
PFInstallation *currentInstallation=[PFInstallation currentInstallation];
currentInstallation[#"currentUser"]=[PFUser currentUser];
[currentInstallation saveInBackground];
}
-(void) notLoggedIn
{
PFInstallation *currentInstallation=[PFInstallation currentInstallation];
[currentInstallation removeObjectForKey:#"currentUser"];
[currentInstallation saveInBackground];
}

Sent push notification to Parse, how to receive it in device

I am trying to send and receive push notifications, so when, for example, a certain switch is turned off, another phone with the same app is notified that this has happened by sending an alert message.
The push notifications are being sent successfully to Parse as my account shows all of them sent by my app. However, no messages actually reach the intended device. The list of notifications sent by my app show 0 "Pushes sent" each.
I have sent push notifications from Parse itself to my device and I do receive those correctly, so I don't think it's a problem with the configuration for the notifications.
I followed the Parse guide to configure these but I'll post my code anyways:
AppDelegate.m
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
[Parse setApplicationId:#"****My app id****"
clientKey:#"****My key****"];
UIUserNotificationType userNotificationTypes = (UIUserNotificationTypeAlert |
UIUserNotificationTypeBadge |
UIUserNotificationTypeSound);
UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:userNotificationTypes
categories:nil];
[application registerUserNotificationSettings:settings];
[application registerForRemoteNotifications];
return YES;
}
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
// Store the deviceToken in the current installation and save it to Parse.
[PFPush storeDeviceToken:deviceToken];
[PFPush subscribeToChannelInBackground:#""];
PFInstallation *currentInstallation = [PFInstallation currentInstallation];
[currentInstallation setObject:[PFUser currentUser] forKey:#"owner"];
[currentInstallation saveInBackground];
}
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo {
[PFPush handlePush:userInfo];
}
Inside my method where my switch changes state:
PFInstallation *currentInstallation = [PFInstallation currentInstallation];
[currentInstallation addUniqueObject:#"HI" forKey:#"try"];
[currentInstallation saveInBackground];
PFPush *push = [[PFPush alloc] init];
[push setChannel:#"HI"];
[push setMessage:#"I am sending a push notification!"];
[push sendPushInBackground];
As shown below, Parse receives my push, but has 0 "Pushes sent". There's only 1 subscriber when I send the push from Parse itself, where my iphone does receive it.
So basically, how can I get Parse to send that push notification I'm sending from my app in the first place back to my device? I've spent hours researching so please help!!
As mentioned by Paulw11, On first device, you need to register for channel "Hi"
PFInstallation *currentInstallation = [PFInstallation currentInstallation];
[currentInstallation addUniqueObject:#"Hi" forKey:#"channels"];
[currentInstallation saveInBackground];
On second device, where you have change switch part
PFPush *push = [[PFPush alloc] init];
[push setChannel:#"Hi"];
[push setMessage:#"I am sending a push notification!"];
[push sendPushInBackground];

Are Parse push notifications very unreliable? Only 50% of mine are received

I am building an app that will implement a Parse backend to send push notifications. Users will be able to send other users a message contained in a push notification. I have been playing around with this and when I send it registers on the Parse website fine but only about 50% of the messages sent are being received on the device. Does anyone else have this problem? I know Push Notifications are not guaranteed but a 50% success rate? Any ideas?
Thanks
code below:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
[Parse setApplicationId:#"***"
clientKey:#"****"];
UIUserNotificationType userNotificationTypes = (UIUserNotificationTypeAlert |
UIUserNotificationTypeBadge |
UIUserNotificationTypeSound);
UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:userNotificationTypes
categories:nil];
[application registerUserNotificationSettings:settings];
[application registerForRemoteNotifications];
return YES;
}
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
// Store the deviceToken in the current installation and save it to Parse.
PFInstallation *currentInstallation = [PFInstallation currentInstallation];
[currentInstallation setDeviceTokenFromData:deviceToken];
currentInstallation.channels = #[ #"global" ];
[currentInstallation saveInBackground];
}
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo
{
[PFPush handlePush:userInfo];
}
- (void)notifyFriendAtIndex:(NSInteger)index completionHandler:(userCompletionHandler)handler
{
PFQuery *pushQuery = [PFInstallation query];
[pushQuery whereKey:#"deviceType" equalTo:#"ios"];
NSString *pushMessage = [NSString stringWithFormat:#"From %# HI!", self.currentUser.username];
NSDictionary *pushData = #{#"alert": pushMessage, #"badge": #0, #"sound": #"notify.wav"};
PFPush *push = [[PFPush alloc] init];
[push setQuery:pushQuery];
[push setData:pushData];
[push sendPushInBackgroundWithBlock:^(BOOL succeeded, NSError *error) {
if (error) {
NSLog(#"Error: %# %#", error, [error userInfo]);
handler(NO, error);
}
else {
handler(YES, nil);
}
}];
}
I have not experienced any major problems in the past with Parse's Push Notification delivery. One of my apps has about 32,000 registered devices and seems to get near 100% delivery.
I also have a couple of chat apps that use Parse as the messaging and push back-end. Users can subscribe to a particular chat room and get Push Notification through Segmentation. One of those apps just launched and so far the push notifications are coming through 100%. The only thing I've noticed is a slight delay sometimes. Maybe a minute or two, but I think that could be because of a slow wifi connection.
I also use PushWoosh for general Broadcast Push Notifications. They are great, but sometimes PushWoosh takes longer to deliver. Parse is usually faster so the bottom line is I think Parse's Push Notifications are reliable.
In my experience, i concluded that most is due the main push notification deliverer ( Apple for iOS, Google for Android ). I'm saying this because we have an app in Parse that send push notification on both iOS and Android, and some days we don't receive any push notification, some others a few or all. All this without changing any implementation. In past, i used another push notification service called Urban Airship (that rely on the proper push notification deliverers), and there was the same problem, some days "almost" ok, some other no work.
Just check if your testing device are correctly registered in the "Installation" table with proper deviceToken set. We send the push notification server side through channels. I write here the code maybe it could help you:
var dataStruct ={
alert: "Hi there!",
my_additional_info: "normal chat message"
};
Parse.Push.send({
channels: ["your_custom_registered_installation_channel_device"],
data: dataStruct
}).then(function() {
promise.resolve();
}, function(error) {
promise.reject(error);
});
So normally it depends by the day, but if you have this statistic (50%) maybe the installation is not always registered/updated when your iPhone register for push notification
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken
{
PFInstallation *currentInstallation = [PFInstallation currentInstallation];
// Save/update device tocken
[currentInstallation setDeviceTokenFromData:deviceToken];
// store your channel
[currentInstallation setChannels:#["channel_123"]];
[currentInstallation saveInBackgroundWithBlock:^(BOOL succeeded, NSError *error) {
// Do your stuff
}];
}

My app crashes when I try to log sign up a user and enable push notifications through parse

I'm trying to enable push notifications through parse. The parse notification code works if there is already a user cached and signed into the app. If I logout and try to signup a new user, however, the app crashes and I get an error that states: 'NSInvalidArgumentException', reason: 'Can't use nil for keys or values on PFObject. Use NSNull for values.'...I believe the issue is with the didRegisterForRemoteNotificationsWithDeviceToken method within the app delegate. Because there isn't a currentUser logged in, when the app tries creating a PFInstallation, all of the associating fields are returning nil. I have tried an if statement checking for a currentUser before running the PFInstallation code, but the app still crashes. I need to register for notifications after signup occurs, but I can't figure out how to do that seeing as didRegisterForRemoteNotificationsWithDeviceToken needs to occur in the app delegate. Any advice or solutions are appreciate. My code snippet is below. Thanks!
EDIT: This code works now!
- (void)application:(UIApplication *)application
didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)newDeviceToken
{
PFInstallation *currentInstallation = [PFInstallation currentInstallation];
if ([PFUser currentUser] != nil)
{
currentInstallation[#"currentUser"]=[PFUser currentUser];
}
else
{
[currentInstallation removeObjectForKey:#"currentUser"];
}
[currentInstallation setDeviceTokenFromData:newDeviceToken];
[currentInstallation saveInBackground];
}
For Sending Push Notifications
- (IBAction)send:(id)sender
{
PFQuery *userQuery = [PFUser query];
[userQuery whereKey:#"objectId" equalTo:self.recipient.objectId];
PFQuery *query = [PFInstallation query];
[query whereKey:#"user" matchesQuery:userQuery];
NSString *sendingUser = self.currentUser.username;
NSString *message = [NSString stringWithFormat:#"from %#: \n %#", sendingUser,self.message.text];
PFPush *push= [[PFPush alloc]init];
[push setQuery:query];
[push setMessage:message];
[push sendPushInBackground];
NSLog(#"Message sent!");
[self dismissViewControllerAnimated:NO completion:nil];
}
You can still register an installation without a current user, but you have to make sure that the user is removed from the registration -
- (void)application:(UIApplication *)application
didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken
{
// Store the deviceToken in the current installation and save it to Parse.
PFInstallation *currentInstallation = [PFInstallation currentInstallation];
if ([PFUser currentUser] != nil)
{
currentInstallation[#"currentUser"]=[PFUser currentUser];
}
else {
[currentInstallation removeObjectForKey:#"currentUser"];
}
[currentInstallation setDeviceTokenFromData:deviceToken];
[currentInstallation saveInBackground];
}
Then, wherever you handle login/logout events you can update the current installation record. For example -
-(void) loggedIn
{
PFInstallation *currentInstallation=[PFInstallation currentInstallation];
currentInstallation[#"currentUser"]=[PFUser currentUser];
[currentInstallation saveInBackground];
}
-(void) notLoggedIn
{
PFInstallation *currentInstallation=[PFInstallation currentInstallation];
[currentInstallation removeObjectForKey:#"currentUser"];
[currentInstallation saveInBackground];
}

setting user Device token after registration with Parse

From the push notification guide, Im noticing that parse recommends setting the device token from within the AppDelegate. Im interested in sending push notifications to certain users, and Im wondering if its possible to move the code for registering a device and their deviceToken within the login code which is found outside of the AppDelegate.
I think you should keep the deviceToken association in the delegate, but after the user logs in, grab the current installation and associate it with the user:
PFInstallation *current = [PFInstallation currentInstallation];
[current setObject:[PFUser currentUser] forKey:#"owner"];
[current saveInBackground];
You can run this code after login/ signup in application
PFInstallation *currentInstallation = [PFInstallation currentInstallation];
[currentInstallation setDeviceTokenFromData:sharedInstance.DeviceToken];
[currentInstallation setObject:[PFUser currentUser] forKey:#"user"];
currentInstallation.channels = #[ #"channel" ];
[currentInstallation saveInBackground];

Resources