iOS - Can I open my VoIP app on answering call using Callkit? - ios

I'm planning to create an iOS VoIP app(not made any iOS app before). I was reading about Callkit in IOS by which one can make his app receive phone call through iPhone native call screen.
I read Callkit api here where it is mentioned that one can know if a call is answered.
Going through this tutorial and here is the code which detects the call is answered:
-(void)reportIncomingCallWithHandle:(NSString *)handle
success:(void (^)())success
failure:(void (^)(NSError * error))failure {
CXCallUpdate *update = [self newCallUpdateWithHandle:handle];
self.callId = [NSUUID UUID];
[self.provider reportNewIncomingCallWithUUID:self.callId update:update completion:^(NSError * _Nullable error) {
if (error) {
if (failure) failure(error);
} else {
if (success) {
success();
}
}
}];
}
See the success block. So is there is a way to open my app when this success block executed? Or can I override default buttons on caller screen to open my app?
I know there is no way to open an app on receiving any kind of notification, or event trigger. So thought may be there is some way if I can do the same using Callkit
I Googled everything but found no clue regarding my above queries. Please help me if it is possible or not.

I encountered the same issue. The behavior varies depending on if the device is locked or not.
Locked: System calling screen appears. You can run the app in the background including view transitions. However, the user will only see the system calling screen although your app is kind of presented underneath the view. As the device is locked, deep links does not work as well.
Unlocked: Calling screen is the same but once the user answers the call, the app will be presented.
As you may know, we can change the icon of the button on the calling screen which opens the app, and that's the best we can do as of now.

You can not open your own VoIP app or custom UI of your App from CallKit. Use can use it in a way as Whatsapp does.
Means you can awake your app from background without using local notification. And OS will show the default incoming screen. You need not to handle anything during call. CallKit is specially made for enhancing VoIP apps by receiving calls in background, by making outgoing calls, by managing Call directory and blocking of users.

Related

Jitsi iOS sdk and Callkit

