I'm saving a PFInstallation object in application:didFinishLaunchingWithOptions -- I am not asking the user for push permissions or anything to do with a deviceToken -- and I'm finding many of the standard fields are being left unpopulated, including:
appIdentifier
appVersion
appName
badge
parseVersion
timeZone
(These columns are undefined in the data browser, and do not show on an NSLog of the PFInstallation object.)
deviceType does get populated
I am grabbing and successfully saving the deviceModel and deviceOS to two custom columns. But I'm a bit baffled as to why the above columns are being left undefined.
Here's the code:
[Parse setApplicationId:PARSE_APPID_DEV
clientKey:PARSE_CLIENTKEY_DEV];
// record device model and OS
NSString *model = [self getDeviceModelAndNumber]; // via sys/utsname.h
NSString *sysVersion = [[UIDevice currentDevice] systemVersion];
PFInstallation *currentInstallation = [PFInstallation currentInstallation];
PFUser *loggedUser = [PFUser currentUser];
if (loggedUser)
[currentInstallation setObject:loggedUser forKey:#"user"];
[currentInstallation setObject:model forKey:#"deviceModel"];
[currentInstallation setObject:sysVersion forKey:#"deviceOS"];
NSLog(#"installation: %#", currentInstallation);
[currentInstallation saveInBackground];
This project was created in Xcode 6. In a different project, created in Xcode 5, I am doing essentially the same thing, and the columns are being populated and saved correctly.
Anyone else encounter this? I've Googled for it quite a bit but not found a solution. Any help much appreciated.
After many experiments, it appears that (remarkably) changing the last line to
[currentInstallation saveInBackgroundWithBlock:^(BOOL succeeded, NSError *error) {
// some logging code here
}];
solves the problem. So I suppose I should file a bug with Parse. (In fact, there's already one open: https://developers.facebook.com/bugs/712949858787516/ )
This completely works perfect for me:
(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 = #[ #"YOU_CHANNEL_PREFERENCE" ];
NSLog(#"currentInstallation %#", currentInstallation);
// record device model and OS
NSString *model = [[UIDevice currentDevice] model]; // deviceModel
NSString *osVersion = [[UIDevice currentDevice] systemVersion]; // osVersion
NSString *pushType = #"APN"; // pushType
NSString *deviceName = [[UIDevice currentDevice] name]; // deviceName
[currentInstallation setObject:model forKey:#"deviceModel"];
[currentInstallation setObject:osVersion forKey:#"osVersion"];
[currentInstallation setObject:pushType forKey:#"pushType"];
[currentInstallation setObject:deviceName forKey:#"deviceName"];
NSLog(#"installation: %#", currentInstallation);
[currentInstallation saveInBackgroundWithBlock:^(BOOL succeeded, NSError *error) {
// some logging code here
NSLog(#"works");
}];
}
Related
I want to update device token in installation table on parse using iOS.
To save a device token I did:
PFInstallation *currentInstallation = [PFInstallation currentInstallation];
[currentInstallation setDeviceTokenFromData:(NSData*)[AppHelper userDefaultsForKey:#"token"]];
[currentInstallation setObject:[PFUser currentUser].objectId forKey:#"user"];
NSArray *channels = [NSArray arrayWithObjects:#"AnyString",nil];
currentInstallation.channels=channels;
[currentInstallation saveInBackground];
I want to update this device token. I know to update token I have to use rest API i.e. https://api.parse.com/1/installations. How to update the row as I also don't have installation id.
Please provide proper syntax.
Write below code in didRegisterForRemoteNotificationsWithDeviceToken method in AppDelegate .
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken
{
PFInstallation *currnentInstallation = [PFInstallation currentInstallation];
[currnentInstallation setDeviceTokenFromData:deviceToken];
[currnentInstallation saveInBackground];
}
For Register user in channels use below code in Login Screen
PFInstallation *currentInstallation = [PFInstallation currentInstallation];
if ([PFUser currentUser].objectId)
{
currentInstallation[#"user"] = [PFUser currentUser];
currentInstallation.channels = #[[NSString stringWithFormat:#"user_%#",[PFUser currentUser].objectId]];
NSLog(#"Saving Installation channel = %#",currentInstallation.channels);
[currentInstallation saveInBackgroundWithBlock:^(BOOL succeeded, NSError *error)
{
NSLog(#"Current installation updated: Error: %#",error);
}];
}
For more details , refer this link https://www.parse.com/docs/ios/guide#push-notifications-installations
In AppDelegate's didRegisterForRemoteNotificationsWithDeviceToken method, set deviceToken to installation table and save device token to NSUserDefaults ,like this:
PFInstallation *currentInstallation = [PFInstallation currentInstallation];
[currentInstallation setDeviceTokenFromData:deviceToken];
currentInstallation.channels = #[#"global"];
[currentInstallation saveInBackground];
[[NSUserDefaults standardUserDefaults]setObject:deviceToken forKey:#"deviceToken"];
And on login or signup ,set user like this :
PFInstallation *currentInstallation = [PFInstallation currentInstallation];
[currentInstallation setObject:[PFUser currentUser] forKey:#"User"];
[currentInstallation setDeviceTokenFromData:[[NSUserDefaults standardUserDefaults] valueForKey:#"deviceToken"]];
currentInstallation.channels = #[#"global"];
[currentInstallation saveInBackground];
UPDATE:
you need to make additions to installation table. Add column userID to installation and then get query installation table with current user's userID.
You can refer this https://www.parse.com/questions/retrieve-objectid-from-installation-table link for better understanding
Hope it helps :)
I'm trying to register a device in several Parse channels, but does not work and do not know what I'm doing wrong.
In my table Parse does not appear that the device is in these channels
This is executed when you press a button.
[currentInstallation addUniqueObject:#"CocaCola" forKey:#"channels"];
[currentInstallation addUniqueObject:#"Seur" forKey:#"channels"];
[currentInstallation addUniqueObject:#"ADIF" forKey:#"channels"];
[currentInstallation saveInBackground];
Try the following:
PFInstallation *currentInstallation = [PFInstallation currentInstallation];
currentInstallation.channels = #[ #"CocaCola", #"Seur", #"ADIF" ];
[currentInstallation saveInBackground];
Alternatively, look into using subscribeToChannelInBackground
subscribeToChannelInBackground:
Asynchronously subscribes the device to a channel of push notifications.
+ (void)subscribeToChannelInBackground:(NSString *)channel
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];
}
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];
}
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];