Silent push on iOS 9 device for xCode 8 build - background

Does anybody known why didReceiveRemoteNotification: fetchCompletionHandler: method not called in background on iOS 9 device for app built with xCode 8?
Previously, for xCode 7, all was ok. App's background mode is On, Remote notification is also On.
Push payload looks like this:
{
"aps":{
"content-available" : 1,
"alert" : "Hello",
"sound" : "default",
},
}
As I said, for xCode 7 all was ok both for foreground and background modes.
I've added iOS 10 pushes with UNUserNotificationCenter, and now it is ok for iOS 10 devices only, but no success for iOS 9 devices.
I've tried to add corresponding entitlements files, also to implement didReceiveRemoteNotification: method
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo
{
[self application:application didReceiveRemoteNotification:userInfo fetchCompletionHandler:^(UIBackgroundFetchResult result){}];
}
but still the same.
Can anybody help me with this?

Related

Can't endBackgroundTask: no background task exists with identifier, or it may have already been ended

I am using background task to run the timer in the background to update the user's location. It's declared as:
UIBackgroundTaskIdentifier bgTask;
in the header file, and initialized as:
bgTask = UIBackgroundTaskInvalid;
But still, I am getting this message in the gdb:
Can't endBackgroundTask: no background task exists with identifier 23dc, or it may have already been ended. Break in UIApplicationEndBackgroundTaskError() to debug.
Why? And how can I solve this?
I lose many days looking for the piece of code or framework that was causing this warning in the debug console Can't end BackgroundTask: no background task exists with identifier 2 (0x2), or it may have already been ended. Break in UIApplicationEndBackgroundTaskError() to debug.
Finally I've created an empty project Single View App. Only code generated by Xcode, I run the app on simulator, put it in background and I see the same warning.
So I can say it's an iOS 13 issue.
I hope Apple will fix it quickly because in Crashlytics I found some crash in my app caused by it.
In Xcode, switch to the breakpoint navigator (View > Navigators > Show Breakpoint Navigator) then push the + button in the bottom left and select Add Symbolic Breakpoint and enter “UIApplicationEndBackgroundTaskError” as the symbol.
You need to set
bgTask = UIBackgroundTaskInvalid
in two moments
In the expiration handler.
After finishing your task.
I believe you are missing any of those two moments and that is why you are getting that error.
See apple example code:
- (void)applicationDidEnterBackground:(UIApplication *)application
{
bgTask = [application beginBackgroundTaskWithName:#"MyTask" expirationHandler:^{
// Clean up any unfinished task business by marking where you
// stopped or ending the task outright.
[application endBackgroundTask:bgTask];
bgTask = UIBackgroundTaskInvalid;
}];
// Start the long-running task and return immediately.
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// Do the work associated with the task, preferably in chunks.
[application endBackgroundTask:bgTask];
bgTask = UIBackgroundTaskInvalid;
});
}
link:
https://developer.apple.com/documentation/backgroundtasks/bgtask?language=objc
Reproduced, here is my entire app:
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate
{
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool
{
return true
}
}
And when I take it to background I get the same message. No storyboard or any other noise.
Are you using location update in the background?
If yes, add the below code at the time of getting location authorization from the user - Apple changed the default for allowsBackgroundLocationUpdates to NO from iOS 9 onwards.
if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 9) {
locationManager.allowsBackgroundLocationUpdates = YES;
}
Please make sure that you activated the 'Location updates' for background modes under your project 'Signing & Capabilities'. Otherwise it will crash.
Using Swift 5 - IOS 13.2.2 - Xcode 11.2 beta 2 (11B44)
I managed to get rid of this error by
enabling Push notifications in the Capabilities of the app
Import the UserNotifications framework
then add this code to
func application(_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions:
[UIApplication.LaunchOptionsKey: Any]?) -> Bool {
let center = UNUserNotificationCenter.current()
center.requestAuthorization(options:[.badge, .alert, .sound]) { (granted, error) in
// If granted comes true you can enabled features based on authorization.
guard granted else { return }
DispatchQueue.main.async {
application.registerForRemoteNotifications()
}
}
Regarding the “Can’t end BackgroundTask: no background task exists with identifier ...” message, as others have said, this can be a red herring, unrelated to what you’re doing.
Regarding your goal of trying to periodically retrieve the user’s location, rather than trying to keep your app running in the background with a timer, you should instead avail yourself of various services for updating the user location in the background, such as the visits location service or the significant change location service. With these services, the OS can wake your app when there is a change in the user’s location.
I had the same issue and figured out the cause and solution!
Apple has fixed this issue in iOS 13.4 GM though I have workaround for the earlier versions.
While you should embrace using scenes when your app is run under iOS 13 and later, you can fully opt-out while you still support iOS 12 or earlier.
First, completely remove the “Application Scene Manifest” entry from Info.plist.
If there is a scene delegate class, remove it.
If there are any scene related methods in your app delegate, remove those methods.
If missing, add the property var window: UIWindow? to your app delegate.
Your app should now only use the app delegate and under iOS 13 it should have the same life cycle as iOS 12.
Happy coding!
I think there is a bug working with xcode 11.2 and the swiftUI framework because I always get the
"Can't end BackgroundTask: no background task exists with
identifier..."
message even when my app is not working with background tasks!
The good news is that this only stops my app when executing from xcode; use the 'continue program execution' button and the app will be running again.
This has been fixed in iOS 13.4 GM.
https://developer.apple.com/forums/thread/121990

IOS 7 background fetch

I am developing a app that use the background fetch.
I would need that the function it execute in background each 5sec, but with the code that I saw in google, the SO decide when the function should to be call.
I would want the this function it execute each 5sec.
The my code is here:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// Override point for customization after application launch.
[[UIApplication sharedApplication] setMinimumBackgroundFetchInterval:UIApplicationBackgroundFetchIntervalMinimum];
return YES;
}
There's no way to do this. iOS is responsible to decide when it's best to give your app a chance to fetch content:
At appropriate times, the system gives background execution time to the apps that support this background mode, launching the app directly into the background if needed.
(From the docs)

