Метод обратного вызова, если пользователь отклоняет подсказку с уведомлением об отправке?
Моя проблема в том, что я хочу показать экран загрузки для первоначальной подсказки уведомления о выпуске "Приложение хочет отправить вам push-уведомления".
Итак, если пользователь нажимает yes
, я могу продолжить и запустить приложение в методах делегата, который вызывается:
- (void)application:(UIApplication*)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData*)deviceToken
{
[self hideLoadingScreen];
}
- (void)application:(UIApplication*)application didFailToRegisterForRemoteNotificationsWithError:(NSError*)error
{
[self hideLoadingScreen];
}
Однако, если пользователь нажимает no
, ни один из этих методов не вызван, что имеет смысл. Мой вопрос в том, есть ли другой метод делегата, который увольняется, если он откажется?
Моя проблема в том, что если выбрано no
, экраны загрузки никогда не исчезают. Поэтому мне как-то нужно знать, когда пользователь выполнил выбор.
Ответы
Ответ 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.")
}
}
}