49

Prior to iOS7 it was possible to inject touch events with the GSSendSystemEvent and GSSendEvent private API calls, eg:

On iOS7 these calls seem to silently fail though. An alternative has been suggested in Simulating system-wide touches in iOS 7 but it only works on jailbroken devices. https://github.com/kif-framework/KIF looks like another option, but it appears that it only supports injecting events for the current app rather than system wide (so you couldn't inject a touch event while you're app is in the background, for example).

So how can you inject system wide touch events on iOS7, without a jailbreak?

Community
  • 1
  • 1
Ben Dowling
  • 15,775
  • 8
  • 80
  • 100
  • 3
    @user2485972 suggested an alternative to GSSendEvent is available here http://stackoverflow.com/questions/16160589/gssendevent-inject-touch-event-ios#comment28537671_17855886 – Ben Dowling Oct 19 '13 at 21:54
  • I don't see any evidence that @user2485972 had a solution that works in the background. Sounds like maybe he was simulating touches with his app in the foreground. (Since he mentions using KIF except needing to deal with gesture recognizers.) Would love it if someone came up with a solution for this... – funroll Nov 07 '13 at 06:03
  • 2
    What are you using these touch events to accomplish? Is there another way the problem could be solved? – Jonah Dec 09 '13 at 21:56
  • 1
    I would suggest that Apple probably think that injecting system wide touch events is open to malicious intent, thus closed it in ios7? – DEzra Dec 16 '13 at 21:00
  • Does anybody got the answer for this question? I need to inject system wide touch in iOS8. I have already asked similar question here: http://stackoverflow.com/questions/26915920/ios8-touch-injection-programatically but nobody replied to it. I really need answer asap. – TechFlitter Nov 27 '14 at 22:01
  • Hey, did you ever end up going anywhere with this problem? Facing a similar issue where I want to simulate system wide touches on a device . – Munib Feb 06 '20 at 17:28

3 Answers3

2

I assume you need to do this system-wide for a testing scenario? In which case you might be well served by Apple's UI Automation framework, a JavaScript-based tool useful for on-device testing.

While you can't do things like simulate a home-button press, you can send your app to the background for a specified duration, for example:

UIATarget.localTarget().deactivateAppForDuration(seconds);

Here are the docs:

https://developer.apple.com/library/ios/documentation/DeveloperTools/Reference/UIAutomationRef

cleverbit
  • 4,995
  • 4
  • 24
  • 35
  • 3
    UI Automation is one of the worst testing frameworks. Unreadable output (not documented and often it breaks). Tests often breaks because there is no way to test for animations and you have to include random sleep times everywhere. Gestures sometimes freeze the app. There are better testing frameworks out there. – Sulthan Jan 31 '14 at 11:51
  • Thanks for your feedback. I'd be interested to know your experience with other frameworks and which ones you might recommend? (I have limited exposure to UI Automation and I was under the impression it had been improved upon along with the new integrated testing in Xcode 5 and Mac OSX 10.9 Mavericks Server.) – cleverbit Jan 31 '14 at 13:27
  • I can't speak about Mac OS but using UI Automation for iOS is just terrible. There are many open source and paid frameworks. Most of them are using the lower levels of UI Automation to generate events but they are much more powerful. – Sulthan Jan 31 '14 at 14:00
  • Sounds good. I'd be most interested in the iOS side. Which ones have you used that are better than UI Automation? – cleverbit Jan 31 '14 at 16:05
  • "Frank" for example. It also has a problem with gestures but at least it works. – Sulthan Jan 31 '14 at 16:40
  • @Sulthan: Frank (I'm not speaking in the third person here!) links to UIAutomation (via Public Automation), which works great on the simulator but requires entitlements in iOS7+ to run on the device. – Frank Apr 29 '14 at 03:49
  • 1
    @richarddas: The op is asking how to inject system wide events, but your suggestion cannot work because using the UI Automation javascript framework (from your line of code) in Instruments only works in the current app under test. When you deactivate the app, the script pauses till the app comes back, therefore NOT allowing you to send system-wide events. – Frank Apr 29 '14 at 03:55
-4

You can subclass UIWindow and overwrite sendEvent. I use it to implement a multiple listeners pattern, but you can also use it to fire events...

- (void)sendEvent:(UIEvent*)event {
    [super sendEvent:event];
    //NSLog(@"NSEventListenerWindow.sentEvent: %@\n", event);

    // pass all events on to those who listen
    for ( id listener in listeners) {
        if ([listener respondsToSelector:@selector(sendEvent:)]) {
            [listener sendEvent:event]; 
        }
    }
    .....
CocoaChris
  • 498
  • 3
  • 7
-5

I think you'd be better off using iOS SDK Notification service api. That would be the cleanest way to achieve what you want.

Conceptually, Apple doesn't (yet) intend third-parties to issue system wide events since that wouldn't sit well with iOS careful curating model, that's why people resort to private APIs and jailbreaking. Private APIs, as the name implies, are not supposed to be relied upon.

Think about it this way, unless you were responsible for the whole system, which a user app couldn't possibly be, you really have no business generating system wide events. I know how Android does this, but that's another story (not fit for this topic).

On the Mac, the XPC Services api for allows processes to communicate with one another, still not quite a method for generating system wide event. I'd suggest you use iOS SDK's notification API, that would probably be the cleanest method to achieve what you want. Yes, it goes out to Apple and back to the device, but that's the mechanism that is available up to now.

Isaka
  • 33
  • 4