NS_CLASS_AVAILABLE_IOS(2_0) @interface UIDevice : NSObject @available(iOS 2.0, *) public class UIDevice : NSObject
iOS 的 APP 应用开发的过程当中,有时为了 bug 跟踪或者获取用反馈的须要自动收集用户设备、系统信息、应用信息等等,这些信息方便开发者诊断问题,固然这些信息是用户的非隐私信息,是经过开发 api 能够获取到的。那么经过那些 api 能够获取这些信息呢,iOS 的 SDK 中提供了 UIDevice,NSBundle,NSLocale。html
UIDevice 提供了多种属性、类函数及状态通知,帮助咱们全方位了解设备情况。从检测电池电量到定位设备与临近感应,UIDevice 所作的工做就是为应用程序提供用户及设备的一些信息。UIDevice 类还可以收集关于设备的各类具体细节,例如机型及 iOS 版本等。其中大部分属性都对开发工做具备积极的辅助做用。ios
bundle 是一个目录,其中包含了程序会使用到的资源。这些资源包含了如图像、声音、编译好的代码、nib 文件(用户也会把 bundle 称为 plug-in),对应 bundle,cocoa 提供了类 NSBundle。一个应用程序看上去和其余文件没有什么区别. 可是实际上它是一个包含了 nib 文件,编译代码,以及其余资源的目录。咱们把这个目录叫作程序的 main bundle。经过这个路径能够获取到应用的信息,例如应用名、版本号等。git
NSLocale 能够获取用户的本地化信息设置,例如货币类型,国家,语言,数字,日期格式的格式化,提供正确的地理位置显示等等。下面的代码获取机器当前语言和国家代码。github
Objective-Capi
设备基本信息安全
// 获取当前设备 UIDevice *device = [UIDevice currentDevice]; // 获取设备名称 /* e.g. "My iPhone" */ NSString *name = device.name; // 获取设备类型 /* e.g. @"iPhone", @"iPod touch" */ NSString *model = device.model; // 获取本地化设备类型 /* localized version of model */ NSString *localizedModel = device.localizedModel; // 获取设备系统名称 /* e.g. @"iOS" */ NSString *systemName = device.systemName; // 获取设备系统版本 /* e.g. @"4.0" */ NSString *systemVersion = device.systemVersion; // 获取设备 UUID /* 可用于惟一标识该设备,同一供应商不一样应用具备相同的 UUID */ NSUUID *identifierForVendor = device.identifierForVendor; NSString *UUID = identifierForVendor.UUIDString;
设备方向网络
// 判断设备是否生成设备转向通知 BOOL generatesDeviceOrientationNotifications = device.isGeneratingDeviceOrientationNotifications; // 开启设备转向通知 /* 经过调用该方法通知设备:若是用户改变了设备的朝向,咱们想获悉这一点 在注册设备方向通知时,须要先调用该方法 */ [device beginGeneratingDeviceOrientationNotifications]; // 中止设备转向通知 /* 在移除设备方向通知后,须要调用该方法 */ [device endGeneratingDeviceOrientationNotifications]; // 注册屏幕方向变化通知 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(deviceOrientationDidChange) name:@"UIDeviceOrientationDidChangeNotification" object:nil]; // 获取设备方向 /* UIDeviceOrientationUnknown, UIDeviceOrientationPortrait, // home button on the bottom 竖向,头向上 UIDeviceOrientationPortraitUpsideDown, // home button on the top 竖向,头向下 UIDeviceOrientationLandscapeLeft, // home button on the right 横向,头向左 UIDeviceOrientationLandscapeRight, // home button on the left 横向,头向右 UIDeviceOrientationFaceUp, // face up 平放,屏幕朝上 UIDeviceOrientationFaceDown // face down 平放,屏幕朝下 除非正在生成设备方向的通知,不然返回 UIDeviceOrientationUnknown */ UIDeviceOrientation orientation = [UIDevice currentDevice].orientation;
设备电池监控app
// 判断设备是否开启电池监控 /* default is NO */ BOOL batteryMonitoringEnabled = device.isBatteryMonitoringEnabled; // 开启电池监控 /* default is NO */ device.batteryMonitoringEnabled = YES; // 获取设备电池状态 /* UIDeviceBatteryStateUnknown, UIDeviceBatteryStateUnplugged, // on battery, discharging 未充电 UIDeviceBatteryStateCharging, // plugged in, less than 100% 正在充电 UIDeviceBatteryStateFull, // plugged in, at 100% 满电 若是禁用电池监控,则电池状态为 UIDeviceBatteryStateUnknown */ UIDeviceBatteryState batteryState = device.batteryState; // 注册电池状态变化通知 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(deviceBatteryStateDidChange) name:@"UIDeviceBatteryStateDidChangeNotification" object:nil]; // 获取电池电量 /* 0 .. 1.0. 若是电池状态为 UIDeviceBatteryStateUnknown,百分比为 -1.0 */ float batteryLevel = device.batteryLevel; // 注册电池电量变化通知 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(deviceBatteryLevelDidChange) name:@"UIDeviceBatteryLevelDidChangeNotification" object:nil];
设备接近状态监控框架
// 判断设备是否开启接近状态监控 /* default is NO */ BOOL proximityMonitoringEnabled = device.isProximityMonitoringEnabled; // 开启接近状态监控 /* default is NO */ device.proximityMonitoringEnabled = YES; // 获取接近状态 /* 若是设备不具有接近感应器,则老是返回 NO */ BOOL proximityState = device.proximityState; // 注册接近状态变化通知 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(deviceProximityStateDidChange) name:@"UIDeviceProximityStateDidChangeNotification" object:nil];
设备性能less
// 判断设备是否支持多任务 BOOL multitaskingSupported = device.multitaskingSupported;
设备操做
// 获取用户界面模式 /* UIUserInterfaceIdiomUnspecified = -1, UIUserInterfaceIdiomPhone // iPhone and iPod touch style UI iPhone 和 iPod touch 风格 UIUserInterfaceIdiomPad // iPad style UI iPad 风格 UIUserInterfaceIdiomTV // Apple TV style UI Apple TV 风格 UIUserInterfaceIdiomCarPlay // CarPlay style UI CarPlay 风格 */ UIUserInterfaceIdiom userInterfaceIdiom = device.userInterfaceIdiom; // 播放一个输入的声音 [device playInputClick]; // UIInputViewAudioFeedback 协议方法 /* 实现该方法,返回 YES 则自定义的视图可以播放输入的声音 */ - (BOOL)enableInputClicksWhenVisible { return YES; }
Swift
设备基本信息
// 获取当前设备 let device:UIDevice = UIDevice.currentDevice() // 获取设备名称 /* e.g. "My iPhone" */ let name:String = device.name // 获取设备类型 /* e.g. @"iPhone", @"iPod touch" */ let model:String = device.model // 获取本地化设备类型 /* localized version of model */ let localizedModel:String = device.localizedModel // 获取设备系统名称 /* e.g. @"iOS" */ let systemName:String = device.systemName // 获取设备系统版本 /* e.g. @"4.0" */ let systemVersion:String = device.systemVersion // 获取设备 UUID /* 可用于惟一标识该设备,同一供应商不一样应用具备相同的 UUID */ let identifierForVendor:NSUUID = device.identifierForVendor! let UUID:String = identifierForVendor.UUIDString
设备方向
// 判断设备是否生成设备转向通知 let generatesDeviceOrientationNotifications:Bool = device.generatesDeviceOrientationNotifications // 开启设备转向通知 /* 经过调用该方法通知设备:若是用户改变了设备的朝向,咱们想获悉这一点 在注册设备方向通知时,须要先调用该方法 */ device.beginGeneratingDeviceOrientationNotifications() // 中止设备转向通知 /* 在移除设备方向通知后,须要调用该方法 */ device.endGeneratingDeviceOrientationNotifications() // 注册屏幕方向变化通知 NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(UiDevice.deviceOrientationDidChange), name: UIDeviceOrientationDidChangeNotification, object: nil) // 获取设备方向 /* UIDeviceOrientationUnknown, UIDeviceOrientationPortrait, // home button on the bottom 竖向,头向上 UIDeviceOrientationPortraitUpsideDown, // home button on the top 竖向,头向下 UIDeviceOrientationLandscapeLeft, // home button on the right 横向,头向左 UIDeviceOrientationLandscapeRight, // home button on the left 横向,头向右 UIDeviceOrientationFaceUp, // face up 平放,屏幕朝上 UIDeviceOrientationFaceDown // face down 平放,屏幕朝下 除非正在生成设备方向的通知,不然返回 UIDeviceOrientationUnknown */ let orientation:UIDeviceOrientation = UIDevice.currentDevice().orientation
设备电池监控
// 判断设备是否开启电池监控 /* default is NO */ let batteryMonitoringEnabled:Bool = device.batteryMonitoringEnabled // 开启电池监控 /* default is NO */ device.batteryMonitoringEnabled = true // 获取设备电池状态 /* UIDeviceBatteryStateUnknown, UIDeviceBatteryStateUnplugged, // on battery, discharging 未充电 UIDeviceBatteryStateCharging, // plugged in, less than 100% 正在充电 UIDeviceBatteryStateFull, // plugged in, at 100% 满电 若是禁用电池监控,则电池状态为 UIDeviceBatteryStateUnknown */ let batteryState:UIDeviceBatteryState = device.batteryState // 注册电池状态变化通知 NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(UiDevice.deviceBatteryStateDidChange), name: UIDeviceBatteryStateDidChangeNotification, object: nil) // 获取电池电量 /* 0 .. 1.0. 若是电池状态为 UIDeviceBatteryStateUnknown,百分比为 -1.0 */ let batteryLevel:Float = device.batteryLevel // 注册电池电量变化通知 NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(UiDevice.deviceBatteryLevelDidChange), name: UIDeviceBatteryLevelDidChangeNotification, object: nil)
设备接近状态监控
// 判断设备是否开启接近状态监控 /* default is NO */ let proximityMonitoringEnabled:Bool = device.proximityMonitoringEnabled // 开启接近状态监控 /* default is NO */ device.proximityMonitoringEnabled = true // 获取接近状态 /* 若是设备不具有接近感应器,则老是返回 NO */ let proximityState:Bool = device.proximityState // 注册接近状态变化通知 NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(UiDevice.deviceProximityStateDidChange), name: UIDeviceProximityStateDidChangeNotification, object: nil)
设备性能
// 判断设备是否支持多任务 let multitaskingSupported:Bool = device.multitaskingSupported
设备操做
// 获取用户界面模式 /* UIUserInterfaceIdiomUnspecified = -1, UIUserInterfaceIdiomPhone // iPhone and iPod touch style UI iPhone 和 iPod touch 风格 UIUserInterfaceIdiomPad // iPad style UI iPad 风格 UIUserInterfaceIdiomTV // Apple TV style UI Apple TV 风格 UIUserInterfaceIdiomCarPlay // CarPlay style UI CarPlay 风格 */ let userInterfaceIdiom:UIUserInterfaceIdiom = device.userInterfaceIdiom // 播放一个输入的声音 device.playInputClick()
Objective-C
NSDictionary *dicInfo = [[NSBundle mainBundle] infoDictionary]; CFShow((__bridge CFTypeRef)(dicInfo)); // App 应用名称 NSString *appName = [dicInfo objectForKey:@"CFBundleName"]; // App 应用版本 NSString *appVersion = [dicInfo objectForKey:@"CFBundleShortVersionString"]; // App 应用 Build 版本 NSString *appBuild = [dicInfo objectForKey:@"CFBundleVersion"];
Swift
let dicInfo:[String : AnyObject]? = NSBundle.mainBundle().infoDictionary CFShow(dicInfo) // App 应用名称 let appName = dicInfo!["CFBundleName"] // App 应用版本 let appVersion = dicInfo!["CFBundleShortVersionString"] // App 应用 Build 版本 let appBuild = dicInfo!["CFBundleVersion"]
Objective-C
// 语言 en NSString *language = [[NSLocale preferredLanguages] objectAtIndex:0]; // 国家 en_US NSString *country = [[NSLocale currentLocale] localeIdentifier];
Swift
// 语言 en let language:String = NSLocale.preferredLanguages()[0] // 国家 en_US let country:String = NSLocale.currentLocale().localeIdentifier
iOS系统中,获取设备惟一标识的方法有不少:
获取代码:
#import <AdSupport/AdSupport.h> NSString *adId = [[[ASIdentifierManager sharedManager] advertisingIdentifier] UUIDString];
从 17 年 2 月初开始,Apple 开始拒绝采集 IDFA(identifier for advertising)而未集成任何广告服务的应用进入 AppStore。
获取代码:
NSString *idfv = [[[UIDevice currentDevice] identifierForVendor] UUIDString];
上面全部这些表示设备惟一的标识,在 iOS 7 中要么被禁止使用,要么从新安装程序后两次获取的标识符不同。因为 iOS 系统存储的数据都是在 sandBox 里面,一旦删除 App,sandBox 也不复存在。
iOS 中获取设备惟一标示符的方法一直随版本的更新而变化。iOS 2.0 版本之后 UIDevice 提供一个获取设备惟一标识符的方法 uniqueIdentifier,经过该方法咱们能够获取设备的序列号,这个也是目前为止惟一能够确认惟一的标示符。好景不长,由于该惟一标识符与手机一一对应,苹果以为可能会泄露用户隐私,因此在 iOS 5.0 以后该方法就被废弃掉了;iOS 6.0 系统新增了两个用于替换 uniqueIdentifier 的接口,分别是:identifierForVendor,advertisingIdentifier,但这两个接口会在应用从新安装时改变数值,并非惟一的标示符,因此开发者改成使用 WiFi 的 mac 地址来取代;iOS 7 中苹果又封杀 mac 地址,因此开发者再次改变思路使用 KeyChain 来保存获取到的 UDID,这样之后即便 App 删了再装回来,也能够从 KeyChain 中读取回来。
首先保存设备的 UUID,可使用类方法 + (id)UUID 是一个类方法,调用该方法能够得到一个 UUID。经过下面的代码能够得到一个 UUID 字符串:
NSString *uuid = [[NSUUID UUID] UUIDString];
也能够保存在 iOS 6 中新增的 Vindor 标示符 (IDFV-identifierForVendor),获取这个 IDFV 的新方法被添加在已有的 UIDevice 类中。跟 advertisingIdentifier 同样,该方法返回的是一个 NSUUID 对象。
NSString *idfv = [[[UIDevice currentDevice] identifierForVendor] UUIDString];
若是用户卸载了同一个 vendor 对应的全部程序,而后在从新安装同一个 vendor 提供的程序,此时 identifierForVendor 会被重置,因此这里要用到 KeyChain 来保存。KeyChain(钥匙串)是使用苹果设备常用的,一般要调试的话,都得安装证书之类的,这些证书就是保存在 KeyChain 中,还有咱们平时浏览网页记录的帐号密码也都是记录在 KeyChain 中。iOS 中的 KeyChain 相比 OS X 比较简单,整个系统只有一个 KeyChain,每一个程序均可以往 KeyChain 中记录数据,并且只能读取到本身程序记录在 KeyChain 中的数据。iOS 中 Security.framework 框架提供了四个主要的方法来操做 KeyChain:
// 查询 OSStatus SecItemCopyMatching(CFDictionaryRef query, CFTypeRef *result); // 添加 OSStatus SecItemAdd(CFDictionaryRef attributes, CFTypeRef *result); // 更新 KeyChain 中的 ItemOSStatus SecItemUpdate(CFDictionaryRef query, CFDictionaryRef attributesToUpdate); // 删除 KeyChain 中的 ItemOSStatus SecItemDelete(CFDictionaryRef query)
这四个方法参数比较复杂,一旦传错就会致使操做 KeyChain 失败,文档中介绍的比较详细,你们能够查查官方文档。而苹果提供的 KeyChain 使用起来略麻烦,因此这里推荐一个第三方库 SSKeychain/SAMKeychain 对苹果安全框架 API 进行了简单封装,支持对存储在钥匙串中密码、帐户进行访问,包括读取、删除和设置。SSKeyChains 使用简单,经过实例代码即可掌握。
// 保存一个 UUID 字符串到钥匙串: CFUUIDRef uuid = CFUUIDCreate(NULL); assert(uuid != NULL); CFStringRef uuidStr = CFUUIDCreateString(NULL, uuid); [SSKeychain setPassword:[NSString stringWithFormat:@"%@", uuidStr] forService:@"com.yourapp.yourcompany"account:@"user"]; // 从钥匙串读取 UUID: NSString *retrieveuuid = [SSKeychainpasswordForService:@"com.yourapp.yourcompany"account:@"user"]; // 注意: setPassword 和 passwordForSevice 方法中的 services 和 accounts 参数应该是一致的。
基本的实现思路即是这样,下面是具体的一种具体实现代码,仅供参考。
+ (NSString *)getDeviceId { NSString *currentDeviceUUIDStr = [SSKeychain passwordForService:[NSBundle mainBundle].bundleIdentifier account:@"uuid"]; if (currentDeviceUUIDStr == nil || [currentDeviceUUIDStr isEqualToString:@""]) { NSUUID *currentDeviceUUID = [UIDevice currentDevice].identifierForVendor; currentDeviceUUIDStr = currentDeviceUUID.UUIDString; currentDeviceUUIDStr = [currentDeviceUUIDStr stringByReplacingOccurrencesOfString:@"-" withString:@""]; currentDeviceUUIDStr = [currentDeviceUUIDStr lowercaseString]; [SSKeychain setPassword: currentDeviceUUIDStr forService:[NSBundle mainBundle].bundleIdentifier account:@"uuid"]; } return currentDeviceUUIDStr; }