Sending a Push Notification from one user to another user with Parse

15,921

Solution 1

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];
                }
            }];
        }
    }];
}

Solution 2

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.

Share:
15,921

Related videos on Youtube

tagabek
Author by

tagabek

Updated on June 14, 2022

Comments

  • tagabek
    tagabek almost 2 years

    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. enter image description here

  • tagabek
    tagabek over 10 years
    Hey Nic, thanks. When I change it to that, I get this error: "Error: invalid type for key owner, expected *_User, but got string".
  • Nic Huang
    Nic Huang over 10 years
    You have that error because you trying to assign a string into a non-string column "owner"; You can drop the "owner" column in parse and created another column like "userId", and most importantly, give it a string type. And make sure your device saves PFInstallation with new userId string.
  • Nikolay Derkach
    Nikolay Derkach almost 10 years
    If you create a new user while logging in, application will crash. You have to check that [PFUser currentUser] is not nil in applicationDidBecomeActive and then set currentInstallation[@"installationUser"] in didLoginUser
  • Wesley Smith
    Wesley Smith almost 10 years
    @NikolayDerkach Nice catch, fixed my answer to check for currentUser
  • Jason McDermott
    Jason McDermott almost 10 years
    I got stuck here also: if you create a field with the wrong data type, you need to drop the column before you can attempt to insert new data.
  • user379468
    user379468 over 9 years
    I'm getting stuck here as well, I am storing a user id in my installation table as a string, and the passing that to my Push query. It appears to show up in the push browser online but just like in the original question shows that 0 were sent. is there any way to test the Push query?
  • Nic Huang
    Nic Huang over 9 years
    @user379468 Did you assign the exact userId to pushQuery or just the [PFUser currentUser]? It's different. And there is another way to test that. Try push from Parse push console. Choose segment and select userId column from your installation and "equals" your userId (the user you want to send).
  • Bhavesh Nayi
    Bhavesh Nayi over 8 years
    @DelightedD0D [[PFUser currentUser]objectId] getting null value. any idea about :(
  • Wesley Smith
    Wesley Smith over 8 years
    @BhaveshNai are you sure have a user logged in? Have you called [PFUser logInWithUsernameInBackground:@"myname" password:@"mypass"......]
  • Bhavesh Nayi
    Bhavesh Nayi over 8 years
    @DelightedD0D Thanks for reply. one more thing , how to send multiple user notification like group discussion. Thanks in advance :)
  • Wesley Smith
    Wesley Smith over 8 years
    @BhaveshNai, note the ` // self.recipients is an NSMutableArray of the objectIds for each ` comment in the above code. This code will send the notification to a group of recipients. just make sure that self.recipients is an NSArray or NSMutableArray containing the parse object ids of all the users you want to send the message to
  • Wesley Smith
    Wesley Smith over 8 years
    @BhaveshNai, I have edited the above to include more of the code that creates and manages the array in question, you can download the full .h and .m files from my project at samepage.io/app/#!/374e4f647569725d10cb0f5599baeea78c233bd4/‌​…. A word of warning though, I wrote this code over a year ago. It worked then but I have not used it since so I cant say for certain it'll work in the newest xcode without making changes.
  • Bhavesh Nayi
    Bhavesh Nayi over 8 years
    @DelightedD0D Thanks dear :)