in our app we are logging (with an external analytics service) every time the user open our app.
However, we have noticed that there are many weird app sessions (almost 15% of total sessions).
Following the device timestamp of the events, the following methods are called:
application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?)
applicationDidBecomeActive(_ application: UIApplication)
viewDidAppear(_ animated: Bool) // App Splash Screen
applicationDidEnterBackground(_ application: UIApplication)
Looking at the timestamp, from didFinishLaunchingWithOptions to applicationDidEnterBackground there is just a very short delay (<1 sec).
Our hypothesis is that the system sometimes wakes up the app without it being actually opened and "seen" by the user. But we can't find any docs about this kind of use case, and we can't reproduce ourself the issue.
Did someone have experienced something similar?
EDIT:
I want to add that these suspicious sessions are often (but not always) linked to an app update.
I'm not sure...
I suppose if app wasn't user terminated nor suspended but was just put out of memory because other apps needed the memory, then almost a launch options can wake the app up if needed. Some examples:
geofence
interaction with push notification's actions. Example if you have userNotificationCenter(_:didReceive:withCompletionHandler:) implemented...
silent notification
background app refresh
Take a look at here and see what launch options are possible for your app. I'm not sure if all of them can actually launch the app or what...
If you want more visibility into this, then make sure for future you log the launchoptionskey that caused the app to get launched...
You need more info - I would extend your logging to dump the launchOptions dictionary in
application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?)
Looking at UIApplication.LaunchOptionsKey, there are a lot of options which may be involved. Note, as the help says: The contents of this dictionary may be empty in situations where the user launched the app directly
if let lop = launchOptions {
let toLog = lop.map{"\($0.0.rawValue) \($0.1)"}.joined(separator:"\n")
// log the options
...}
I did have an idea this might be related to previewing in AppSwitcher but that doesn't seem to trigger didFinishLaunchingWithOptions, unless you actually bring the app to the front. Maybe some split-screen stuff on iPad? It feels like the app is being invoked in a context where it can't get past the launch screen.
Related
As we all know, application(_:didFinishLaunchingWithOptions:) callback is called after app is almost ready to run, but there are cases, that push notifications, voip-push notifications, etc. do call this method as well, when app terminated to perform some tasks.
I need a solid answer, is there a way to tell when app launch was user-initiated, or something else did order app launch from background?
Is it safe to assume that the method parameter launchOptions: [UIApplication.LaunchOptionsKey : Any]? will always be nil on user-initiated launch?
Is it safe to assume that the method parameter launchOptions: [UIApplication.LaunchOptionsKey : Any]? will always be nil on user-initiated launch?
No, absolutely not. For example if the user launches your app by way of a Quick Action, that is user-initiated but the Quick Action will be in the launch options.
However, if the launchOptions is empty, you can pretty much rely on the fact that the user tapped the app's icon in the springboard.
I'm trying to call a method in my iOS app only when I enter in it from a dead state, meaning that the app isn't running in the background. I have searched for it and I came up with the method:
applicationWillEnterForeground:
But when I put some prints inside this method in my app delegate, the prints are not called at any time. Specifically what I want to do is to call a service to check wether the user's token access is valid or not, so I would show him the Log In view or the home view.
The app delegate method you're asking for is:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool
This is called when the app finishes launching, which occurs when it was previously not in a background or suspended state.
That said, for your use case, I'd put this in:
func applicationWillEnterForeground(_ application: UIApplication)
This gets called anytime the app enters the foreground which is more appropriate for this problem. If it's not being called (as you suggest), I expect that you haven't declared the method correctly (declare it exactly as above), or you haven't declared it on the UIApplicationDelegate.
For full details, including how to handle the new scene delegates in iOS 13+ (which are different, and tied to the UISceneDelegate), see Managing Your App's Life Cycle.
I want to clear the app data when the user removes the app from the app switcher by swiping up after the app is kept in the background about 3 to 4 hours.
Is there any function or delegate to know when the app is killed without coming into the foreground.
I want the login page to be open when the user kills the app from the app switcher. Otherwise, it should open the home page.
Solution for Swift:
In your AppDelegate.swift File add the following function (if not present):
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// clean your apps data here
cleanAppData()
//show the login
showLogin()
}
This function is only called if the app is "cold started".
This means:
it is called if the app was started for the first time
if the app was "killed" by iOS
if the app was "killed" by the user
it is not called if the app runs in the background and is opened again
Then add the following function (if not present) to AppDelegate.swift:
func applicationWillEnterForeground(_ application: UIApplication) {
// 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.
// show the homepage
showHomePage()
}
This function is only called if the app is "warm started" which means if the app was running before and sent to the background by the user.
You can save the current time in UIApplicationDelegate.applicationWillTerminate(_:) and UIApplicationDelegate.applicationDidEnterBackground(_:) to the user defaults. When the app comes back to the foreground or is launching you read this time from user defaults.
It's very important for my app to be notified every time the user kills my app (not moving it to the background, but actually quitting it altogether by double-tapping the Home button and swiping my app screenshot up). I know applicationWillTerminate() barely ever gets called, so I was wondering what the safest way is to be notified when a user will kill the app. It seems very unlikely that Apple hasn't provided ANY form of solution for this, as a lot of iOS users make it a custom to kill apps when they're done using it, so it would be really really REALLY weird if it would be impossible to catch this event. The only thing I need to do is fire off a URLRequest to send some updating instructions to my web service.
I get more consistency when I add an observer to handle UIApplicationWillTerminateNotification. It gets called when the user double-taps the Home button and swipe the app to kill it.
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool
{
NSNotificationCenter.defaultCenter().addObserver(self, selector:#selector(AppDelegate.onAppWillTerminate(_:)), name:UIApplicationWillTerminateNotification, object:nil)
return true
}
func onAppWillTerminate(notification:NSNotification)
{
print("onAppWillTerminate")
}
I have very strange behavior of APNS in my app. All my certificates, profiles etc is configured correctly and I actually can receive push notifications if I run my app first time on the device. But after few minutes they stop to come.
If I delete my app from device and run again from project, notifications come but only during short time. Then I have to delete it again, install again and so on...
I'm very wondering with this proplem. As I know there is no limitation to send push notifications and device token does not have expiration date (even if has,
few minutes are too short).
I have this first time and have no idea what a reason it can be...
Looks like you have called the fetching notifications methods not from
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool
This is one method of App Delegate which will always be called when your application launches,
Check out the descriptions of these methods. Hope this helps.