iOS Corespotlight search: When app is not running - ios

When the app is running, the continueUserActivity method gets called in which I handle the deep linking into the right location. However, when the app is not running, this function never gets called. I believe in the case when the app is not running, the call goes into application:didFinishLaunchingWithOptions:.
public override bool ContinueUserActivity(UIApplication application, NSUserActivity userActivity, UIApplicationRestorationHandler completionHandler)
{
if (userActivity.UserInfo.ContainsKey(CSSearchableItem.ActivityIdentifier))
{
// do stuff to handle deep link
}
}
The above implementation works fine when the app is backgrounded, but when I kill it the search results no longer deep link correctly.
Any clue on how to handle this in application:didFinishLaunchingWithOptions:? Is there a way to tell if the app is launched from a corespotlight search item specifically?

I just checked in my app by adding an alert to both methods.
When the app is running only the continuation method is called. When the app is not running both methods will be called.

Related

AppDelegate ContinueUserActivity not called when launching app from deep link, Firebase SDK is to blame

In my AppDelegate class I'm trying to handle deep links that launch my Xamarin iOS app, so that I can navigate the user to the proper place in the app based on the url. I'm overriding all of the ContinueUserActivity and OpenUrl methods, however none of these methods are ever called (either when the app is closed or just suspended.) I'm testing by including the deep link (https://example.com/path1/path2) in a iOS Calendar event, then tapping on the link on my iPhone 6 (running iOS 12.3.1) while the app is running in debug mode. My app does open when the link is tapped, but none of the break points are hit in any of the overridden methods.
public override bool ContinueUserActivity (UIApplication application, NSUserActivity userActivity, UIApplicationRestorationHandler completionHandler) {
return true;
}
public override bool OpenUrl (UIKit.UIApplication app, Foundation.NSUrl url, Foundation.NSDictionary options) {
return true;
}
public new bool OpenUrl (UIKit.UIApplication app, Foundation.NSUrl url, UIKit.UIApplicationOpenUrlOptions options) {
return true;
}
public override bool OpenUrl (UIApplication application, NSUrl url, string sourceApplication, NSObject annotation) {
return true;
}
I think that the universal links are set up correctly (associated domains, etc...), otherwise it wouldn't be launching my app. Also, I've confirmed that my FinishedLaunching method returns true, as I read elsewhere that if this returns false then ContinueUserActivity and OpenUrl aren't called. Other overridden methods in AppDelegate like OnActivated and WillContinueUserActivity are called, but not the ones that I need to get at the deep link url.
Is this a Xamarin iOS bug? Or is there something I'm doing incorrectly? I'm using the latest version of Xamarin iOS (12.8.0.2).
EDIT: A little more info... It turns out that the Firebase SDK is to blame for breaking deep links. If I disable it, then clicking on a deep link will successfully call ContinueUserActivity. However, as soon as I call Firebase.Core.App.Configure(), then subsequent deep link clicks will still open the app but no longer call ContinueUserActivity. I'm not sure how to work around this issue, as I need Firebase for Analytics (Google Analytics is going away soon...)
The credit goes to #Andrew McKinley, but for others who run into the same issue the resolution is to add a new key to your Info.plist file:
Key: FirebaseAppDelegateProxyEnabled
Type: Boolean
Value: No (false)
After that Firebase stops hijacking handling of deep link urls, so AppDelegate.ContinueUserActivity is correctly called when a deep link is clicked.

iOS - How to guarantee that applicationWillTerminate will be executed

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.

Call order of performActionForShortcutItem vs applicationWillEnterForeground

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
}

Programmatically Terminate an iOS App Extension [duplicate]

