ios - Instruments Automation 屏幕截图忽略以编程方式添加的控件

标签 ios xcode automation instruments

我正在 Instruments Automation 中保存屏幕截图,但该屏幕截图中缺少一些控件。看起来以编程方式添加的控件被“忽略”了。

我该如何解决?

模拟器中的手动截图:(注意黄色方框)

Screenshot in Simulator with Yellow Button

Instruments Automation 中的屏幕截图:

Screenshot in Instruments Automation without Yellow Button

自动化脚本:

var target = UIATarget.localTarget();
target.delay(0.5)
target.captureScreenWithName( "screenshot1.png" );

我在 Xcode(通用,objective-c)中创建了一个新的单 View 应用程序。我在 Storyboard 中添加了一个按钮和一个带有自动布局约束的标签。

我添加了这段代码以编程方式添加黄色按钮:

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.

    UIButton *b = [[UIButton alloc] init];
    b.backgroundColor = [UIColor yellowColor];
    [b setTitle:@"Extra" forState:UIControlStateNormal];
    [b setTranslatesAutoresizingMaskIntoConstraints:NO];
    [self.view addSubview:b];
    [self.view addConstraint:[NSLayoutConstraint constraintWithItem:b attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeTopMargin multiplier:1.0 constant:0.0]];
    [self.view addConstraint:[NSLayoutConstraint constraintWithItem:b attribute:NSLayoutAttributeTrailing relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeTrailingMargin multiplier:1.0 constant:0.0]];

    [self.view setNeedsUpdateConstraints];
    // Correction: - initially I used the line below, but that was wrong
    // The problem is not solved with using setNeedsUpdateConstraints.
    // [self.view updateConstraints];
}

我使用的是 Xcode 版本 7.1.1 (7B1005),我的操作系统是 El Capitan 10.11.1 (15B42)。我知道它在早期版本中有效,因为我使用 ui-screen-shooter对于我的应用程序的屏幕截图和现在出现的问题,它以前工作过。这不是 ui-screen-shooter 的问题,因为我可以单独使用仪器自动化重现它。

我该怎么办?

编辑:

Storyboard 中的控件与手动创建的控件之间的一个区别可能是对象 ID,您可以在 Storyboard 源中看到它。如果这是问题所在,我可以为手动创建的控件设置 id 吗? (或者一旦从 Storyboard 中读取场景,它就丢失了吗?)

编辑 2:

我获取了 View Controller View 中元素的所有属性(通过 objc/runtime)并比较了两个按钮的属性值。差异很小:(不包括相同的条目)

Button from Storyboard           |  Manual Button
-----------------------------------------------------------------
"_defaultRenderingMode" = 2;     |  "_defaultRenderingMode" = 1;
text = Button;                   |  text = Extra;
                                 |
        (several position values slightly different)
                                 |
description contains:            |
"autoresize = RM+BM;"            | 
                                 | backgroundColorSystemColorName = yellowColor;

EDIT 3:

A screenshot of the output of target.logElementTree():

target.logElementTree() output

EDIT 4:

I added

[UIButton appearance].backgroundColor = [UIColor yellowColor];

所有按钮现在都有黄色背景,但是屏幕截图中没有“额外”按钮。

我主要关注的不是自定义外观。我也试过了

UIButton *b = [UIButton buttonWithType:UIButtonTypeSystem];

所以这个按钮就像典型的蓝色按钮一样。该按钮仍然没有出现在自动化屏幕截图中。

编辑 5:

如果它是相关的:我可以从自动化脚本访问控件并进行点击 - 例如(从另一个应用程序,而不是这个测试代码):

target.frontMostApp().mainWindow().buttons()[25].tap()

点击已处理,因此自动化脚本可以访问控件。

编辑 6:我在 Apple 的错误报告系统中创建了错误报告。如果您可以重现它,那么做同样的事情可能会很好(至少我是这样理解 Apple 错误报告的预期用途的)。

编辑 7:(感谢 quellish 的回答 - 在这里处理我的第一波想法:)我更正了代码中的一个错误 - 我调用了 [self.view updateConstraints];,但是它应该是 [self.view setNeedsUpdateConstraints];。然而,这对自动化屏幕截图结果没有影响。

