我遇到了一个非常奇怪的问题,我实现了:
- (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; }
可能有很多事情可能出了问题,首先是我的经验。为了使静默推送通知工作。您的有效载荷必须结构正确,
{
"aps" : {
"content-available" : 1
},
"data-id" : 345
}
content-available: 1
如果您的推送消息没有,则iOS不会调用新的委托方法。
- (void) application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler
可能的原因是您的iPhone上的“后台应用刷新”已关闭。
您可以在“设置”->“常规”->“后台应用程序刷新”中打开/关闭此选项。
当手机上的“后台应用刷新”功能关闭时,didReceiveRemoteNotification:fetchCompletionHandler
仅当手机连接到XCode时才会调用方法。
只想添加一个更新的答案。
我正面临着同样的问题。
-(void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler;
当应用程序从后台多任务处理中被杀死时(双击主页按钮并向上滑动以杀死应用程序),不会被调用。
我已经使用开发推送通知和NWPusher工具(https://github.com/noodlewerk/NWPusher)对自己进行了测试
过时的文档
上一个文档块说:
与application:didReceiveRemoteNotification:方法不同,该方法仅在您的应用程序运行时才被调用,而无论应用程序的状态如何,系统都会调用此方法
。如果您的应用程序已挂起或未运行,则系统会在调用该方法之前唤醒或启动您的应用程序并将其置于后台运行状态。如果用户从系统显示的警报中打开您的应用程序,则系统会再次调用此方法,以便您知道用户选择了哪个通知。
已过时(在撰写本文时,2015年4月6日)。
更新的文档(截至2015年6月6日)
我检查了文档(在撰写本文时,2015年4月6日),其中说:
使用此方法可以为您的应用处理传入的远程通知。与application:didReceiveRemoteNotification:方法不同,后者仅在您的应用程序在前台运行时才调用,而在您的应用程序在前台或
后台运行时,系统会调用此方法。此外,如果启用了远程通知后台模式,则系统将启动您的应用程序(或将其从挂起状态唤醒),并在远程通知到达时将其置于后台状态。但是,如果用户强制退出应用程序,系统不会自动启动您的应用程序。在这种情况下,用户必须重新启动您的应用程序或重新启动设备,然后系统才会尝试再次自动启动您的应用程序。
如果仔细阅读,您会发现它现在说:
当您的应用程序在前台或
后台运行时,系统会调用此方法。
不:
无论您的应用程序状态如何
所以看起来从iOS 8+开始我们很不走运:(
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上使用的存档相同),但允许您的二进制文件在Beta中使用。从Test Flight安装的版本可能(我无法证明)使用与App Store中相同的Production Provisioning Profile,并且该应用程序像一个超级按钮一样工作。
以下链接可帮助您设置“测试飞行”帐户:
http://code.tutsplus.com/tutorials/ios-8-beta-testing-with-testflight--cms-22224
甚至没有一个静默有效载荷被错过。
我希望这可以帮助某人在这个问题上不会浪费整整一周的时间。
今天这对我来说是个问题,我感到莫名其妙。
iOS:10.2.1 xCode:8.2.1 Swift:3.0.2
问题仅在一部手机上,只有插入xCode时我才能打包。
我重新阅读了Apple的推送文档,以防万一我错过了新UserNotifications
框架的内容,或者弄乱了我的代码以退回到iOS 9贬值的委托函数。
无论如何,我注意到文档中的 这一行application:didReceiveRemoteNotification:fetchCompletionHandler:
:
“在处理远程通知时使用大量电量的应用程序可能不会总是被早期唤醒以处理将来的通知。”
这是页面上的最后一行。
我希望苹果能告诉我更多信息,但事实证明,简单的电话重启可以为我解决问题。我真的希望我能弄清楚到底出了什么问题,但这是我的推测性结论:
1)由于上述文档中的内容,因此推送通知未通过此特定手机传递到此应用。
2)当插入xCode时,iOS将忽略上述已记录的规则。
3)我检查了系统设置中的(令人困惑的)电池百分比计算器。它显示我的应用仅占6%,但出于某些原因,Safari在该手机上的使用率高达75%。
4)手机重启后,Safari的故障率降至约25%
5)在那之后推工作得很好。
所以...我的最终结论。要清除记录在案的电池问题,请尝试重启手机或尝试使用其他手机,看看问题是否仍然存在。
要在iOS应用程序开发中使用Background Push Download,以下是我们需要遵循的一些重点...
-
UIBackgroundModes
在info.plist文件中启用具有远程通知值的密钥。 -
然后在您的AppDelegate文件中实现以下方法。
application:didReceiveRemoteNotification:fetchCompletionHandler
更多详细信息:ios-7-true-multitasking
大家好,您可以调用您的方法
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult result))handler {
}
脚步:
-
项目->功能->后台模式,然后选中“背景获取”和“远程通知”复选框,或者进入.plist并选择一行并命名为“背景模式”,它将使用数组创建带有字符串“远程通知”的“项目0”。
-
对服务器端开发人员说他应该发送
“ aps”:{“内容可用”:1}
就这样,现在您可以调用您的方法了:
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult result))handler {
}
此问题已在iOS 7.1 Beta 3中修复。我再次检查了一下,并确认它运行正常。
花了两天时间!在检查代码和推送参数之前-在将设备连接到xCode == power时,请确保您未处于低功耗模式!低功耗模式将禁用后台应用刷新。
可用于获取远程通知的代码,在后台模式下启用远程通知功能,并且我也启用了后台获取(我不知道是否有必要),我使用以下代码:
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult result))handler{
DLog(@"899- didReceiveRemoteNotification userInfo: %@",userInfo);
NSDictionary *custom=userInfo[@"custom"];
if(custom){
NSInteger code = [custom[@"code"] integerValue];
NSInteger info = [custom[@"info"] integerValue];
NSDictionary *messageInfo = userInfo[@"aps"];
[[eInfoController singleton] remoteNotificationReceived:code info:info messageInfo:messageInfo appInBackground:[UIApplication sharedApplication].applicationState==UIApplicationStateBackground];
handler(UIBackgroundFetchResultNewData);
}
}
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo{
DLog(@"899- didReceiveRemoteNotification userInfo: %@",userInfo);
NSDictionary *custom=userInfo[@"custom"];
if(custom){
NSInteger code = [custom[@"code"] integerValue];
NSInteger info = [custom[@"info"] integerValue];
NSDictionary *messageInfo = userInfo[@"aps"];
[[eInfoController singleton] remoteNotificationReceived:code info:info messageInfo:messageInfo appInBackground:[UIApplication sharedApplication].applicationState==UIApplicationStateBackground];
}
}
- (void)application:(UIApplication*)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData*)deviceToken
{
//NSLog(@"My token is: %@", deviceToken);
const unsigned *tokenBytes = (const unsigned *)[deviceToken bytes];
NSString *hexToken = [NSString stringWithFormat:@"%08x%08x%08x%08x%08x%08x%08x%08x",
ntohl(tokenBytes[0]), ntohl(tokenBytes[1]), ntohl(tokenBytes[2]),
ntohl(tokenBytes[3]), ntohl(tokenBytes[4]), ntohl(tokenBytes[5]),
ntohl(tokenBytes[6]), ntohl(tokenBytes[7])];
[[eInfoController singleton] setPushNotificationToken:hexToken];
}
- (void)application:(UIApplication*)application didFailToRegisterForRemoteNotificationsWithError:(NSError*)error
{
NSLog(@"Failed to get token, error: %@", error);
}
在后台存储通知的代码,对我来说,关键是启动后台下载任务以允许我下载信息以进行存储,然后在应用程序变为活动方法时触发我检查是否存储了丢失的通知展示它。
-(void)remoteNotificationReceived:(NSInteger)code info:(NSInteger)info messageInfo:(NSDictionary*)messageInfo appInBackground:(BOOL)appInBackground{
DLog(@"Notification received appInBackground: %d,pushCode: %ld, messageInfo: %@",appInBackground, (long)code,messageInfo);
switch (code){
case 0:
break;
case 1:
{
NSArray *pendingAdNotifiacations=[[NSUserDefaults standardUserDefaults] objectForKey:@"pendingAdNotifiacations"];
NSMutableDictionary *addDictionary=[[NSMutableDictionary alloc] initWithDictionary:messageInfo copyItems:YES];
[addDictionary setObject:[NSNumber numberWithInteger:info] forKey:@"ad_id"];
if(!pendingAdNotifiacations){
pendingAdNotifiacations=[NSArray arrayWithObject:addDictionary];
}else{
pendingAdNotifiacations=[pendingAdNotifiacations arrayByAddingObject:addDictionary];
}
[addDictionary release];
[[NSUserDefaults standardUserDefaults] setObject:pendingAdNotifiacations forKey:@"pendingAdNotifiacations"];
[[NSUserDefaults standardUserDefaults] synchronize];
DLog(@"pendingAdNotifiacations received: %@.",pendingAdNotifiacations);
[[UIApplication sharedApplication] setApplicationIconBadgeNumber:(pendingAdNotifiacations)?[pendingAdNotifiacations count]:0];
DLog(@"783- pendingAdNotifiacations: %lu.",(unsigned long)((pendingAdNotifiacations)?[pendingAdNotifiacations count]:0));
if(appInBackground){
[AdManager requestAndStoreAd:info];
}else{
[AdManager requestAndShowAd:info];
}
}
break;
default:
break;
}
}
这是使用后台任务在后台下载信息的相关代码:
-(void)requestAdinBackgroundMode:(NSInteger)adId{
DLog(@"744- requestAdinBackgroundMode begin");
if(_backgroundTask==UIBackgroundTaskInvalid){
DLog(@"744- requestAdinBackgroundMode begin dispatcher");
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
DLog(@"744- passed dispatcher");
[self beginBackgroundUpdateTask];
NSURL *requestURL=[self requestURL:adId];
if(requestURL){
NSURLRequest *request = [NSURLRequest requestWithURL:requestURL];
NSURLResponse * response = nil;
NSError * error = nil;
DLog(@"744- NSURLConnection url: %@",requestURL);
NSData * responseData = [NSURLConnection sendSynchronousRequest: request returningResponse: &response error: &error];
if(NSClassFromString(@"NSJSONSerialization"))
{
NSError *error = nil;
id responseObject = [NSJSONSerialization
JSONObjectWithData:responseData
options:0
error:&error];
if(error) {
NSLog(@"JSON reading error: %@.",[error localizedDescription]);
/* JSON was malformed, act appropriately here */ }
else{
if(responseObject && [responseObject isKindOfClass:[NSDictionary class]]){
if(responseObject && [[responseObject objectForKey:@"success"] integerValue]==1){
NSMutableDictionary *adDictionary=[[[NSMutableDictionary alloc] initWithDictionary:[responseObject objectForKey:@"ad"]] autorelease];
DLog(@"744- NSURLConnection everythig ok store: %@",adDictionary);
[self storeAd: adDictionary];
}
}
}
}
}
// Do something with the result
[self endBackgroundUpdateTask];
});
}
}
- (void) beginBackgroundUpdateTask
{
DLog(@"744- requestAdinBackgroundMode begin");
_backgroundTask = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
[self endBackgroundUpdateTask];
}];
}
- (void) endBackgroundUpdateTask
{
DLog(@"744- End background task");
[[UIApplication sharedApplication] endBackgroundTask: _backgroundTask];
_backgroundTask = UIBackgroundTaskInvalid;
}
好吧,这就是我想的全部,我发布它是因为有人要求我发布更新,希望它可以对某人有所帮助...
文章标签:apple-push-notifications , background , debugging , ios , objective-c
版权声明:本文为原创文章,版权归 admin 所有,欢迎分享本文,转载请保留出处!
评论已关闭!