Подтвердить что ты не робот

Метод обратного вызова, если пользователь отклоняет подсказку с уведомлением об отправке?

Моя проблема в том, что я хочу показать экран загрузки для первоначальной подсказки уведомления о выпуске "Приложение хочет отправить вам push-уведомления".

Итак, если пользователь нажимает yes, я могу продолжить и запустить приложение в методах делегата, который вызывается:

- (void)application:(UIApplication*)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData*)deviceToken
{
  [self hideLoadingScreen];
}

- (void)application:(UIApplication*)application didFailToRegisterForRemoteNotificationsWithError:(NSError*)error
{
  [self hideLoadingScreen];
}

Однако, если пользователь нажимает no, ни один из этих методов не вызван, что имеет смысл. Мой вопрос в том, есть ли другой метод делегата, который увольняется, если он откажется?

Моя проблема в том, что если выбрано no, экраны загрузки никогда не исчезают. Поэтому мне как-то нужно знать, когда пользователь выполнил выбор.

4b9b3361

Ответ 1

В iOS 7 при появлении приглашения уведомления о нажатии системы приложение становится неактивным и запускается UIApplicationWillResignActiveNotification. Аналогично, когда пользователь отвечает на запрос (нажав Да или Нет), приложение снова активируется и запускается UIApplicationDidBecomeActiveNotification.

Итак, вы можете прослушать это уведомление, а затем скрыть свой экран загрузки.

Примечание. Пока отображается приглашение, кнопка "Домой", Центр уведомлений и Центр управления отключены, поэтому они не могут запускать ложноположительную UIApplicationDidBecomeActiveNotification. Однако, если пользователь нажимает кнопку блокировки, он вызывает UIApplicationDidBecomeActiveNotification.

Ответ 2

Вы всегда можете получать текущие разрешенные типы уведомлений:

UIRemoteNotificationType notificationTypes = [[UIApplication sharedApplication] enabledRemoteNotificationTypes];

Помните, что пользователь может также отключить уведомление в настройках телефона.

Если вы отметите, что на didRegisterForRemoteNotificationsWithDeviceToken вы должны увидеть, разрешены ли типы, которые вы запрашивали.

Ответ 3

Не могли бы вы просто сделать следующее:

- (void)application:(UIApplication *)application didRegisterUserNotificationSettings:(UIUserNotificationSettings *)notificationSettings {
    BOOL pushEnabled = notificationSettings.types & UIUserNotificationTypeAlert;
}

Этот метод должен быть обратным вызовом этого приглашения push push, и оттуда вы можете проверить битмаску, чтобы увидеть, включены ли push-уведомления или нет.

Ответ 4

Вот как я это сделал в Swift 3. Они здесь, чтобы отслеживать состояние жизненного цикла приложения внутри. Когда нажимается приглашение, приложение уходит в отставку, но не входит в фоновый режим. Это все в моем AppDelegate.swift.

Это действительно большой взлом и не рекомендуется в производстве. Apple может изменить способ представления этих предупреждений, и это может сломаться в любое время. Это было протестировано с использованием различных iPhones и iPads под управлением iOS 9 и 10.

/// An internal value used to track application lifecycle state
enum ApplicationLifecycleState {
    case willResignActive
    case didEnterBackground
    case willEnterForeground
    case didBecomeActive
    case unknown
}

/// This is used purely for tracking the application lifecycle for handling the system push notification alert
var internalLifecycleState: ApplicationLifecycleState = .unknown {
    didSet {
        // If we're not in the middle of asking for push permissions, none of the below applies, just bail out here
        if !isAskingForPushPermissions { return }

        // WARNING: Application lifecycle trickery ahead
        // The normal application lifecycle calls for backgrounding are as follows:
        // applicationWillResignActive -> applicationDidEnterBackground -> applicationWillEnterForeground -> applicationDidBecomeActive
        // However, when the system push notification alert is presented, the application resigns active, but does not enter the background:
        // applicationWillResignActive -> [user taps on alert] -> applicationDidBecomeActive
        // We can use this discrepancy to our advantage to detect if the user did not allow push permissions

        // If applicationDidBecomeActive
        // AND the previous state was applicationWillResignActive
        // AND the notification types bitmask is 0, we know that the user did not allow push permissions
        // User denied permissions
        if internalLifecycleState == .didBecomeActive
            && oldValue == .willResignActive
            && UIApplication.shared.currentUserNotificationSettings?.types.rawValue == 0 {
            // We're done
            firePushCompletionBlockAndCleanup(registered: false)
        } else {
            // The state below can only be entered on iOS 10 devices.
            // If the user backgrounds the app while the system alert is being shown,
            // when the app is foregrounded the alert will dismiss itself without user interaction.
            // This is the equivalent of the user denying push permissions.
            // On iOS versions below 10, the user cannot background the app while a system alert is being shown.

            if #available(iOS 10, *), internalLifecycleState == .didBecomeActive {
                firePushCompletionBlockAndCleanup(registered: false)
            }
        }
    }
}

