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