I am working with JitsiMeet iOS (Create Jitsi Meet Framework for native iOS application and integrate in Xcode Project) for video call implementation in an application. For background mode calling I am trying to achieve a skype like interface. Where user receives an audio call can start talking right away by accepting that call. Hence when I receive PKPushNotification, I trigger this code to initiate calling screen:
[JMCallKitProxy reportNewIncomingCallWithUUID:activeCallUUID_ handle:message.messageText displayName:message.senderName hasVideo:false completion:^(NSError * _Nullable error) {
if (error != nil) NSLog(#"%s error = %#", __PRETTY_FUNCTION__, error.localizedDescription);
}];
This works fine and call get triggered as native call. Then I have implemented then I have implemented JMCallKitListener and inside performAnswerCallWithUUID I tried to initialize my JitsiViewController to joint the call group.
But problem is when application is in background these listeners doesn't trigger. Although they work fine when app is active.

Refreshing Watch App From Watch

I started messing around with the Watch OS framework today and wanted to throw together a quick app, but have come to a couple questions.
I made an iOS app that just shows the current battery % as well as the state of the battery. I then wanted to show that over on the watch.
The only time the watch app will update is when I totally close the iOS app, then open it, while the watch app is active. How do I allow my watch app to be updated if I open it after the iOS app has been opened?
This kind of goes with number 2. But how do I allow the watch app to fetch info from the iOS app, after it has been in the background? As an example, lets say the iOS app has been in the background and I wanted to fetch the battery % without opening the iOS app to the foreground.
Some side notes on how I set this up -
Within the iOS app, in the viewDidLoad method, I start my session.
if ([WCSession isSupported]) {
wcSession = [WCSession defaultSession];
wcSession.delegate = self;
[wcSession activateSession];
}
Then call my method to update the actual battery % and state. Within that method, I have this which sends the info over to the watch:
NSDictionary *message = #{
#"message" : [NSString stringWithFormat:#"%#", [numberFormatter stringFromNumber:levelObj]],
#"message_2" : [NSString stringWithFormat:#"%ld",(long)[UIDevice currentDevice].batteryState],
};
[wcSession sendMessage:message replyHandler:nil errorHandler:^(NSError * _Nonnull error) {
NSLog(#"%#", error.localizedDescription);
}];
I also call this same method in the viewDidAppear, so I don't have to relaunch the app completely, to allow refreshing of the watch counterpart.
On the watch side I have the viewWillActivate method with the same activation as the iOS side as well as the method to handle what the watch app receives from the iOS side. But it will only update when I restart the iOS app fully.
- (void)session:(WCSession *)session didReceiveMessage:(NSDictionary<NSString *,id> *)message {
NSLog(#"Message recieved!");
[_batteryLevelLabelW setText:message[#"message"]];
}
Also in there is the code to handle the battery state message, which is a bit long.
I hope I gave a good amount of information to help.
According to documentation:
Use the send​Message(_:​reply​Handler:​error​Handler:​) or
send​Message​Data(_:​reply​Handler:​error​Handler:​) method to
transfer data to a reachable counterpart. These methods are intended
for immediate communication between your iOS app and WatchKit
extension. The is​Reachable property must currently be true for these
methods to succeed.
If watchapp is not foreground, message will not be delivered since isReachable is false.
Method you should use is update​Application​Context(_:​) - it will wait till watch app will be opened at foreground and only then will be delivered.

iOS: How to show alertview while app in background? [duplicate]

I want to show an alert view when my iOS app is in the background (and it's using location).
For example, the Uber Partner (Driver) app shows an alert and plays a sound even when:
I have turned off notifications!
My iPhone is in Silent mode!
I am aware of the local notifications approach and it doesn't work if the user turns off/ changes the Notifications in Settings. I am looking for something different.
Actions performed to reach the above state:
Go online on Uber Partner App (you are the driver!)
Disable Notifications for the app in Settings
Move the app to background and wait for a Ride Request
After some time, a ride Request is popped up as an Alert view and a sound is played in the background
Of course, silent remote notifications can be tapped in by the app using the didReceiveRemoteNotification: fetchCompletionHandler: API even if the user disables Notifications in Settings. But, how the alert is popped up, that's what I am trying to find out.
I would imagine that Uber has some special permissions or uses some private API that allow them to achieve this behavior without using local notifications. While I don't know how Uber implemented this in their partner app, I can talk a little bit about how alerts work on the home screen.
SpringBoard is the singleton class that manages the SpringBoard application (SpringBoard.app), the application launcher for the iPhone. SpringBoard doesn't use the standard UIAlertView/UIAlertController classes, since they don't participate in the SpringBoard-wide alert system. iOS 5 introduced SBAlertItem the which is used to display UIAlertViews on SpringBoard (Battery Notification Alerts, Sim Unlock Alert, etc.). Apple uses SBAlertItem for their lock and home screen alerts, I'll be working on the assumption that Uber is using an SBAlertItem for this answer.
SBAlertItem has a protected ivar UIAlertView *_alertSheet. Assuming this acts as a normal UIAlertView, you should be able to change the properties on this alert to fit your needs. I would also read through saurik's Cydia Substrate project, specifically MobileSafety.mm to see some use cases. I've also found noweibogoodsleep which provides an example of using SBAlertItem on the SpringBoard.
I've also found SBUserNotificationAlert, a subclass of SBAlertItem. This appears to have more methods to facilitate alert customization that may fit your needs better than the standard SBAlertItem.
I realize hooking into private APIs is probably not what you were expecting when asking this question. Since I don't know how Uber works, I can only provide an answer from my personal experience working with the runtime and jailbroken devices.
After some static analysis of the binary, it became clear that they are not using PKPushRegistry (VOIP), undocumented NSNotificationCenter calls or SBAlertItem.
Took a little while to find it, but they are actually using CFUserNotification for the alerts. The class is documented for Mac, but private for iOS.
I found the usage by doing this:
nm -u ~/Downloads/Payload/UberDriver.app/UberDriver | grep CFUserNotification
The output is:
_CFUserNotificationCancel
_CFUserNotificationCreate
_CFUserNotificationCreateRunLoopSource
_kCFUserNotificationAlertHeaderKey
_kCFUserNotificationAlertMessageKey
_kCFUserNotificationAlertTopMostKey
_kCFUserNotificationAlternateButtonTitleKey
_kCFUserNotificationDefaultButtonTitleKey
_kCFUserNotificationSoundURLKey
If I grep for PKPushRegistry or for SBAlertItem, both return no results.
Can use the class by importing this file to your project.
UPDATE
I have 'working' code, however it immediately calls the callback function (responseFlags set to kCFUserNotificationCancelResponse) without showing the alert..
I am using the same keys and calls as the Uber app (compare code below to list above), so there must be something extra. Will keep looking.
#import "CFUserNotification.h"
#interface AppDelegate ()
#property (nonatomic) CFRunLoopSourceRef runLoopSource;
#property (nonatomic) CFUserNotificationRef notification;
#end
#implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
SInt32 error;
NSDictionary *keys = #{(__bridge NSString*)kCFUserNotificationAlertHeaderKey: #"Hello",
(__bridge NSString*)kCFUserNotificationAlertMessageKey: #"World",
(__bridge NSString*)kCFUserNotificationAlertTopMostKey: #YES,
(__bridge NSString*)kCFUserNotificationDefaultButtonTitleKey: #"asdf",
(__bridge NSString*)kCFUserNotificationAlternateButtonTitleKey: #"asdf",
};
self.notification = CFUserNotificationCreate(NULL, 10, kCFUserNotificationPlainAlertLevel, &error, (__bridge CFDictionaryRef)keys);
self.runLoopSource = CFUserNotificationCreateRunLoopSource(NULL, self.notification, NotificationCallback, 0);
CFRunLoopAddSource(CFRunLoopGetMain(), self.runLoopSource, kCFRunLoopCommonModes);
return YES;
}
void NotificationCallback(CFUserNotificationRef userNotification, CFOptionFlags responseFlags) {
NSLog(#"got response: %lu", responseFlags);
}
Your question missed the most important part regarding the "Uber Partner" app that would make things a lot clearer. The "Uber Partner" app is an Enterprise app and is not restricted to the Appstore guide lines.
it didn't got any special permissions like other answers suggested.
It is possible to display an alert view using SBAlertItem regardless of Sound \ Notification settings but if your end goal is to make it to the appstore, unfortunately, your app will be rejected for using private API.

Show an alert when iOS app is in the background

I want to show an alert view when my iOS app is in the background (and it's using location).
For example, the Uber Partner (Driver) app shows an alert and plays a sound even when:
I have turned off notifications!
My iPhone is in Silent mode!
I am aware of the local notifications approach and it doesn't work if the user turns off/ changes the Notifications in Settings. I am looking for something different.
Actions performed to reach the above state:
Go online on Uber Partner App (you are the driver!)
Disable Notifications for the app in Settings
Move the app to background and wait for a Ride Request
After some time, a ride Request is popped up as an Alert view and a sound is played in the background
Of course, silent remote notifications can be tapped in by the app using the didReceiveRemoteNotification: fetchCompletionHandler: API even if the user disables Notifications in Settings. But, how the alert is popped up, that's what I am trying to find out.
I would imagine that Uber has some special permissions or uses some private API that allow them to achieve this behavior without using local notifications. While I don't know how Uber implemented this in their partner app, I can talk a little bit about how alerts work on the home screen.
SpringBoard is the singleton class that manages the SpringBoard application (SpringBoard.app), the application launcher for the iPhone. SpringBoard doesn't use the standard UIAlertView/UIAlertController classes, since they don't participate in the SpringBoard-wide alert system. iOS 5 introduced SBAlertItem the which is used to display UIAlertViews on SpringBoard (Battery Notification Alerts, Sim Unlock Alert, etc.). Apple uses SBAlertItem for their lock and home screen alerts, I'll be working on the assumption that Uber is using an SBAlertItem for this answer.
SBAlertItem has a protected ivar UIAlertView *_alertSheet. Assuming this acts as a normal UIAlertView, you should be able to change the properties on this alert to fit your needs. I would also read through saurik's Cydia Substrate project, specifically MobileSafety.mm to see some use cases. I've also found noweibogoodsleep which provides an example of using SBAlertItem on the SpringBoard.
I've also found SBUserNotificationAlert, a subclass of SBAlertItem. This appears to have more methods to facilitate alert customization that may fit your needs better than the standard SBAlertItem.
I realize hooking into private APIs is probably not what you were expecting when asking this question. Since I don't know how Uber works, I can only provide an answer from my personal experience working with the runtime and jailbroken devices.
After some static analysis of the binary, it became clear that they are not using PKPushRegistry (VOIP), undocumented NSNotificationCenter calls or SBAlertItem.
Took a little while to find it, but they are actually using CFUserNotification for the alerts. The class is documented for Mac, but private for iOS.
I found the usage by doing this:
nm -u ~/Downloads/Payload/UberDriver.app/UberDriver | grep CFUserNotification
The output is:
_CFUserNotificationCancel
_CFUserNotificationCreate
_CFUserNotificationCreateRunLoopSource
_kCFUserNotificationAlertHeaderKey
_kCFUserNotificationAlertMessageKey
_kCFUserNotificationAlertTopMostKey
_kCFUserNotificationAlternateButtonTitleKey
_kCFUserNotificationDefaultButtonTitleKey
_kCFUserNotificationSoundURLKey
If I grep for PKPushRegistry or for SBAlertItem, both return no results.
Can use the class by importing this file to your project.
UPDATE
I have 'working' code, however it immediately calls the callback function (responseFlags set to kCFUserNotificationCancelResponse) without showing the alert..
I am using the same keys and calls as the Uber app (compare code below to list above), so there must be something extra. Will keep looking.
#import "CFUserNotification.h"
#interface AppDelegate ()
#property (nonatomic) CFRunLoopSourceRef runLoopSource;
#property (nonatomic) CFUserNotificationRef notification;
#end
#implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
SInt32 error;
NSDictionary *keys = #{(__bridge NSString*)kCFUserNotificationAlertHeaderKey: #"Hello",
(__bridge NSString*)kCFUserNotificationAlertMessageKey: #"World",
(__bridge NSString*)kCFUserNotificationAlertTopMostKey: #YES,
(__bridge NSString*)kCFUserNotificationDefaultButtonTitleKey: #"asdf",
(__bridge NSString*)kCFUserNotificationAlternateButtonTitleKey: #"asdf",
};
self.notification = CFUserNotificationCreate(NULL, 10, kCFUserNotificationPlainAlertLevel, &error, (__bridge CFDictionaryRef)keys);
self.runLoopSource = CFUserNotificationCreateRunLoopSource(NULL, self.notification, NotificationCallback, 0);
CFRunLoopAddSource(CFRunLoopGetMain(), self.runLoopSource, kCFRunLoopCommonModes);
return YES;
}
void NotificationCallback(CFUserNotificationRef userNotification, CFOptionFlags responseFlags) {
NSLog(#"got response: %lu", responseFlags);
}
Your question missed the most important part regarding the "Uber Partner" app that would make things a lot clearer. The "Uber Partner" app is an Enterprise app and is not restricted to the Appstore guide lines.
it didn't got any special permissions like other answers suggested.
It is possible to display an alert view using SBAlertItem regardless of Sound \ Notification settings but if your end goal is to make it to the appstore, unfortunately, your app will be rejected for using private API.

Proper way to exit iPhone application?

I am programming an iPhone app, and I need to force it to exit due to certain user actions. After cleaning up memory the app allocated, what's the appropriate method to call to terminate the application?
On the iPhone there is no concept of quitting an app. The only action that should cause an app to quit is touching the Home button on the phone, and that's not something developers have access to.
According to Apple, your app should not terminate on its own. Since the user did not hit the Home button, any return to the Home screen gives the user the impression that your app crashed. This is confusing, non-standard behavior and should be avoided.
Have you tried exit(0)?
Alternatively, [[NSThread mainThread] exit], although I have not tried that it seems like the more appropriate solution.
exit(0) appears to a user as crashes, so show a confirmation message to user. After confirmation suspend(home button press programmatically) and wait 2 seconds while app is going background with animation then exit behind user's view
-(IBAction)doExit
{
//show confirmation message to user
UIAlertView* alert = [[UIAlertView alloc] initWithTitle:#"Confirmation"
message:#"Do you want to exit?"
delegate:self
cancelButtonTitle:#"Cancel"
otherButtonTitles:#"OK", nil];
[alert show];
}
-(void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
if (buttonIndex != 0) // 0 == the cancel button
{
//home button press programmatically
UIApplication *app = [UIApplication sharedApplication];
[app performSelector:#selector(suspend)];
//wait 2 seconds while app is going background
[NSThread sleepForTimeInterval:2.0];
//exit app when app is in background
exit(0);
}
}
Check the Q&A here: https://developer.apple.com/library/content/qa/qa1561/_index.html
Q: How do I programmatically quit my iOS application?
There is no API provided for gracefully terminating an iOS application.
In iOS, the user presses the Home button to close applications. Should your application have conditions in which it cannot provide its intended function, the recommended approach is to display an alert for the user that indicates the nature of the problem and possible actions the user could take — turning on WiFi, enabling Location Services, etc. Allow the user to terminate the application at their own discretion.
WARNING: Do not call the exit function. Applications calling exit will appear to the user to have crashed, rather than performing a graceful termination and animating back to the Home screen.
Additionally, data may not be saved, because -applicationWillTerminate: and similar UIApplicationDelegate methods will not be invoked if you call exit.
If during development or testing it is necessary to terminate your application, the abort function, or assert macro is recommended
Its not really a way to quit the program, but a way to force people to quit.
UIAlertView *anAlert = [[UIAlertView alloc] initWithTitle:#"Hit Home Button to Exit" message:#"Tell em why they're quiting" delegate:self cancelButtonTitle:nil otherButtonTitles:nil];
[anAlert show];
Go to your info.plist and check the key "Application does not run in background". This time when the user clicks the home button, the application exits completely.
Add UIApplicationExitsOnSuspend property on application-info.plist to true.
After some tests, I can say the following:
using the private interface : [UIApplication sharedApplication] will cause the app looking like it crashed, BUT it will call - (void)applicationWillTerminate:(UIApplication *)application before doing so;
using exit(0); will also terminate the application, but it will look "normal" (the springboard's icons appears like expected, with the zoom out effect), BUT it won't call the - (void)applicationWillTerminate:(UIApplication *)application delegate method.
My advice:
Manually call the - (void)applicationWillTerminate:(UIApplication *)application on the delegate.
Call exit(0);.
Your ApplicationDelegate gets notified of intentional quitting by the user:
- (void)applicationWillResignActive:(UIApplication *)application {
When I get this notification I just call
exit(0);
Which does all the work. And the best thing is, it is the useres intent to quit, which is why this should not be a problem calling it there.
On my Audio-App it was necessary to quit the app after people were syncing their device while the music was still playing. As soon as the syncing is complete I get a notification. But quitting the app right after that would actually look like a crash.
So instead I set a flag to REALLY quit the app on the next backgrounding action. Which is okay for refreshing the app after a sync.
My App has been rejected recently bc I've used an undocumented method. Literally:
"Unfortunately it cannot be added to the App Store because it is using a private API. Use of non-public APIs, which as outlined in the iPhone Developer Program License Agreement section 3.3.1 is prohibited:
"3.3.1 Applications may only use Documented APIs in the manner prescribed by Apple and must not use or call any private APIs."
The non-public API that is included in your application is terminateWithSuccess"
Apple say:
"Warning: Do not call the exit function. Applications calling exit will appear to the user to have crashed, rather than performing a graceful termination and animating back to the Home screen."
I think that this is a bad assumption. If the user tap a quit button and a message appears that say something like: "The application will now quit.", it doesn't appear to be crashed. Apple should provide a valid way to quit an application (not exit(0)).
You should not directly call the function exit(0) as it will quit the application immediately and will look like your app is crashed. So better to show users a confirmation alert and let them do this themselves.
Swift 4.2
func askForQuit(_ completion:#escaping (_ canQuit: Bool) -> Void) {
let alert = UIAlertController(title: "Confirmation!", message: "Do you want to quit the application", preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "Yes", style: UIAlertAction.Style.default, handler: { (action) in
alert.dismiss(animated: true, completion: nil)
completion(true)
}))
alert.addAction(UIAlertAction(title: "No", style: UIAlertAction.Style.cancel, handler: { (action) in
alert.dismiss(animated: true, completion: nil)
completion(false)
}))
self.present(alert, animated: true, completion: nil)
}
/// Will quit the application with animation
func quit() {
UIApplication.shared.perform(#selector(NSXPCConnection.suspend))
/// Sleep for a while to let the app goes in background
sleep(2)
exit(0)
}
Usage:
self.askForQuit { (canQuit) in
if canQuit {
self.quit()
}
}
This has gotten a good answer but decided to expand a bit:
You can't get your application accepted to AppStore without reading Apple's iOS Human Interface Guidelines well. (they retain the right to reject you for doing anything against them) The section "Don't Quit Programmatically" http://developer.apple.com/library/ios/#DOCUMENTATION/UserExperience/Conceptual/MobileHIG/UEBestPractices/UEBestPractices.html
is an exact guideline in how you should treat in this case.
If you ever have a problem with Apple platform you can't easily find a solution for, consult HIG. It's possible Apple simply doesn't want you to do it and they usually (I'm not Apple so I can't guarantee always) do say so in their documentation.
Hm, you may 'have to' quit the application if, say, your application requires an internet connection. You could display an alert and then do something like this:
if ([[UIApplication sharedApplication] respondsToSelector:#selector(terminate)]) {
[[UIApplication sharedApplication] performSelector:#selector(terminate)];
} else {
kill(getpid(), SIGINT);
}
We can not quit app using exit(0), abort() functions, as Apple strongly discourage the use of these functions. Though you can use this functions for development or testing purpose.
If during development or testing it is necessary to terminate your
application, the abort function, or assert macro is recommended
Please find this Apple Q&A thread to get more information.
As use of this function create impression like application is crashing. So i got some suggestion like we can display Alert with termination message to aware user about closing the app, due to unavailability of certain functionality.
But iOS Human Interface Guideline for Starting And Stopping App, suggesting that Never use Quit or Close button to terminate Application. Rather then that they are suggesting to display proper message to explain situation.
An iOS app never displays a Close or Quit option. People stop using an
app when they switch to another app, return to the Home screen, or put
their devices in sleep mode.
Never quit an iOS app programmatically. People tend to interpret this
as a crash. If something prevents your app from functioning as
intended, you need to tell users about the situation and explain what
they can do about it.
In addition to the above, good, answer I just wanted to add, think about cleaning up your memory.
After your application exits, the iPhone OS will automatically clean up anything your application left behind, so freeing all memory manually can just increase the amount of time it takes your application to exit.
- (IBAction)logOutButton:(id)sender
{
//show confirmation message to user
CustomAlert* alert = [[CustomAlert alloc] initWithTitle:#"Confirmation" message:#"Do you want to exit?" delegate:self cancelButtonTitle:#"Cancel" otherButtonTitles:#"OK", nil];
alert.style = AlertStyleWhite;
[alert setFontName:#"Helvetica" fontColor:[UIColor blackColor] fontShadowColor:[UIColor clearColor]];
[alert show];
}
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
if (buttonIndex != 0) // 0 == the cancel button
{
//home button press programmatically
UIApplication *app = [UIApplication sharedApplication];
[app performSelector:#selector(suspend)];
//wait 2 seconds while app is going background
[NSThread sleepForTimeInterval:2.0];
//exit app when app is in background
NSLog(#"exit(0)");
exit(0);
}
}
I used the [[NSMutableArray new] addObject:nil] approach mentioned above to force-quit (crash) the app without making a tell-tale exit(0) function call.
Why? Because my app uses certificate pinning on all network API calls to prevent man-in-the-middle attacks. These include the initialization calls my financial app makes on startup.
If certificate authentication fails, all of my initialization calls error out and leave my app in an indeterminate state. Letting the user go home and then back into the app doesn't help, as unless the app has been purged by the OS it's still uninitialized and untrustworthy.
So, in this one case, we deemed it best to pop an alert informing the user that the app is operating in an insecure environment and then, when they hit "Close", force quit the app using the aforementioned method.
[[UIApplication sharedApplication] terminateWithSuccess];
It worked fine and automatically calls
- (void)applicationWillTerminateUIApplication *)application delegate.
to remove compile time warning add this code
#interface UIApplication(MyExtras)
- (void)terminateWithSuccess;
#end
The user should decide when an app exits.
I don't think it is a good user interaction when an app quits. Therefore there is no nice API for it, only the home button has one.
If there is an error: Implement it better or Notify the user.
If there have to be a restart: Implement it better of Notify the user.
It sounds dumb, but it's bad practice to exit the app without letting the user decide and not notifying him. And since there is a home button for the user interaction, Apple states, there should not be 2 things for the same function (exiting an app).
Exit an app other way than the home button is really non-iOS-esque approach.
I did this helper, though, that use no private stuff:
void crash()
{ [[NSMutableArray new] addObject:NSStringFromClass(nil)]; }
But still not meant for production in my case. It is for testing crash reportings, or to fast restart after a Core Data reset. Just made it safe not to be rejected if function left in the production code.
It may be appropriate to exit an app if it is a long lived app that also executes in the background, for example to get location updates (using the location updates background capability for that).
For example, let's say the user logs out of your location based app, and pushes the app to the background using the home button. In this case your app may keep running, but it could make sense to completely exit it. It would be good for the user (releases memory and other resources that don't need to be used), and good for app stability (i.e. making sure the app is periodically restarted when possible is a safety net against memory leaks and other low memory issues).
This could (though probably shouldn't, see below :-) be achieved with something like:
- (void)applicationDidEnterBackground:(UIApplication *)application
{
if (/* logged out */) {
exit(0);
} else {
// normal handling.
}
}
Since the app would then exit out of the background it will not look wrong to the user, and will not resemble a crash, providing the user interface is restored the next time they run the app. In other words, to the user it would not look any different to a system initiated termination of the app when the app is in the background.
Still, it would be preferable to use a more standard approach to let the system know that the app can be terminated. For example in this case, by making sure the GPS is not in use by stopping requesting location updates, including turning off show current location on a map view if present. That way the system will take care of terminating the app a few minutes (i.e. [[UIApplication sharedApplication] backgroundTimeRemaining]) after the app enters the background. This would get all the same benefits without having to use code to terminate the app.
- (void)applicationDidEnterBackground:(UIApplication *)application
{
if (/* logged out */) {
// stop requesting location updates if not already done so
// tidy up as app will soon be terminated (run a background task using beginBackgroundTaskWithExpirationHandler if needed).
} else {
// normal handling.
}
}
And of course, using exit(0) would never be appropriate for the average production app that runs in the foreground, as per other answers that reference http://developer.apple.com/iphone/library/qa/qa2008/qa1561.html
Swift 4.2 (or older)
Library called Darvin can be used.
import Darwin
exit(0) // Here you go
NB: This is not recomanded in iOS applications.
Doing this will get you crash log.
In iPadOS 13 you can now close all scene sessions like this:
for session in UIApplication.shared.openSessions {
UIApplication.shared.requestSceneSessionDestruction(session, options: nil, errorHandler: nil)
}
This will call applicationWillTerminate(_ application: UIApplication) on your app delegate and terminate the app in the end.
But beware of two things:
This is certainly not meant to be used for closing all scenes. (see https://developer.apple.com/design/human-interface-guidelines/ios/system-capabilities/multiple-windows/)
It compiles and runs fine on iOS 13 on an iPhone, but seems to do nothing.
More info about scenes in iOS/iPadOS 13: https://developer.apple.com/documentation/uikit/app_and_environment/scenes

Resources