/// Used internally to track if the system push notification alert is currently being presented
var isAskingForPushPermissions = false

typealias PushNotificationRegistrationCompletionBlock = ((_ registered: Bool) -> Void)

// ...

func applicationWillResignActive(_ application: UIApplication) {    
    internalLifecycleState = .willResignActive
}

func applicationDidEnterBackground(_ application: UIApplication) {
    internalLifecycleState = .didEnterBackground
}

func applicationWillEnterForeground(_ application: UIApplication) {
    internalLifecycleState = .willEnterForeground
}

func applicationDidBecomeActive(_ application: UIApplication) {
    internalLifecycleState = .didBecomeActive
}

// ...

func setupPushNotifications(_ application: UIApplication = UIApplication.shared, completion: @escaping PushNotificationRegistrationCompletionBlock) {
    isAskingForPushPermissions = true
    pushCompletionBlock = completion
    let settings = UIUserNotificationSettings(types: [.alert, .sound, .badge], categories: nil)
    application.registerUserNotificationSettings(settings)
    application.registerForRemoteNotifications()
}

fileprivate func firePushCompletionBlockAndCleanup(registered: Bool) {
    pushCompletionBlock?(registered)
    pushCompletionBlock = nil
    isAskingForPushPermissions = false
}

func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {

    // application:didRegisterForRemoteNotificationsWithDeviceToken may be called more than once (once for each notification type)
    // By checking that the notification types bitmask is greater than 0, we can find the final time this is called (after the user actually tapped "allow")
    // If the user denied push permissions, this function is never called with a positive notification type bitmask value
    if UIApplication.shared.currentUserNotificationSettings?.types.rawValue ?? 0 > 0 {
        firePushCompletionBlockAndCleanup(registered: true)
    }
}

func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) {
    print("Failed to register for notifications with error: " + error.localizedDescription)
    firePushCompletionBlockAndCleanup(registered: false)
}

Использование:

appDelegate.setupPushNotifications(completion: { [weak self] (registered) in
    // If registered is false, the user denied permissions
})

Ответ 5

Некоторые из ответов здесь уже не актуальны или более сложны, чем должно быть, поскольку в среде UserNotifications и iOS 10 вы можете легко получить эти данные примерно так:

let center = UNUserNotificationCenter.current()

// Request permission to display alerts and play sounds.
center.requestAuthorization(options: [.alert, .sound]) 
{ (granted, error) in
  // Enable or disable features based on authorization.
}

Ответ 6

Для Swift 3 и Swift 4.0 Использование NotificationCenter и метода AppDelegate didRegister notificationSettings. NotificationSettings показывает, были ли пользователи выбраны значки, звуки и т.д. И будут пустым массивом, если они отклонят push-уведомления. Он запускается специально, когда пользователи отвечают на подсказку push push и, похоже, используют большинство разработчиков, поскольку это более специфично, чем проверка didBecomeActive. Но Apple может изменить это. Кто знает?

К сожалению, NotificationCenter не имеет предустановленного имени уведомления, поэтому вам нужно либо настроить и расширить (см. конец), либо использовать исходное значение в (SO имеет больше на этом).

В AppDelegate:

    func application(_ application: UIApplication, didRegister notificationSettings: UIUserNotificationSettings) {
      // if not registered users will have an empty set of settings
      let accepted: Bool = !notificationSettings.types.isEmpty
      NotificationCenter.default.post(name: Notification.Name(rawValue: "didRespondToPrompt"), object: self, userInfo: ["didAccept" : accepted])
}

Затем наблюдайте, где вам нужно, например, в контроллере вида:

class MyViewController: UIViewController {

//MARK: - Lifecycle
   override func viewDidLoad() {
      super.viewDidLoad()
      NotificationCenter.default.addObserver(self, selector: #selector(MyViewController.didRespondToPushPrompt(_:)), name: NSNotification.Name(rawValue: "didRespondToPrompt"), object: nil)

   }
    @objc func didRespondToPushPrompt(_ notification: Notification) {

       if let userInfo: [AnyHashable : Any] = notification.userInfo, let didAccept: Bool = userInfo[NSNotificationKeyNames.didAccept] as? Bool, !didAccept {
        //if user doesn't accept, do this...

       } else  {
       //all other situations code goes here
      }

   }
}

Пара вещей: во-первых, для Swift 4.0, я использую "@objc" перед одним методом, но это не обязательно для Swift 3.
Кроме того, для использования NotificationCenter на практике я не использовал "rawValue". Вместо этого я сделал расширение следующим образом:

import Foundation

extension NSNotification.Name {
   static let DidRegisterForPushNotifications = NSNotification.Name("DidRegisterForPushNotifications")
}

Что я мог бы использовать так:

NotificationCenter.default.post(name: Notification.Name.DidRegisterForPushNotifications, object: self, userInfo: ["didAccept" : myBool]) и т.д. и т.д.

Ответ 7

Я предполагаю, что у вас может быть переменная BOOL, чтобы проверить ее в AppDelegate, потому что, похоже, нет никакого способа, кроме использования внешних API. См. это.

AppDelegate.m

// declare a BOOL 
BOOL allow = NO;

- (void)application:(UIApplication*)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData*)deviceToken
{
allow = YES;
  [self hideLoadingScreen];
}