Turning off "Use Autolayout" causes app to only run in portrait mode

I want my app to be compatible with iOS 5, so I had to disable "Use Autolayout" in the XIB files. The whole app is designed to be run in landscape mode. When the app is launched after disabling autolayout (whether in iOS 5 or iOS 6), the app always launches in portrait mode and refuses to rotate to landscape.
In Info.plist, Supported Interface Orientations (iPad) is set only to landscape. What am I doing wrong? This only occurs after disabling autolayout.
I was able to fix the issue in iOS 6 by using Ismael's answer.
- (NSUInteger)supportedInterfaceOrientations {
return UIInterfaceOrientationMaskLandscape;
}
I was able to fix it in iOS 5 by using the code below.
-(BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation {
return UIInterfaceOrientationIsLandscape(toInterfaceOrientation);
}
Add this to your controller:
- (NSUInteger)supportedInterfaceOrientations {
return UIInterfaceOrientationMaskLandscape;
}
Edit: If you don't want to support portrait, you should return NO in shouldAutorotate

Launching an app in landscape under ios6 while supporting all orientations

I have done a ton of research and am still unable to find a solution for this...
I have an app that supports all orientations. When the app is run on the iPad I want it to launch in landscape mode. The user can then rotate to portrait if they choose. Under ios5, I accomplished this by setting supported orientations for the iPad in the info.plist file to lansdcape left. I then used the shouldAutorotateToInterfaceOrientation method in each view controller to allow all orientations when the app was running.
I then changed my code to support the new orientation methods for iOS6 but when I ran the app on the iPad, it was not rotating at all. I then changed the info.plist file to support all orientations for the iPad. This solved the problem with the iPad not autorotating but now I can't figure out how to force the app to initially open in landscape mode. Any ideas?
Thanks in advance for any help you can give!
I ran into something similar recently, although my problem was that I wanted to force portrait in an iPhone app, but allow movies to play in landscape. Here's what I did:
Add a property to my app delegate to store the orientations I want to allow:
#property (nonatomic, assign) NSUInteger supportedOrientations;
Then in the app delegate, implemented the new iOS 6 method:
- (NSUInteger)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window {
return supportedOrientations;
}
On app launch I forced portrait:
self.supportedOrientations = UIInterfaceOrientationMaskPortrait;
And then once the app had finished launching and I'd shown my root view controller, I set it to support both orientations:
self.supportedOrientations = UIInterfaceOrientationMaskPortrait | UIInterfaceOrientationMaskLandscape;
I had to add the additional step of subclassing my UINavigationController to prevent rotation after that, because I wanted to allow landscape video but not rotation:
- (BOOL)shouldAutorotate {
return FALSE;
}
But that's just for info. You won't need that

iOS Handle notifications after starting app from not-running state

I've been trying to handle receiving notifications in my app, but its not really working out.
When I use didReceiveLocalNotification:(UILocalNotification *)notification. I can receive and use the notification that is used to enter the app, without any problems
However, this function is only fired when the app is already running (active, inactive, background, and possibly suspended, but I haven't tried that yet).
Now, there is this function didFinishLaunchingWithOptions:(NSDictionary *)launchOptions where you can use [launchOptions objectForKey:UIApplicationLaunchOptionsLocalNotificationKey] which would return a UILocalNotification.
However, when you launch the app from not-running state, this event is not fired. The LocalNotification then opens the app, but I can not use it in any way.
Now, my question is: How can I make it work, so I can receive and process notifications when starting the app, from a notification, when the app is in not-running state? Is there perhaps something I'm doing wrong here?
Here is a bit of sample code from my app:
First, the didFinishLaunchingWithOptions function, which, unfortunatly does not work. The function [sharedLocalNotificationsInstance processNotification:notification] is never launched...
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{
LocalNotificationsController *sharedLocalNotificationsInstance = [LocalNotificationsController sharedLocalNotificationsInstance];
[sharedLocalNotificationsInstance checkNotifications];
UILocalNotification *notification = [launchOptions objectForKey:UIApplicationLaunchOptionsLocalNotificationKey];
if ( notification != nil ) {
// Process the received notification
[sharedLocalNotificationsInstance processNotification:notification];
application.applicationIconBadgeNumber = 0;
}
return YES;
}
And a second piece of code: The didReceiveLocalNotification function, which works perfectly: I receive the notification, and [sharedLocalNotificationsInstance processNotification:notification] works perfectly.
- (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification{
// Used when the application launches from a notification
LocalNotificationsController *sharedLocalNotificationsInstance = [LocalNotificationsController sharedLocalNotificationsInstance];
// Process the received notification
[sharedLocalNotificationsInstance processNotification:notification];
}
This is how iOS handles local notification. It depends on which state of your app, e.g. active, running in background, or not started yet. The iOS will invoke either didFinishLaunchingWithOptions or didReceiveLocalNotification, or won't touch your app at all.
Please see this article for clarification - http://www.thekspace.com/home/component/content/article/62-uilocalnotification-demystified.html
<Matrix-Morpheus-Meme title="WHAT IF I TOLD YOU">
When an application is launched from the "not-running" state because a user tapped on a local notification alert, the application has been started by iOS, not by Xcode, thus IT IS NOT RUNNING UNDER THE DEBUGGER. You cannot breakpoint inside it and neither does NSLog() send anything to the Xcode console. Test with a UIAlertController.
</Matrix-Morpheus-Meme>