【问题标题】:Automate Screenshots on iPhone Simulator?在 iPhone 模拟器上自动截图?
【发布时间】:2009-09-01 04:40:41
【问题描述】:

每次我为我的 iPhone 应用程序更改 UI 时,我都厌倦了拍摄新的屏幕截图。我希望能够运行脚本/程序/任何东西来在模拟器上加载我的二进制文件,然后截取一些屏幕截图。

解决方案可以是任何语言......这对我来说并不重要。

谢谢!

【问题讨论】:

  • 我也想从设备上听到答案。

标签: iphone


【解决方案1】:

使用 iPhone SDK 4,您可以自动化 GUI 测试,它可以为您截取屏幕截图。

基本上,你编写一个 Javascript 脚本,然后 Instruments(使用自动化模板)可以在设备上运行它来测试 UI,并且可以记录数据、屏幕截图等,还可以在出现问题时发出警报。

我找不到它的参考指南,但在 SDK 参考库中搜索 UIA* 类(如 UIAElement)。

还有一个来自 WWDC 会议 306 的视频演示。

【讨论】:

【解决方案2】:

我也有同样的愿望。我希望能够在我的应用程序中保存几个屏幕的屏幕截图,而无需所有手动工作。我还没到,但我已经开始了。

这个想法是尾随 /var/log/system.log,NSLog 语句的输出所在的位置。我将输出通过管道传输到 python 程序。 python 程序从标准输入读取所有行,当该行匹配特定模式时,它调用屏幕捕获。

NSLog(@"screenshot mainmenu.png");

这将导致每次调用时都会创建一个名为“XX.mainmenu YY.png”的屏幕截图。 XX 是程序启动后截屏的编号。 YY 是“主菜单”截图的编号。

我什至添加了一些不必要的功能:

NSLog(@"screenshot -once mainmenu.png");

这只会保存一次“XX.mainmenu.png”。

NSLog(@"screenshot -T 4 mainmenu.png");

这将在延迟 4 秒后生成屏幕截图。

使用正确的日志记录运行应用程序后,可能会创建具有以下名称的屏幕截图:

00. SplashScreen.png
01. MainMenu 01.png
03. StartLevel 01.png
04. GameOver 01.png
05. MainMenu 02.png

试一试:

  1. 在代码中添加一些 NSLog 语句

  2. $ tail -f -n0 /var/log/system.log | ./grab.py

  3. 在模拟器中启动您的 iPhone 应用

  4. 玩转您的应用

  5. 查看显示您启动 grab.py 程序的屏幕截图

抓取.py:

#!/usr/bin/python

import re
import os
from collections import defaultdict

def screenshot(filename, select_window=False, delay_s=0):
    flags = []
    if select_window:
        flags.append('-w')
    if delay_s:
        flags.append('-T %d' % delay_s)
    command_line = 'screencapture %s "%s"' % (' '.join(flags), filename)
    #print command_line
    os.system(command_line)

def handle_line(line, count=defaultdict(int)):
    params = parse_line(line)
    if params:
        filebase, fileextension, once, delay_s = params
        if once and count[filebase] == 1:
            print 'Skipping taking %s screenshot, already done once' % filebase
        else:
            count[filebase] += 1
            number = count[filebase]
            count[None] += 1
            global_count = count[None]
            file_count_string = (' %02d' % number) if not once else ''

            filename = '%02d. %s%s.%s' % (global_count, filebase, file_count_string, fileextension)
            print 'Taking screenshot: %s%s' % (filename, '' if delay_s == 0 else (' in %d seconds' % delay_s))
            screenshot(filename, select_window=False, delay_s=delay_s)

def parse_line(line):
    expression = r'.*screenshot\s*(?P<once>-once)?\s*(-delay\s*(?P<delay_s>\d+))?\s*(?P<filebase>\w+)?.?(?P<fileextension>\w+)?'
    m = re.match(expression, line)
    if m:
        params = m.groupdict()
        #print params
        filebase = params['filebase'] or 'screenshot'
        fileextension = params['fileextension'] or 'png'
        once = params['once'] is not None
        delay_s = int(params['delay_s'] or 0)
        return filebase, fileextension, once, delay_s
    else:
        #print 'Ignore: %s' % line
        return None

def main():
    try:
        while True:
            handle_line(raw_input())
    except (EOFError, KeyboardInterrupt):
        pass

