performSelector "backgroundRefreshStatus" crashes on iOS 7 - objective-c

I am building with Xcode 5/iOS SDK 6.1. If the app runs on an iOS 7.x device it should check whether the setting "Settings -> General -> BackgroundAppRefresh" is set for the app. Since this property is only available on iOS 7 I am doing:
if([[UIApplication sharedApplication] respondsToSelector:#selector(backgroundRefreshStatus)])
{
NSInteger outcome=[[[UIApplication sharedApplication] performSelector:#selector(backgroundRefreshStatus)] integerValue];
//do something with "outcome"
}
However... the app crashes on iOS 7 at the "performSelector" line which is strange because it passes the "respondsToSelector" call?? Anyone knows why? I also tried NSSelectorFromString(#"backgroundRefreshStatus") with the same result.

You've got a lot of unnecessary code there. Unless the backgroundRefreshStatus selector exists before iOS 7 as a private API you don't need the version check.
Your use of #selector is also incorrect and you don't need to use performSelector, just call the method:
if ([[UIApplication sharedApplication] respondsToSelector:#selector(backgroundRefreshStatus)]) {
UIBackgroundRefreshStatus refreshStatus = [[UIApplication sharedApplication] backgroundRefreshStatus];
}

You are using a string as the selector. Try without the string:
UIApplication *app = [UIApplication sharedApplication];
if([app respondsToSelector:#selector(backgroundRefreshStatus)])
{
UIBackgroundRefreshStatus outcome = [app performSelector:#selector(backgroundRefreshStatus)];
// or outcome = [app backgroundRefreshStatus]
}

Related

Open the Bluetooth Settings Menu in Ios 10

I need to open the bluetooth settings menu in IOS10 and above.But [[UIApplication sharedApplication] openURL:
[NSURL URLWithString:#"prefs:root=Bluetooth"]]; is not working in ios 10.
After exploring multiple document I got below link which provide code which will work properly. https://gist.github.com/johnny77221/bcaa5384a242b64bfd0b8a715f48e69f
But, Now I have question will app store accept this patch code or they will reject application.
Please help me to solve this issue.
Thanks in advance
Swift 3.0:- Working in all iOS version upto iOS 10.2
let url = URL(string: "App-Prefs:root") //for system setting app
#IBAction func blutootheButtonTapped(_ sender: AnyObject) {
let url = URL(string: "App-Prefs:root=Bluetooth") //for bluetooth setting
let app = UIApplication.shared
app.openURL(url!)
}
As of iOS 10 "App-Prefs:root" should be used rather than "prefs:root". See below Objective C code. Tested this , code works fine but Apple may reject the app because of this.
NSString *settingsUrl= #"App-Prefs:root=Bluetooth";
if ([[UIApplication sharedApplication] respondsToSelector:#selector(openURL:options:completionHandler:)]) {
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:settingsUrl] options:#{} completionHandler:^(BOOL success) {
NSLog(#"URL opened");
}];
}

didRegisterForRemoteNotificationsWithDeviceToken is not called on ios10

I have 2 iphones: 1 - with ios 10 and 2 - with ios 9
While trying the 1st iphone:
didRegisterForRemoteNotificationsWithDeviceToken method is not called when user clicks "allow" on the alert
Though, the method didRegisterUserNotificationSettings IS called.
In this case device does NOT receive push notifications.
While trying the 2nd iphone:
Both methods are called here. And device DOES receive push notifications.
Then I checked on simulator ios 8
In this case the same as in 1st. Only one method is called.
I checked some answers for similar question but they didn't help me.
I doubt that the issue is somewhere within push notifications settings, cuz ios 9 works OK.
So the issue is somewhere within ios 10.
The very questions are:
How can I call method didRegisterForRemoteNotificationsWithDeviceToken
Or how can I get the device token since it's the goal
Looking forward for your help!
For iOS 10 using xCode 8 GM.
This issue solved with the following steps.
Requirements :- Xcode 8 GM Seed.
MAC OS :- Captain EL 10.11.6
Do not remove your code for IOS 9 or below versions.
Step 1:-
Go To --> Target Settings in Xcode --> Capabilities --> Enable PushNotifications.
Step 2:-
Add UserNotifications framework --> Build Phase --> Link Libraries
Step 3:-
#import <UserNotifications/UserNotifications.h>
#interface AppDelegate : UIResponder <UIApplicationDelegate,UNUserNotificationCenterDelegate>
#end
Step 4:-
In the method didFinishLaunchingWithOptions register for UIUserNotificationSettings.
-(BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{
if(SYSTEM_VERSION_EQUALTO(#"10.0")){
UNUserNotificationCenter *notifiCenter = [UNUserNotificationCenter currentNotificationCenter];
notifiCenter.delegate = self;
[notifiCenter requestAuthorizationWithOptions:(UNAuthorizationOptionSound | UNAuthorizationOptionAlert | UNAuthorizationOptionBadge) completionHandler:^(BOOL granted, NSError * _Nullable error){
if( !error ){
[[UIApplication sharedApplication] registerForRemoteNotifications];
}
}];
}
return YES;
}
Step 5:- Implement the 2 delegate methods of UNUserNotificationCenterDelegate.
-(void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions options))completionHandler{
//Do Your Code.................Enjoy!!!!
}
-(void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void(^)())completionHandler{
}
You may want to check the Project Settings. Select your project. Go to Second tab -> Capabilities -> Select Push Notification to ON.
You should call this method inside 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.")
if !(SharedPrefs.sharedInstance!.isLoggedIn){
Defaults.sharedPref.removeNotificationToken()
}else{
UIApplication.shared.unregisterForRemoteNotifications()
print("We will delete the token at the time of logout")
}
}
}
} 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()
}
}

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

"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?

Stopping ios 7 remote notification sound

In iOS 7, when a user swipes one of my notifications from the lockscreen and is taken to my app, the notification sound keeps playing (unlike iOS 6). Is there any way to programmatically stop that sound when my app launches in iOS 7?
NOTE: see the accepted answer for a shoddy workaround.
I'm pretty sure this is a bug on Apple's end, see devforums.apple.com/message/888091 (thanks Gui13). File a duplicate bug report to get Apple to pay attention to it, as that is how Apple assigns priority to bugs. In the meantime, the following will work but will also clear all of your notifications in the notification center, which of course is a shoddy workaround, but in my case is worth it until this gets fixed:
[[UIApplication sharedApplication] setApplicationIconBadgeNumber: 1];
[[UIApplication sharedApplication] setApplicationIconBadgeNumber: 0];
it doesn't help by using
[[UIApplication sharedApplication] setApplicationIconBadgeNumber: 1];
[[UIApplication sharedApplication] setApplicationIconBadgeNumber: 0];
after entering the app by clicking the notification.
I have solved this problem by sending another empty notification when dealing with the notification with sound:
if (notification.soundName != nil) {
if (IS_IOS7) {
UILocalNotification *emptyNotification = [[UILocalNotification alloc] init];
emptyNotification.timeZone = [NSTimeZone defaultTimeZone];
emptyNotification.fireDate = [NSDate date];
emptyNotification.alertBody = #"";
[[UIApplication sharedApplication] scheduleLocalNotification:emptyNotification];
}
}
For iOS 7, the accepted answer may be the only viable option. For developers who have come here that can support a minimum of iOS 10, this works.
You can remove all notifications from Notification Center by calling
UNUserNotificationCenter.current().removeAllDeliveredNotifications()
This has a very similar affect as the accepted answer: the audio stops playing and all the notifications are removed from Notification Center.
An improved solution is to use
UNUserNotificationCenter.current().removeDeliveredNotifications(withIdentifiers: [String])
This stops the audio for only the given notifications, and removes them from Notification Center.
To get the ids for all the delivered notifications, use
UNUserNotificationCenter.current().getDeliveredNotifications { notifications in
let ids = notifications.map { $0.request.identifier }
}

cancelAllLocalNotifications; not working on iPhone 3GS

So my app has been around for 5 days now and iPhone 3GS users are reporting that their notifications doesn't cancel when the button is switched.
The button executes the following code:
[[UIApplication sharedApplication] cancelAllLocalNotifications];
However, this code works on iPhone 4,iPhone 4S,iPhone 5 and iPad.
Is this a known bug of the iPhone 3GS? Or does the 3GS require different code to achieve the same thing?
I'm running into this problem on iOS 8.1 on an iPhone 6+. It turns out that cancelAllLocalNotifications is not a synchronous call, so there is no guarantee that the cancelation has been completed when it returns. I've had to implement the following as a workaround
- (void) clearNotifications
{
NSLog(#"Clearing notifications");
[[UIApplication sharedApplication] cancelAllLocalNotifications];
long count;
while ((count = [[[UIApplication sharedApplication] scheduledLocalNotifications] count]) > 0) {
NSLog(#"Remaining notificaitons to cancel: %lu",(unsigned long)count);
[NSThread sleepForTimeInterval:.01f];
}
NSLog(#"Notifications cleared");
}
Don't know why but I had to cancel all notification by notifcation ID instead of CancelAll on iPhone 3GS