I have built a messaging app that is similar to Snapchat - one user can send another user pictures. I am trying to add push notifications to the app, so that when a message is sent from UserA to UserB, UserB receives a push notification of "New Message from UserA".
I have been researching this for hours now, and I feel like I am very close.
I am trying to use Parse to send push notifications. I would like it to work like this: When UserA sends UserB a message, UserB is also sent a push notification that says "New Message from UserA". I was successfully able to use the Parse website to send a push notification to devices using the application, but am NOT able to successfully send a push notification from within the app (when a user sends a message) to the receiving user's device.
The push notifications are apparently being sent successfully, as my Parse account shows the messages that I have sent. However, no messages actually reaches the intended device and the list of push notifications shows 0 subscribers for each push notification.
And I can click on one of those to see the details.
Also, I am using a Distribution/Production Provisioning Profile & Certificate.
Here's the code that I am using the send the push notification after UserA would send a message to UserB - the message
object is the message that has been uploaded to Parse, and the messageRecipients are the users that the message is being sent to:
// Send Push Notification to recipients
NSArray *messageRecipients = [message objectForKey:@"recipientIds"];
PFQuery *pushQuery = [PFInstallation query];
[pushQuery whereKey:@"owner" containedIn:messageRecipients];
PFPush *push = [[PFPush alloc] init];
[push setQuery:pushQuery];
[push setMessage:[NSString stringWithFormat: @"New Message from %@!", [PFUser currentUser].username]];
[push sendPushInBackground];
Here are my AppDelegate.m related methods:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
[Parse setApplicationId:@"[This is where my app Id is]"
clientKey:@"[This is where client Id is]"];
[self customizeUserInterface];
[application registerForRemoteNotificationTypes:UIRemoteNotificationTypeAlert|UIRemoteNotificationTypeBadge|UIRemoteNotificationTypeSound];
return YES;
}
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken
{
[PFPush storeDeviceToken:deviceToken];
[PFPush subscribeToChannelInBackground:@""];
}
- (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error
{
NSLog(@"Did fail to register for push, %@", error);
}
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo
{
[PFPush handlePush:userInfo];
}
I have also submitted a post on the Parse.com forums: https://parse.com/questions/sending-a-push-notification-from-one-user-to-another-user
Is there something that I am missing or doing wrong?
EDIT: I am now able to see subscribers in my Parse account, but I am not actually receiving the push notifications on my device. The same goes for when I try to send a push notification test from the Parse website.
My searches kept coming back to here but nothing here really spelled it out for me. So here's how I got mine working:
In my AppDelegate.m I have:
- (void)applicationDidBecomeActive:(UIApplication *)application
{
PFUser *currentUser = [PFUser currentUser];
if (currentUser) {
//save the installation
PFInstallation *currentInstallation = [PFInstallation currentInstallation];
currentInstallation[@"installationUser"] = [[PFUser currentUser]objectId];
// here we add a column to the installation table and store the current user’s ID
// this way we can target specific users later
// while we’re at it, this is a good place to reset our app’s badge count
// you have to do this locally as well as on the parse server by updating
// the PFInstallation object
if (currentInstallation.badge != 0) {
currentInstallation.badge = 0;
[currentInstallation saveInBackgroundWithBlock:^(BOOL succeeded, NSError *error) {
if (error) {
// Handle error here with an alert…
}
else {
// only update locally if the remote update succeeded so they always match
[[UIApplication sharedApplication] setApplicationIconBadgeNumber:0];
NSLog(@"updated badge");
}
}];
}
} else {
[PFUser logOut];
// show the signup screen here....
}
}
in the viewController where I send the push I have:
myViewController.h
@property (nonatomic, strong) NSMutableArray *recipients; // declare the array we'll use to store our recipients
myViewController.m
- (void)viewDidLoad
{
[super viewDidLoad];
self.recipients = [[NSMutableArray alloc] init]; // initialize the array we'll use to hold our recipients
}
// in another part of the code (not shown here) we set up a tableView with all of the current user's friends in it
// when the user taps a row in that tableView we add or remove the selected friend from our recipients list
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[self.tableView deselectRowAtIndexPath:indexPath animated:NO];
UITableViewCell *cell = [self.tableView cellForRowAtIndexPath:indexPath];
PFUser *user = [self.friends objectAtIndex:indexPath.row];
if (cell.accessoryType == UITableViewCellAccessoryNone) {
cell.accessoryType = UITableViewCellAccessoryCheckmark;
[self.recipients addObject:user.objectId]; // user selected a recipient, add them to the array
}
else {
cell.accessoryType = UITableViewCellAccessoryNone;
[self.recipients removeObject:user.objectId]; // user de-selected a recipient, remove them from the array
}
}
- (void)uploadMessage
{
UIImage *newImage = [self resizeImage:self.image toWidth:640.0f andHeight:960.0f];
NSData *fileData= UIImageJPEGRepresentation(newImage, 1.0);
NSString *fileName= @"image.jpg";;
NSString *fileType= @"image";
PFFile *file = [PFFile fileWithName:fileName data:fileData];
[file saveInBackgroundWithBlock:^(BOOL succeeded, NSError *error) {
if (error) {
// Handle error here with an alert…
}
else {
PFObject *message = [PFObject objectWithClassName:@"Messages"];
[message setObject:file forKey:@"file"];
[message setObject:fileType forKey:@"fileType"];
[message setObject:self.recipients forKey:@"recipientIds"];
// self.recipients is an NSMutableArray of the objectIds for each
// user the message will go to
[message setObject:[[PFUser currentUser] objectId] forKey:@"senderId"];
[message setObject:[[PFUser currentUser] username] forKey:@"senderName"];
[message saveInBackgroundWithBlock:^(BOOL succeeded, NSError *error) {
if (error) {
// Handle error here with an alert…
}
else {
// Everything was successful! Reset UI… do other stuff
// Here’s where we will send the push
//set our options
NSDictionary *data = [NSDictionary dictionaryWithObjectsAndKeys:
@“Ne messages available!!”, @"alert",
@"Increment", @"badge",
nil];
// Now we’ll need to query all saved installations to find those of our recipients
// Create our Installation query using the self.recipients array we already have
PFQuery *pushQuery = [PFInstallation query];
[pushQuery whereKey:@"installationUser" containedIn:self.recipients];
// Send push notification to our query
PFPush *push = [[PFPush alloc] init];
[push setQuery:pushQuery];
[push setData:data];
[push sendPushInBackground];
}
}];
}
}];
}
I think I have the answer. I encountered the same problem and I just solved it.
When you are setting value to owner, you should use "[PFUser currentUser].objectId", instead of [PFUser currentUser]. The latter gives you a pointer to owner, but we need a string to set Push query within this situation.
When we first set owner to Installation, we should set objectId as string to owner instead of just [PFUser currentUser] like below.
[currentInstallation setObject:[PFUser currentUser].objectId forKey:@"owner"];
And later we could set the owner (string) to our pushQuery.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With