Show an alert when iOS app is in the background
Asked Answered
G

3

23

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.

enter image description here
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.

Gilletta answered 16/4, 2016 at 21:9 Comment(17)
I'm not 100% sure, but I believe that uber app is configured as a "Routing" iOS app and therefore gets some additional permissions to do things in the background. You can find more info here: developer.apple.com/library/ios/documentation/IDEs/Conceptual/…. Though I imaging you're not actually wanting to create a routing app?Esteresterase
Thanks a lot @George George. My intention is the same: show the alert at any cost. Let me go through the link you provided. At least I have some lead.Gilletta
Essentially, in iOS you cannot just display an alert while the app is in the background unless the user has opted in to notifications. If you submit an app that is doing this using the routing capability and is not a routing app, Apple will reject it at review time.Esteresterase
Yes, I am aware of that. Do you know how to show the alertview from the background when your app is a Routing app?Gilletta
Are you making a routing app?Bagdad
Yes, I am making something similar to Uber Partner app. Anyone who has downvoted my question, please let me know why.Gilletta
I've never heard of an app, any app, being able to display an alert when its in the background, regardless of what background mode it has. (Certain apps in the background might trigger an OS alert view if they try to access something such as a bluetooth peripheral for example, but the alert is coming from the OS not from the app). Therefore I would be very curious to see the alert you have mentioned in your question, would you be able to post it in the question.Lise
@SausageMachine Well, you heard it now :) I have attached the screenshot.Gilletta
@K.K. Thanks very much. That's very interesting. I'm so consumed with curiosity now that I must find out what's going on here. I'll post back(eventually) if I manage to find something out and if you get no answers in the meanwhile.Lise
@K.K. What was the action you performed that resulted in that being displayed? I know you said you've disabled them, but are you sure thats not a remote push notification?Lise
@SausageMachine I have updated the question. Let me know if you need more information.Gilletta
@K.K. I'm presuming Uber must be using voip (I don't have the app installed, can you talk to people using the app?). Otherwise there is no way it can remain responsive while in the background in order for it to receive the trip request in a timely manner (non voip background push notifications don't have the ability to be received instantaneously all the time, but voip background pushes do). Hence my conclusion is Uber has the voip background mode enabled and that particular mode provides the ability to display an alert.Lise
@SausageMachine I don't think Uber has Voip enabled because it doesn't make voip calls. Even if it has voip enabled, can you provide evidence that voip-enabled apps can show alert from background?Gilletta
Its an assumption at the moment, I'm going to have a look at the voip developer guild. But it makes perfect sense - voip is for calls, if somebody is calling your app using voip your app needs to get the user's attention so they can answer the incoming voip call. A local notification wouldn't be very good for this and if the user can turn them off then its defiantly no good. So its logical that a voip app should be able to get the users attention from the background.Lise
@Gilletta reading help.uber.com/h/d1b28fc8-589c-458f-b205-c44431170652 I'm assuming that they are using local/push notifications. There is also info about the sound help.uber.com/h/907d664a-4e56-4bf1-b2ef-f680c4fee433Daveta
@Daveta As I mentioned, I did turn off notifications and put my cellphone to silent. The alert and sound still comes. This maybe their fallback mechanism or some old articles.Gilletta
@K.K: Have you found any solution over this. I have read all comments but not able to get the exact solution to show the alert on home screen. Can you please share any piece of code/links/etc so I can get idea to do this.Nabal
D
12

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.

Dicho answered 25/4, 2016 at 17:28 Comment(1)
Thanks for the answer. I will be trying it out and accept it soon. Sorry for the late reply, just got busy with other things. If it does work, you are our messiah. :)Gilletta
R
10

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);
}
Rankin answered 1/5, 2016 at 21:17 Comment(6)
@Rankin Thanks a lot for doing this. This would really help a lot of people.Gilletta
Ah very cool. I've heard of CFUserNotification but didn't think to use mention it. How did you get the UberDriver binary? Are you a driver?Dicho
not a driver, so Cycript/theos wasn't of much use... found it via Google, open this link on your phone (or via user agent) partners.uber.com/drive-nowRankin
@Casey, how to display the alert like the originally asked question ? Can you please share the code ?Djokjakarta
I think this worked in the past, but Apple has now protected it (iOS ~9.3). I'm now getting Sep 1 23:09:23 iPhone6s SpringBoard[404] <Warning>: Authentication failure: <FBApplicationProcess: 0x148337f00; HelloAlert; pid: 3485> is not permitted to send CFUserNotifications messages in the console log when running this code.Ferwerda
There is an entitlement protection for using the CFUserNotification API. Uber most likely has received a special entitlement permission in their provisioning profile.Administration
S
5

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.

Selfacting answered 1/5, 2016 at 7:18 Comment(4)
Can only Enterprise apps use SBAlertItem? What do you mean by private API?Gilletta
Enterprise apps can use Private API so the answer is yes, You can use SBAlertItem. There is no review process when deploying an enterprise app. Private API is an API that is not open to the general public and is not documented by apple. You can research classes headers to gain access to it but, like I said in my answer, your app will be rejected.Selfacting
"It didn't got any special permissions like other answers suggested." How can you be so sure of this? Apple provides proprietary documentation to select partners all the time. Do you think uber dug through the headers and did this on their own? I doubt it:Dicho
I'm sure because it's an Enterprise app and you don't need permissions to do anything. I've deployed my share of Enterprise apps and there's no review process and no "Enterprise Review Guidelines". There's a chance that an apple representative helped UBER achieve what they were after but that is beside the point.Selfacting

© 2022 - 2024 — McMap. All rights reserved.