我该如何在程序中模拟滑动手势?

4

我目前正在尝试使用Frank(以及UISpec)为我们的新iOS应用程序编写一些验收测试。虽然该框架支持触摸作为与视图交互的基本方式,但它目前不支持更多涉及手势的操作(例如,捏合,滑动等)。至少需要添加对滑动的支持,因为这是我们应用程序功能的核心,并且如果没有它,我们的测试将几乎无用。

如果我能找到一种模拟Cocoa中事件的方法,那么实现这个应该是非常简单的。如果您使用苹果的UIAutomation框架(请参阅此处),则可以发送滑动手势,因此有一个生成这些事件的外部示例。我在网上搜索过,但没有找到任何人做过这样的例子(尽管以前有一个线程有人要求类似的东西...)。非常感谢您提前的帮助/想法...
1个回答

6
我昨天花了一整天时间尝试让它工作,最终找到了一个解决方案。虽然我并不完全满意,但目前这是我所能做到的最好 - 如果有人能提出任何改进或有效的替代方案,我将非常欢迎... 无论如何,对于任何试图做类似事情的人来说,我基于这篇文章中详细介绍的API来实现我的解决方案 - 我记录下了我想要模拟的事件序列,然后进行了回放。唯一的问题是,我无法让内置的播放API正常工作(我得到了底部评论中提到的相同崩溃)。在ASM领域挖掘了一段时间后,我最终编写了自己的版本。
@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

上面的代码片段展示了我如何回放事件。我的实现相当粗糙-你会看到我不得不处理这样一个事实,即如果我盲目地使用计时器来安排下一个事件,有时它不会触发-似乎是当延迟太小的时候。你看到的可怕的hack似乎让事情正常运行。

无论如何,希望这能以某种方式帮助其他人。


1
这种技术适用于iOS 5吗?我该如何包含GSEventRef? - Anthony Blake

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接