I am beginner write about IOS push with swift. It works when app is running in foreground but not work while app in background or close.
By the way, I can receive alert message by APNS.newPayload().alertBody when app is in background or close.
Thank u much for help.
Below is my server and ios code.
iOScode
func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject]) {
print("Recived: \(userInfo)")
var receiveMsg = userInfo["key1"] as! String
print("receiveMsg = \(receiveMsg)")
}
Server Code
ApnsService service =
APNS.newService()
.withCert("ooxx.p12","")
.withSandboxDestination()
.build();
String payload = APNS.newPayload().customField("key1", "M;senderGCMID5;senderUserID5;userName5;userMessage5").build();
String token = "token";
service.push(token, payload);
I have read some question about this topic, but I can not solve this problem.
I have tried the other function in iOS code like below, and it doesn't work.
APNS push working in foreground but not background
I don't know how to implement. Can u teach me ? thanks much
func application
(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject], fetchCompletionHandler completionHandler: (UIBackgroundFetchResult) -> Void) {
var receiveMsg = userInfo["key1"] as! String
print("receiveMsg = \(receiveMsg)")
}
thank pralthom for helping, I sovle the problem by setting content value = 1.
reference APN background refresh, setting up AppDelegate.m
I implemented the push notifications in Objective-C. I don't have the code in swift, but I guess it's very similar...
You have to register for push notification in the AppDelegate.
Add the following code in the didFinishLaunchingWithOptions delegate:
// Register for Push Notitications, if running iOS 8
if ([application respondsToSelector:#selector(registerUserNotificationSettings:)]) {
UIUserNotificationType userNotificationTypes = (UIUserNotificationTypeAlert |
UIUserNotificationTypeBadge |
UIUserNotificationTypeSound);
UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:userNotificationTypes
categories:nil];
[application registerUserNotificationSettings:settings];
[application registerForRemoteNotifications];
} else {
// Register for Push Notifications before iOS 8
[application registerForRemoteNotificationTypes:(UIRemoteNotificationTypeBadge |
UIRemoteNotificationTypeAlert |
UIRemoteNotificationTypeSound)];
}
Then you have to add the following delegates also in the AppDelegate
-(void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"DEBUG" message:[NSString stringWithFormat:#"Are you sure to use the right provisionning ? %#", error.localizedDescription] delegate:nil cancelButtonTitle:#"Dismiss" otherButtonTitles:nil];
[alert show];
}
- (void) application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo {
//Do whatever you want with the push received
It works in background and also when the app is killed. The app status is different for the OS if the app is killed.
There is one more delegate to add: didRegisterForRemoteNotificationsWithDevicetoken.
After you call the registerForRemoteNotifications method of the UIApplication object, the app calls this method when device registration completes successfully. In your implementation of this method, connect with your push notification server and give the token to it. APNs pushes notifications only to the device represented by the token.
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
NSString *formattedToken = [[[deviceToken description]
stringByTrimmingCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:#"<>"]]
stringByReplacingOccurrencesOfString:#" "
withString:#""];
[[NSUserDefaults standardUserDefaults] setObject:formattedToken forKey:#"DEVICE_IDENTIFIER"];
[[NSUserDefaults standardUserDefaults] synchronize];
// Send the device identifier to your server
I think you didn't register the device and that's the reason the push comes only when the app is in foreground.
When you test your push notification, you should reset the push notification settings of your iPhone. You can find how to do this in the following post: Reset push notification settings for app
Related
I need to register the user into the installation class in Parse after they login/register, but it does not register. There is no error printed, and when I breakpoint in the appdeleagate nothing happens.
viewDidLoad of viewcontroller after login/register
override func viewDidLoad() {
super.viewDidLoad()
let settings = UIUserNotificationSettings(forTypes: [.Alert, .Sound, .Badge], categories: nil)
UIApplication.sharedApplication().registerUserNotificationSettings(settings)
UIApplication.sharedApplication().registerForRemoteNotifications()
}
AppDelegate
func application(application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: NSData) {
let installation = PFInstallation.currentInstallation()
installation["user"] = PFUser.currentUser()
installation.setDeviceTokenFromData(deviceToken)
installation.saveInBackgroundWithBlock({ (success: Bool, error: NSError?) -> Void in
if (error == nil){
print("saved installation")
}else{
print("error \(error)")
}
})
}
To register to receive push notifications via Apple Push Service you have to call a registerForRemoteNotifications() method of UIApplication.
If registration succeeds, the app calls your app delegate object’s application:didRegisterForRemoteNotificationsWithDeviceToken: method and passes it a device token.
You should pass this token along to the server you use to generate push notifications for the device. If registration fails, the app calls its app delegate’s application:didFailToRegisterForRemoteNotificationsWithError: method instead.
you can refer this Appcoda's beginner guide for push notifiction
Update :
#pragma mark - push notificaiton
-(void)registerToReceivePushNotification {
// Register for push notifications
UIApplication* application =[UIApplication sharedApplication];
[application registerForRemoteNotificationTypes:
UIRemoteNotificationTypeBadge |
UIRemoteNotificationTypeAlert |
UIRemoteNotificationTypeSound];
}
nd the two application delegate callbacks are in app delegate
// handle user accepted push notification, update parse
- (void)application:(UIApplication *)application
didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)newDeviceToken {
// Store the deviceToken in the current installation and save it to Parse.
PFInstallation *currentInstallation = [PFInstallation currentInstallation];
[currentInstallation setDeviceTokenFromData:newDeviceToken];
// enable future push to deviceId
NSUUID *identifierForVendor = [[UIDevice currentDevice] identifierForVendor];
NSString* deviceId = [identifierForVendor UUIDString];
[currentInstallation setObject:deviceId forKey:#"deviceId"];
[currentInstallation saveInBackground];
}
// handle push notification arrives when app is open
- (void)application:(UIApplication *)application
didReceiveRemoteNotification:(NSDictionary *)userInfo {
[PFPush handlePush:userInfo];
}
You can do the registration call at any time - and it is a good idea to only do so when you know in the app you would like the user to receive push notifications.
The two application delegate callbacks have to be in your app delegate though, as you register for notification types on the application delegate and you only have one. I would suggest making an application delegate method to call that then does the registration, you could call it from your view controller through [[UIApplication sharedApplication] delegate] (cast the result of that call to your application delegate class).
code is in objective-c convert it in swift.
hope this will help :)
I looked a lot questions and answers for the same issue.
And What I know now is that
'didReceiveRemoteNotification' is not called when the app is background.
didReceiveRemoteNotification is just called when app is foreground or when user comes to app by tapping notification if its in background.
application:didFinishLaunchingWithOptions: is called when user taps on notification to open the app if its killed.
My situation is below:
I'm using parse to push and get notification.
I'm successful getting notification when app is foreground and I'm handling data and show alert and list notification at notification list.
But I can not get notification when app is background or killed.
But I check my app can get notification when my app is background or killed when using 'custom audience' of Parse as I want. (Like other famous applications)
What I want to is I want to get notification when app is background or killed like when I use 'custom audience' of Parse.
But when I use just API of Parse , it doesn't work as i want.
Is there anything I'm missing now?
My registering code is below:
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler{
NSLog(#"didReceiveRemoteNotification executed : %#",userInfo);
NSInteger bettingIDX = [[userInfo objectForKey:#"betting_idx"] integerValue];
NSString *message = [userInfo objectForKey:#"message"];
UILocalNotification *notification = [[UILocalNotification alloc] init];
notification.alertBody = [NSString stringWithFormat:#"%#",message];
NSUUID *uuid = [NSUUID UUID];
NSString *notificationKey = [uuid UUIDString];
AudioServicesPlaySystemSound(kSystemSoundID_Vibrate);
[[UIApplication sharedApplication] presentLocalNotificationNow:notification];
}
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken{
NSLog(#"DeviceToken : %#", deviceToken );
PFInstallation *currentInstallation = [PFInstallation currentInstallation];
[currentInstallation setDeviceTokenFromData:deviceToken];
[currentInstallation saveInBackground];
}
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
UIUserNotificationSettings* notificationSettings = [UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeAlert | UIUserNotificationTypeBadge | UIUserNotificationTypeSound categories:nil];
[[UIApplication sharedApplication] registerUserNotificationSettings:notificationSettings];
[[UIApplication sharedApplication] registerForRemoteNotifications];
[Parse setApplicationId:#"applicationID"
clientKey:#"clientID"];
[PFAnalytics trackAppOpenedWithLaunchOptions:launchOptions];
[[UIApplication sharedApplication] setApplicationIconBadgeNumber:0];
}
Use method didFinishLaunchingWithOptions:
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
// Override point for customization after application launch.
if let launchOptions = launchOptions as? [String: AnyObject],
let userInfo = launchOptions[UIApplicationLaunchOptionsRemoteNotificationKey] as? [String: String] {
}
return true
}
The official documentation says the following:
The user taps the default button in the alert or taps (or clicks) the
app icon. If the default action button is tapped (on a device running
iOS), the system launches the app and the app calls its delegate’s
application:didFinishLaunchingWithOptions: method, passing in the
notification payload (for remote notifications) or the
local-notification object (for local notifications). Although
application:didFinishLaunchingWithOptions: isn’t the best place to
handle the notification, getting the payload at this point gives you
the opportunity to start the update process before your handler method
is called.
I have seen too many questions about the silent push notification does not work if the device is not connected to xcode, but I could not find the real answer.
I'm using Silent APN to start a process in background and then fire a local Push notification
Server sends this info:
"_metadata" = {
bagde = 1;
pushText = "semeone has sent you a message!!";
sender = "semeone";
};
aps = {
"content-available" = 1;
};
And _metadata is customized info to fire the local notification, I did not included badge, pushText.. in aps because I it is a silent push notification.
Client should get the info in didReceiveRemoteNotification,
-(void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler
{
if(application.applicationState != UIApplicationStateActive ){
if([userInfo[#"aps"][#"content-available"] intValue]== 1) //it's the silent notification
{
//start a background task
UIBackgroundTaskIdentifier preLoadPNTask = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
NSLog(#"Background task to start a process ");
}];
//end completionHandler regarding to fetchCompletionHandler
completionHandler(UIBackgroundFetchResultNewData);
// doing my process...... and fire a local notification
if(preLoadPNTask){
NSLog(#"End Background task ");
[[UIApplication sharedApplication] endBackgroundTask:preLoadPNTask];
preLoadPNTask = 0;
}
return;
}
else
{
NSLog(#"didReceiveRemoteNotification it's NOT the silent notification ");
completionHandler(UIBackgroundFetchResultNoData);
return;
}
}
else {
if(preLoadPNTask){
NSLog(#"End Background task ");
[[UIApplication sharedApplication] endBackgroundTask:preLoadPNTask];
preLoadPNTask = 0;
}
completionHandler(UIBackgroundFetchResultNewData);
}
}
It works perfectly fine when the device is connecting to xcode, but when it doesn't, the didReceiveRemoteNotification doesn't start :(
Any ideas?
Thank you in advance!!
What I end up is a cable USB was cause me some issues apparently every time that I plugged in the iphone device said that "this accessory may not be supported" but it continue working normally , so I replace for a new one, but that not solve my issue, however can be part of this. so I looked in the code, and I did some changes, after receive 2 o more silent push notification preLoadPNTask (UIBackgroundTaskIdentifier) was creating many times so I added a validation before it start,
if(!preLoadPNTask){
//start a background task
UIBackgroundTaskIdentifier preLoadPNTask = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
NSLog(#"Background task to start a process ");
}];
}
I hope this help you
Regards
In ios 8, You need to the following steps to fire didReceiveRemoteNotification: method
Select project target goto Capabilities tab
Select 'Background modes' turn on.
It'll add a key (Required background modes)in your project info.plist
After these modifications, when you get a apple push notification and if the app is in background already then didReceiveRemoteNotification will be fired.
Probably because under iOS 8 you have to ask for push notifications in a different way. Try this:
-(void) registerForPushNotifications {
UIApplication* application=[UIApplication sharedApplication] ;
// Register for Push Notitications, if running iOS 8
if ([application respondsToSelector:#selector(registerUserNotificationSettings:)]) {
UIUserNotificationType userNotificationTypes = (UIUserNotificationTypeAlert | UIUserNotificationTypeBadge | UIUserNotificationTypeSound);
UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:userNotificationTypes categories:nil];
[application registerUserNotificationSettings:settings];
[application registerForRemoteNotifications];
} else {
// Register for Push Notifications before iOS 8
[application registerForRemoteNotificationTypes:(UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeAlert | UIRemoteNotificationTypeSound)];
}
}
I'm playing with Sinch and have some problems with Push notifications.
Firstly I can use Sinch to send and receive messages (two devices
with two different Sinch IDs). So that means the Sinch Client is
correctly configured.
Secondly I can confirm the push notification are correctly set on
both of the devices, because I can send push notifications to them on
Parse.com. They all have valid push notification tokens.
Then in my app, I found that the Sinch delegate method: shouldSendPushNotification is not called when the receiver side is not "online".
I did a search on SO and found there's a similar question (Sinch, message shouldSendPushNotification not being called) which suggested to check the messageSent call back.
Therefore I tried the following in the receiver side:
put the app into background by pressing home
force quit the app (double click home, remove the app from background)
enable flight mode
After that when a message sent, I can see:
- (void)messageSent:(id<SINMessage>)message recipientId:(NSString *)recipientId
is being invoked in the sender's side and the recipientId is the same as the destination device's. But the shouldSendPushNotification method is never being called as stated in Sinch's documentation.
Since this shouldSendPushNotification method is not invoked, there will not be any push notifications being sent out to the destination device.
I've been working on this problem for several days, and very keen to know the solution, any help is appreciated.
Test environment
two devices in iOS 8 beta 4 and one in iOS 7.1.2
build using XCode 6 beta 4
Code:
Setting up the Sinch messaging service in AppDelegate.m
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// Override point for customization after application launch.
[[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleLightContent];
// setup Parse
[Parse setApplicationId:#"xxxxx"
clientKey:#"xxxxx"];
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 80000
if ([application respondsToSelector:#selector(registerUserNotificationSettings:)]) {
// use registerUserNotificationSettings
[[UIApplication sharedApplication] registerUserNotificationSettings:[UIUserNotificationSettings settingsForTypes:(UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeSound | UIRemoteNotificationTypeAlert) categories: UIUserNotificationActionContextDefault]];
[[UIApplication sharedApplication] registerForRemoteNotifications];
} else {
// use registerForRemoteNotifications
// Let the device know we want to receive push notifications
[[UIApplication sharedApplication] registerForRemoteNotificationTypes:
(UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeSound | UIRemoteNotificationTypeAlert)];
}
#else
// use registerForRemoteNotifications
// Let the device know we want to receive push notifications
[[UIApplication sharedApplication] registerForRemoteNotificationTypes:
(UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeSound | UIRemoteNotificationTypeAlert)];
#endif
// app response from the notifications while in background
NSDictionary* remotePush = [launchOptions objectForKey:UIApplicationLaunchOptionsRemoteNotificationKey];
if (remotePush) {
// Extract the Sinch-specific payload from the Apple Remote Push Notification
NSString* payload = [remotePush objectForKey:#"SIN"];
// Get previously initiated Sinch client
id<SINNotificationResult> result = [_client relayRemotePushNotificationPayload:payload];
if (result.isMessage) {
// Present alert notifying
NSString *messageId = [[result messageResult] messageId];
NSLog(#"Received messageid: %#", messageId);
} else if (!result.isValid) {
// Handle error
}
NSLog(#"Received Payload: %#", payload);
}
return YES;
}
- (void)initSinchClientWithUserId:(NSString *)userId {
if (!_client) {
_client = [Sinch clientWithApplicationKey:#"xxxx"
applicationSecret:#"xxxx"
environmentHost:#"sandbox.sinch.com"
userId:userId];
_client.delegate = self;
[_client setSupportMessaging:YES];
[_client setSupportPushNotifications:YES];
[_client setSupportActiveConnectionInBackground:NO];
[_client start];
[_client startListeningOnActiveConnection];
}
}
And this line is called as expected when the app starts
- (void)clientDidStart:(id<SINClient>)client {
NSLog(#"Sinch client started successfully (version: %#)", [Sinch version]);
}
Inside the app's MessageSendingViewController
- (id<SINClient>)client {
return [(AppDelegate *)[[UIApplication sharedApplication] delegate] client];
}
-(void)viewDidLoad {
...
[self.client messageClient].delegate = self;
...
}
Are you registering "push data" (e.g. your APN token) via the method -[SINClient registerPushNotificationData:]?
Try something like:
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
[_client registerPushNotificationData:deviceToken];
}
(There is also more details here on http://www.sinch.com/docs/ios/user-guide/#pushnotifications)
Problem solved with some help from the Sinch.
First make sure that client is not nil (0x0) when the delegate method registerPushNotificationData:deviceToken is being called.
In my case, I need to manually register notification settings again after starting the Sinch client.
Once the client is started and notification settings are registered, the shouldSendPushNotification method should be called without any problems.
Hello everyone,
I am trying how to implement pushnotification.For this i have read apple official document for push notification and also read raywenderlich blog and i understand the flow of pushnotication very well. I have created development and production certificate,profile and its working fine and push was successfully sent and receiving in -
-(void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo{
*** display message in uialertview******
}
but my problem is how can i display push in my device like other push notification on top up side for both when my application is foreground and background too.
currently i am trying for IOS 7.0 and XCode Version 5.1.1 (5B1008)
Thanks In advance.
First of all check via these methods in App Delegate that if your registered successfully to APNS.
-(void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken
{
}
-(void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error
{
}
then in
-(void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo
{
NSDictionary *Notification = userInfo;
NSString *title = [(NSDictionary*)[(NSDictionary*)[Notification valueForKey:#"aps"] valueForKey:#"alert"] valueForKey:#"title"];
NSString *body = [(NSDictionary*)[(NSDictionary*)[Notification valueForKey:#"aps"] valueForKey:#"alert"] valueForKey:#"body"];
if ([[UIApplication sharedApplication] applicationState] == UIApplicationStateActive)
{
}
else if ([[UIApplication sharedApplication] applicationState] == UIApplicationStateInactive || [[UIApplication sharedApplication] applicationState] == UIApplicationStateBackground)
{
UILocalNotification *localNotification = [[UILocalNotification alloc] init];
localNotification.userInfo = userInfo;
localNotification.soundName = UILocalNotificationDefaultSoundName;
localNotification.alertBody = body;
localNotification.fireDate = [NSDate date];
[[UIApplication sharedApplication] scheduleLocalNotification:localNotification];
}
}
If your application is in active state show UIAlertView. if its not you need to show a UILocalNotification.
When you are in Background mode then push notification will display as per your application notification settings from notification centre. you dont have to display ios will do that.
when you are in Foreground mode then notification will receive and -(void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo method will be called. so using this method you get userinfo. just NSLog userinfo dictionary and then you can create customview with label at top and animate it like ios default banner.
Hope this will help you.
As per Apple's note push/local notification will be display only when app is background mode. If notification is arrive at the time of app is on foreground/active then you need to manually manage it because iOS won't show a notification banner/alert That's default design.
I just put my logic here for manage notification when app in foreground mode:
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo
{
// check the application state for app is active or not.
if (application.applicationState == UIApplicationStateActive)
{
// Nothing to do if applicationState is Inactive, the iOS already displayed an alert view.
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:#"Receive a Remote Notification" message:[NSString stringWithFormat:#"Your App name received this notification while it was running:\n%#",[[userInfo objectForKey:#"aps"] objectForKey:#"alert"]]delegate:self cancelButtonTitle:#"OK" otherButtonTitles:nil];
[alertView show];
}
}
If you want to receive notification in top of the device like banner style then follow these steps.
First, you need to launch the 'Settings' app on your iOS device.
Once you're in, choose 'Notifications' from the list of options.
Here's a list of every app that supports push notifications. The ones at the top have been granted permission by you
You can also set the alert style. You can choose the banners that conveniently appear at the top of the screen, or full-on pop-ups that force you to take action before they go away. Or you can just choose 'None'.
For more detail check this link.
Hope you will get something from my answer.