You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 08:02:10