if __name__ == '__main__':
    main()

这个版本的问题:

如果您只想截取 iPhone Simulator 窗口的屏幕截图,则必须为每个屏幕截图单击 iPhone Simulator 窗口。 screencapture 拒绝捕获单个窗口,除非您愿意与之交互,这对于命令行工具来说是一个奇怪的设计决定。

更新:现在 iPhone 模拟器裁剪器(http://www.curioustimes.de/iphonesimulatorcropper/index.html)可以从命令行运行。因此,不要使用内置的屏幕截图,而是下载并使用它。所以现在这个过程是完全自动化的。

【讨论】:

  • 这种技术的一个主要问题是它需要一个招聘屏幕才能工作。我在没有外接显示器的 15 英寸 MBP 上进行开发,这个工具无法捕获 iPad 大小的屏幕截图。关于如何在没有更大屏幕的情况下自动执行此操作的任何建议?
【解决方案3】:

在 iPhone 模拟器中,有一个“复制屏幕”菜单项。当您按住 Control 时,它会替换编辑菜单中的 Copy 菜单项。 按键是 Ctrl-Cmd-C 一个简单的 AppleScript 可以复制屏幕截图并保存。类似的东西(它对我有用,即使它 hacky):

tell application "iPhone Simulator" to activate
tell application "System Events"
    keystroke "c" using {command down, control down}
end tell
tell application "Preview" to activate
tell application "System Events"
    keystroke "n" using {command down}
    keystroke "w" using {command down}
    delay 1
    keystroke return
    delay 1
    keystroke "File Name"
    keystroke return
end tell

如果不明白,请评论...

【讨论】:

    【解决方案4】:

    私有UIGetScreenImage(void) API 可用于捕获屏幕内容:

    CGImageRef UIGetScreenImage();
    void SaveScreenImage(NSString *path)
    {
        NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
        CGImageRef cgImage = UIGetScreenImage();
        void *imageBytes = NULL;
        if (cgImage == NULL) {
            CGColorSpaceRef colorspace = CGColorSpaceCreateDeviceRGB();
            imageBytes = malloc(320 * 480 * 4);
            CGContextRef context = CGBitmapContextCreate(imageBytes, 320, 480, 8, 320 * 4, colorspace, kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Big);
            CGColorSpaceRelease(colorspace);
            for (UIWindow *window in [[UIApplication sharedApplication] windows]) {
                CGRect bounds = [window bounds];
                CALayer *layer = [window layer];
                CGContextSaveGState(context);
                if ([layer contentsAreFlipped]) {
                    CGContextTranslateCTM(context, 0.0f, bounds.size.height);
                    CGContextScaleCTM(context, 1.0f, -1.0f);
                }
                [layer renderInContext:(CGContextRef)context];
                CGContextRestoreGState(context);
            }
            cgImage = CGBitmapContextCreateImage(context);
            CGContextRelease(context);
        }
        NSData *pngData = UIImagePNGRepresentation([UIImage imageWithCGImage:cgImage]);
        CGImageRelease(cgImage);
        if (imageBytes)
            free(imageBytes);
        [pngData writeToFile:path atomically:YES];
        [pool release];
    }
    

    确保将其包装在 #ifdef 中,这样它就不会出现在发布版本中。

    【讨论】:

    • 似乎 UIGetScreenImage 不再适用于模拟器:((我最后一次尝试是在 2.x 上)。我已经更新了代码以包含手动屏幕捕获的基础知识......它似乎工作纵向窗口非常好,但横向窗口不太好,它不包括状态栏;但这是一个开始。如果你改进它,请更新我的答案:)
    【解决方案5】:

    如果您对自动更改模拟器语言和设备类型感兴趣,我开发了一些脚本来实现这一点:http://github.com/toursprung/iOS-Screenshot-Automator

    【讨论】:

      【解决方案6】:

      您也可以使用一些屏幕捕捉应用程序在模拟器的屏幕上捕捉视频。

      我经常使用 Jing 应用程序。

      我什至用它来发送视频,向客户展示应用程序...

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2016-02-29
        • 2011-10-28
        • 1970-01-01
        • 1970-01-01
        • 2018-03-25
        • 1970-01-01
        • 1970-01-01
        • 2022-01-22
        相关资源
        最近更新 更多