iOS11全新安装App时UILocalNotification失效问题求助
问题根源分析
这个情况我之前帮不少开发者排查过,核心原因是iOS 11开始彻底切断了对UILocalNotification新安装应用的支持:
- 从低版本升级到iOS11的应用,因为在iOS11之前已经通过旧API获取了通知权限,iOS11会保留权限并兼容旧的通知调度逻辑,所以能正常运行;
- 全新安装在iOS11+的应用,系统会直接忽略
UILocalNotification相关调用,甚至不会触发通知权限请求——这就是你在通知设置里找不到应用、闹钟完全失效的根本原因。
苹果在iOS10就标记UILocalNotification为弃用,到了iOS11直接对新安装应用禁用了这套API的核心功能,所以必须改用UserNotifications框架重写通知逻辑,没有绕开的捷径。
具体解决步骤
下面是针对你「每日重复闹钟」需求的完整改造方案:
1. 导入并配置UserNotifications框架
在AppDelegate中导入框架并遵循代理协议:
#import <UserNotifications/UserNotifications.h> @interface AppDelegate () <UNUserNotificationCenterDelegate> @end
2. 启动时请求通知权限
这是让应用出现在通知设置里的前提,替换你原来的启动逻辑:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { // iOS10+ 请求通知权限 if (@available(iOS 10.0, *)) { UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter]; center.delegate = self; [center requestAuthorizationWithOptions:(UNAuthorizationOptionAlert | UNAuthorizationOptionSound | UNAuthorizationOptionBadge) completionHandler:^(BOOL granted, NSError * _Nullable error) { granted ? NSLog(@"通知权限已获取") : NSLog(@"用户拒绝了通知权限"); }]; } else { // iOS10以下兼容旧逻辑 UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:(UIUserNotificationTypeAlert | UIUserNotificationTypeSound | UIUserNotificationTypeBadge) categories:nil]; [application registerUserNotificationSettings:settings]; } // 处理启动时的通知 if (@available(iOS 10.0, *)) { UNNotification *notification = launchOptions[UIApplicationLaunchOptionsLocalNotificationKey]; if (notification) { UIAlertController *alert = [UIAlertController alertControllerWithTitle:APP_NAME message:notification.request.content.body preferredStyle:UIAlertControllerStyleAlert]; [alert addAction:[UIAlertAction actionWithTitle:@"确定" style:UIAlertActionStyleDefault handler:nil]]; // 确保获取顶层控制器再弹窗 UIViewController *topVC = [UIApplication sharedApplication].keyWindow.rootViewController; [topVC presentViewController:alert animated:YES completion:nil]; } } else { // iOS10以下保留你原来的逻辑 UILocalNotification *notification = launchOptions[UIApplicationLaunchOptionsLocalNotificationKey]; if (notification) { UIAlertView *view = [[UIAlertView alloc] initWithTitle:APP_NAME message:notification.alertBody delegate:self cancelButtonTitle:notification.alertAction otherButtonTitles:nil]; [view show]; } } application.applicationIconBadgeNumber = 0; return YES; }
3. 重写每日通知调度方法
替换你原来的scheduleNotification方法,用新API实现:
- (void)scheduleNotification { LOGDEBUG(NSLog(@"schedule notification")); if (alertDate == nil) { alertDate = self.as.alertTime; LOGDEBUG(NSLog(@"alert Date insider notification: %@", alertDate)); } if (@available(iOS 10.0, *)) { // 1. 创建通知内容 UNMutableNotificationContent *content = [[UNMutableNotificationContent alloc] init]; content.title = APP_NAME; content.body = @"AlertBody here..."; content.sound = [UNNotificationSound defaultSound]; content.badge = @([UIApplication sharedApplication].applicationIconBadgeNumber + 1); // 2. 创建每日重复触发器(对应原来的NSDayCalendarUnit) NSCalendar *calendar = [NSCalendar currentCalendar]; NSDateComponents *components = [calendar components:(NSCalendarUnitHour | NSCalendarUnitMinute) fromDate:alertDate]; UNCalendarNotificationTrigger *trigger = [UNCalendarNotificationTrigger triggerWithDateMatchingComponents:components repeats:YES]; // 3. 创建通知请求(用唯一ID方便后续管理) NSString *requestIdentifier = @"DailyAlarmNotification"; UNNotificationRequest *request = [UNNotificationRequest requestWithIdentifier:requestIdentifier content:content trigger:trigger]; // 4. 添加到通知中心 UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter]; [center addNotificationRequest:request withCompletionHandler:^(NSError * _Nullable error) { error ? NSLog(@"调度通知失败:%@", error.localizedDescription) : LOGDEBUG(NSLog(@"To be alert at: %@", alertDate)); }]; } else { // iOS10以下保留你原来的旧逻辑 UILocalNotification *notification = [[UILocalNotification alloc] init]; notification.fireDate = alertDate; notification.timeZone = [NSTimeZone defaultTimeZone]; notification.alertBody = @"AlertBody here..."; notification.alertAction = @"AlertAction..."; notification.soundName = UILocalNotificationDefaultSoundName; notification.applicationIconBadgeNumber += 1; notification.repeatInterval = NSDayCalendarUnit; LOGDEBUG(NSLog(@"To be alert at: %@", alertDate)); [[UIApplication sharedApplication] scheduleLocalNotification:notification]; } }
4. 处理通知接收逻辑
替换原来的application:didReceiveLocalNotification:方法,适配新框架:
// iOS10+:前台收到通知时调用 - (void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions))completionHandler { UIAlertController *alert = [UIAlertController alertControllerWithTitle:APP_NAME message:notification.request.content.body preferredStyle:UIAlertControllerStyleAlert]; [alert addAction:[UIAlertAction actionWithTitle:@"确定" style:UIAlertActionStyleDefault handler:nil]]; UIViewController *topVC = [UIApplication sharedApplication].keyWindow.rootViewController; [topVC presentViewController:alert animated:YES completion:nil]; // 告诉系统要展示的通知样式 completionHandler(UNNotificationPresentationOptionAlert | UNNotificationPresentationOptionSound); } // iOS10+:点击通知打开应用时调用 - (void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void(^)(void))completionHandler { // 这里可以添加通知点击后的跳转逻辑 completionHandler(); } // iOS10以下保留原来的方法 - (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification { UIAlertView *view = [[UIAlertView alloc] initWithTitle:APP_NAME message:notification.alertBody delegate:self cancelButtonTitle:notification.alertAction otherButtonTitles:nil]; [view show]; application.applicationIconBadgeNumber = 0; }
关键注意点
- 必须请求通知权限:没有权限的话,不管用什么API都发不出通知,这也是你之前设置里看不到应用的核心原因;
- 唯一标识符:给每个通知请求设置唯一ID,方便后续需要取消或更新通知时调用
removePendingNotificationRequestsWithIdentifiers:; - 版本适配:如果你的应用还要支持iOS10以下,可以保留旧的
UILocalNotification逻辑,用版本判断分开处理,但iOS11+新安装的应用只能用新框架。
内容的提问来源于stack exchange,提问作者user6539552
相关产品推荐
相关产品推荐

