0

I am trying to update to NSUserNotifications.

I have changed how my code is written and changed where it is place but the same thing keeps happening.

In my AnotherViewController.h

#import <UserNotifications/UserNotifications.h>
#import <UserNotifications/UNUserNotificationCenter.h>

@interface AnotherViewController : UIViewController <UNUserNotificationCenterDelegate>

{
UNAuthorizationOptions UNAuthorizationOptionBadge;;
    UNAuthorizationOptions UNAuthorizationOptionAlert;
    UNAuthorizationOptions UNAuthorizationOptionSound;
}

@property(readonly, copy) NSString *localizedDescription;

In my AnotherViewController.m

@synthesize localizedDescription;

-(void)viewDidAppear:(BOOL)animated;{
[super viewDidAppear:YES];



NSLog(@"viewDidAppear");


UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
center.delegate = self;



[center getNotificationSettingsWithCompletionHandler:^(UNNotificationSettings * _Nonnull settings) {
        if (@available(iOS 14.0, *)) {
            if (settings.authorizationStatus == UNAuthorizationStatusEphemeral) {
                NSLog(@"Ephermeral");
            }
            else if (settings.authorizationStatus == UNAuthorizationStatusProvisional) {
                NSLog(@"provisional");
            }
    
  else if (settings.authorizationStatus == UNAuthorizationStatusAuthorized) {
      NSLog(@"authorized");
  }
   else if (settings.authorizationStatus == UNAuthorizationStatusDenied) {
        NSLog(@"denied");
    }
   
   else if (settings.authorizationStatus == UNAuthorizationStatusNotDetermined) {
           NSLog(@"Not determined");
       [center requestAuthorizationWithOptions:(self->UNAuthorizationOptionBadge|self->UNAuthorizationOptionAlert|self->UNAuthorizationOptionSound)
                 completionHandler:^(BOOL granted, NSError * _Nullable error) {
                     if (! error) {
                        
                         NSLog(@"success");
                     }
                     else {
                         NSLog(@"desc%@",self.localizedDescription);
                     }
                 }];
       }
  
   }
    else {
       NSLog(@"earlier");
   }
   
}];

In my log I get Not determined and then success.

 if (! error){NSLog(@"success");}

So even though the status is Not determined the app calls the method but does not display the Alert asking for permission.
Still not sure why this is happening.

user1114881
  • 731
  • 1
  • 12
  • 25
  • The expression `UNAuthorizationOptionAlert + UNAuthorizationOptionSound + UNAuthorizationOptionBadge` is wrong, for one thing. – matt Mar 26 '21 at 23:57
  • Thank you for the suggestion. I tried to put | in between the options but that didn't work so I tried putting just NSAuthorizationOptionAlert instead of the options but that didn't work either. Could you suggest something that would make that app ask for the permissions that I am missing. – user1114881 Mar 27 '21 at 00:18
  • You can't force the dialog to appear. For example, if you have denied permission already, you won't see the dialog again. Moreover, the completion handler is handing you an error that explains if there's an issue, and you are throwing it away without looking at it. Similarly your `getNotificationSettingsWithCompletionHandler` is trying to tell you what the authorization status actually is, but you are not listening; all you know is what it is _not_. – matt Mar 27 '21 at 00:49
  • I understand what you are saying. The problem is that when I first install the app on my device I am not asked to permit or deny it. No tag shows up. So after I install and launch the app for the first time and I go into the settings under notifications it doesn't show my app as having any notification status. So I am not sure why it is not being called. I have tried to put localizedDescription in the error but I returns (null). So I do not know what I am doing wrong. Sorry. – user1114881 Mar 27 '21 at 04:08
  • You have not even shown where your code is. – matt Mar 27 '21 at 04:10
  • I have changed my code to show what I have included and where it is. And what is or is not happening. I hope this helps. – user1114881 Mar 27 '21 at 18:27
  • Hmm. Well, for one thing, `didFinishLaunchingWithOptions` is a really bad place to put this code. Consider that this code runs before there is even an interface. So the first thing I would try would be doing this in a better place, such as the first call to the view controller's `viewDidAppear`. – matt Mar 27 '21 at 21:19
  • This is where it was suggested to put it in several examples but I have changed it to a completely different view controller under viewDidLoad and viewDidAppear but with no change. The method is called because I get "success" but no Alert asking for permission anytime. Do I need to specify the iOS is above v10.0? – user1114881 Mar 27 '21 at 21:50
  • Well as I said before, if you see no dialog it is because this device / simulator has already been used to grant or deny authorization to this app. – matt Mar 27 '21 at 21:53
  • If this were true when I delete the app and reinstall it, it would not have notifications permissions of any kind. But when I do that on different devices an Alert never appears asking for notification permissions. And when I go into setting under Notifications my app does not appear and when I look under my app in settings there are no Notifications settings. – user1114881 Mar 27 '21 at 22:24
  • Well, look at my answer below and try implementing it in a completely new clean project. You will see that what I'm saying is correct. – matt Mar 27 '21 at 22:32

2 Answers2

0

The main problem so far is this code:

[center getNotificationSettingsWithCompletionHandler:^(UNNotificationSettings * _Nonnull settings) {
    if (settings.authorizationStatus != UNAuthorizationStatusAuthorized) {
    }
}];

That is too blunt a test. You are asking what the authorization status is not. You need to examine the authorization status to see what it is is.

If it is not "not determined", you can not cause the authorization dialog to appear to the user; the answer to the question of status is already known. The user can elect to make a change in the settings app, and you can put up a normal dialog asking the user to do that, but you cannot make the system present the authorization dialog.

Moreover, there are several ways to be authorized; "authorized" is not the only one.

So your entire approach is backwards. The correct strategy is:

  1. Call getNotificationSettingsWithCompletionHandler.

  2. In the completion handler, examine the status. Look at what it is, not at what it is not:

    a. If the status is "authorized" or "provisional" or "ephemeral", you know you are clear to go ahead and post a notification to the system.

    b. If the status is "denied", don't post a notification.

    c. If the status is "not determined", you may now call requestAuthorizationWithOptions to put up the authorization dialog, if you wish.

    • In that method's completion handler, if the BOOL is YES, you are now authorized and you are clear to post a notification.

This is a complete example that works on my machine:

#import "ViewController.h"
@import UserNotifications;

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    UNUserNotificationCenter* center = [UNUserNotificationCenter currentNotificationCenter];
    [center getNotificationSettingsWithCompletionHandler:^(UNNotificationSettings * _Nonnull settings) {
        UNAuthorizationStatus status = settings.authorizationStatus;
        if (status == UNAuthorizationStatusNotDetermined) {
            UNAuthorizationOptions opts = UNAuthorizationOptionAlert;
            [center requestAuthorizationWithOptions:opts completionHandler:^(BOOL granted, NSError * _Nullable error) {
                if (granted) {
                    NSLog(@"Hoorah");
                } else {
                    NSLog(@"User refused.");
                }
            }];
        } else {
            NSLog(@"status was %ld", status);
        }
    }];
}

@end
matt
  • 515,959
  • 87
  • 875
  • 1,141
  • I have updated my post to reflect what you suggested I do (I think I did). I also put this in a brand new app in the ViewDidLoad of the ViewController and no Alert showed up just Not determined and success. So clearly I am doing something wrong but I am not sure what. Thank you for your patience and help. – user1114881 Mar 27 '21 at 23:46
  • Well, I don't know what you're doing now. I assure you that if you do what I said, you will either see the dialog or you will know why not. – matt Mar 28 '21 at 00:04
  • Added a complete working example. I really don't see what more I can do. – matt Mar 28 '21 at 00:07
0

I finally figured this out. I had to enable the modules. I went to the Target > Build Settings and set the Enable Modules (C and Objective-C modules) to YES. It was set to NO so the modules included with UNUsersNotification weren't being used. Now I get the call for permissions. Now just have to finish figuring how to get the notification to come up when the app is in the background or not running. But that is a different post and question. Thanks

user1114881
  • 731
  • 1
  • 12
  • 25