我想知道是否更新了约束并记录了对 updateViewConstraints 和其他一些调用的调用。这是应用加载时的记录方式:

viewDidLoad
viewWillAppear
updateViewConstraints
viewWillLayoutSubviews
viewWillLayoutSubviews
viewDidAppear

因此,当我在 viewDidLoad 中添加按钮和约束并调用 updateViewConstraints 时,我会假设在 viewDidAppear 时所有约束都已解决> 被调用。

我在 viewDidAppear 中使用它做了一个快速测试:(还不确定,这是否是要走的路 - 我对可访问性没有什么经验。)

_extraButton.accessibilityFrame = UIAccessibilityConvertFrameToScreenCoordinates(_extraButton.frame, self.view);

自动化屏幕截图保持白色。

然而,有趣的是,在元素树中,额外按钮的屏幕截图部分显示了正确的位置。所以我假设,自动化选择了正确的位置。

最佳答案

您遇到的问题是由多种因素造成的。如您的问题所述,您的问题是:

  • 鉴于您包含的测试项目和自动化脚本,UIAutomation 屏幕截图不会包含您的样式按钮。

在不同的条件下你会看到不同的行为:

  • 当通过 nib 或 Storyboard 实例化按钮时,不会出现问题,只有当按钮被声明并添加到代码中的 View 层次结构时(具体来说,viewDidLoad View Controller )。

  • 当在早期版本的 iOS(即 iOS 8)中运行时,该按钮确实出现在 UIAutomation 屏幕截图中。

就是说,如果您删除 viewDidLoad 中添加的约束,您将看到样式化的按钮开始出现在屏幕截图中。这应该是一个提示 - 约束是问题的一部分。

当布局引擎解决约束时,它会尝试分批处理尽可能多的工作,合并约束以提高性能。当在 nib 或 Storyboard中描述按钮和约束时,约束引擎将同时获取它们,并且在 View 层次结构的生命周期中更早。因此,可以显着简化布局过程的步骤。

但是,当稍后在 View 层次结构生命周期中添加约束时,需要重新评估约束。将添加的约束视为添加到队列中,布局引擎将在下次队列“满”时重新评估它们。 UIAutomation Hook 到 UIAccessibility API 中来做它的事情 - 可访问性可能不知道或不关心视觉表示的布局发生了什么。视觉表示可能会发生变化,但不会影响可访问性,因此不会影响 UIAutomation 的世界观。

iOS 9 改变了布局过程背后的几个方面,这就是您现在看到这个问题的原因。

您可以采取多种行动:

  • 在 nib 或 Storyboard中构建您的 View 层次结构。这将为您带来最一致的体验,并具有性能和其他优势。

  • 使用辅助功能 API 提示按钮的位置(辅助功能框架)在布局传递后发生了变化。遗憾的是,除非在布局完成之前禁用可访问性、可见性或用户交互,否则您仍然可能会在布局发生时看到 UIAutomation 捕获它。

  • 与其在自动化脚本中任意延迟,不如有效地使用 UIAutomation 超时来等待元素可用。这是 covered in the documentation并且是最佳实践。在布局完成之前使其不可用或无效。

使用这些方法,我能够轻松地让您的示例项目不再重现您所看到的问题。这些解决方案中的部分或全部可能适合您的项目,也可能不适合。

关于ios - Instruments Automation 屏幕截图忽略以编程方式添加的控件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33975321/

相关文章:

ios - UIView UIScrollview - 框架、边界、中心混淆

xcode - 如何指示 XCODE 在子项目的 DERIVED_FILES_DIR 中查找 header

ios - 如何在单独的线程中刷新单元格(从 channel 内时间递减、UTC 并显示新值)以避免阻塞 UI?

ios - Swift:打印没有警告框

ios - 编辑框架高度集合可重用 View

javascript - Protractor:是否可以同时使用多个.get()?

VB.NET GetObject(,"Excel.Application") 无法运行 Excel

python Selenium : wait until an element is no longer stale?

iphone - iOS 中的并行下载

objective-c - Xcode 4.5 GM 上的 Restkit 在 iOS 6 设备上不起作用 - 文件是为存档构建的,不是链接的体系结构