So, i have an app that has server state, and i refresh it by a timeout value and checking that timeout in applicationWillEnterForeground, reloading if timeout has expired.
This has worked well up until now.
I now want to implement new force touch shortcut action that performs a server operation. However, i don’t want the status-fetch operation to happen at the same time as the shortcut action. This is not a problem when the app is launched through a shortcut, but when transitioning from inactive -> active, i could end up starting one server operation in the applicationWillEnterForeground, and another in performActionForShortcutItem, which is not optimal.
What i'm after is to only potentially refresh my state if the app is not (re)launched as a result of a force touch press.
I thought i would solve this by a bool, “isHandlingShortcut” that i set in performActionForShortcutItem and then check in applicationWillEnterForeground, and in that case skip my refresh - but turns out it doesn’t work since applicationWillEnterForeground is called first!
Is there any way i can find out that i’ve (re)launched the app via a shortcut in applicationWillEnterForeground?
EDIT: perhaps i could move my "refresh"-logic to applicationDidBecomeActive? That one is called after performActionForShortcutItem.
According to the documentation:
[...] check, on launch, whether your app is being launched via a quick
action. Perform this check in your
application:willFinishLaunchingWithOptions: or
application:didFinishLaunchingWithOptions: method by checking for the
UIApplicationLaunchOptionsShortcutItemKey launch option key. The
UIApplicationShortcutItem object is available as the value of the
launch option key.
https://developer.apple.com/documentation/uikit/uiapplicationdelegate/1622935-application
What I'm doing is checking the shortcut that comes in didFinishLaunchingWithOptions so later in performActionForShortcutItem I know whether the app was launched due to the shortcut or the app was already launched.
In didFinishLaunchingWithOptions (executed if shourtcut launches the app):
self.launchShortcutItem = launchOptions[UIApplicationLaunchOptionsShortcutItemKey];
And later in performActionForShortcutItem:
if (self.launchShortcutItem) {
// app launched due to shortcut
} else {
// app was already launched
}
Related
Just starting out iOS development.
When starting my app, I'd like it to check if the user has a known account and if they do, "login" by acquiring an access token and then display the main / first view. If they don't have an account or if login fails, they should be redirected to a login / registration screen.
Initially I thought I'd hide this process (check for account + call to get access token) behind a splash screen, but apparently this is against Apples guidelines. Is there a common / recommended way to do this on iOS?
By referencing to application:didFinishLaunchingWithOptions: you can read that this method is good for initializing.
Use this method (and the corresponding
application:willFinishLaunchingWithOptions: method) to complete your
app’s initialization and make any final tweaks. This method is called
after state restoration has occurred but before your app’s window and
other UI have been presented. At some point after this method returns,
the system calls another of your app delegate’s methods to move the
app to the active (foreground) state or the background state. This
method represents your last chance to process any keys in the
launchOptions dictionary. If you did not evaluate the keys in your
application:willFinishLaunchingWithOptions: method, you should look at
them in this method and provide an appropriate response. Objects that
are not the app delegate can access the same launchOptions dictionary
values by observing the notification named
UIApplicationDidFinishLaunchingNotification and accessing the
notification’s userInfo dictionary. That notification is sent
shortly after this method returns.
There may be several ways. But using singleton for token and launching your app is one of the best ways. As you might not need to use that launcher class again. Just for checking user have token and if yes then show main view otherwise login view.
Hope it helps you !!
Is there A way to guarantee that the applicationWillTerminate method in the AppDelegate delegate will be hit? Something like a key in the info.plist file, etc..?
My goal: I'm working in a beacon app, the piece of code is in this article. My problem is that the message from the didEnterRegion keeps poping even when i'm beside the beacon. To solve that I'm setting a flag to control the message. My code below:
if(!UserDefaults.standard.bool(forKey: Constants.EnterZoneMsgShowName)){
let notification = UILocalNotification()
notification.alertBody = "Hi, you are about to arrive at CIDMA's office. Please open de demo app and turn on the bluetooth on your device to enrich your experience. "
UIApplication.shared.presentLocalNotificationNow(notification)
UserDefaults.standard.set(true, forKey: Constants.EnterZoneMsgShowName)
}
I want to set this flag to false when I close the app. I tried to put it at the applicationWillTerminate but this method is not hit every time.
I would like to know how to guarantee that this code will be hit or if there is a better place to put the code: UserDefaults.standard.set(false, forKey: Constants.EnterZoneMsgShowName)
applicationWillTerminate(_:) - Tells the delegate when the app is about
to terminate.
For apps that do not support background execution or are linked against iOS 3.x or earlier, this method is always called when the user quits the app.
For apps that support background execution, this method is generally not called when the user quits the app because the app simply moves to the background in that case. However, this method may be called in situations where the app is running in the background (not suspended) and the system needs to terminate it for some reason.
What you want to call is applicationDidEnterBackground if your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
I am using swift 2 and Xcode7 for iOS9. I want to know if I can maintain a function (that checks for something to delete) running "forever" even if the user kills the app?
I am deleting contacts from the contact list according to some rules and time. It is running ok, but just with the app opened or in second plan. I want to make this app capable to delete those contacts even when the user kills it.
You can use background thread when user opens the app. But if the app will be terminated, there is no option to run functions.
Look for the app lifecycle here and redesign your architecture: https://developer.apple.com/library/ios/documentation/iPhone/Conceptual/iPhoneOSProgrammingGuide/TheAppLifeCycle/TheAppLifeCycle.html
If the user kills the app it is no longer running, therefore your code is no longer running. There is no such state that your code/app can be in where this is possible.
By "kill", I don't mean "background". Backgrounding an app is different. Check Apple's docs on the different app states (see m.albin's answer) as well as various strategies for handling those app states.
func applicationWillTerminate(_ application: UIApplication) {
// Called when the user discards a scene session.
// If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions.
// Use this method to release any resources that were specific to the discarded scenes, as they will not return.
print("Application Will Terminate")
}
I am wondering if this is intended by Apple that these lifecycle methods are called upon using TouchID functionality.
Is there any possibility to check if the touchID process is calling these methods (I want to avoid things like a BOOL in app delegate which is set if touchID input is currently shown or not..)
br
Im guessing the problem you're having is that you have code in applicationWillResignActive and applicationDidBecomeActive that affects the view controller that requests Touch ID-validation and that it sets off a tricky loop.
What you need to do is move those calls to applicationDidEnterBackground and applicationWillEnterForeground, because they're not invoked when the Touch ID-mechanism is called.
To explain the sequence, when your app starts the following sequence executes:
applicationDidBecomeActive
..other stuff your app does
Your app invokes Touch ID, which fires:
applicationWillResignActive
... Your app is disabled until the user verifies fingerprint (fails or
succeeds) ...
applicationDidBecomeActive
If you have code in applicationDidBecomeActive -or- applicationWillResignActive that affects Touch ID, you will create an endless loop or worse, you will create code that is riddled with flags and special cases.
Instead you should invoke Touch ID in two cases:
When your app starts (usually in didFinishLaunchingWithOptions)
When your app's applicationWillEnterForeground is called.
You can create a static bool in your login script that you can check from your AppDelegate!
static var isShowingTouchID = false
Then before your context.evaluatePolicy call, you can set it to true, and in the callback function, set it to false. I believe you use the reply argument to set a callback to this.
Then in your AppDelegate, check the status of this bool.
Originally I was using a public variable in AppDelegate and setting that, but I feel similarly in that I didn't want to do that. Frankly, I don't like this solution either, but it was the only one I could come up.
I even tried overriding viewDidDisappear in my login script, but I quickly found out that it was not being called even when I tapped "Cancel" on the touch ID prompt.
If anyone has a better solution, I would love to know.
I have an iOS application where I need to persist a set of data after the application HARD CLOSES (when the user double clicks the Home button and slides the application upwards). Then, when the application comes back to the foreground, I need to fetch that data and do something with it. I'm just not sure where I need to put that logic for Application Hard Close and Resuming the Application.
In your AppDelegate
When your app is going to be closed, but still in Multitasking menu the following method is getting called
-(void)applicationWillResignActive:(UIApplication*)application
If after 3 minutes user doesn re-open your app this method is going to be called
-(void)applicationDidEnterBackground:(UIApplication*)application
If user re-opens your app from multitasking menu the following method is getting called
-(void)applicationWillEnterForeground:(UIApplication*)application
If user is going to close your app from multitasking menu this method is getting called(you will have limited time to perform some logic here)
-(void)applicationWillTerminate:(UIApplication*)application
When user presses home twice applicationWillResignActive and applicationDidEnterBackground is called. You can save data here.
When user opens app, applicationWillEnterForeground is called, you get data which you save and process.
When a user hard-closes the application, the UIViewController's Delegate's method called applicationWillTerminate. Here I can catch and save the model data before it's all destroyed.
Then when a user launches the application again, there are many choices like didFinishLaunchingWithOptions where I can grab the data stored to disk.
Your app no longer gets an applicationWillTerminate call ever. You are simply silently killed while in the background. You have to write your app to save state in the applicationDidEnterBackground handler, as nmh describes. That's your only option.