ios - 在 iOS 7 - 7.1.x 上截图

标签 ios iphone objective-c ios7

主要问题,如何在后台/跳板的情况下截取 iOS 7+ 的屏幕截图?

我正在尝试开发一个应用程序来在后台记录 iOS 设备的屏幕。使用私有(private)或公共(public) API 并不让我担心,除非这可能成为可能。我对通过编程在 iOS 设备上截屏做了一些研究。我发现的第一个“解决方案”要么已弃用,要么无法截取当前事件屏幕,只能截取应用内可见的内容(无状态栏、通知中心、通知或控制中心)。

我最终遇到了似乎是 iOS 7.0 - 7.1.x 上唯一可行的方法,它使用的是 IOSurface。根据我的研究,如果您安装了 10.6 Xcode iOS 4 SDK,IOSurface 是一个在 OSX 10.6 中公开可用的框架。 (/System/Library/Frameworks/IOSurface.framework/Headers/IOSurfaceAPI.h)

这里有几个关于 Stack Overflow 的问题,并解释了这些用户让 IOSurface 工作:

Using IOSurface to take screenshot in iOS7 in games - 用户表示他不介意截屏,只是观看游戏。

How to take screenshot for the entire screen no matter which app is at front most in iOS 7(Jailbroken)该用户想使用此方法在越狱设备上截取屏幕截图,响应的用户使用 IOSurface 成功,无需越狱。

https://stackoverflow.com/a/16505514/3139899用户 myCodeHurts 也取得了成功,所有这些都使用非常相似的代码。

上面的所有用户似乎都取得了成功,甚至没有一个人提到需要 IOSurface.framework。

我当前的代码:

-(void)SavePhoto
{
IOMobileFramebufferConnection connect;
kern_return_t result;
IOSurfaceRef screenSurface = NULL;

io_service_t framebufferService = IOServiceGetMatchingService(kIOMasterPortDefault, IOServiceMatching("AppleH1CLCD"));
if(!framebufferService)
    framebufferService = IOServiceGetMatchingService(kIOMasterPortDefault, IOServiceMatching("AppleM2CLCD"));
if(!framebufferService)
    framebufferService = IOServiceGetMatchingService(kIOMasterPortDefault, IOServiceMatching("AppleCLCD"));

result = IOMobileFramebufferOpen(framebufferService, mach_task_self(), 0, &connect);

result = IOMobileFramebufferGetLayerDefaultSurface(connect, 0, &screenSurface);

uint32_t aseed;
IOSurfaceLock(screenSurface, kIOSurfaceLockReadOnly, &aseed);
uint32_t width = IOSurfaceGetWidth(screenSurface);
uint32_t height = IOSurfaceGetHeight(screenSurface);
//int m_width = 320;
//int m_height = 480;
CFMutableDictionaryRef dict;
int pitch = width*4, size = width*height*4;
int bPE=4;
char pixelFormat[4] = {'A','R','G','B'};
dict = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
CFDictionarySetValue(dict, kIOSurfaceIsGlobal, kCFBooleanTrue);
CFDictionarySetValue(dict, kIOSurfaceBytesPerRow, CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &pitch));
CFDictionarySetValue(dict, kIOSurfaceBytesPerElement, CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &bPE));
CFDictionarySetValue(dict, kIOSurfaceWidth, CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &width));
CFDictionarySetValue(dict, kIOSurfaceHeight, CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &height));
CFDictionarySetValue(dict, kIOSurfacePixelFormat, CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, pixelFormat));
CFDictionarySetValue(dict, kIOSurfaceAllocSize, CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &size));

IOSurfaceRef destSurf = IOSurfaceCreate(dict);

void* outAcc;
IOSurfaceAcceleratorCreate(NULL, 0, &outAcc);

IOSurfaceAcceleratorTransferSurface(outAcc, screenSurface, destSurf, dict, NULL);

IOSurfaceUnlock(screenSurface, kIOSurfaceLockReadOnly, &aseed);
CFRelease(outAcc);

CGDataProviderRef provider = CGDataProviderCreateWithData(NULL, IOSurfaceGetBaseAddress(destSurf), (width * height * 4), NULL);
CGImageRef cgImage=CGImageCreate(width, height, 8,
                                 8*4, IOSurfaceGetBytesPerRow(destSurf),
                                 CGColorSpaceCreateDeviceRGB(), kCGImageAlphaNoneSkipFirst |kCGBitmapByteOrder32Little,
                                 provider, NULL,
                                 YES, kCGRenderingIntentDefault);
UIImage *img = [UIImage imageWithCGImage:cgImage];
UIImageWriteToSavedPhotosAlbum(img, self, nil, nil);

// MOST RELEVANT PART OF CODE

//CVPixelBufferCreateWithBytes(NULL, width, height, kCVPixelFormatType_32BGRA, IOSurfaceGetBaseAddress(destSurf), IOSurfaceGetBytesPerRow(destSurf), NULL, NULL, NULL, &sampleBuffer);
}

这取自 myCodeHurts'另一个问题的回答。

我尝试过使用或不使用 IOSurface 的官方版本,以及我在互联网上找到的其他一些链接,在 Xcode 中构建时都返回相同的错误,如果不是非常相似的话:

http://pastie.org/9176533 (这里放不下)

显然,我收到的大部分错误都是关于 iOS 不可用的 API,但让我感到困惑的是其他人如何能够成功地使用 IOSurface 在 iOS 7+ 上捕获屏幕截图。

最佳答案

这实际上是 IOSurfaceBase.h 文件的错误,而不是 IOSurfaceAPI.h 文件的错误。也可能是您在 IOSurface 框架中没有 IOSurfaceBase.h 文件。您必须确保在 IOSurfaceBase.h 文件中声明了 #define IOSFC_AVAILABLE_STARTING(_mac,_iphone)。或者,如果您使用的是 theos header ,https://github.com/rpetrich/iphoneheaders , 这应该已经在 IOSurface.h 中声明了,然后你所要做的就是将 IOSurfaceAPI.h 文件从你的 Mac OS X 系统复制到其他 IOSurface 头文件,并通过转到你的 SDK 文件夹将它添加到你的项目中,然后是 PrivateFrameworks,然后是 IOSurface.framework。在那里创建一个新文件夹并将其命名为“标题”。将所有 IOSurface 文件复制到新创建的 headers 文件夹中,然后应该可以清除错误!

关于ios - 在 iOS 7 - 7.1.x 上截图,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23666502/

相关文章:

iphone - 从 uiwebview 获取更新的 url

objective-c - 如何为 iOS 5 编译 Rabbitmq-c 库?

ios - 无法在 NSURLConnection 函数之外访问字典的内容

iphone - 在 iPhone 中测量车辆加速所需的时间

ios - 我可以在 IOS 的特定位置开始在 UITextField 中输入文本吗?

ios - byteArray to Hex NSString - 添加了一些错误的十六进制内容

ios - 使用试飞时应用程序崩溃

ios - 使用 AVCaptureDevice 扫描图像后立即继续

ios - QuickLook 类不工作

ios - 空气原生扩展 FDT