问题
I'm testing push notifications with content-available=1, and they don't seem to be delivered to the app in the background unless on Wi-Fi.
I have a simple log statement at the beginning of the push notification handler:
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo
fetchCompletionHandler:(void (^) (UIBackgroundFetchResult))completionHandler {
NSLog(@"Notification received: %@", userInfo);
completionHandler(UIBackgroundFetchResultNewData);
}
Here is my test:
- Run the app, then press the home button to put the app in the background.
- Send a push notification with content-available=1
- Watch console logs
On Wi-Fi, the console log shows the notification. If I go to Settings and turn off Wi-Fi, switching to 4G, notifications no longer appear in the log (although they do slide in at the top of the screen, so I know they are being delivered).
There are no crash logs, and the notification is logged if I manually tap on it. Furthermore, this problem does NOT occur if I am debugging the app in Xcode. (i.e., if I am debugging in Xcode, the app will receive the notification in the background on 4G). Has anyone else experienced this behavior? Or am I doing something wrong?
EDIT: To be specific: according to my tests, if the following conditions are true, then the remote notification delegate method above will not be called:
- App is running in the background
- Phone is on LTE network, not connected to Wi-Fi
- App is NOT running in the Xcode debugger
- Notification with content-available=1 is received by the phone
However if condition 2 is removed (i.e., the phone is connected to Wi-Fi), then the handler will be called.
回答1:
Try the following code:
// AppDelegate.h
@class ViewController;
@interface AppDelegate : UIResponder <UIApplicationDelegate>
{
NSString *DeviceToken;
NSMutableDictionary *App_Messages;
NSString *Longitude,*Latitude;
NSMutableDictionary * badge;
}
@property (strong, nonatomic) UIWindow *window;
@property (strong, nonatomic) ViewController *viewcontrollervc;
@property (strong, nonatomic) UINavigationController *navcontroller;
@property (nonatomic,retain)NSMutableDictionary *badge;
@property (nonatomic,retain)NSString *DeviceToken;
// AppDelegate.m
#import "ViewController.h"
@implementation AppDelegate
@synthesize badge,DeviceToken;
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc]initWithFrame:[[UIScreen mainScreen]bounds]];
self.viewcontrollervc = [[ViewController alloc]initWithNibName:@"ViewController" bundle:nil];
self.navcontroller = [[UINavigationController alloc]initWithRootViewController:self.viewcontrollervc];
self.window.rootViewController = self.navcontroller;
self.navcontroller.navigationBarHidden = YES;
//Notification
[[UIApplication sharedApplication] registerForRemoteNotificationTypes:
(UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeSound | UIRemoteNotificationTypeAlert)];
NSDictionary * remoteNotificationObj = [launchOptions objectForKey:@"UIApplicationLaunchOptionsRemoteNotificationKey"];
if (remoteNotificationObj)
{
[self performSelector:@selector(handleRemoteNotificationWithUserInfo:) withObject:remoteNotificationObj afterDelay:3.0];
}
[self.window makeKeyAndVisible];
return YES;
}
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo
{
[self handleRemoteNotificationWithUserInfo:userInfo];
}
-(void)handleRemoteNotificationWithUserInfo:(NSDictionary *)userInfo
{
NSLog(@"userInfo - %@",userInfo);
NSDictionary *alertData = [userInfo objectForKey:@"aps"];
NSDictionary *returnDatalert=[alertData objectForKey:@"alert"];
NSString *alertmsg=[returnDatalert objectForKey:@"body"];
NSLog(@"alertmsg %@",alertmsg);
self.badge = [NSMutableDictionary dictionaryWithDictionary:[alertData objectForKey:@"badge"]];
NSString *notificationtype=[badge objectForKey:@"fnct"];
NSLog(@"%@",notificationtype);
}
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken
{
NSLog(@"didRegisterForRemoteNotificationsWithDeviceToken: %@", deviceToken);
NSString *dt = [[deviceToken description] stringByTrimmingCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@"<>"]];
dt = [dt stringByReplacingOccurrencesOfString:@" " withString:@""];
self.DeviceToken=dt;
NSLog(@"~~~~devToken(dv)=%@",deviceToken);
}
- (void)application:(UIApplication*)application didFailToRegisterForRemoteNotificationsWithError:(NSError*)error
{
NSLog(@"Failed to get token, error: %@", error);
}
回答2:
Based on feedback from a commenter here and repeated testing on multiple devices, this appears to be a bug (or intended behavior) on iOS.
回答3:
For me, it worked on Wi-Fi and on 4G (LTE forced off in cellular settings), but did not work on LTE.
Update: After extensive debugging, I've found this issue related to two things for me when on LTE. One is power. I discovered if the iPhone was plugged into the wall, the app was woken up as expected. If it wasn't plugged in, the app was not woken up in response to content-available = 1. Second, was device settings. Even though every related setting was set correctly, doing a 'Reset all Settings' fixed the issue for me.
Assuming this is not an Apple bug, my guess is as iOS develops a power profile for a given app identifier, it opts, under certain circumstances (network status, battery status, etc) to not wake up apps that use excessive background cycles. For example, using beginBackgroundTaskWithExpirationHandler incorrectly, causing an app to stay active in the background and forcing iOS to expire it. Even fixing excessive background usage might not correct the issue, as iOS has already determined your app is a background hog. This would explain the 'Rest all Settings' clearing up the issue for me.
Unfortunately, all of this is just a guess based on 2-3 days of debugging this issue and we will probably never know for sure as there are so many variables in play with push notifications, not to mention vague and varying documentation.
来源:https://stackoverflow.com/questions/24928590/ios-uibackgroundmode-remote-notification-doesnt-work-on-4g