Unchecking a switch depending on user decision - ios

I'm building an app that asks the user for permission to post notifications when the user enables a switch. I'm using this code:
- (IBAction)mySwitchValueChanged:(id)sender {
if ([UIApplication instancesRespondToSelector:#selector(registerUserNotificationSettings:)]){
[[UIApplication sharedApplication] registerUserNotificationSettings:[UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeAlert|UIUserNotificationTypeBadge|UIUserNotificationTypeSound categories:nil]]; // ask the user for permission
}
if ([[UIApplication sharedApplication] respondsToSelector:#selector(currentUserNotificationSettings)]) { // Check it's iOS 8 and above
UIUserNotificationSettings *grantedSettings = [[UIApplication sharedApplication] currentUserNotificationSettings];
if (grantedSettings.types != UIUserNotificationTypeNone)
{
// Accepted
} else
{
[self.mySwitch setOn:NO]; // Declined
}
}
}
The desired behaviour is as follows:
User slides switch
Alert asks for permission
Code waits for user to decide
Either does whatever I code where I've put // accepted, or disables the switch.
The current behaviour makes the code run through at once, and doesn't wait for the user to decide. How can I change this to get the desired behaviour?
Thanks!

Note: This is workaround idea
Once you call this method :- [UIApplication sharedApplication] registerUserNotificationSettings and user grants push notification for the app, then didRegisterForRemoteNotificationsWithDeviceToken in AppDelegate get fired,
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken
{
//call a notification when user granted Push Notifiaction
[[NSNotificationCenter defaultCenter]
postNotificationName:#"PushNotificationSuccess"
object:self];
}
So what you have to do, you can call a NSNotification from the mentioned method, to update the UI accordingly.
- (void)updateUIOnNotification:(NSNotification *) notification
{
// Accepted
}

//Call the below method in your else part and remove the line
//[self.mySwitch setOn:NO];
-(void)Showalert{
UIAlertview*Temp=[[UIAlertview alloc]initWithTitle:#"Need Permission to Send Notifications" message:#"The App Wants The Permission to Work Properly!\nPermit The App in Notification settings"delegate:self cancelButtonTitle:#"Okay!" otherButtonTitles:nil];
[Temp show];
}
#pragma mark Alertview delegate method
- (void)alertViewCancel:(UIAlertView *)alertView{
//Remove the Below line From Else part of your code
[self.mySwitch setOn:NO];
}

Related

Bring app to foreground from iPhone lock screen

I have an application an I managed to make a custom remote controller with help of this question on stack overflow.
it works fine but in I want to bring app to foreground by asking the user to unlock the phone, something like apple Musics share button action. Is it possible to ask user to unlock the phone and bring app to foreground to complete an action?
I managed to make it work using local notification, but I think there need to be an alert view or a user interaction with button. Is it possible to make it work without any pop-up?
Here is the code I used to change lock screen controllers button
//App delegate
-(void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification {
if ([UIApplication instancesRespondToSelector:#selector(registerUserNotificationSettings:)]){
[application registerUserNotificationSettings:[UIUserNotificationSettings
settingsForTypes:UIUserNotificationTypeAlert|UIUserNotificationTypeBadge|
UIUserNotificationTypeSound categories:nil]];
}
}
// inside viewDidLoad
MPRemoteCommandCenter *rcc = [MPRemoteCommandCenter sharedCommandCenter];
MPFeedbackCommand *likeCommand = [rcc likeCommand];
[likeCommand setEnabled:YES];
[likeCommand setLocalizedTitle:#"I love it"]; // can leave this out for default
[likeCommand addTarget:self action:#selector(likeEvent:)];
MPFeedbackCommand *dislikeCommand = [rcc dislikeCommand];
[dislikeCommand setEnabled:YES];
[dislikeCommand setActive:YES];
[dislikeCommand setLocalizedTitle:#"I hate it"]; // can leave this out for default
[dislikeCommand addTarget:self action:#selector(dislikeEvent:)];
BOOL userPreviouslyIndicatedThatTheyDislikedThisItemAndIStoredThat = YES;
if (userPreviouslyIndicatedThatTheyDislikedThisItemAndIStoredThat) {
[dislikeCommand setActive:YES];
}
//Selectors:
-(void)dislikeEvent: (MPFeedbackCommandEvent *)feedbackEvent
{
//I need to ask user to unlock the phone and bring app to foreground
NSLog(#"Mark the item disliked");
}
-(void)likeEvent: (MPFeedbackCommandEvent *)feedbackEvent
{
//I need to ask user to unlock the phone and bring app to foreground
NSLog(#"Mark the item liked");
UILocalNotification *notification = [[UILocalNotification alloc] init];
notification.fireDate = [NSDate dateWithTimeIntervalSinceNow:0];
notification.alertBody = #"This is local notification!";
notification.timeZone = [NSTimeZone defaultTimeZone];
notification.soundName = UILocalNotificationDefaultSoundName;
[[UIApplication sharedApplication] scheduleLocalNotification:notification];
}
I suppose these delegate methods in the appdelegate.h would be helpful.
I think you could use the last one, "application did become active."
- (void)applicationDidEnterBackground:(UIApplication *)application {
// Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
// If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
}
- (void)applicationWillEnterForeground:(UIApplication *)application {
// Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
}
- (void)applicationDidBecomeActive:(UIApplication *)application {
// Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
}
OR
By using notification center you can perform any actions in particular classes, i have used will enter foreground. There are different options available as per users requirements.
- (void)viewDidLoad {
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(appReturnToForeground) name:UIApplicationWillEnterForegroundNotification object:nil];
}
- (void)appReturnToForeground {
// Your code...What you want to perform.
}

iOS: Programmatic way to tell whether or not push notifications are enabled

I have an iPhone development application with APNS enabled for the appID. In my applicationDidBecomeActive event I check to see whether or not push notifications are enabled by doing the following:
- (void)applicationDidBecomeActive:(UIApplication *)application {
NSLog(#"applicationDidBecomeActive");
//Check if remote notifications are enabled for this app, if not proceed with performSetupAndWebService calls
UIRemoteNotificationType types = [[UIApplication sharedApplication] enabledRemoteNotificationTypes];
if(types == UIRemoteNotificationTypeNone)
{
//User has push notifications DISABLED for this application.
NSLog(#"PUSH NOTIFICATIONS DISABLED");
[self performSetupAndWebServiceCalls];
}
else
{
//User has push notifications ENABLED for this application.
NSLog(#"PUSH NOTIFICATIONS ENABLED");
NSLog(#"Registering for push notifications...");
[[UIApplication sharedApplication]
registerForRemoteNotificationTypes:(UIRemoteNotificationType)(UIRemoteNotificationTypeBadge|UIRemoteNotificationTypeSound|UIRemoteNotificationTypeAlert)];
}
}
It seems that no matter what I do, my code always tells me that push notifications are disabled. My app icon is in Notification Center in Settings and it is included. I have tried turning off specific types of notification and turning them back on but types == UIRemoteNotificationTypeNone is always true.
Am I missing something obvious? The bad thing is this seems to be affecting users of our production app as well, but not all of them. Very inconsistent and very frustrating.
Any advice?
When notifications are disabled and you try to register for them you get the following UIApplicationDelegate method called:
application:didFailToRegisterForRemoteNotificationsWithError:
- (BOOL) getpushNotificationstatus
{
if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 8.0)
{
return ([[UIApplication sharedApplication] isRegisteredForRemoteNotifications]);
}
else
{
UIRemoteNotificationType types = [[UIApplicationy sharedApplication] enabledRemoteNotificationTypes]; return (types & UIRemoteNotificationTypeAlert);
}
}
It will work in iOS8 as well

iOS how to execute a task with beginBackgroundTaskWithExpirationHandler

I am trying to do two things for a simple test app.
I am stuck at trying to learn how to use beginBackgroundTaskWithExpirationHandler
I want to execute a backgroundTask when the user presses the home button (nothing fancy). In 9 minutes, I'd like to alert the user that the time is about to expire (if possible) and allow the user to switch back into the app to renew the 10 minutes.
I don't need backward compatibility with iOS 3, or 4.
If you want your code to continue in the background, then you'll need to wrap it in a background task. It's also very important that you call endBackgroundTask when you're finished - otherwise the app will be killed after it's allotted time has expired
- (IBAction) buttonPressed: (id) sender
[self beingBackgroundUpdateTask];
// Do your long running background thing here
[self endBackgroundUpdateTask];
});
}
- (void) beingBackgroundUpdateTask
{
self.backgroundUpdateTask = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
[self endBackgroundUpdateTask];
}];
}
- (void) endBackgroundUpdateTask
{
[[UIApplication sharedApplication] endBackgroundTask: self.backgroundUpdateTask];
self.backgroundUpdateTask = UIBackgroundTaskInvalid;
}
Put the code in the applicationDidEnterBackground function in your UIApplicationDelegate. You will need to set up a UILocalNotification and schedule it. You should also probably disable it in applicationWillEnterForeground so it doesn't fire off the user goes back to the app before it expires.
- (void)applicationDidEnterBackground:(UIApplication *)application
{
UILocalNotification *timerNotification = [[UILocalNotification alloc] init];
//set up notification with proper time and attributes
[[UIApplication sharedApplication] scheduleLocalNotification:timerNotification];
}
- (void)applicationWillEnterForeground:(UIApplication *)application
{
[[UIApplication sharedApplication] cancelAllLocalNotifications];
}
The cancelling code I gave there will actually cancel all notifications. If you have multiple notifications and only want to cancel a specific one, you should give the userInfo property of your notification a key/value when you set it up. Then, when the application enters the foreground, get the list of all active notifications by doing
NSArray *notifications = [[UIApplication sharedApplication] scheduledLocalNotifications];
and loop through them, checking userInfo until you get to the one you want and then just cancelling that one with
[[UIApplication sharedApplication] cancelLocalNotification:whateverNotification];

Setting the application badge number to 0 is not clearing notifications [duplicate]

I've an iOS application where some Push Notification are sent to. My problem is, that the messages/notifications stays in the Notification Center in iOS after then are tapped. How can I remove a notification for my application in the Notification Center next time the application opens?
I came across posts where people are calling setApplicationIconBadgeNumber to a zero-value to clear the notifications. That's seems very weird to me, so I believe that maybe another solution exists?
EDIT1:
I'm having some problems clearing the notifications. Please see my code here:
- (void) clearNotifications {
[[UIApplication sharedApplication] setApplicationIconBadgeNumber: 0];
[[UIApplication sharedApplication] cancelAllLocalNotifications];
}
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
if (launchOptions != nil)
{
NSDictionary* dictionary = [launchOptions objectForKey:UIApplicationLaunchOptionsRemoteNotificationKey];
if (dictionary != nil)
{
NSLog(#"Launched from push notification: %#", dictionary);
[self clearNotifications];
}
}
return YES;
}
- (void)application:(UIApplication*)application didReceiveRemoteNotification:(NSDictionary*)userInfo
{
NSLog(#"Received notification: %#", userInfo);
[self clearNotifications];
}
I'm running the App through Xcode. When the App is minimized and I start the App using the notification in the Notification Center, I can see in the log, that the didReceiveRemoteNotification is called and using breakpoints I can see, that the clearNotifications has ran. But still the notification hangs in the Notification Center. Why?
Most likely because Notification Center is a relatively new feature, Apple didn't necessarily want to push a whole new paradigm for clearing notifications. So instead, they multi-purposed [[UIApplication sharedApplication] setApplicationIconBadgeNumber: 0]; to clear said notifications. It might seem a bit weird, and Apple might provide a more intuitive way to do this in the future, but for the time being it's the official way.
Myself, I use this snippet:
[[UIApplication sharedApplication] setApplicationIconBadgeNumber: 0];
[[UIApplication sharedApplication] cancelAllLocalNotifications];
which never fails to clear all of the app's notifications from Notification Center.
Just to expand on pcperini's answer. As he mentions you will need to add the following code to your application:didFinishLaunchingWithOptions: method;
[[UIApplication sharedApplication] setApplicationIconBadgeNumber: 0];
[[UIApplication sharedApplication] cancelAllLocalNotifications];
You Also need to increment then decrement the badge in your application:didReceiveRemoteNotification: method if you are trying to clear the message from the message centre so that when a user enters you app from pressing a notification the message centre will also clear, ie;
[[UIApplication sharedApplication] setApplicationIconBadgeNumber: 1];
[[UIApplication sharedApplication] setApplicationIconBadgeNumber: 0];
[[UIApplication sharedApplication] cancelAllLocalNotifications];
It might also make sense to add a call to clearNotifications in applicationDidBecomeActive so that in case the application is in the background and comes back it will also clear the notifications.
- (void)applicationDidBecomeActive:(UIApplication *)application
{
[self clearNotifications];
}
Update for iOS 10 (Swift 3)
In order to clear all local notifications in iOS 10 apps, you should use the following code:
import UserNotifications
...
if #available(iOS 10.0, *) {
let center = UNUserNotificationCenter.current()
center.removeAllPendingNotificationRequests() // To remove all pending notifications which are not delivered yet but scheduled.
center.removeAllDeliveredNotifications() // To remove all delivered notifications
} else {
UIApplication.shared.cancelAllLocalNotifications()
}
This code handles the clearing of local notifications for iOS 10.x and all preceding versions of iOS. You will need to import UserNotifications for the iOS 10.x code.
If you have pending scheduled local notifications and don't want to use cancelAllLocalNotifications to clear old ones in Notification Center, you can also do the following:
[UIApplication sharedApplication].scheduledLocalNotifications = [UIApplication sharedApplication].scheduledLocalNotifications;
It appears that if you set the scheduledLocalNotifications it clears the old ones in Notification Center, and by setting it to itself, you retain the pending local notifications.
If you're coming here wondering the opposite (as I was), this post may be for you.
I couldn't figure out why my notifications were clearing when I cleared the badge...I manually increment the badge and then want to clear it when the user enters the app. That's no reason to clear out the notification center, though; they may still want to see or act on those notifications.
Negative 1 does the trick, luckily:
[UIApplication sharedApplication].applicationIconBadgeNumber = -1;
In Swift I'm using the following code inside my AppDelegate:
func applicationDidBecomeActive(application: UIApplication) {
application.applicationIconBadgeNumber = 0
application.cancelAllLocalNotifications()
}
Maybe in case there are scheduled alarms and uncleared app icon badges.
NSArray *scheduledLocalNotifications = [application scheduledLocalNotifications];
NSInteger applicationIconBadgeNumber = [application applicationIconBadgeNumber];
[application cancelAllLocalNotifications];
[application setApplicationIconBadgeNumber:0];
for (UILocalNotification* scheduledLocalNotification in scheduledLocalNotifications) {
[application scheduleLocalNotification:scheduledLocalNotification];
}
[application setApplicationIconBadgeNumber:applicationIconBadgeNumber];
When you have repeated notifications at future, you do not want to cancel those notifications, you can clear the item in notification center by:
func clearNotificationCenter() {
UIApplication.sharedApplication().applicationIconBadgeNumber = 1
UIApplication.sharedApplication().applicationIconBadgeNumber = 0
}
You cannot clear notification when your app is open in the foreground by calling the method below immediately after receiving local notification, otherwise you will receive tens of hundreds of notifications. Maybe because the same notification apply again, and now is the time to fire, so you keep fire, apply again, fire, apply....:
[UIApplication sharedApplication].scheduledLocalNotifications = [UIApplication sharedApplication].scheduledLocalNotifications;
When you logout from your app, at that time you have to use a below line of code on your logout button click method.
[[UIApplication sharedApplication] setApplicationIconBadgeNumber: 0];
[[UIApplication sharedApplication] cancelAllLocalNotifications];
and this works perfectly in my app.
You need to add below code in your AppDelegate applicationDidBecomeActive method.
[[UIApplication sharedApplication] setApplicationIconBadgeNumber: 0];
Got it from here. It works for iOS 9
UIApplication *app = [UIApplication sharedApplication];
NSArray *eventArray = [app scheduledLocalNotifications];
for (int i=0; i<[eventArray count]; i++)
{
UILocalNotification* oneEvent = [eventArray objectAtIndex:i];
//Cancelling local notification
[app cancelLocalNotification:oneEvent];
}

Push Notifications Permissions

Trying to work around a few corner cases for when push notifications are denied in the app and I have two questions:
1) Is there a way to reset whether the user has seen the notification request pop up?
2) Is there any way to determine if the user has said no to the notification request?
1) No, unless there's some private API that does that, but that's not allowed by Apple
2) The first time your app is started, after calling registerForRemoteNotificationTypes, you can check if didRegisterForRemoteNotificationsWithDeviceToken is called. If it's not, the user said "No thanks".
You can always check the status of the permissions if the user changes them, you can check them on applicationDidBecomeActive
- (void)applicationDidBecomeActive:(UIApplication *)application
{
if ([[UIApplication sharedApplication] respondsToSelector:#selector(isRegisteredForRemoteNotifications)]) {
if ([[UIApplication sharedApplication] isRegisteredForRemoteNotifications]){
NSLog(#"Notifications Enabled ios 8");
} else {
NSLog(#"Notifications not Enabled ios 8");
}
} else {
UIRemoteNotificationType types = [[UIApplication sharedApplication] enabledRemoteNotificationTypes];
if (types & UIRemoteNotificationTypeAlert)
{
NSLog(#"Notifications Enabled");
}
else
{
NSLog(#"Notifications not Enabled");
}
}
}
updated to make it work on iOS 8 too

Resources