当我的应用 不 正在运行并收到推送通知时,如果我点击该通知,应用程序就会启动 - 但它不会提示用户我设置了警报视图,询问他们是否要查看通知的内容。它只是发射,并坐在那里。
当应用 正在运行时,推送通知可以完美 - 无论是作为活动应用还是在后台 - 但没有任何作用当应用 不 正在运行时正确无误。
我尝试在launchOptions
中注销application: didFinishLaunchingWithOptions:
NSDictionary以查看其带来的负载 - 但它出现为“(null)”。所以它基本上什么都没有 - 这没有意义,因为它不应该包含Notification的负载吗?
任何人都有任何想法如何在应用程序未运行时如何使Push Notifications工作?
编辑:这是我在application: didReceiveRemoteNotification
中使用的代码,只是为了看看它是什么:
if (UIApplicationStateBackground) {
NSLog(@"===========================");
NSLog(@"App was in BACKGROUND...");
}
else if (UIApplicationStateActive == TRUE) {
NSLog(@"===========================");
NSLog(@"App was ACTIVE");
}
else {
[[UIApplication sharedApplication] setApplicationIconBadgeNumber: 99];
UIAlertView *BOOM = [[UIAlertView alloc] initWithTitle:@"BOOM"
message:@"app was INACTIVE"
delegate:self
cancelButtonTitle:@"a-ha!"
otherButtonTitles:nil];
[BOOM show];
NSLog(@"App was NOT ACTIVE");
}
所以这应该照顾所有应用程序的状态 - 但事实并非如此。推送通知仅在应用程序运行时有效 - 无论是在后台还是在前台......
=============================================== =
UPDATE / EDIT#2:
根据“@dianz”建议(下方),我修改了application: didFinishLaunchingWithOptions
的代码以包含以下内容:
UILocalNotification *localNotif = [launchOptions objectForKey:UIApplicationLaunchOptionsRemoteNotificationKey];
if (localNotif) {
NSString *json = [localNotif valueForKey:@"data"];
UIAlertView *bam = [[UIAlertView alloc] initWithTitle:@"appDidFinishWithOptions"
message:json
delegate:self
cancelButtonTitle:@"cool"
otherButtonTitles:nil];
[bam show];
}
这确实会显示AlertView框,但似乎没有有效负载:AlertView的标题显示(“appDidFinishWithOptions”),但json NSString出现EMPTY ...将继续调整...
======================
编辑#3 - 它现在正在工作几乎 100%
所以,在didFinishLaunchingWithOptions
:
UILocalNotification *localNotif = [launchOptions objectForKey:UIApplicationLaunchOptionsRemoteNotificationKey];
if (localNotif) {
// Grab the pushKey:
pushKey = [localNotif valueForKey:@"pushKey"];
// "pushKey" is an NSString declared globally
// The "pushKey" in the "valueForKey" statement is part of my custom JSON Push Notification pay-load.
// The value of pushKey will always be a String, which will be the name of the
// screen I want the App to navigate to. So when a Notification arrives, I go
// through an IF statement and say "if pushKey='specials' then push the
// specialsViewController on, etc.
// Here, I parse the "alert" portion of my JSON Push-Notification:
NSDictionary *tempDict = [localNotif valueForKey:@"aps"];
NSString *pushMessage = [tempDict valueForKey:@"alert"];
// Finally, ask user if they wanna see the Push Notification or Cancel it:
UIAlertView *bam = [[UIAlertView alloc] initWithTitle:@"(from appDidFinishWithOptions)"
message:pushMessage
delegate:self
cancelButtonTitle:@"Cancel"
otherButtonTitles:@"View Info", nil];
[bam show];
}
我接下来实现alertView: clickedButtonAtIndex
方法,以查看用户在AlertView上选择的内容并继续进行。
这与didReceiveRemoteNotification
逻辑完美配合。
但是......当应用程序没有运行时,我发送推送通知,如果我没有在它到达时立即点击推送通知警报而是等待它淡出(这发生在之后比如3-4秒),然后我点击应用程序的图标 - 它现在有一个BADGE为1 - 应用程序启动,但我根本没有得到推送通知警报它发射。它只是坐在那里。
猜猜我需要明确那个排列......
答案 0 :(得分:36)
当您的应用未运行或被杀时,您点按推送通知此功能将触发;
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
所以你应该像这样处理它,
UILocalNotification *localNotif = [launchOptions objectForKey:UIApplicationLaunchOptionsRemoteNotificationKey];
if (localNotif) {
NSString *json = [localNotif valueForKey:@"data"];
// Parse your string to dictionary
}
答案 1 :(得分:11)
最好是覆盖didReceiveRemoteNotification
你去吧
NSDictionary * pushNotificationPayload = [launchOptions valueForKey:UIApplicationLaunchOptionsRemoteNotificationKey];
if(pushNotificationPayload) {
[self application:application didReceiveRemoteNotification:pushNotificationPayload];
}
这将再次触发didReceiveRemoteNotification
方法,您的push notification
代码将在应用程序运行时运行时执行。
答案 2 :(得分:7)
我试过了@ dianz的回答,这对我没有用,但我从答案中得到了帮助。
就我而言;
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
NSDictionary *apnsBody = [launchOptions objectForKey:UIApplicationLaunchOptionsRemoteNotificationKey];
if (apnsBody) {
// Do your code with apnsBody
}
答案 3 :(得分:3)
虽然已经回答了这个问题,但所提供的答案都没有真正起作用。这是我的实现,我能够工作。
此代码位于application:didFinishLaunchingWithOptions:
<强>夫特:强>
if let options = launchOptions, notification = options[UIApplicationLaunchOptionsRemoteNotificationKey] as? [NSObject : AnyObject] {
// NOTE: (Kyle Begeman) May 19, 2016 - There is an issue with iOS instantiating the UIWindow object. Making this call without
// a delay will cause window to be nil, thus preventing us from constructing the application and assigning it to the window.
Quark.runAfterDelay(seconds: 0.001, after: {
self.application(application, didReceiveRemoteNotification: notification)
})
}
<强>目标-C:强>
if (launchOptions[UIApplicationLaunchOptionsRemoteNotificationKey]) {
[self application:application didReceiveRemoteNotification:launchOptions[UIApplicationLaunchOptionsRemoteNotificationKey]];
}
一对夫妇注意到:
可能由于iOS队列分配的方式,在被杀死后启动应用程序时,根UIApplication.sharedApplication().window
对象为nil。添加1毫秒延迟解决了这个问题。没有在Objective-C
为了避免类型冲突,需要转换为[NSObject:AnyObject],但我没有尝试过这么多;在您自己的项目中实施时,请记住这一点。 Objective-C不要求这样做。
Quark只是一个有趣的小库,我在我的所有项目中使用它包含有用且常用的扩展和方法。只需使用适合您应用需求的任何形式的延迟。
答案 4 :(得分:3)
我遇到了同样的问题,但是当使用Notification Service Extension处于非活动状态(未运行)时,我终于可以处理推送通知。这个解决方案是由Apple Team Support推荐的,它仅适用于iOS 10,我实现了它并且运行良好!我留下链接:
这是程序:
注意:请考虑使用三个标识符: 1)您的应用的标识符(您已经拥有) 2)您的分机的标识符(您将创建) 3)应用程序组的标识符。 (您将创建)
必须启用应用程序组才能创建资源,您可以在其中保存和阅读应用和扩展程序的信息。单击“显示项目导航器”。进入目标列表中选择您的主项目。然后,单击“功能”并打开名为“应用程序组”的选项。请添加App Group的标识符以标识共享资源。您应该对您创建的扩展目标执行相同的步骤(选择扩展目标 - 功能 - 在“应用程序组”处启用 - 为应用程序组添加相同的标识符)
您应该将扩展的标识符添加到Apple开发者网站以识别通知服务扩展,您还应该制作新的临时配置文件(开发,AdHoc和/或生产)并将其与新的临时关联配置文件。
在两个标识符(应用程序和扩展程序)上,您应该编辑它们并在它们中启用“应用程序组”服务。您应该将标识符应用程序组添加到应用程序组服务中。
注意:应用程序的标识符和扩展的标识符应该有 APP GROUP的相同标识符。
在Xcode上下载新的临时配置文件,并将它们与您的通知服务扩展相关联。请确保一切顺利。
之后,在您的应用和扩展程序的“功能”中,打开“应用程序组”部分并更新它们。这三个步骤 - 1)将应用程序组权利添加到您的权利文件,2)将应用程序组功能应用到您的应用程序ID,3)将应用程序组添加到您的应用程序ID - 应该进行检查。
返回Project导航器并选择扩展程序的文件夹。打开.m文件。您将看到一个名为didReceiveNotificationRequest:(UNNotificationRequest *)请求的方法。在此方法中,您将创建一个不同的NSUserDefaults,其SuiteName与应用程序组的标识符完全相同,如下所示:
NSUserDefaults * defaultsGroup = [[NSUserDefaults alloc] initWithSuiteName:@“app group的标识符”];
在同一方法中,获取通知正文并将其保存到NSMutableArray中,然后将其保存在共享资源中。像这样:
- (void)didReceiveNotificationRequest:(UNNotificationRequest *)request withContentHandler:(void (^)(UNNotificationContent * _Nonnull))contentHandler{ self.contentHandler = contentHandler; self.bestAttemptContent = [request.content mutableCopy]; NSMutableArray *notifications = [NSMutableArray new]; NSUserDefaults *defaultsGroup = [[NSUserDefaults alloc] initWithSuiteName: @"Identifier for app group"]; notifications = [[defaultsGroup objectForKey:@"notifications"] mutableCopy]; if (notifications != nil){ [notifications addObject:self.bestAttemptContent.userInfo]; }else{ notifications = [NSMutableArray new]; [notifications addObject:self.bestAttemptContent.userInfo]; } [defaultsGroup setObject:notifications forKey:@"notifications"]; }
NSUserDefaults *defaultsGroup = [[NSUserDefaults alloc] initWithSuiteName: @"Identifier for app group"]; NSMutableArray *notifications = [[defaultsGroup objectForKey:@"notifications"] mutableCopy];
我希望每一步都清楚。我将写一篇帖子来实现这个解决方案,并在我的页面中显示图像。您应该考虑的另一点是它不适用于静音推送通知。
答案 5 :(得分:1)
尝试使用didReceiveRemoteNotification
方法并在那里处理它。在那里,您可以通过为applicationState
执行条件来检查应用程序状态,例如检查它是UIApplicationStateActive
还是其他。
答案 6 :(得分:0)
试试这个
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// Override point for customization after application launch.
self.window.backgroundColor = [UIColor whiteColor];
[self.window makeKeyAndVisible];
//register notifications
if([application respondsToSelector:@selector(registerUserNotificationSettings:)]) // ios 8
{
[application registerUserNotificationSettings:[UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeAlert|UIUserNotificationTypeBadge|UIUserNotificationTypeSound categories:nil]];
[application registerForRemoteNotifications];
}
else // ios 7
{
[[UIApplication sharedApplication] registerForRemoteNotificationTypes:UIRemoteNotificationTypeSound | UIRemoteNotificationTypeAlert | UIRemoteNotificationTypeBadge];
}
// open app from a notification
NSDictionary *notification = [launchOptions objectForKey:UIApplicationLaunchOptionsRemoteNotificationKey];
if (notification)
{
//your alert should be here
}
// Set icon badge number to zero
application.applicationIconBadgeNumber = 0;
return YES;
}
答案 7 :(得分:0)
Swift 3 和 xCode 8.3.2 :
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
// your code here
// Check if app was not running in background and user taps on Push Notification
// This will perform your code in didReceiveRemoteNotification where you should handle different application states
if let options = launchOptions, let notification = options[UIApplicationLaunchOptionsKey.remoteNotification] as? [NSObject : AnyObject] {
self.application(application, didReceiveRemoteNotification: notification)
}
return true
}