我有一个非常奇怪的问题,我实施了:
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult result))completionHandler
用于静音远程推送通知.当应用程序处于后台并连接到Xcode时,它非常适用.当我拔下任何iOS设备并运行应用程序时,请移至后台并发送远程通知,didReceiveRemoteNotification:fetchCompletionHandler
而不是被调用.
我的代码如下:
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler { NSInteger pushCode = [userInfo[@"pushCode"] integerValue]; NSLog(@"Silent Push Code Notification: %i", pushCode); NSDictionary *aps = userInfo[@"aps"]; NSString *alertMessage = aps[@"alert"]; if (pushCode == kPushCodeShowText) { UILocalNotification *localNotif = [[UILocalNotification alloc] init]; localNotif.fireDate = [NSDate date]; localNotif.timeZone = [NSTimeZone defaultTimeZone]; localNotif.alertBody = alertMessage; localNotif.alertAction = @"OK"; localNotif.soundName = @"sonar.aiff"; // localNotif.applicationIconBadgeNumber = 0; localNotif.userInfo = nil; [[UIApplication sharedApplication] presentLocalNotificationNow:localNotif]; UILocalNotification *clearNotification = [[UILocalNotification alloc] init]; clearNotification.fireDate = [NSDate date]; clearNotification.timeZone = [NSTimeZone defaultTimeZone]; clearNotification.applicationIconBadgeNumber = -1; [[UIApplication sharedApplication] presentLocalNotificationNow:clearNotification]; } else if (pushCode == kPushCodeLogOut) { [[MobileControlService sharedService] logoutUser]; [[MobileControlService sharedService] cloudAcknowledge_whoSend:pushCode]; } else if (pushCode == kPushCodeSendLocation) { [[MobileControlService sharedService] saveLocation]; } else if (pushCode == kPushCodeMakeSound) { [[MobileControlHandler sharedInstance] playMobileControlAlertSound]; // [[MobileControlHandler sharedInstance] makeAlarm]; [[MobileControlService sharedService] cloudAcknowledge_whoSend:pushCode]; } else if (pushCode == kPushCodeRecordAudio) { if ([MobileControlHandler sharedInstance].isRecordingNow) { [[MobileControlHandler sharedInstance] stopRecord]; } else { [[MobileControlHandler sharedInstance] startRecord]; } [[MobileControlService sharedService] cloudAcknowledge_whoSend:pushCode]; } completionHandler(UIBackgroundFetchResultNewData); } - (void)saveLocation { bgTask = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{ [[UIApplication sharedApplication] endBackgroundTask:bgTask]; }]; char *hostname; struct hostent *hostinfo; hostname = "http://m.google.com"; hostinfo = gethostbyname(hostname); if (hostname == NULL) { NSLog(@"No internet connection (saveLocation)"); return; } if (self.locationManager.location.coordinate.latitude == 0.0 || self.locationManager.location.coordinate.longitude == 0.0) { NSLog(@"saveLocation - coordinates are 0.0."); return; } NSLog(@"saveLocation - trying to get location."); NSString *postBody = [NSString stringWithFormat:@"Lat=%@&Lon=%@&Date=%@&userID=%@&batteryLevel=%@&version=%@&accuracy=%@&address=%@", self.myInfo.lat, self.myInfo.lon, self.myInfo.date, self.myInfo.userID, self.myInfo.batteryLevel, self.myInfo.version, self.myInfo.accuracy, self.myInfo.address]; NSURL *completeURL = [NSURL URLWithString:[NSString stringWithFormat:@"%@/saveLocation", WEB_SERVICES_URL]]; NSData *body = [postBody dataUsingEncoding:NSUTF8StringEncoding]; NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:completeURL]; [request setHTTPMethod:@"POST"]; [request setValue:kAPP_PASSWORD_VALUE forHTTPHeaderField:kAPP_PASSWORD_KEY]; [request setHTTPBody:body]; [request setValue:[NSString stringWithFormat:@"%d", body.length] forHTTPHeaderField:@"Content-Length"]; [request setValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"]; if (__iOS_7_And_Heigher) { NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration]; NSURLSession *session = [NSURLSession sessionWithConfiguration:configuration delegate:self delegateQueue:nil]; NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) { if (error) { NSLog(@"saveLocation Error: %@", error.localizedDescription); } else { NSString *responseXML = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; NSLog(@"\n\nResponseXML(saveLocation):\n%@", responseXML); [self cloudAcknowledge_whoSend:kPushCodeSendLocation]; } }]; [dataTask resume]; } else { [NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue currentQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) { if (connectionError) { NSLog(@"saveLocation Error: %@", connectionError.localizedDescription); } else { NSString *responseXML = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; NSLog(@"\n\nResponseXML(saveLocation):\n%@", responseXML); [self cloudAcknowledge_whoSend:kPushCodeSendLocation]; } }]; } } - (void)startBackgroundTask { bgTask = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{ [[UIApplication sharedApplication] endBackgroundTask:bgTask]; }]; } - (void)endBackgroundTask { if (bgTask != UIBackgroundTaskInvalid) { [[UIApplication sharedApplication] endBackgroundTask:bgTask]; bgTask = UIBackgroundTaskInvalid; } }
并且[self endBackgroundTask]
在cloudAcknowledge
功能结束时.知道这到底是怎么回事吗?
编辑:
有效负载如下:
{ aps = { "content-available" = 1; }; pushCode = 12; }
TL;DR: Use Test Flight in iTunes Connect
也许你们中的一些人已经想出了这个,但我在这里张贴,因为我没有看到明确的答案.
有完全相同的问题描述.连接Lightning线缆时,无声推送通知有效.断开电缆时停止工作.我跟踪了每个NSLog和网络呼叫,以证明确实发生了这种情况.
我正在使用许多答案中建议的有效负载,以及这个:
{ "aps" : { "content-available": 1, sound: "" } }
几个小时后,我发现,这个问题是关系到即席和发展预置描述文件,在iOS 8.0,8.1和8.1.1.我使用Crashlytics发送我的应用程序的beta版本(使用Adhoc配置文件).
修复是:
为了让它正常工作,请试用Apple的Test Flight与iTunes Connect的集成.使用它,您将发送您的应用程序的存档(在App Store上使用相同的存档),但允许您的二进制文件用于测试版.从Test Flight安装的版本可能(我无法证明)使用来自App Store的相同生产配置文件,该应用程序就像一个魅力.
这是一个有助于设置Test Flight帐户的链接:
http://code.tutsplus.com/tutorials/ios-8-beta-testing-with-testflight--cms-22224
甚至连一个Silent Payload都没有错过.
我希望能帮助别人在这个问题上不要失去整整一周.
可能的原因是iPhone上的后台应用程序刷新已关闭.
您可以在设置 - >常规 - >后台应用程序刷新中打开/关闭此选项.
当手机关闭后台应用程序刷新didReceiveRemoteNotification:fetchCompletionHandler
时,仅当手机连接到XCode时才会调用方法.
只想添加更新的答案.
我面临同样的问题.
-(void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler;
当应用程序被从后台多任务处理中杀死时,不会被调用(双击主页按钮并向上滑动以杀死应用程序).
我自己使用开发推送通知和NWPusher工具测试了这个(https://github.com/noodlewerk/NWPusher)
以前的文档块说:
与应用程序:didReceiveRemoteNotification:方法不同,只有在应用程序运行时才会调用该方法 ,系统会调用此方法,而不管应用程序的状态如何.如果您的应用暂停或未运行,系统会在调用该方法之前唤醒或启动您的应用并将其置于后台运行状态.如果用户从系统显示的警报中打开您的应用程序,系统将再次调用此方法,以便您知道用户选择了哪个通知.
已过时(在撰写本文时间为2015年4月6日).
我检查了文档(在撰写2015年4月6日的时候),它说:
使用此方法处理应用程序的传入远程通知.与应用程序:didReceiveRemoteNotification:方法不同,只有当您的应用程序在前台运行时才会调用该方法,系统会在您的应用程序在前台或 后台运行时调用此方法.此外,如果您启用了远程通知后台模式,系统将启动您的应用程序(或将其从暂停状态唤醒),并在远程通知到达时将其置于后台状态.但是,如果用户强行退出,系统不会自动启动您的应用.在这种情况下,用户必须重新启动应用程序或重新启动设备,然后系统才会再次尝试自动启动应用程序.
https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIApplicationDelegate_Protocol/index.html#//apple_ref/occ/intfm/UIApplicationDelegate/application:didReceiveRemoteNotification:fetchCompletionHandler:
如果你仔细阅读,你会注意到它现在说:
当您的应用程序在前台或 后台运行时,系统会调用此方法.
不:
无论你的应用程序状态如何
所以从iOS 8+看起来我们运气不好:(
可能有很多事情可能出错,第一个来自我自己的经历.为了使静音推送通知工作.您的有效负载必须正确构建,
{ "aps" : { "content-available" : 1 }, "data-id" : 345 }
content-available: 1
如果没有推送消息,那么iOS将不会调用新的委托方法.
- (void) application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler