每次我为iPhone应用程序更改UI时,我都厌倦了拍摄新截图.我希望能够运行脚本/程序/无论在模拟器上加载我的二进制文件,然后拍摄一些截图.
解决方案可以是任何语言......对我来说无关紧要.
谢谢!
使用iPhone SDK 4,您可以自动执行GUI测试,它可以为您截取屏幕截图.
基本上,您编写了一个Javascript脚本,然后Instruments(使用自动化模板)可以在设备上运行它来测试UI,并且可以记录数据,屏幕截图等,并且还可以在出现问题时发出警报.
我找不到它的参考指南,但在SDK参考库中搜索UIA*
类(如UIAElement
).
还有一个视频演示来自WWDC,会话306.
我有同样的愿望.我希望能够在我的应用程序中保存几个屏幕的屏幕截图,而无需全部手动工作.我还没到,但我已经开始了.
想法是尾随/var/log/system.log,其中NSLog语句的输出去.我将输出传递给python程序.python程序从stdin读取所有行,当行匹配特定模式时,它调用screencapture.
NSLog(@"screenshot mainmenu.png");
这将导致每次调用时都会创建一个名为"XX.mainmenu YY.png"的屏幕截图.XX是程序启动后的屏幕截图编号.YY是"mainmenu"屏幕截图的编号.
我甚至添加了一些不必要的功能:
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
试试看:
在代码中添加一些NSLog语句
$ tail -f -n0 /var/log/system.log | ./grab.py
在模拟器中启动您的iPhone应用程序
玩你的应用程序
看一下屏幕截图,显示你启动grab.py程序的位置
grab.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)?\s*(-delay\s*(?P \d+))?\s*(?P \w+)?.?(?P \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模拟器窗口的屏幕截图,则必须单击每个屏幕截图的iPhone模拟器窗口.screencapture拒绝捕获单个窗口,除非您愿意与它进行交互,这是命令行工具的一个奇怪的设计决策.
更新:现在iPhone模拟器裁剪器(在http://www.curioustimes.de/iphonesimulatorcropper/index.html)从命令行工作.因此,不要使用内置的screencapture,而是下载并使用它.所以现在这个过程是完全自动的.
在iPhone模拟器内部,有一个"复制屏幕"菜单项.按住Control时,它将替换编辑菜单中的"复制"菜单项.按键是Ctrl-Cmd-C简单的AppleScript可以复制ScreenShot并保存.有点像(它对我有用,即使它很黑):
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
如果你没有得到它,请评论......
私有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
以便它不会出现在发布版本中.