IOS后台截取手机屏幕的实现(录屏)

来源:互联网 发布:电视点播软件 编辑:程序博客网 时间:2024/04/30 23:10

最近自己在搞全局截屏,抓取屏幕的方法很多,但是大多都是抓取UIView的,或者只能抓取应用window的,当程序进入后台的时候就没法抓取手机桌面的,搜了很多也没有抓取全局屏幕的,只有一个利用硬件缓冲区的方式来抓取全局屏幕的方法,需要用到苹果的私有API。主要是IOKIT IOMobileFramebuffer IOSurface 三个framework、因为需要修改一些地方才可以用使用。下面我就把我整理的代码写上来,供大家参考使用
#import <IOMobileFramebuffer.h>#import <IOKit/IOKitLib.h>#import <IOSurface/IOSurface.h>#import <QuartzCore/QuartzCore.h>

extern  IOReturn IOSurfaceLock(IOSurfaceRef buffer, uint32_t options, uint32_t *seed);

extern  IOReturn IOSurfaceUnlock(IOSurfaceRef buffer, uint32_t options, uint32_t *seed);

extern  size_t IOSurfaceGetWidth(IOSurfaceRef buffer);

extern  size_t IOSurfaceGetHeight(IOSurfaceRef buffer);

extern  IOSurfaceRef IOSurfaceCreate(CFDictionaryRef properties);

extern  void *IOSurfaceGetBaseAddress(IOSurfaceRef buffer);

extern  size_t IOSurfaceGetBytesPerRow(IOSurfaceRef buffer);

extern const CFStringRef kIOSurfaceAllocSize;

extern const CFStringRef kIOSurfaceWidth;

extern const CFStringRef kIOSurfaceHeight;

extern const CFStringRef kIOSurfaceIsGlobal;

extern const CFStringRef kIOSurfaceBytesPerRow;

extern const CFStringRef kIOSurfaceBytesPerElement;

extern const CFStringRef kIOSurfacePixelFormat;

//enum

//{

//    kIOSurfaceLockReadOnly  =0x00000001,

//    kIOSurfaceLockAvoidSync =0x00000002

//};

UIImage * screenshot(void);


UIImage * screenshot(){

    IOMobileFramebufferConnection connect;

    kern_return_t result;

    CoreSurfaceBufferRef 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((IOSurfaceRef)screenSurface, 0x00000001, &aseed);

    size_t width = IOSurfaceGetWidth((IOSurfaceRef)screenSurface);

    size_t height = IOSurfaceGetHeight((IOSurfaceRef)screenSurface);

    CFMutableDictionaryRef dict;

    size_t pitch = width*4, size = width*height*4;

    int bPE=4;

    char pixelFormat[4] = {'A','R','G','B'};

    dict = CFDictionaryCreateMutable(kCFAllocatorDefault0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);

    CFDictionarySetValue(dict, kIOSurfaceIsGlobalkCFBooleanTrue);

    CFDictionarySetValue(dict, kIOSurfaceBytesPerRowCFNumberCreate(kCFAllocatorDefault,kCFNumberSInt32Type, &pitch));

    CFDictionarySetValue(dict, kIOSurfaceBytesPerElementCFNumberCreate(kCFAllocatorDefault,kCFNumberSInt32Type, &bPE));

    CFDictionarySetValue(dict, kIOSurfaceWidthCFNumberCreate(kCFAllocatorDefault,kCFNumberSInt32Type, &width));

    CFDictionarySetValue(dict, kIOSurfaceHeightCFNumberCreate(kCFAllocatorDefault,kCFNumberSInt32Type, &height));

    CFDictionarySetValue(dict, kIOSurfacePixelFormatCFNumberCreate(kCFAllocatorDefault,kCFNumberSInt32Type, pixelFormat));

    CFDictionarySetValue(dict, kIOSurfaceAllocSizeCFNumberCreate(kCFAllocatorDefault,kCFNumberSInt32Type, &size));

    IOSurfaceRef destSurf = IOSurfaceCreate(dict);

    IOSurfaceAcceleratorRef outAcc;

    IOSurfaceAcceleratorCreate(NULL0, &outAcc);

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

    IOSurfaceUnlock((IOSurfaceRef)screenSurface, kIOSurfaceLockReadOnly, &aseed);

    CFRelease(outAcc);

    CGDataProviderRef provider =  CGDataProviderCreateWithData(NULL,  IOSurfaceGetBaseAddress(destSurf), (width * height *4), NULL);

    CGImageRef cgImage = CGImageCreate(width, height, 8,

                                       8*4IOSurfaceGetBytesPerRow(destSurf),

                                       CGColorSpaceCreateDeviceRGB(), kCGImageAlphaNoneSkipFirst |kCGBitmapByteOrder32Little,provider,NULLYESkCGRenderingIntentDefault);

    UIImage *image = [UIImage imageWithCGImage:cgImage];

    return image;

}

上面的这段代码有个问题也许大家会发现,就是IOSurfaceRef(destSurf)的释放问题,这个东西释放早了录不下屏,晚了内存会在几秒内崩溃,所以需要在用完用

CFRelease立即释放。血的教训。

编译时你会发现,编译出错了,因为IOSurfaceAcceleratorRef这个定义和IOSurfaceAcceleratorCreate,IOSurfaceAcceleratorTransferSurface这个两个函数你找不到,是因为最初的编辑者少上传了一个头文件导致的,下面我就把这个头文件给贴上来:

//// IOSurfaceAccelerator.h//#ifndef _IOSURFACE_ACCELERATOR_H#define _IOSURFACE_ACCELERATOR_H 1#include <IOSurface/IOSurfaceAPI.h>#include <IOKit/IOReturn.h>#if __cplusplusextern "C" {#endiftypedef IOReturn IOSurfaceAcceleratorReturn;enum {kIOSurfaceAcceleratorSuccess = 0,};typedef struct __IOSurfaceAccelerator *IOSurfaceAcceleratorRef;IOSurfaceAcceleratorReturn IOSurfaceAcceleratorCreate(CFAllocatorRef allocator, uint32_t type, IOSurfaceAcceleratorRef *outAccelerator);IOSurfaceAcceleratorReturn IOSurfaceAcceleratorTransferSurface(IOSurfaceAcceleratorRef accelerator, IOSurfaceRef sourceSurface, IOSurfaceRef destSurface, CFDictionaryRef dict, void *unknown);#if __cplusplus}#endif#endif
就是它了,把它拷贝下去,写到IOSurfaceAccelerator.h中,并且放到headers/IOSurface目录下,修改一下IOSurface.h文件,在文件最后添加上,

#include <IOSurface/IOSurfaceAccelerator.h>

就算完工了。剩下的就是编译了连接了。

连接的时候,你需要添加IOKit.framework,IOMobileFramebuffer.framework和IOSurface.framework这三个包,才能够顺利的编译过去。

文章前半部分引用了这个shenyi0106文章解决了我的

IOSurfaceAcceleratorRef找不到的问题。代码是我目前正在使用的内容。希望能对你们遇到同样问题的人有点帮助

稍后给上修改过的头文件

<pre name="code" class="html"><a target=_blank href="http://download.csdn.net/detail/benyoulai5/9058913" target="_blank">这里给上头文件</a>

0 0
原创粉丝点击