Friday, March 2, 2012

tl;dr: Can a alert view shown by the framework (Core Location, …) automatically be dismissed by sending the appropriate touch events to the "OK"-button? Answer: No, not so easy. Want to know why? Read the whole thing.

Every iPhone user out there has probably seen the dialog below (in one way or the other):
If an app wants to use the current location of an iPhone it has to get the users permission first. This is enforced by a so called "alert view" that is shown automatically by the framework once you (as a developer) try to use Core Location to get the current location of an iPhone. The alert view shown above has two options: "OK" which allows the app to use the current location and "Don't Allow" which is the opposite.
I always wondered if it is possible to automatically dismiss an alert view like this by simulating a click on the "OK"-button. It should be pretty straight forward because a alert view is an instance of UIAlertView which inherits from UIView. What a developer could do, once a alert view like this is shown by the framework automatically is this:

find the root view of the app

go through the whole view hierarchy recursively and try to find the instance of UIAlertView

suppose the "OK"-button on the UIAlertView is just another UIView (or UIButton) then it has to respond to touch events (UITouch, UIEvent)

create a "touch up inside" event and send it to the "OK"-button

the alert view should be dismissed and your app could use the current location without the users consent

A few days ago I tried to find out if it is really that easy. To make it short: It is not that easy.

Here is why

I believe that the alert view is contained in another process and so there is no way I know of that lets you access the view hierarchy of another process since they don't share the same address space.

How?

I wrote a sample application that registers an object as an observer at the default notification center. As name and object parameter I simply pass nil which means that my notification handler wants to receive every notification of the default notification center no matter who sent the notification and no matter how the notification is called:

[[NSNotificationCenterdefaultCenter] addObserverForName:nil

object:nil

queue:nil

usingBlock:^(NSNotification *note) {

NSLog(@"%@", note.name);

}];

The sample app then tries to access the current location and as soon the alert view pops up the sample app receives a notification saying that it will resign the active state. This does not proof that the alert view is shown by another process because an application usually resigns the active state because of two reasons:

An application is active when it is receiving events. An active application can be said to have focus. It gains focus after being launched, loses focus when an overlay window pops up or when the device is locked, and gains focus when the device is unlocked. ( found in the documentation about UIApplication)

So I turned on Instruments and made a few heapshots and analyzed the stack trace. Lets have a look:
The -[SISViewController start:] method is the one requesting the current location. Then you see a few CL-calls and then three XPC function calls. XPC is Apples new inter process communication library. So clearly there is some kind of inter process communication going on. This may be the communication with the Core Location Deamon. More importantly I haven't seen a hint in the stacktraces that suggest that a overlay window or a view is created in the address space of the app.
To be clear: I have not found any evidence that suggests that the alert view is in the address space of another process either. Never the less what I found lets me believe exactly that and I think this would be a wise decision. I will try to find absolute proof by using more sophisticated reverse engineering techniques and then I will report back.