iOS截屏功能的实现

使用场景:

本人在自定义UITabBarController的时候,想要实现手势滑动返回上一页面的效果,也就是仿QQ的滑动返回,这种滑动返回是基于UIPanGestureRecognizer这一手势,实现原理是在导航条Push的时候截取当前屏幕,并把截取到的图片添加的Window的视图上,让后当启用滑动手势的时候只要把当前(Push到的)视图滑动开来,就可以看到之前截取到的倾慕快照,当返回上一页面的时候再把截取的图片从Window上移除即可。遇到的问题是:小编自定义的UITabBarController是继承于UIViewControler,而不是系统的UITabBarController,底部的按钮区域是一个View,截取屏幕的时候总是不能截取到按钮区域的View;这就是*种截屏方法,而后通过查找资料找到一种能够解决此问题的方法,也就是第二种截屏方法。

*种截屏方法:

//获取截屏图片
– (UIImage *)getCurrentScreenShot{

UIGraphicsBeginImageContextWithOptions([[[UIApplication sharedApplication] keyWindow] bounds].size, NO, 0.0);
[[[UIApplication sharedApplication] keyWindow].layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();

return image;
}

注:*种截图方法适合于屏幕上只有一个View的时候,效率较高,一般场景下就够用了。原理是首先创建一个和主屏幕(KeyWindow)一样大小的画布,然后通过 renderInContext方法把屏幕图层上的内容绘制到画布上,然后根据这张画布生成图片即可。

第二种截屏方法:

//截取全屏视图
-(UIImage *)getImageWithFullScreenshot
{

UIInterfaceOrientation orientation = [UIApplication sharedApplication].statusBarOrientation;
CGSize imageSize = CGSizeZero;

//适配横屏状态
if (UIInterfaceOrientationIsPortrait(orientation) )
imageSize = [UIScreen mainScreen].bounds.size;
else
imageSize = CGSizeMake([UIScreen mainScreen].bounds.size.height, [UIScreen mainScreen].bounds.size.width);

UIGraphicsBeginImageContextWithOptions(imageSize, NO, [UIScreen mainScreen].scale);
CGContextRef context = UIGraphicsGetCurrentContext();

for (UIWindow *window in [[UIApplication sharedApplication] windows])
{
CGContextSaveGState(context);
CGContextTranslateCTM(context, window.center.x, window.center.y);
CGContextConcatCTM(context, window.transform);
CGContextTranslateCTM(context, -window.bounds.size.width * window.layer.anchorPoint.x, -window.bounds.size.height * window.layer.anchorPoint.y);

// Correct for the screen orientation
if(orientation == UIInterfaceOrientationLandscapeLeft)
{
CGContextRotateCTM(context, (CGFloat)M_PI_2);
CGContextTranslateCTM(context, 0, -imageSize.width);
}
else if(orientation == UIInterfaceOrientationLandscapeRight)
{
CGContextRotateCTM(context, (CGFloat)-M_PI_2);
CGContextTranslateCTM(context, -imageSize.height, 0);
}
else if(orientation == UIInterfaceOrientationPortraitUpsideDown)
{
CGContextRotateCTM(context, (CGFloat)M_PI);
CGContextTranslateCTM(context, -imageSize.width, -imageSize.height);
}

if([window respondsToSelector:@selector(drawViewHierarchyInRect:afterScreenUpdates:)])
[window drawViewHierarchyInRect:window.bounds afterScreenUpdates:NO];
else
[window.layer renderInContext:UIGraphicsGetCurrentContext()];

CGContextRestoreGState(context);
}

UIImage *image = UIGraphicsGetImageFromCurrentImageContext();

UIGraphicsEndImageContext();

return image;
}

注:第二种截屏方法适用于屏幕上有多个视图的场景,原理基本和*种方法一样,只是第二种方法不仅会绘制主屏幕的视图,它还会遍历已存在的所有window,并拼接所得到的画布。

附:此两种方法是适用于iOS 7及以后版本,除此之外还有一些过期的方法和私有API,小编是不建议使用的,在此也就不再粘贴代码,如有问题可留言告知,多谢!

iOS中正确的截屏姿势

iOS中正确的截屏姿势

*种

这是iOS 3时代开始就被使用的方法,它被废止于iOS 7。iOS的私有方法,效率很高。

1
2
3
4
5
6
7
#import
extern  "C"  CGImageRef UIGetScreenImage();
UIImage * screenshot(void) NS_DEPRECATED_IOS(3_0,7_0);
UIImage * screenshot(){
     UIImage *image = [UIImage imageWithCGImage:UIGetScreenImage()];
     return  image;
}

第二种

这是在比较常见的截图方法,不过不支持Retina屏幕。

1
2
3
4
5
6
7
8
UIImage * screenshot(UIView *);
UIImage * screenshot(UIView *view){
     UIGraphicsBeginImageContext(view.frame.size);
     [view.layer renderInContext:UIGraphicsGetCurrentContext()];
     UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
     UIGraphicsEndImageContext();
     return  image;
}

第三种

从iPhone 4、iPod Touch 4开始,Apple逐渐采用Retina屏幕,于是在iOS 4的SDK中我们有了,上面的截图方法也自然变成了这样。

1
2
3
4
5
6
7
8
9
10
11
12
13
UIImage * screenshot(UIView *) NS_AVAILABLE_IOS(4_0);
UIImage * screenshot(UIView *view){
     if (UIGraphicsBeginImageContextWithOptions != NULL)
     {
         UIGraphicsBeginImageContextWithOptions(view.frame.size, NO, 0.0);
     else  {
         UIGraphicsBeginImageContext(view.frame.size);
     }
     [view.layer renderInContext:UIGraphicsGetCurrentContext()];
     UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
     UIGraphicsEndImageContext();
     return  image;
}

第四种

或许你会说有时Hook的是一个按钮的方法,用第三个方法的话,根本找不到view来传值,不过还好,iOS 7又提供了一些UIScreen的API。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
UIImage * screenshot(void) NS_AVAILABLE_IOS(7_0);
UIImage * screenshot(){
     UIView * view = [[UIScreen mainScreen] snapshotViewAfterScreenUpdates:YES];
     if (UIGraphicsBeginImageContextWithOptions != NULL)
     {
         UIGraphicsBeginImageContextWithOptions(view.frame.size, NO, 0.0);
     else  {
         UIGraphicsBeginImageContext(view.frame.size);
     }
     [view.layer renderInContext:UIGraphicsGetCurrentContext()];
     UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
     UIGraphicsEndImageContext();
     return  image;
}

第五种

1
2
3
4
@interface SBScreenShotter : NSObject
+ (id)sharedInstance;
- (void)saveScreenshot:(_Bool)arg1;
@end

然后直接

1
[[SBScreenShotter sharedInstance] saveScreenshot:YES];

一道白光之后,咱们就模拟了用户截屏的动作,不过这个方法在只需要截屏时比较好,如果要对屏幕录像(其实就是不断截图)的话,那不得闪瞎了。。而且我们也拿不到UIImage的实例去拼成一个视频呀。即使通过Hook别的类拿到UIImage的实例,这个私有API的效率大概也是达不到30FPS的视频要求的。

那么现在我们有5种方法了,*种是私有API,私有API通常效率和质量都比Documented API的好,可是它在iOS 7以后就被废除了啊,就没有别的了吗?

答案当然是————有的!用Private Framework来完成这项任务!直接走底层拿屏幕的缓冲数据,然后生成UIImage的实例。

第六种

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
#import #import #import #import #import extern "C" IOReturn IOSurfaceLock(IOSurfaceRef buffer, uint32_t options, uint32_t *seed);
extern  "C"  IOReturn IOSurfaceUnlock(IOSurfaceRef buffer, uint32_t options, uint32_t *seed);
extern  "C"  size_t IOSurfaceGetWidth(IOSurfaceRef buffer);
extern  "C"  size_t IOSurfaceGetHeight(IOSurfaceRef buffer);
extern  "C"  IOSurfaceRef IOSurfaceCreate(CFDictionaryRef properties);
extern  "C"  void *IOSurfaceGetBaseAddress(IOSurfaceRef buffer);
extern  "C"  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(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);
     IOSurfaceAcceleratorRef outAcc;
     IOSurfaceAcceleratorCreate(NULL, 0, &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*4, IOSurfaceGetBytesPerRow(destSurf),
  CGColorSpaceCreateDeviceRGB(), kCGImageAlphaNoneSkipFirst |kCGBitmapByteOrder32Little,provider, NULL, YES, kCGRenderingIntentDefault);
     UIImage *image = [UIImage imageWithCGImage:cgImage];
     return  image;
}

需要注意的是,第五种方法需要修改一下IOMobileFramebuffer的头文件。

1
typedef void * IOMobileFramebufferConnection;

In the reversed header, IOMobileFramebufferConnection is typedef’d to io_connect_t, which is typedef’d to io_object_t, which is mach_port_t, which is __darwin_mach_port_t, which is __darwin_mach_port_name_t, which is __darwin_natural_t, which is unsigned int! Int just happens to be pointer-sized on 32-bit, but is not under 64-bit。

——StackoverFlow

修改好的头文件顺便也丢上来吧,解压后放在Project的根目录下。

如果你使用的是theos的话,记得在Makefile里写上,

YOUR_TWEAK_NAME_PRIVATE_FRAMEWORKS = IOSurface IOKit IOMobileFramebuffer

YOUR_TWEAK_NAME_CFLAGS = -I./headers/ -I./headers/IOSurface

如果是XCode上的Logos Tweak的话,在Build Settings -> Search Paths -> Header Search Paths里面添加一项:$(PROJECT_DIR)/YOUR_PROJECT_NAME/headers, 搜索方式为recursive. *后在Build Phases里Link上IOSurface IOKit IOMobileFramebuffer这三个私有Framework。

iOS开发 调试 网络限速

在iOS开发中,针对不同网络状况做一下测试处理是很有必要的。但是我发现还是有一些iOS开发者不太注意到不同网络环境下的调试问题,或者说不清楚如何调试这种情况。

下面我将针对真机和模拟器分别做简单的说明。告诉大家如何模拟不同的网络状况。

1.真机情况下

其实Apple在iOS系统中预置了网络调试工具,但是只有添加过测试设备,并使用XCode连接下设备才能激活.

这时只要去设置中就可以看到多出来一项:开发者

%title插图%num

注意中间的那行NETWORK LINK CONDITIONER

%title插图%num

上图中的Status是表示网络限制是否开启,点击进去就可看到详细设置

%title插图%num

可以看到系统默认配置的网络条件还是很多的,其中:

100%Loss是全丢包,

3G这个大家应该都知道

DSL是电话线上网,

Edge是2G网络,

High Latency DNS是高延迟,

Very Bad Network是网络状况不稳定。

并且底部还有一个添加额外配置的选项可以自定义网络状况。

PS:这项开启后影响的是整个系统,所以调试完毕后不要忘记关掉,免得奇怪网络状态咋不正常了。。。

2.模拟器

由于模拟器是在电脑上的,mac上也有和iOS设备中一样的调试工具,并且被收录在Apple官网工具中。同样,这工具也是影响整个系统的。

详情可看:http://nshipster.com/network-link-conditioner/

该工具的Apple官方地址:https://developer.apple.com/downloads/index.action?q=Network%20Link%20Conditioner#

具体的步骤:

下载:

%title插图%num%title插图%num

打开DMG文件,里面包含了许多调试工具,其他的工具有兴趣的可以自己去看一下。这里我们只打开Network Link Conditioner.prefPane这个文件%title插图%num

%title插图%num

在系统偏好中出现了工具:

%title插图%num

打开工具,看一下,几乎和手机上是一样的。

%title插图%num%title插图%num

*后:

希望各位看完这篇文章,能更好的做好应用的各种调试,开发出更加稳定可靠的应用来。

iOS 播放flash视频文件

找一个相对比较简单的swf,在WIN下面用闪客精灵7打开。
(这个软件可以实现反编译swf和提取swf资源等,破解版找了很久,方便大家就直接发上来了)
http://115.com/file/ankbb0zw

%title插图%num

这里我选了一个比较简单的倒计时swf

然后,用闪客精灵的swf转html5功能把这个swf转成html5

%title插图%num

然后可以看到一个html和一个js,打开那个html就可以看到动画

%title插图%num

但是这个js看着很烦,而且xcode会把js当作源文件编译,所以先要把那个js和那个html合并掉
用DreamWeaver打开那个html和js,在html文件里面找到这样的代码

%title插图%num

这个代码用于引用这个js,接下来把它换成这样

%title插图%num

然后把那个js里面的所有代码粘到中间,就成这样

%title插图%num

接下来就可以把这个js删掉了,html照样可以播放

%title插图%num

然后,换到Mac系统,用xcode新建一个单界面项目,在界面里面放入一个uiwebview

%title插图%num

再修改试图控制器代码:

复制代码

  1. //ViewController.h
  2. #import <UIKit/UIKit.h>
  3. @interface ViewController : UIViewController{
  4.     IBOutlet UIWebView *myWebView;
  5. }
  6. @property(retain,nonatomic)IBOutlet UIWebView *myWebView;
  7. @end

 

复制代码

  1. //ViewController.m
  2. #import “ViewController.h”
  3. @implementation ViewController
  4. @synthesize myWebView;
  5. – (void)viewDidLoad
  6. {
  7.     [super viewDidLoad];
  8.     [self loadDocument:@”Flash.html”];
  9. }
  10. -(void)dealloc{
  11.     [super dealloc];
  12.     [myWebView release];
  13. }
  14. – (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
  15. {
  16.     return YES;
  17. }
  18. -(void)loadDocument:(NSString*)htmlName{
  19.     NSString *bundlePath=[[NSBundle mainBundle]bundlePath];
  20.     NSString *path=[bundlePath stringByAppendingPathComponent:htmlName];
  21.     NSURL *url=[NSURL fileURLWithPath:path];
  22.     NSURLRequest *request=[NSURLRequest requestWithURL:url];
  23.     NSLog(@”%@”,url);
  24.     self.myWebView.scalesPageToFit=YES;
  25.     [self.myWebView loadRequest:request];
  26. }
  27. @end

*后,把那个html的名称改成“Flash.html”,当作资源放入项目,一切OK啦。。。。。。。。
虽然比较牵强,但是至少还是实现了哈,原创帖欢迎转载,如有问题可以回复提出。我才初一,希望大哥大姐们可以体谅我。。。

附上Demo  IOS_Flash.zip (99 K)

1.将swf视频转换成html。–闪客精灵

会出现两个文件(html,js)

2.在html文件*后面添加上

</script>

<script>

此处把js的内容全部粘帖过来即可

</script>

</body>

</html>

 

3.

UIWebView * webView = [[UIWebViewalloc]initWithFrame:CGRectMake(10,50, 300, 250)];

NSString *bundlePath=[[NSBundle mainBundle]bundlePath];

NSString *path=[bundlePathstringByAppendingPathComponent:htmlName];

NSURL *url=[NSURL fileURLWithPath:path];

NSURLRequest *request=[NSURLRequestrequestWithURL:url];

NSLog(@”%@”,url);

[webView setDelegate:self];

webView.scalesPageToFit=YES;

[webView loadRequest:request];

[self.viewaddSubview:webView];

IOS7毛玻璃效果

关于毛玻璃效果 首先要区分动态毛玻璃 和 静态毛玻璃

ios6上做动态毛玻璃 基本上 是不可能,除非整体界面用opengl开发。UIkit基础上去做动态毛玻璃,可行性为0,就算有GPUImage去做模糊(GPUImage的模糊效果 和系统那个相差的还很远)固然是很快,但是屏幕资源截取的过程才是瓶颈所在。ios6 和ios7 屏幕截取的方法效率相差5倍,ios6上还没等模糊 就是截取屏幕资源 就已经很卡了。
如果说是静态的毛玻璃(不需要动态的截取屏幕资源) 在iphone5这样高性能的机器上 还勉强可以尝试去做。

毛玻璃效果 还是要考虑系统与性能 ios6上不建议 去尝试做动态毛玻璃效果 如果硬是要尝试去做 那程序的稳定性 以及 效率 肯定没有保障。
ios7上的api对实现静态毛玻璃的支持问题不大,不过目前如果想要在自定义控件上实现动态毛玻璃,还比较困难。

关于android的毛玻璃 可以关注github上*近一个项目,BlurEffectForAndroidDesign ,这个项目blur的算法并没有用opengl实现。

参考文章: http://www.zhihu.com/question/21260575

http://www.zhihu.com/question/21260575/answer/17695559

%title插图%num

Demo 下载地址:

https://github.com/nicklockwood/FXBlurView

https://github.com/BTLibrary/BTBlurredView

https://github.com/denivip/BlurCompare

https://github.com/JagCesar/iOS-blur

https://github.com/kronik/DKLiveBlur

IOS代码判断设备类型

判断IOS设备类型一般会使用

[objc]  view plain copy 在CODE上查看代码片 派生到我的代码片

  1. //设备名称
  2. return [UIDevice currentDevice].name;
  3. //设备型号,只可得到是何设备,无法得到是第几代设备
  4. return [UIDevice currentDevice].model;
  5. //系统版本型号,如iPhone OS 
  6. return [UIDevice currentDevice].systemVersion;
  7. //系统版本名称,如6.1.3
  8. return [UIDevice currentDevice].systemName;

但是,这样只能区分iPhone,iPad

真正能够实现设备类型区分的方法如下

[objc]  view plain copy 在CODE上查看代码片 派生到我的代码片

  1. #import <sys/utsname.h>
  2. NSString*
  3. machineName()
  4. {
  5.     struct utsname systemInfo;
  6.     uname(&systemInfo);
  7.     return [NSString stringWithCString:systemInfo.machine
  8.                               encoding:NSUTF8StringEncoding];
  9. }

结果可能为如下的以逗号分隔的字符串

[objc]  view plain copy 在CODE上查看代码片 派生到我的代码片

  1. @”i386″      on the simulator
  2. @”iPod1,1″   on iPod Touch
  3. @”iPod2,1″   on iPod Touch Second Generation
  4. @”iPod3,1″   on iPod Touch Third Generation
  5. @”iPod4,1″   on iPod Touch Fourth Generation
  6. @”iPhone1,1″ on iPhone
  7. @”iPhone1,2″ on iPhone 3G
  8. @”iPhone2,1″ on iPhone 3GS
  9. @”iPad1,1″   on iPad
  10. @”iPad2,1″   on iPad 2
  11. @”iPad3,1″   on 3rd Generation iPad
  12. @”iPhone3,1″ on iPhone 4
  13. @”iPhone4,1″ on iPhone 4S
  14. @”iPhone5,1″ on iPhone 5 (model A1428, AT&T/Canada)
  15. @”iPhone5,2″ on iPhone 5 (model A1429, everything else)
  16. @”iPad3,4″ on 4th Generation iPad
  17. @”iPad2,5″ on iPad Mini
  18. @”iPhone5,3″ on iPhone 5c (model A1456, A1532 | GSM)
  19. @”iPhone5,4″ on iPhone 5c (model A1507, A1516, A1526 (China), A1529 | Global)
  20. @”iPhone6,1″ on iPhone 5s (model A1433, A1533 | GSM)
  21. @”iPhone6,2″ on iPhone 5s (model A1457, A1518, A1528 (China), A1530 | Global)
  22. @”iPad4,1″ on 5th Generation iPad (iPad Air) – Wifi
  23. @”iPad4,2″ on 5th Generation iPad (iPad Air) – Cellular
  24. @”iPad4,4″ on 2nd Generation iPad Mini – Wifi
  25. @”iPad4,5″ on 2nd Generation iPad Mini – Cellular

为了简化代码,网上找到了如下实现,是通过NSDictionary实现快速查询

[objc]  view plain copy 在CODE上查看代码片 派生到我的代码片

  1. #import <sys/utsname.h>
  2. NSString *machineName()
  3. {
  4.     struct utsname systemInfo;
  5.     uname(&systemInfo);
  6.     NSString *iOSDeviceModelsPath = [[NSBundle mainBundle] pathForResource:@”iOSDeviceModelMapping” ofType:@”plist”];
  7.     NSDictionary *iOSDevices = [NSDictionary dictionaryWithContentsOfFile:iOSDeviceModelsPath];
  8.     NSString* deviceModel = [NSString stringWithCString:systemInfo.machine
  9.                                                encoding:NSUTF8StringEncoding];
  10.     return [iOSDevices valueForKey:deviceModel];
  11. }

在xCode解决方案中添加以 iOSDeviceModelMapping.plist 命名的plist文件,内容如下

[html]  view plain copy 在CODE上查看代码片 派生到我的代码片

  1. <?xml version=“1.0” encoding=“UTF-8”?>
  2. <!DOCTYPE plist PUBLIC “-//Apple//DTD PLIST 1.0//EN” “http://www.apple.com/DTDs/PropertyList-1.0.dtd”>
  3. <plist version=“1.0”>
  4. <dict>
  5.     <key>x86_64</key>
  6.     <string>Simulator</string>
  7.     <key>i386</key>
  8.     <string>Simulator</string>
  9.     <key>iPod1,1</key>
  10.     <string>iPod Touch 1st Gen</string>
  11.     <key>iPod2,1</key>
  12.     <string>iPod Touch 2nd Gen</string>
  13.     <key>iPod3,1</key>
  14.     <string>iPod Touch 3rd Gen</string>
  15.     <key>iPod4,1</key>
  16.     <string>iPod Touch 4th Gen</string>
  17.     <key>iPod5,1</key>
  18.     <string>iPod Touch 5th Gen</string>
  19.     <key>iPhone1,1</key>
  20.     <string>iPhone</string>
  21.     <key>iPhone1,2</key>
  22.     <string>iPhone 3G</string>
  23.     <key>iPhone2,1</key>
  24.     <string>iPhone 3GS</string>
  25.     <key>iPhone3,1</key>
  26.     <string>iPhone 4</string>
  27.     <key>iPhone3,2</key>
  28.     <string>iPhone 4</string>
  29.     <key>iPhone3,3</key>
  30.     <string>iPhone 4</string>
  31.     <key>iPhone4,1</key>
  32.     <string>iPhone 4S</string>
  33.     <key>iPhone5,1</key>
  34.     <string>iPhone 5 model A1428</string>
  35.     <key>iPhone5,2</key>
  36.     <string>iPhone 5 model A1429</string>
  37.     <key>iPhone5,3</key>
  38.     <string>iPhone 5C</string>
  39.     <key>iPhone5,4</key>
  40.     <string>iPhone 5C</string>
  41.     <key>iPhone6,1</key>
  42.     <string>iPhone 5S</string>
  43.     <key>iPhone6,2</key>
  44.     <string>iPhone 5S</string>
  45.     <key>iPad1,1</key>
  46.     <string>iPad</string>
  47.     <key>iPad2,1</key>
  48.     <string>iPad 2</string>
  49.     <key>iPad2,2</key>
  50.     <string>iPad 2</string>
  51.     <key>iPad2,3</key>
  52.     <string>iPad 2</string>
  53.     <key>iPad2,4</key>
  54.     <string>iPad 2</string>
  55.     <key>iPad3,1</key>
  56.     <string>iPad 3rd Gen</string>
  57.     <key>iPad3,2</key>
  58.     <string>iPad 3rd Gen</string>
  59.     <key>iPad3,3</key>
  60.     <string>iPad 3rd Gen</string>
  61.     <key>iPad3,4</key>
  62.     <string>iPad 4th Gen</string>
  63.     <key>iPad3,5</key>
  64.     <string>iPad 4th Gen</string>
  65.     <key>iPad3,6</key>
  66.     <string>iPad 4th Gen</string>
  67.     <key>iPad4,1</key>
  68.     <string>iPad Air</string>
  69.     <key>iPad4,2</key>
  70.     <string>iPad Air</string>
  71.     <key>iPad2,5</key>
  72.     <string>iPad Mini 1st Gen</string>
  73.     <key>iPad2,6</key>
  74.     <string>iPad Mini 1st Gen</string>
  75.     <key>iPad2,7</key>
  76.     <string>iPad Mini 1st Gen</string>
  77.     <key>iPad4,4</key>
  78.     <string>iPad Mini 2nd Gen</string>
  79.     <key>iPad4,5</key>
  80.     <string>iPad Mini 2nd Gen</string>
  81. </dict>
  82. </plist>

当MachineName方法时,NSDictionary通过匹配key,即utsname.machine的值,判断设备类型。

  1. #import <sys/utsname.h>
  2. – (NSString*) deviceName
  3. {
  4.     struct utsname systemInfo;
  5.     uname(&systemInfo);
  6.     NSString* code = [NSString stringWithCString:systemInfo.machine
  7.                                         encoding:NSUTF8StringEncoding];
  8.     static NSDictionary* deviceNamesByCode = nil;
  9.     if (!deviceNamesByCode) {
  10.         deviceNamesByCode = @{@”i386″      :@”Simulator”,
  11.                               @”iPod1,1″   :@”iPod Touch”,      // (Original)
  12.                               @”iPod2,1″   :@”iPod Touch”,      // (Second Generation)
  13.                               @”iPod3,1″   :@”iPod Touch”,      // (Third Generation)
  14.                               @”iPod4,1″   :@”iPod Touch”,      // (Fourth Generation)
  15.                               @”iPhone1,1″ :@”iPhone”,          // (Original)
  16.                               @”iPhone1,2″ :@”iPhone”,          // (3G)
  17.                               @”iPhone2,1″ :@”iPhone”,          // (3GS)
  18.                               @”iPad1,1″   :@”iPad”,            // (Original)
  19.                               @”iPad2,1″   :@”iPad 2″,          //
  20.                               @”iPad3,1″   :@”iPad”,            // (3rd Generation)
  21.                               @”iPhone3,1″ :@”iPhone 4″,        //
  22.                               @”iPhone4,1″ :@”iPhone 4S”,       //
  23.                               @”iPhone5,1″ :@”iPhone 5″,        // (model A1428, AT&T/Canada)
  24.                               @”iPhone5,2″ :@”iPhone 5″,        // (model A1429, everything else)
  25.                               @”iPad3,4″   :@”iPad”,            // (4th Generation)
  26.                               @”iPad2,5″   :@”iPad Mini”,       // (Original)
  27.                               @”iPhone5,3″ :@”iPhone 5c”,       // (model A1456, A1532 | GSM)
  28.                               @”iPhone5,4″ :@”iPhone 5c”,       // (model A1507, A1516, A1526 (China), A1529 | Global)
  29.                               @”iPhone6,1″ :@”iPhone 5s”,       // (model A1433, A1533 | GSM)
  30.                               @”iPhone6,2″ :@”iPhone 5s”,       // (model A1457, A1518, A1528 (China), A1530 | Global)
  31.                               @”iPad4,1″   :@”iPad Air”,        // 5th Generation iPad (iPad Air) – Wifi
  32.                               @”iPad4,2″   :@”iPad Air”,        // 5th Generation iPad (iPad Air) – Cellular
  33.                               @”iPad4,4″   :@”iPad Mini”,       // (2nd Generation iPad Mini – Wifi)
  34.                               @”iPad4,5″   :@”iPad Mini”        // (2nd Generation iPad Mini – Cellular)
  35.                               };
  36.     }
  37.     NSString* deviceName = [deviceNamesByCode objectForKey:code];
  38.     if (!deviceName) {
  39.         // Not found on database. At least guess main device type from string contents:
  40.         if ([deviceName rangeOfString:@”iPod”].location != NSNotFound) {
  41.             deviceName = @”iPod Touch”;
  42.         }
  43.         else if([deviceName rangeOfString:@”iPad”].location != NSNotFound) {
  44.             deviceName = @”iPad”;
  45.         }
  46.         else if([deviceName rangeOfString:@”iPhone”].location != NSNotFound){
  47.             deviceName = @”iPhone”;
  48.         }
  49.     }
  50.     return deviceName;
  51. }
  52. // (rest of class implementation omitted)
  53. @end

 

后面加个获取系统版本号的,好记心不如烂笔头

[objc]  view plain copy

  1. NSLog(@”System Name: %@”, [[UIDevice currentDevice] systemName]);  //”iPhone OS”
  2. NSLog(@”System Version: %@”, [[UIDevice currentDevice] systemVersion]);  //7.0.3

iOS 判断系统是否越狱的代码

+ (BOOL) hasCydia{

    return [[NSFileManager defaultManager] fileExistsAtPath:@”/Applications/Cydia.app”];

}

+ (BOOL) hasAPT

{

   return [[NSFileManager defaultManager] fileExistsAtPath:@”/private/var/lib/apt/”];

}

+ (BOOL) successCallSystem

{

    return (system(“ls”) == 0) ? YES : NO;

}

+ (bool) testLibEnv

{

    char *env = getenv(“DYLD_INSERT_LIBRARIES”);

    NSLog(@”%s”, env);

    return env != NULL;

}

+ (BOOL) isJailbreak

{

    BOOL b0 = [self hasCydia],

    b1 = [self hasAPT],

    b2 = [self successCallSystem],

    b3 = [self testLibEnv];

    return b0||b1||b2||b3;

}