- (void)application:(UIApplication*)application didFailToRegisterForRemoteNotificationsWithError:(NSError*)error
{
  allow = YES;
  [self hiedLoadingScreen];
}

Теперь, я думаю, вы можете получить доступ к этой переменной BOOL, чтобы дифференцировать ее, если не разрешено нажатие или нет.

Ответ 8

Вот пример кода SWIFT 2 для вас, ребята... Это немного сработало, но я надеюсь, что мои комментарии помогут вам понять это.

Определить переменные

var appDidBecomeActiveCount = 0
var userDefaults:NSUserDefaults!

AppDelegate - didFinishLaunchingWithOptions

func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {

        userDefaults = NSUserDefaults.standardUserDefaults()
        if userDefaults.valueForKey("FirstLaunche") == nil {
            userDefaults.setBool(true, forKey: "FirstLaunche")
            userDefaults.synchronize()
        }

        // Register for notification
        //iOS 8+
        let settings:UIUserNotificationSettings = UIUserNotificationSettings(forTypes: [UIUserNotificationType.Alert , UIUserNotificationType.Badge ,UIUserNotificationType.Sound], categories: nil)
        UIApplication.sharedApplication().registerUserNotificationSettings(settings)
        UIApplication.sharedApplication().registerForRemoteNotifications()
}

AppDelegate - applicationDidBecomeActive

func applicationDidBecomeActive(application: UIApplication) {
            //Delay until alert get dismissed and notification type setted in app
            delay(0.5, closure: { () -> () in
                self.checkTheDilemma()
            })
}
//I love this short method <3_<3
func delay(delay:Double, closure:()->()) {
    dispatch_after(
        dispatch_time(
            DISPATCH_TIME_NOW,
            Int64(delay * Double(NSEC_PER_SEC))
        ),
        dispatch_get_main_queue(), closure)
}

Проверить действие

func checkTheDilemma (){
        //Checking if this user turned off push notifications or didn't allow it at all
        let notificationType = UIApplication.sharedApplication().currentUserNotificationSettings()?.types

        if userDefaults.valueForKey("FirstLaunche") as! Bool == true {
            //User now is asked for notification permission because it app first launche
            // if appDidBecomeActiveCount == 0 --> Pop up message will appeare
            // if appDidBecomeActiveCount == 1 --> Pop up message dismissed
            // if notificationType?.rawValue == 0 --> Notifications off
            // if notificationType?.rawValue > 0  --> Notifications on
            if notificationType?.rawValue == 0
                && appDidBecomeActiveCount == 1 { //If user disabled notifications from pop up alert
                    // ** User just tapped "Don't allow" btn :\
                    // Do what ever you are here for

                    //Now set FirstLaunche = false
                    userDefaults.setBool(false, forKey: "FirstLaunche")
                    userDefaults.synchronize()
            }
        } else {
            if notificationType?.rawValue == 0
                && appDidBecomeActiveCount == 0 { // This guy is not registered for push notification
                    // ** User disabled notifications in past (because this is not his first launch)
            }
        }
        appDidBecomeActiveCount++
    }

Ответ 9

Вы можете обнаружить, что пользователь отменил приглашение уведомления в методе didRegisterUserNotificationSettings, который запускается после вызова registerForRemoteNotificationTypes, проверив notificationSettings.types.

Если вы запросили несколько параметров, но notificationSettings.types == UIUserNotificationTypeNone означает, что пользователь отменил приглашение.

Но не забывайте, что метод registerForRemoteNotificationTypes теперь устарел!

Ответ 10

2 мая 2019 г.

Это реализация для проверки, разрешены ли уведомления в любое время в вашем приложении. Просто вызовите эту функцию.

    private func checkNotificationsAuthorizationStatus() {
    let userNotificationCenter = UNUserNotificationCenter.current()
    userNotificationCenter.getNotificationSettings { (notificationSettings) in
        switch notificationSettings.authorizationStatus {
        case .authorized:
            print("The app is authorized to schedule or receive notifications.")
        case .denied:
            print("The app isn't authorized to schedule or receive notifications.")

        case .notDetermined:
            print("The user hasn't yet made a choice about whether the app is allowed to schedule notifications.")
        case .provisional:
            print("The application is provisionally authorized to post noninterruptive user notifications.")
        }
    }

}