Local Notification: No Permission to Play Sound Even After Registering fo UIUserNotificationTypeSound - objective-c

"Attempting to schedule a local notification UIConcreteLocalNotification: with a sound but haven't received permission from the user to play sounds"
- (void)registerForRemoteNotifications
{
if ([[UIApplication sharedApplication] respondsToSelector:#selector(isRegisteredForRemoteNotifications)]) {
// iOS 8 Notifications
[[UIApplication sharedApplication] registerUserNotificationSettings:[UIUserNotificationSettings settingsForTypes:(UIUserNotificationTypeAlert|UIUserNotificationTypeSound|UIUserNotificationTypeBadge) categories:nil]];
} else{
// iOS < 8 Notifications
[[UIApplication sharedApplication] registerForRemoteNotificationTypes:(UIUserNotificationTypeAlert)];
}
}
//added for ios8
- (void)successfullyRegisteredUserNotificationSettings
{
[[UIApplication sharedApplication] registerForRemoteNotifications];
}
I followed the guide of other users in stackoverflow to use registerUserNotificationSettings for ios8. After invoking the function, I wait for the callback in AppDelegate:
- (void)application:didRegisterUserNotificationSettings:
In the function, I call my successfullyRegisteredUserNotificationSettings method above to formally register.
Even after doing this, I still get the error. Can someone tell me why? Or has anyone encountered the same issue? How can this be solved?

Related

Local Notifications - asking for permission again after initially rejected

When an app launches for the first time, it will ask the user for permission to send local notifications.
If the user denies the permission at launch, how do we ask for permission again in the future?
For example, is there a way that on a button click, I can request permission again?
Here is my code to initially ask for permission at launch:
- (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];
}
}
If for the first time you have disallowed local notification and on the second time use the blow mentioned code:
if ([[UIApplication sharedApplication] respondsToSelector:#selector(currentUserNotificationSettings)]
{
UIUserNotificationSettings *grantedSettings = [[UIApplication sharedApplication] currentUserNotificationSettings];
if (grantedSettings.types == UIUserNotificationTypeNone)
{
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:#"app-settings:"]];
}
}
This will open your application settings where you can find the settings to enable/disable local notification and other settings.
Hope this helps!
You can not request the system prompt again. You can detect a situation in which the access was denied and show an alert yourself or show the button that will open settings app to make the process of changing the setting easier for the user.

Some time apple push notification not getting

I am developing an iOS application in iOS 8 .That has one module called message sending. This module developed with help of Apple push notification. My issue is some time we are not getting Push message to iOS device .The server successfully sent the message to APNS. Is it any APNS reliability issue?
i am using the following steps:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
if([[UIApplication sharedApplication] respondsToSelector:#selector(registerUserNotificationSettings:)])
{
UIUserNotificationSettings* notificationSettings = [UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeAlert | UIUserNotificationTypeSound categories:nil];
[[UIApplication sharedApplication] registerUserNotificationSettings:notificationSettings];
[[UIApplication sharedApplication] registerForRemoteNotifications];
}
return YES;
}
- (void)application:(UIApplication *)application didRegisterUserNotificationSettings:(UIUserNotificationSettings *)notificationSettings
{
[application registerForRemoteNotifications];
}
- (void)application:(UIApplication*)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData*)deviceToken
{
}
- (void)application:(UIApplication*)application didFailToRegisterForRemoteNotificationsWithError:(NSError*)error
{
}
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo
{
}
APNs are not reliable, they are not 100% guaranteed to reach the client.
As of Apple's documentation, APNs are best effort, so many times they might not reach.
Via answer
Samraan is not wrong, Apple does not guarantee delivery, however it is pretty reliable in my experience. What I do notice from the code you have posted here is that you have an empty implementation for didReceiveRemoteNotification. When your app is active, and it receives a push notification, there is no system banner or alert shown. Instead the notification is delivered to the didReceiveRemoteNotification callback for your app to handle directly. If you have an empty definition of this function and you send a notification to that device, it may appear like the notification never arrived, but instead it was just hidden.
You could try adding a UIAlertView popup to this callback to find out if this is what is happening in your case.

iOS Notification not playing sound

I've created a notification in my iOS app using iOS 8. The notification is correctly being displayed but it's not playing the sound, although UIUserNotificationTypeSound was registered and default sound name was specified. How can I make the sound play when I get the notification?
Registering UIUserNotificationTypeSound
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
[application registerUserNotificationSettings:[UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeAlert|UIUserNotificationTypeBadge|UIUserNotificationTypeSound categories:nil]]
return YES;
}
Setting default sound name
localNotif.soundName = UILocalNotificationDefaultSoundName;
I have not tested your code
But comparing to my code, I found you are not calling [application registerForRemoteNotifications]; method
if ([application respondsToSelector:#selector(isRegisteredForRemoteNotifications)])
{
// iOS 8 Notifications
[application registerUserNotificationSettings:[UIUserNotificationSettings settingsForTypes:(UIUserNotificationTypeSound | UIUserNotificationTypeAlert | UIUserNotificationTypeBadge) categories:nil]];
[application registerForRemoteNotifications];
}
Try this, I guess it will help you.

iOS 8 and Xcode 6 Push Notification

I am really new to iOS development and was trying to implement a simple push notification app for iOS 8 using Xcode 6. I have all the required certificates from the apple developer website along with the provision profile tied to my app id. following is the code i am implementing in app delegate.m (The code is borrowed from the web)
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary*)launchOptions
{
//-- Set Notification
if ([application respondsToSelector:#selector(isRegisteredForRemoteNotifications)])
{
// iOS 8 Notifications
[application registerUserNotificationSettings:[UIUserNotificationSettings settingsForTypes:(UIUserNotificationTypeSound | UIUserNotificationTypeAlert | UIUserNotificationTypeBadge) categories:nil]];
[application registerForRemoteNotifications];
}
else
{
// iOS < 8 Notifications
[application registerForRemoteNotificationTypes:
(UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeAlert | UIRemoteNotificationTypeSound)];
}
//--- your custom code
NSLog(#"Registering for push notifications...");
return YES;
}
- (void)application:(UIApplication*)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData*)deviceToken
{
NSLog(#"Registering for push notifications...II"); //to see if this code gets executed...it doesnt, why?
NSLog(#"My token is: %#", deviceToken);
}
- (void)application:(UIApplication*)application didFailToRegisterForRemoteNotificationsWithError:(NSError*)error
{
NSLog(#"Failed to get token, error: %#", error);
}
I am running it on a physical iPhone, the problem is I cannot seem to get the device token in the nslog. I have even tried to put a simple nslog test out put under the device token code, but it seem it never gets that far. If someone could please point out what the issue is, it would most helpful.
Thank You.
gokhangultekin, Cornelius,
Thank You for your replies, I feel really silly typing the resolution to my issue, it was just that my iPhone was not connected to the internet, for some reason I just assumed that there was a tethered connection through my laptop because of the usb connection.
Thank you both for your time.
Hamood

why didRegisterForRemoteNotificationsWithDeviceToken is not called

I am making an application in which I want to implement apple push notification service. I am following the step-by-step instructions given in this tutorial.
But still, the methods are not called. I don't know what is causing the problem. Can anyone help me?
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
//NSString * token = [[NSString alloc] initWithData:deviceTokenencoding:NSUTF8StringEncoding];
NSString *str = [NSString stringWithFormat:#"Device Token=%#",deviceToken];
NSLog(#"Device Token:%#",str);
//NSLog(#"Device token is called");
//const void *devTokenBytes = [deviceToken bytes];
//NSLog(#"Device Token");
}
- (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)err {
NSString *str = [NSString stringWithFormat: #"Error: %#", err];
NSLog(#"Error:%#",str);
}
I had the same issue: calling registerForRemoteNotificationTypes: invoked neither application:didRegisterForRemoteNotificationsWithDeviceToken: nor application:didFailToRegisterForRemoteNotificationsWithError:
I eventually resolved this issue with the help of Apple's technical note TN2265.
This is what I did:
First off, I double-checked that I am indeed registering correctly for Push Notifications, including verifying my provisioning profile for "aps-environment" key and the codesigning of the .app file itself. I had it all set up correctly.
I then had to debug Push Notification status messages in the console (you need to install PersistentConnectionLogging.mobileconfig provisioning profile on your device and reboot it. See TN2265 under "Observing Push Status Messages"). I noticed that apns process starts a timer and calculates a minimum fire date, which made me suspect that the Push-Notification registration confirmation message, which is normally presented at this point, is supressed by APNS, as indicated in TN2265:
Resetting the Push Notifications Permissions Alert on iOS
The first time a push-enabled app registers for push notifications, iOS asks the user if they wish to receive notifications for that app. Once the user has responded to this alert it is not presented again unless the device is restored or the app has been uninstalled for at least a day.
If you want to simulate a first-time run of your app, you can leave the app uninstalled for a day. You can achieve the latter without actually waiting a day by setting the system clock forward a day or more, turning the device off completely, then turning the device back on.
So, I removed the app from the device, then manually changed the iPhone's date in Settings, rebooted the device, and re-installed the app.
The next time my code called registerForRemoteNotificationTypes, it received callbacks as expected.
This resolved the issue for me. Hope it helps.
In iOS 8, some methods are deprecated. Follow the steps below for iOS 8 compatibility
1. Register notification
if([[UIDevice currentDevice] systemVersion].floatValue >= 8.0)
{
UIUserNotificationSettings* notificationSettings = [UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeAlert | UIUserNotificationTypeBadge | UIUserNotificationTypeSound categories:nil];
[[UIApplication sharedApplication] registerUserNotificationSettings:notificationSettings];
}
else
{
[[UIApplication sharedApplication] registerForRemoteNotificationTypes:(UIRemoteNotificationTypeAlert | UIRemoteNotificationTypeSound|UIRemoteNotificationTypeBadge)];
}
2. Add new 2 methods
- (void)application:(UIApplication *)application didRegisterUserNotificationSettings:(UIUserNotificationSettings *)notificationSettings
{
//register to receive notifications
[application registerForRemoteNotifications];
}
//For interactive notification only
- (void)application:(UIApplication *)application handleActionWithIdentifier:(NSString *)identifier forRemoteNotification:(NSDictionary *)userInfo completionHandler:(void(^)())completionHandler
{
//handle the actions
if ([identifier isEqualToString:#"declineAction"]){
}
else if ([identifier isEqualToString:#"answerAction"]){
}
}
Note : above two new methods are required in iOS 8 in addition to didRegisterForRemoteNotificationsWithDeviceToken and didReceiveRemoteNotification..Otherwise delegate method will not be invoked.
See: Remote Notification iOS 8
In iOS 8, in addition to requesting push notification access differently, you also need to register differently.
Request Access:
if ([application respondsToSelector:#selector(registerUserNotificationSettings:)]) {
// iOS 8
UIUserNotificationSettings* settings = [UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeAlert | UIUserNotificationTypeBadge | UIUserNotificationTypeSound categories:nil];
[[UIApplication sharedApplication] registerUserNotificationSettings:settings];
} else {
// iOS 7 or iOS 6
[[UIApplication sharedApplication] registerForRemoteNotificationTypes:(UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeSound | UIRemoteNotificationTypeAlert)];
}
Handle registered device:
// New in iOS 8
- (void)application:(UIApplication *)application didRegisterUserNotificationSettings:(UIUserNotificationSettings *)notificationSettings {
[application registerForRemoteNotifications];
}
// iOS 7 or iOS 6
- (void)application:(UIApplication *)app didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
NSString *token = [[deviceToken description] stringByTrimmingCharactersInSet: [NSCharacterSet characterSetWithCharactersInString:#"<>"]];
token = [token stringByReplacingOccurrencesOfString:#" " withString:#""];
// Send token to server
}
Bear in mind that remote notifications are not supported in the simulator. Therefore, if you run your app in the simulator, didRegisterForRemoteNotificationsWithDeviceToken won't be called.
Make sure you call in your code (update according to supported notification kinds)
[[UIApplication sharedApplication] registerForRemoteNotificationTypes: UIRemoteNotificationTypeAlert | UIRemoteNotificationTypeSound];
and the provisioning profile is APNS enabled. You may need to re-download the provisioning profile after enabing APNS. If you have troubles and you get errors, then maybe you should create an Entitlements.plist and add the key "aps-environment" with value "development" or "production" depending on the kind of build (normally this key-value pair is contained in the provisioning profile, but sometimes Xcode mess with them).
If the provisioning profiles are used before to Enable and Configure Apple Push Notification service, you will need to redownload the provisioning profiles again.
Delete provisioning profiles from Xcode Organizer and from the iPhone/iPad.
Go to Settings -> General -> Profiles -> [Your provisioning] -> Remove.
Install the new downloaded provisioning profiles. Then clean and run the project from XCode.
Now didRegisterForRemoteNotificationsWithDeviceToken should be called.
Try this it working for me ,
First Step
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
In above method add below code
UIApplication *application = [UIApplication sharedApplication];
if ([application respondsToSelector:#selector(registerUserNotificationSettings:)]) {
UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:(UIUserNotificationTypeBadge
|UIUserNotificationTypeSound
|UIUserNotificationTypeAlert) categories:nil];
[application registerUserNotificationSettings:settings];
}
else {
UIRemoteNotificationType myTypes = UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeAlert | UIRemoteNotificationTypeSound;
[application registerForRemoteNotificationTypes:myTypes];
}
Second Step
Add below code Function
#ifdef __IPHONE_8_0
- (void)application:(UIApplication *)application didRegisterUserNotificationSettings:(UIUserNotificationSettings *)notificationSettings
{
//register to receive notifications
[application registerForRemoteNotifications];
}
- (void)application:(UIApplication *)application handleActionWithIdentifier:(NSString *)identifier forRemoteNotification:(NSDictionary *)userInfo completionHandler:(void(^)())completionHandler
{
//handle the actions
if ([identifier isEqualToString:#"declineAction"]){
}
else if ([identifier isEqualToString:#"answerAction"]){
}
}
#endif
You will get device Token in below function
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken
for detail answer please refer This
Hope this is help for some one .
I made a mistake and overlooked an implementation detail that lead me here. I tried to get fancy and ask the user for Push Notifications later in the application onboarding process, so I had my registerForRemoteNotificationTypes, didRegisterForRemoteNotificationsWithDeviceToken and didFailToRegisterForRemoteNotificationsWithError all in a custom UIView.
FIX: the didRegisterForRemoteNotificationsWithDeviceToken and didFailToRegisterForRemoteNotificationsWithError need to be in the UIApplicationDelegate (YourAppDelegate.m) to be triggered.
seems obvious now, heh.
Be sure that your internet connection is on.
This took me hours to get work notifications because of internet connection.
If you have added push to an existing App ID, make sure you re-generate your provisioning profiles. If you don't, the profile will not know about your enabling of push on the App ID.
-​(BOOL)application:(UIApplication​*)application​ didFinishLaunchingWithOptions:(NSDictionary​*)launchOptions​{​​​​ ​​​​ ​​​​//​Override​point​for​customization​after​application​launch.
​​​​//​Add​the​view​controller’s​view​to​the​window​and​display. ​​​​[window​addSubview:viewController.view]; ​​​​[window​makeKeyAndVisible];
NSLog(#”Registering for push notifications...”);
[[UIApplication sharedApplication]
registerForRemoteNotificationTypes: (UIRemoteNotificationTypeAlert | UIRemoteNotificationTypeBadge |
UIRemoteNotificationTypeSound)];
​​​​return​YES;
}
- (void)application:(UIApplication *)app didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
}
NSString *str = [NSString stringWithFormat:#”Device Token=%#”,deviceToken];
NSLog(#”%#”, str);
- (void)application:(UIApplication *)app didFailToRegisterForRemoteNotificationsWithError:(NSError *)err {
NSString *str = [NSString stringWithFormat: #”Error: %#”, err]; NSLog(#”%#”, str);
}
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo {
}
for (id key in userInfo) { NSLog(#”key: %#, value: %#”, key, [userInfo objectForKey:key]);
}
Minimal Requirement to Get Device Token:No need to configure app id, provisioning or certificate etc thus no code signing set to get the delegate method didRegisterForRemoteNotificationsWithDeviceToken called.
I just created a new iOS project in Xcode 7 for single view with default settings and gave a random bundle id like com.mycompany.pushtest which is not configured in apple dev portal. With the following code, I'm getting my device token in didRegisterForRemoteNotificationsWithDeviceToken method on my iPad with internet access to WIFI. My device is attached and I'm just running the app directly from xcode and viewing the values in xcode's console.
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
if ([application respondsToSelector:#selector(registerUserNotificationSettings:)])
{
UIUserNotificationType userNotificationTypes = (UIUserNotificationTypeAlert | UIUserNotificationTypeBadge | UIUserNotificationTypeSound);
UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:userNotificationTypes categories:nil];
[application registerUserNotificationSettings:settings];
[application registerForRemoteNotifications];
}
else
{
// Register for Push Notifications, if running iOS version < 8
[application registerForRemoteNotificationTypes:(UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeAlert | UIRemoteNotificationTypeSound)];
}
return YES;
}
- (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error {
NSLog(#"Error: %#", error.description);
}
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
NSLog(#"didRegisterForRemoteNotificationsWithDeviceToken: %#", deviceToken);
}
- (void)application:(UIApplication *)application didRegisterUserNotificationSettings:(UIUserNotificationSettings *)notificationSettings {
NSLog(#"NotificationSettings: %#", notificationSettings);
}
After wasting the most annoying 3h, here are the steps to fix the issue:
Delete the app
Reset the device
Run again
It just worked
This happened to me, because I reset & deleted all the data on the phone (wanted a dev phone to use). This prevented APN from connecting at all after setting up the phone again.
I tried all sorts of things, but the only thing that fixed it was setting the phone up to work with a carrier under a new SIM card.
This link offers more hints as to what might have been going on: https://developer.apple.com/library/ios/technotes/tn2265/_index.html
It says that APN tries to connect preferentially via carrier / towers as opposed to wifi. Maybe the issue also was something was going on with the router blocking port 5223 on the wifi network, but I doubt it because it worked fine on the prior day before the global reset occurred.
I have a point on this.Recently I too face this problem.I have done everything
according to documentation but delegate method was not calling.Finally I saw
one post saying that problem with the network.Then I have changed network and
it works fine.So take care about network also because few networks can block
the APNS.
I had a different issue wherein my push notification callbacks were getting hijacked by the 3rd party libraries, that I had included, namely Firebase. These libraries swizzle push notification callback methods to get the callbacks.
Hope this helps someone.
For me what solved it was going to the build settings and under the code signing section, manually selecting the code signing identity and provisioning profile. Apparently the automatic setting wasn't picking-up the correct one and therefore the app wasn't properly authorized.
if shut down push message of app,
appdidRegisterForRemoteNotificationsWithDeviceToken will never be called
Also, don't forget to check the system status at Apple https://developer.apple.com/system-status/.
I'd tried all the solutions posted above but in the end the fault was because the APNS service was down! The next day all was working again as expected.
Also, you have a typo in your callback method:
- (void)application:(UIApplication *)appdidRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken
As Rupesh pointed out the correct method name is:
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken
That's probably why you never received the token in your case!
You need to call registerForNotifications method from didFinishLaunchingWithOptions.
func registerForNotifications(){
if #available(iOS 10.0, *) {
let center = UNUserNotificationCenter.current()
center.delegate = self
center.requestAuthorization(options:[.alert,.sound,.badge]) { (granted, error) in
if granted{
UIApplication.shared.registerForRemoteNotifications()
}else{
print("Notification permission denied.")
}
}
} else {
// For iOS 9 and Below
let type: UIUserNotificationType = [.alert,.sound,.badge];
let setting = UIUserNotificationSettings(types: type, categories: nil);
UIApplication.shared.registerUserNotificationSettings(setting);
UIApplication.shared.registerForRemoteNotifications()
}
}
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
let token = String(format: "%#", deviceToken as CVarArg).trimmingCharacters(in: CharacterSet(charactersIn: "<>")).replacingOccurrences(of: " ", with: "")
print(token)
}
extension AppDelegate : UNUserNotificationCenterDelegate{
#available(iOS 10.0, *)
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: #escaping (_ options: UNNotificationPresentationOptions) -> Void) {
print("Handle push from foreground”)
let info = ((notification.request.content.userInfo as NSDictionary).value(forKey: "aps") as! NSDictionary)
if let type = info.value(forKey: "type") as? Int{
if type == 0 {
// notification received ,Handle your notification here
}
}
}
#available(iOS 10.0, *)
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: #escaping () -> Void) {
print("Handle push from background or closed")
let info = ((response.notification.request.content.userInfo as NSDictionary).value(forKey: "aps") as! NSDictionary)
if let type = info.value(forKey: "type") as? Int{
if type == 0 {
// notification received ,Handle your notification here
}
}
}
}