Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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

like image 515
tagabek Avatar asked Dec 17 '13 05:12

tagabek


2 Answers

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];
                }
            }];
        }
    }];
}
like image 93
Wesley Smith Avatar answered Oct 02 '22 14:10

Wesley Smith


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.

like image 21
Nic Huang Avatar answered Oct 02 '22 13:10

Nic Huang