At some point in my application I have done this exit(0) which crashes my app. But I haven't figured out what method gets called when this executes.
I've put messages in:
(void)applicationWillTerminate:(UIApplication *)application
(void)applicationDidEnterBackground:(UIApplication *)application
But none of this seem to get called! Any idea about what method is called when exit(0) is done?
From Apple's Human User Guidelines...
Don’t Quit Programmatically
Never quit an iOS application programmatically because people tend to
interpret this as a crash. However, if external circumstances prevent
your application from functioning as intended, you need to tell your
users about the situation and explain what they can do about it.
Depending on how severe the application malfunction is, you have two
choices.
Display an attractive screen that describes the problem and suggests a
correction. A screen provides feedback that reassures users that
there’s nothing wrong with your application. It puts users in control,
letting them decide whether they want to take corrective action and
continue using your application or press the Home button and open a
different application
If only some of your application's features are not working, display
either a screen or an alert when people activate the feature. Display
the alert only when people try to access the feature that isn’t
functioning.
If you've decided that you are going to quit programmatically anyway...
In C, exit(0) will halt execution of the application. This means that no delegate methods or exception handlers will be called. So, if the goal is to make sure that some code gets called when the closes, even on a forced close, there may be another option. In your AppDelegate implement a custom method called something like -(void)applicaitonIsgoingAway. Call this method from within anywhere you want your exiting code to be called:
applicationWillTerminate
applicationDidEnterBackground
onUncaughtException
The first two are ones that you already mentioned in your question. The third can be a catch-all of sorts. It's a global exception handler. This next bit comes from a question on that very topic.
This exception handler will get called for any unhanded exceptions (which would otherwise crash your app). From within this handler, you can call applicaitonIsgoingAway, just like in the other 2 cases. From the other question that I mentioned above, you can find an answer similar to this.
void onUncaughtException(NSException* exception)
{
[[AppDelegate sharedInstance] applicationIsgoingAway];
}
But in order for this to work, you need to set this method up as the exception handler like so...
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
NSSetUncaughtExceptionHandler(&onUncaughtException);
//There may already be more code in this method.
}
Now, you can quit the app programmatically by calling NSAssert(FALSE, #"Quitting the app programmatically."); As long as there is no other exception handler in place to catch this, your app will begin to crash, and your exception handler code will be called. in-turn calling applicationIsGoingAway.
When you call exit(0) you immediately terminate your application. 0 is a status code which means successful termination.
No other method is called, you application just dies. As a result end user may think app is just crashed.
Apple discourages you to call exit anywhere.
exit(0) is a C function that terminates your app's process therefore none of the application delegates methods will be called, the app will be killed immediately. Apple recommends strongly against your app quitting because it appears broken to the user.
There is no Apple-supported method to terminate your application programmatically. Calling exit is certainly out of the question. This causes all sorts of bugs (for example the multitasking switcher will break badly) as well as simply being wrong.
If you are trying to disable multitasking, you can do this with the UIApplicationExitsOnSuspend key in your Info.plist file (the title for the key is "Application does not run in background").
Other than that, it's up to your users to press the home button to close your application.
these methods will be called but you cannot use exit(0) you will need to press the back button to close your app then these methods will be called

call exit(0) in iphone app

At some point in my application I have done this exit(0) which crashes my app. But I haven't figured out what method gets called when this executes.
I've put messages in:
(void)applicationWillTerminate:(UIApplication *)application
(void)applicationDidEnterBackground:(UIApplication *)application
But none of this seem to get called! Any idea about what method is called when exit(0) is done?
From Apple's Human User Guidelines...
Don’t Quit Programmatically
Never quit an iOS application programmatically because people tend to
interpret this as a crash. However, if external circumstances prevent
your application from functioning as intended, you need to tell your
users about the situation and explain what they can do about it.
Depending on how severe the application malfunction is, you have two
choices.
Display an attractive screen that describes the problem and suggests a
correction. A screen provides feedback that reassures users that
there’s nothing wrong with your application. It puts users in control,
letting them decide whether they want to take corrective action and
continue using your application or press the Home button and open a
different application
If only some of your application's features are not working, display
either a screen or an alert when people activate the feature. Display
the alert only when people try to access the feature that isn’t
functioning.
If you've decided that you are going to quit programmatically anyway...
In C, exit(0) will halt execution of the application. This means that no delegate methods or exception handlers will be called. So, if the goal is to make sure that some code gets called when the closes, even on a forced close, there may be another option. In your AppDelegate implement a custom method called something like -(void)applicaitonIsgoingAway. Call this method from within anywhere you want your exiting code to be called:
applicationWillTerminate
applicationDidEnterBackground
onUncaughtException
The first two are ones that you already mentioned in your question. The third can be a catch-all of sorts. It's a global exception handler. This next bit comes from a question on that very topic.
This exception handler will get called for any unhanded exceptions (which would otherwise crash your app). From within this handler, you can call applicaitonIsgoingAway, just like in the other 2 cases. From the other question that I mentioned above, you can find an answer similar to this.
void onUncaughtException(NSException* exception)
{
[[AppDelegate sharedInstance] applicationIsgoingAway];
}
But in order for this to work, you need to set this method up as the exception handler like so...
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
NSSetUncaughtExceptionHandler(&onUncaughtException);
//There may already be more code in this method.
}
Now, you can quit the app programmatically by calling NSAssert(FALSE, #"Quitting the app programmatically."); As long as there is no other exception handler in place to catch this, your app will begin to crash, and your exception handler code will be called. in-turn calling applicationIsGoingAway.
When you call exit(0) you immediately terminate your application. 0 is a status code which means successful termination.
No other method is called, you application just dies. As a result end user may think app is just crashed.
Apple discourages you to call exit anywhere.
exit(0) is a C function that terminates your app's process therefore none of the application delegates methods will be called, the app will be killed immediately. Apple recommends strongly against your app quitting because it appears broken to the user.
There is no Apple-supported method to terminate your application programmatically. Calling exit is certainly out of the question. This causes all sorts of bugs (for example the multitasking switcher will break badly) as well as simply being wrong.
If you are trying to disable multitasking, you can do this with the UIApplicationExitsOnSuspend key in your Info.plist file (the title for the key is "Application does not run in background").
Other than that, it's up to your users to press the home button to close your application.
these methods will be called but you cannot use exit(0) you will need to press the back button to close your app then these methods will be called

Resources