【问题标题】:Ask for User Permission to Receive UILocalNotifications in iOS 8请求用户权限以在 iOS 8 中接收 UILocalNotifications
【发布时间】:2014-07-28 19:33:24
【问题描述】:

我已经在 App Delegate 中设置了本地通知使用这个:

- (void)applicationDidEnterBackground:(UIApplication *)application
{
    UILocalNotification *notification = [[UILocalNotification alloc]init];
    [notification setAlertBody:@"Watch the Latest Episode of CCA-TV"];
    [notification setFireDate:[NSDate dateWithTimeIntervalSinceNow:5]];
    [notification setTimeZone:[NSTimeZone defaultTimeZone]];
    [application setScheduledLocalNotifications:[NSArray arrayWithObject:notification]];
}

当我运行应用程序然后退出时,我收到一条错误消息:

2014-06-07 11:14:16.663 CCA-TV[735:149070] 正在尝试安排本地通知 {fire 日期 = 2014 年 6 月 7 日星期六 11:14:21 太平洋夏令时间,时间 zone = America/Los_Angeles (PDT) offset -25200 (Daylight),重复 间隔 = 0,重复计数 = UILocalNotificationInfiniteRepeatCount, 下一次火灾日期 = 2014 年 6 月 7 日星期六 11:14:21 Pacific Daylight Time, user info = (null)} 有警报但未收到 用户允许显示警报

如何获得显示警报所需的权限?

【问题讨论】:

  • 我认为应用程序已经拒绝了一次权限,您可以尝试从设置中启用。但顺便说一下 UILocalNotification 不需要用户权限..
  • 试试registerUserNotificationSettings。如果是 iOS 8,这个线程会回答你的问题。但是,请先看看 -stackoverflow.com/questions/24006998/…

标签: ios cocoa-touch notifications ios8 uilocalnotification


【解决方案1】:

从 iOS 8 开始,您需要征得用户的许可才能显示来自您的应用的通知,这适用于远程/推送和本地通知。在 Swift 中你可以这样做,

Swift 2.0 更新

func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: NSDictionary?) -> Bool {
    // Override point for customization after application launch.
    if(UIApplication.instancesRespondToSelector(Selector("registerUserNotificationSettings:")))
    {
        let notificationCategory:UIMutableUserNotificationCategory = UIMutableUserNotificationCategory()
        notificationCategory.identifier = "INVITE_CATEGORY"
        notificationCategory.setActions([replyAction], forContext: UIUserNotificationActionContext.Default)

        //registerting for the notification.
        application.registerUserNotificationSettings(UIUserNotificationSettings(forTypes:[.Sound, .Alert, .Badge], categories: nil))
    }
    else
    {
       //do iOS 7 stuff, which is pretty much nothing for local notifications.
    }
    return true
}

Swift 3.2

if(UIApplication.instancesRespond(to: #selector(UIApplication.registerUserNotificationSettings(_:)))){
     let notificationCategory:UIMutableUserNotificationCategory = UIMutableUserNotificationCategory()
     notificationCategory.identifier = "INVITE_CATEGORY"
     notificationCategory.setActions([replyAction], forContext: UIUserNotificationActionContext.Default)

     //registerting for the notification.
        application.registerUserNotificationSettings(UIUserNotificationSettings(types:[.sound, .alert, .badge], categories: nil))
}
else{
        //do iOS 7 stuff, which is pretty much nothing for local notifications.
    }

Objective C 的语法也很相似。

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    if ([UIApplication instancesRespondToSelector:@selector(registerUserNotificationSettings:)]){
        [application registerUserNotificationSettings:[UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeAlert|UIUserNotificationTypeBadge|UIUserNotificationTypeSound categories:nil]];
    }
    // Override point for customization after application launch.
    return YES;
}

要检查当前注册的通知类型,您可以使用 UIApplication 类的方法,

- (UIUserNotificationSettings *)currentUserNotificationSettings

因此,如果用户对您的应用说“不”,那么此函数应该返回一个没有任何类型的设置。

我已经写了一个关于这个的教程,你可以看到它here

【讨论】:

  • 如果用户拒绝权限,你以后如何以编程方式确定?
  • @satheeshwaran 当我使用此代码时,它在 iOS8 模拟器上运行良好。我希望我的应用程序的部署目标从 iOS7 开始。因此,当我在 iOS7 设备上运行此代码时,我收到此错误:dyld: Symbol not found: _OBJC_CLASS_$_UIUserNotificationSettings。 Swift 中是否有任何其他方式向用户询问权限以便在 iOS7 中工作?请帮忙。
  • @Raghav UIUserNotificationSettings 仅适用于 iOS 8,您面临的是正确的行为。你不应该在 iOS 7 中使用它。
  • -1 用于检查 iOS 版本 UIDevice。 stackoverflow.com/a/25735175/1226304 答案有更好的方法来做到这一点。
  • @derpoliuk 为大家的利益更新了答案,好吗??
【解决方案2】:

**适用于 iOS8+ 的具有三个按钮操作的本地通知

