Вопрос

The main question, how do I take a screenshot iOS 7+ while backgrounded/of the springboard?

I am trying to develop an application to record an iOS device's screen while backgrounded. The use of private or public API's does not worry me, only if this could even be possible. I have done some research for taking screen shots on an iOS device with programming. The first 'solutions' that I found were either deprecated or could not screenshot the current active screen, only what was viewable in-app (no status bar, notification center, notifications or control center).

I ended up coming across what seemed to be the only working method on iOS 7.0 - 7.1.x, which was using IOSurface. From my research, IOSurface was a framework publicly available in OSX 10.6 if you had the 10.6 Xcode iOS 4 SDK installed. (/System/Library/Frameworks/IOSurface.framework/Headers/IOSurfaceAPI.h)

Here are a couple of questions on Stack Overflow as well explaining that these users got IOSurface to work:

Using IOSurface to take screenshot in iOS7 in games - The user states he has no issues with taking the screenshot, only viewing games.

How to take screenshot for the entire screen no matter which app is at front most in iOS 7(Jailbroken) This user wants to take a screenshot on a jailbroken device with this method, the users that responded had success with IOSurface, without a jailbreak.

https://stackoverflow.com/a/16505514/3139899 The user myCodeHurts has also had success, all with very similar code.

All of the users above seemed to have success, not a single person even mentioning needing IOSurface.framework.

My current code:

-(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);
}

This was taken from myCodeHurts' answer from another question.

I have tried with, without, the official version of IOSurface, and some other links I have found on the internet, all returning the same if not very similar errors upon building in Xcode:

http://pastie.org/9176533 (Way too long to fit here)

I obviously receive mostly errors about API not available for iOS, but what confused me is how others were able to successfully use IOSurface to capture a screenshot on iOS 7+.

Это было полезно?

Решение

This actually is an error with the IOSurfaceBase.h file, not the IOSurfaceAPI.h file. It also could be that you do not have an IOSurfaceBase.h file in the IOSurface framework. You must make sure #define IOSFC_AVAILABLE_STARTING(_mac,_iphone) is declared in the IOSurfaceBase.h file. Or, if you are using the theos headers, https://github.com/rpetrich/iphoneheaders, this should already be declared in IOSurface.h, and then all you have to do is copy the IOSurfaceAPI.h file from your Mac OS X system to the other IOSurface headers, and add it to your project by going to your SDK folder, then PrivateFrameworks, then to IOSurface.framework. Create a new folder in there and name it "Headers". Copy all the IOSurface files to the newly created headers folder, and then that should clear your errors!

Другие советы

/Users/justin/Desktop/iOS Development/Projects/iRec/iRec/ViewController.m:66:32: error: 'kIOSurfaceWidth' is unavailable: not available on iOS

It's a bit obvious, no? iOS needs kIOSurfaceWidth.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top