UIDevice

  • iOS 的 APP 应用开发的过程当中,有时为了 bug 跟踪或者获取用反馈的须要自动收集用户设备、系统信息、应用信息等等,这些信息方便开发者诊断问题,固然这些信息是用户的非隐私信息,是经过开发 api 能够获取到的。那么经过那些 api 能够获取这些信息呢,iOS 的 SDK 中提供了 UIDevice,NSBundle,NSLocale。ios

  • UIDevice 提供了多种属性、类函数及状态通知,帮助咱们全方位了解设备情况。从检测电池电量到定位设备与临近感应,UIDevice 所作的工做就是为应用程序提供用户及设备的一些信息。UIDevice 类还可以收集关于设备的各类具体细节,例如机型及 iOS 版本等。其中大部分属性都对开发工做具备积极的辅助做用。objective-c

  • bundle 是一个目录,其中包含了程序会使用到的资源。这些资源包含了如图像、声音、编译好的代码、nib 文件(用户也会把 bundle 称为 plug-in),对应 bundle,cocoa 提供了类 NSBundle。一个应用程序看上去和其余文件没有什么区别. 可是实际上它是一个包含了 nib 文件,编译代码,以及其余资源的目录。咱们把这个目录叫作程序的 main bundle。经过这个路径能够获取到应用的信息,例如应用名、版本号等。api

  • NSLocale 能够获取用户的本地化信息设置,例如货币类型,国家,语言,数字,日期格式的格式化,提供正确的地理位置显示等等。下面的代码获取机器当前语言和国家代码。安全

一、设备相关信息的获取

  • 1.1 设备基本信息

// 获取当前设备
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;
  • 1.2 设备方向

// 判断设备是否生成设备转向通知
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;
  • 1.3 设备电池监控

// 判断设备是否开启电池监控
/*
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];
  • 1.4 设备接近状态监控

// 判断设备是否开启接近状态监控
/*
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];
  • 1.5 设备性能

// 判断设备是否支持多任务
BOOL multitaskingSupported = device.multitaskingSupported;
  • 1.6 设备操做

// 获取用户界面模式
/*
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;
}

二、App 应用相关信息的获取

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"];

三、用户的本地化信息的获取

  • NSLocale

// 语言 en
NSString *language = [[NSLocale preferredLanguages] objectAtIndex:0];

// 国家 en_US
NSString *country = [[NSLocale currentLocale] localeIdentifier];

四、获取设备惟一标识

  • iOS系统中,获取设备惟一标识的方法有不少:

    • 一、UDID:UDID 的全称是 Unique Device Identifier Description,顾名思义,它就是苹果 iOS 设备的惟一识别码。
      • UDID 是由子母和数字组成的 40 个字符串的序号,用来区别每个惟一的 iOS 设备,包括 iPhones, iPads, 以及 iPod touches,这些编码看起来是随机的,其实是跟硬件设备特色相联系的。
      • UDID 能够关联其它各类数据到相关设备上。例如,链接到开发者帐号,能够容许在发布前让设备安装或测试应用;也可让开发者得到 iOS 测试版进行体验。苹果用 UDID 链接到苹果的 ID,这些设备能够自动下载和安装从 App Store 购买的应用、保存从 iTunes 购买的音乐、帮助苹果发送推送通知、即时消息。 在 iOS 应用早期,UDID 被第三方应用开发者和网络广告商用来收集用户数据,能够用来关联地址、记录应用使用习惯,以便推送精准广告。
    • 二、OPEN UDID
      • iOS 2.0 版本之后 UIDevice 提供一个获取设备惟一标识符的方法 uniqueIdentifier,经过该方法咱们能够获取设备的序列号,这个也是目前为止惟一能够确认惟一的标示符。许多开发者把 UDID 跟用户的真实姓名、密码、住址、其它数据关联起来;网络窥探者会从多个应用收集这些数据,而后顺藤摸瓜获得这我的的许多隐私数据。同时大部分应用确实在频繁传输 UDID 和私人信息。 为了不集体诉讼,苹果最终决定在 iOS 5 的时候,将这一惯例废除,开发者被引导生成一个惟一的标识符,只能检测应用程序,其余的信息不提供。如今应用试图获取 UDID 已被禁止且不容许上架。因此这个方法做废。
    • 三、UUID:UUID 是 Universally Unique Identifier 的缩写,中文意思是通用惟一识别码.
      • 咱们能够获取到 UUID,而后把 UUID 保存到 KeyChain 里面。这样之后即便 App 删了再装回来,也能够从 KeyChain 中读取回来。使用 group 还能够能够保证同一个开发商的全部程序针对同一台设备可以获取到相同的不变的 UDID。可是刷机或重装系统后 UDID 仍是会改变。
    • 四、MAC Address
      • 使用 WiFi 的 mac 地址来取代已经废弃了的 uniqueIdentifier 方法。
      • 然而在 iOS 7 中苹果再一次无情的封杀 mac 地址,使用以前的方法获取到的 mac 地址所有都变成了 02:00:00:00:00:00。
    • 五、IDFA:广告标示符(IDFA-identifierForIdentifier),iOS6.0 及之后
      • 全名 advertisingIdentifier。直译就是广告 id, 在同一个设备上的全部 App 都会取到相同的值,是苹果专门给各广告提供商用来追踪用户而设的,用户能够在 设置|隐私|广告追踪 里重置此id的值,或限制此 id 的使用,故此 id 有可能会取不到值,但好在 Apple 默认是容许追踪的,并且通常用户都不知道有这么个设置,因此基本上用来监测推广效果,是戳戳有余了。因为 IDFA 会出现取不到的状况,故毫不能够做为业务分析的主 id,来识别用户。
      • 获取代码:
      #import <AdSupport/AdSupport.h>
      NSString *adId = [[[ASIdentifierManager sharedManager] advertisingIdentifier] UUIDString];
    • 从 17 年 2 月初开始,Apple 开始拒绝采集 IDFA(identifier for advertising)而未集成任何广告服务的应用进入 AppStore。网络

    • 六、IDFV:应用提供商标示符(IDFV-identifierForVendor),iOS6.0 及之后
      • 全名 identifierForVendor。顾名思义,是给 Vendor 标识用户用的,每一个设备在所属同一个 Vender 的应用里,都有相同的值。其中的 Vender 是指应用提供商,但准确点说,是经过 BundleID 的反转的前两部分进行匹配,若是相同就是同一个 Vender,例如对于 com.taobao.app1, com.taobao.app2 这两个 BundleID 来讲,就属于同一个 Vender,共享同一个 idfv 的值。和 IDFA 不一样的是,IDFV 的值是必定能取到的,因此很是适合于做为内部用户行为分析的主 id,来标识用户,替代 OpenUDID。若是用户将属于此 Vender 的全部 App 卸载,则 IDFV 的值会被重置,即再重装此 Vender 的 App,IDFV 的值和以前不一样。
      • 获取代码:
      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;
    }
相关文章
相关标签/搜索