//按钮:我接受了,稍后提醒,跳过**

        let completeAction = UIMutableUserNotificationAction()
        completeAction.identifier = "COMPLETE_TODO"
        completeAction.title = "I TOOK IT"
        completeAction.activationMode = .Background
        completeAction.destructive = true
        completeAction.authenticationRequired = false

        let remindAction = UIMutableUserNotificationAction()
        remindAction.identifier = "REMIND_TODO"
        remindAction.title = "REMIND LATER"
        remindAction.activationMode = .Background
        remindAction.destructive = false
        //  remindAction.authenticationRequired = false

        let skipAction = UIMutableUserNotificationAction()
        skipAction.identifier = "SKIP_TODO"
        skipAction.title = "SKIP IT"
        skipAction.activationMode = .Background
        skipAction.destructive = false
        skipAction.authenticationRequired = false


        let todoCategory = UIMutableUserNotificationCategory()
        todoCategory.identifier = "TODO_CATEGORY"
        todoCategory.setActions([completeAction, remindAction, skipAction], forContext: .Default)
        todoCategory.setActions([completeAction,remindAction,skipAction], forContext: .Minimal)


        if application.respondsToSelector("isRegisteredForRemoteNotifications")
        {

            let categories = NSSet(array: [todoCategory,todoVideoCategory])
            let types:UIUserNotificationType = ([.Alert, .Sound, .Badge])

            let settings:UIUserNotificationSettings = UIUserNotificationSettings(forTypes: types, categories: categories as? Set<UIUserNotificationCategory>)

            application.registerUserNotificationSettings(settings)
            application.registerForRemoteNotifications()

        }

    }

【讨论】:

    【解决方案3】:

    在 Objective-C 上试试这个:

    - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:    (NSDictionary *)launchOptions
    {
    // are you running on iOS8?
    if ([application respondsToSelector:@selector(registerUserNotificationSettings:)]) 
      {
        UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:(UIUserNotificationTypeBadge|UIUserNotificationTypeAlert|UIUserNotificationTypeSound) categories:nil];
        [application registerUserNotificationSettings:settings];
      } 
    else // iOS 7 or earlier
      {
        UIRemoteNotificationType myTypes = UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeAlert | UIRemoteNotificationTypeSound;
        [application registerForRemoteNotificationTypes:myTypes];
      }
    }
    

    对于斯威夫特:

    func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: NSDictionary?) -> Bool {
    // Override point for customization after application launch.
     if(UIApplication.instancesRespondToSelector(Selector("registerUserNotificationSettings:")))
     {
        application.registerUserNotificationSettings(UIUserNotificationSettings(forTypes: UIUserNotificationType.Sound | UIUserNotificationType.Alert | UIUserNotificationType.Badge, categories: nil))
     }
     else
     {
        //
     }
    return true
    }
    

    【讨论】:

      【解决方案4】:

      我刚刚遇到了同样的问题。似乎在 iOS 8 中我们需要做一个额外的步骤,通常在内部完成:

      - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { /*...*/ }
      

      如果您想保持向后兼容,可以使用此代码:

      #if __IPHONE_OS_VERSION_MAX_ALLOWED >= 80000
          if ([UIApplication instancesRespondToSelector:@selector(registerUserNotificationSettings:)])
          {
              [[UIApplication sharedApplication] registerUserNotificationSettings:[UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeAlert | UIUserNotificationTypeBadge | UIUserNotificationTypeSound categories:nil]];
          }
      #endif
      

      系统会记住这个决定,并且只会询问一次。

      【讨论】:

      • 最好用这段代码检查 iOS 版本 if ([[UIDevice currentDevice].systemVersion floatValue]
      【解决方案5】:

      将此代码放在您将首先对通知进行编程的视图控制器中(如果您在启动时对其进行编程,那么它将是application:didFinishLaunchingWithOptions:):

      if ([UIApplication instancesRespondToSelector:@selector(registerUserNotificationSettings:)]) {
          [[UIApplication sharedApplication] registerUserNotificationSettings:[UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeAlert|UIUserNotificationTypeSound categories:nil]];
      }
      

      在斯威夫特中:

      if(UIApplication.instancesRespondToSelector(Selector("registerUserNotificationSettings:"))) {
          UIApplication.sharedApplication().registerUserNotificationSettings(UIUserNotificationSettings(forTypes: .Alert | .Sound, categories: nil))
      }
      

      针对系统版本号进行测试的解决方案是次优且容易出错的。

      【讨论】:

      • 我会使用 application.respondsToSelector(Selector("registerUserNotificationSettings"))if ([application respondsToSelector:@selector(registerUserNotificationSettings:)])
      • 这只是因为您在application:didFinishLaunchingWithOptions: 内部使用它,它提供了一个方便的application 对象:)
      猜你喜欢
      • 2014-11-17
      • 2018-07-29
      • 2017-07-06
      • 1970-01-01
      • 2020-09-11
      • 1970-01-01
      • 2012-05-28
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多