How can I simulate a swipe gesture programmatically?

I'm currently trying to write some acceptance tests for our new iOS application using frank (and, in turn, UISpec ). Despite the fact that the framework supports strokes as the main way to interact with representations, it does not currently support tougher gestures (for example, a pinch, napkins, etc.). I need to add support for scrolling, at least because it is the core for the functionality of our application, and our tests would be useless without it.

Implementing this should be fairly simple if I can find a way to simulate events in Cocoa. Gestures can be sent if you use the Apple UIAutomation infrastructure ( see here ), so theres an example of what generates these events from the outside. I searched on the Internet but did not find examples of such people (although there was a thread where someone asked for something similar to this before ...).

Thanks so much for your help / ideas ...

+4
source share
1 answer

I spent yesterday trying to get this to work, ended up with a solution. I am not completely happy with this, but it was the best I could do now - if anyone could offer any improvements or a working alternative, I would welcome them ...

Anyway, for someone else trying to do something like that. I based my decision on the API described in detail in this post - I recorded a sequence of events that I wanted to simulate, and then reproduced them. The only problem is that I could not get the built-in playback API to work (I got the same crash mentioned in the comments mentioned below). After some time in the land of ASM, I finished writing my own version.

@implementation UIApplication (EventReplay) /// /// - replayEventsFromFile: /// - (void)replayEventsFromFile:(NSString *)filename { NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask, YES); NSString *filePath = [[paths objectAtIndex:0] stringByAppendingPathComponent:filename]; NSArray* eventList = [[NSArray arrayWithContentsOfFile:filePath] retain]; [self replayEvents:eventList]; } /// /// - replayEvents: /// - (void)replayEvents:(NSArray *)events { if (!events.count) return; NSDictionary *eventDict = [events objectAtIndex:0U]; GSEventRef thisEvent = GSEventCreateWithPlist((CFDictionaryRef)eventDict); uint64_t eventTime = thisEvent->record.timestamp; thisEvent->record.timestamp = mach_absolute_time(); mach_port_t appPort = GSCopyPurpleNamedPort([[[NSBundle mainBundle] bundleIdentifier] UTF8String]); GSSendEvent(&thisEvent->record, appPort); mach_port_deallocate(mach_task_self(), appPort); if (events.count <= 1) return; NSIndexSet *remainderIndexes = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(1, events.count - 1)]; NSArray *remainingEvents = [events objectsAtIndexes:remainderIndexes]; GSEventRef nextEvent = GSEventCreateWithPlist((CFDictionaryRef)[remainingEvents objectAtIndex:0U]); NSTimeInterval nextEventDelay = GetTimeDelta(nextEvent->record.timestamp, eventTime); if (nextEventDelay > 0.05) [self performSelector:@selector(replayEvents:) withObject:remainingEvents afterDelay:nextEventDelay]; else [self replayEvents:remainingEvents]; CFRelease(nextEvent); CFRelease(thisEvent); } @end 

The snippet above shows how I reproduce the events. My implementation is pretty cruel - you will see that I had to stroke the fact that if I blindly use the timer to schedule the next event, then sometimes it does not work - it seems like the delay is too small. The terrible hack you see seems to be doing fine.

In any case, I hope this helps someone.

+6
source

Source: https://habr.com/ru/post/1339785/


All Articles