由于各個前端系統(tǒng)的權(quán)限設(shè)置贝乎,很多設(shè)備信息都不能得到有效的獲取叽粹;所以览效,公司后臺同學(xué)經(jīng)常詢問前端同學(xué),你們都能獲取到一些什么字段虫几?發(fā)現(xiàn)自己也很長一段時間沒有記錄技術(shù)上的知識點了锤灿,借此時機,將能獲取設(shè)備的信息來統(tǒng)一記錄辆脸。
對于收集設(shè)備信息來說分成兩大塊但校,第一當(dāng)然是設(shè)備的一些私有和唯一的信息,第二就是App的信息啡氢,我們先從簡單的App的信息來說状囱。
第一部分:App的信息
關(guān)于App的信息,我們大概就需要獲取App的版本號空执、App的build版本號浪箭、包名、App顯示名稱等等辨绊。
//DeviceUtils.h中定義
#pragma mark - About App Config Info Method
/**
* 獲取當(dāng)前App的版本號信息
*/
+ (NSString *)getAppVersion;
/**
* 獲取當(dāng)前App的build版本號信息
*/
+ (NSString *)getAppBuildVersion;
/**
* 獲取當(dāng)前App的包名信息
*/
+ (NSString *)getAppBundleId;
/**
* 獲取當(dāng)前App的名稱信息
*/
+ (NSString *)getAppDisplayName;
//DeviceUtils.m中實現(xiàn)
#pragma mark - About App Config Info Method
/*獲取當(dāng)前App的版本號信息*/
+ (NSString *)getAppVersion
{
NSBundle *currentBundle = [NSBundle mainBundle];
NSDictionary *infoDictionary = [currentBundle infoDictionary];
return [infoDictionary objectForKey:@"CFBundleShortVersionString"];
}
/*獲取當(dāng)前App的build版本號信息*/
+ (NSString *)getAppBuildVersion
{
NSBundle *currentBundle = [NSBundle mainBundle];
NSDictionary *infoDictionary = [currentBundle infoDictionary];
return [infoDictionary objectForKey:@"CFBundleVersion"];
}
/*獲取當(dāng)前App的包名信息*/
+ (NSString *)getAppBundleId
{
NSBundle *currentBundle = [NSBundle mainBundle];
NSDictionary *infoDictionary = [currentBundle infoDictionary];
return [infoDictionary objectForKey:@"CFBundleIdentifier"];
}
/*獲取當(dāng)前App的名稱信息*/
+ (NSString *)getAppDisplayName
{
NSBundle *currentBundle = [NSBundle mainBundle];
NSDictionary *infoDictionary = [currentBundle infoDictionary];
return [infoDictionary objectForKey:@"CFBundleDisplayName"];
}
第二部分:設(shè)備的一些私有和唯一的信息
關(guān)于獲取設(shè)備各種標(biāo)識符奶栖,大概統(tǒng)計了一下∶趴溃基本上有IDFA宣鄙、IDFV、IMEI默蚌、IMSI冻晤、UUID、UDID绸吸、MAC地址等等鼻弧。但隨著對用戶隱私信息的保護(hù),蘋果系統(tǒng)對信息的獲取進(jìn)行權(quán)限設(shè)置锦茁,譬如IMEI攘轩、IMSI等的獲取都明確禁止了,除非你發(fā)布的App不通過蘋果商店的渠道码俩。不管獲取權(quán)限度帮,先來介紹下這些字段的含義。
1稿存、IMEI笨篷、IMSI瞳秽、UUID、UDID率翅、MAC地址
IMEI:英文名稱是:International Mobile Equipment Identity练俐,是國際移動設(shè)備身份碼的縮寫,國際移動裝備辨識碼安聘,是由15位數(shù)字組成的”電子串號”痰洒,它與每臺手機一一對應(yīng),而且該碼是全世界唯一的浴韭。每一部手機在組裝完成后都將被賦予一個全球唯一的一組號碼,這個號碼從生產(chǎn)到交付使用都將被制造生產(chǎn)的廠商所記錄脯宿。手機用戶可以在手機中查到自己手機的IMEI碼念颈。因為隱私問題,蘋果用戶在iOS5以后不能再獲取IMEI的值了连霉。如果開發(fā)的App不上架蘋果商店榴芳,又想獲取IMEI值,可參考此鏈接跺撼,獲取IMEI值窟感。
IMSI:英文名稱是:International Mobile Subscriber Identification Number,是國際移動用戶識別碼的縮寫歉井,IMSI分為兩部分:一部分叫MCC(Mobile Country Code移動國家碼)柿祈,MCC的資源由國際電聯(lián)(ITU)統(tǒng)一分配,唯一識別移動用戶所屬的國家哩至,MCC共3位躏嚎,中國地區(qū)的MCC為460;另一部分叫MNC(Mobile Network Code 移動網(wǎng)絡(luò)號碼)菩貌,MNC用于識別移動客戶所屬的移動網(wǎng)絡(luò)運營商卢佣。MNC由二到三個十進(jìn)制數(shù)組成,例如中國移動MNC為00箭阶、02虚茶、07,中國聯(lián)通的MNC為01仇参、06嘹叫、09,中國電信的MNC為03冈敛、05待笑、11。
UUID:英文名稱是:Universally Unique Identifier抓谴,翻譯過來就是通用唯一標(biāo)識符暮蹂。UUID是指在一臺機器上生成的數(shù)字寞缝,它保證對在同一時空中的所有機器都是唯一的。通常平臺會提供生成的API仰泻,是一個32位的十六進(jìn)制序列荆陆,使用小橫線來連接:8-4-4-4-12。由于UUID的本身特性,它保證對在同一時空中的所有機器都是唯一的集侯。所以被啼,需要作為唯一標(biāo)識碼的話,你可以通過保存在keychain或者NSUserDefaults中棠枉。
UDID:所謂UDID指的是設(shè)備的唯一設(shè)備識別符浓体,移動廣告商和游戲網(wǎng)絡(luò)運營商往往需要通過UDID用來識別玩家用戶,并對用戶活動進(jìn)行跟蹤辈讶。UDID 在iOS5.0 的時候已經(jīng)被拋棄使用了命浴。因為隱私問題,蘋果宣稱如果第三方應(yīng)用開發(fā)者繼續(xù)分享或者使用iPhone贱除、Mac生闲、AppleWatch的UDID的話,那么他們的應(yīng)用將會禁止上架月幌。比如我開發(fā)了5款A(yù)pp碍讯,很多用戶都下載了這5款A(yù)pp并使用。如果我能輕易的獲取這些用戶的UDID扯躺,其實我能拼湊出用戶的很多信息捉兴。由于UDID本身的隱私屬性,之前常常用來做第三方統(tǒng)計和其他的目的缅帘。蘋果就推出了一個UDID的替代品identifierForVendor的屬性轴术,關(guān)于IDFV的詳細(xì)內(nèi)容在下一點中查看。UDID目前主要用于配置真機調(diào)試證書钦无。
MAC地址:Mac地址是唯一的逗栽,unix有系統(tǒng)調(diào)用可以獲取Mac地址。iPhone可能有多個Mac地址失暂,wifi的地址彼宠、以及SIM卡的地址。一般來講弟塞,我們?nèi)n0的地址凭峡,因為它是iPhone的wifi的地址,是肯定存在的(例外情況依然有:市面上依然存在一部分聯(lián)通的閹割版無wifi的iPhone)决记。Mac地址涉及到隱私摧冀,不應(yīng)該胡亂將用戶的Mac地址傳播,所以我們需要將Mac地址進(jìn)行hash之后再去使用。同樣因為隱私問題索昂,在iOS7以后建车,蘋果禁止獲取MAC地址,系統(tǒng)現(xiàn)在只會返回02:00:00:00:00:00虛擬的地址椒惨。
2缤至、IDFA、IDFV
- IDFA:廣告標(biāo)示符康谆,iOS6及以后使用领斥。用戶可以在設(shè)置中控制IDFA是否允許獲取以及重置,雖然一般用戶都不知道有這個權(quán)限設(shè)置沃暗,所以IDFA是不能拿來當(dāng)做設(shè)備唯一標(biāo)識(UUID)的替代品月洛。
關(guān)閉IDFA獲取權(quán)限操作:設(shè)置 → 隱私 → 廣告 → 選擇禁止獲取IDFA值
重新生成IDFA操作:
操作一:設(shè)置程序 → 通用 → 還原 → 還原位置與隱私
操作二:設(shè)置程序 → 通用 → 關(guān)于本機 → 廣告 → 還原廣告標(biāo)示符
//導(dǎo)入獲取IDFA的頭文件
#import <AdSupport/ASIdentifierManager.h>
- (NSString *)getDeviceIDFAValue
{
ASIdentifierManager *object = nil;
object = [ASIdentifierManager sharedManager];
return [[object advertisingIdentifier] UUIDString];
}
關(guān)于IDFA的一張很好的圖解:
- IDFV:iOS6.0及以后使用,是給Vendor標(biāo)識用戶用的孽锥,主要用于公司內(nèi)部統(tǒng)計用戶膊存。如果隸屬一個相同的組織下的App獲取到的IDFV是同一個值。例如:
編號 | 包名 | IDFV |
---|---|---|
1 | com.test.app1 | 與2相同忱叭,與3、4不同 |
2 | com.test.app2 | 與1相同今艺,與3韵丑、4不同 |
3 | com.test.develop.app1 | 與4相同,與1虚缎、2不同 |
4 | com.test.develop.app2 | 與3相同撵彻,與1、2不同 |
準(zhǔn)確點說实牡,就是通過BundleID的反轉(zhuǎn)的前兩部分進(jìn)行匹配陌僵,如果相同就是同一個Vender,共享同一個IDFV的值创坞。
NSString *idfv = [[UIDevice currentDevice].identifierForVendor UUIDString];
3碗短、設(shè)備運營商名稱、運營商網(wǎng)絡(luò)
設(shè)備運營商名稱:當(dāng)前設(shè)備上的SIM卡代理商名稱题涨。
運營商網(wǎng)絡(luò):當(dāng)前設(shè)備上的蜂窩網(wǎng)絡(luò)名稱或WiFi偎谁。
4、設(shè)備型號纲堵、設(shè)備的系統(tǒng)名稱巡雨、設(shè)備的系統(tǒng)版本號
設(shè)備型號:主要用來區(qū)分設(shè)備是iPhone 3gs、iPhone 4席函、iPhone 4s铐望、iPhone 5、iPhone 5s、iPhone 6正蛙、iPhone 6s督弓、iPhone 7、iPhone 8跟畅、iPhone X等咽筋,還有iPad、iWatch等蘋果產(chǎn)品型號徊件。蘋果沒有提供直接獲取型號名稱的API方法奸攻,所以這個值獲取出來后,需要在后臺進(jìn)行映射成對應(yīng)的設(shè)備型號虱痕。
設(shè)備的系統(tǒng)名稱:蘋果設(shè)備(手機以及平板)目前只有iOS系統(tǒng)睹耐,蘋果電腦是Mac OS系統(tǒng)等。
設(shè)備的系統(tǒng)版本號:蘋果設(shè)備的系統(tǒng)版本號部翘,可通過UIDevice類直接獲取到一個浮點值硝训。
5、設(shè)備的尺寸新思、設(shè)備的分辨率
設(shè)備的尺寸:蘋果設(shè)備的物理尺寸窖梁,可通過UIScreen類直接獲取到bounds屬性進(jìn)行讀取。
設(shè)備的分辨率:蘋果設(shè)備的分辨率夹囚,可通過UIScreen類直接獲取到bounds屬性和scale屬性進(jìn)行計算纵刘。
下面直接上代碼:
//DeviceUtils.h中定義
#pragma mark - About Device Config Info Method
/**
* 獲取當(dāng)前設(shè)備的IMSI值
*/
+ (NSString *)getDeviceIMSIValue;
/**
* 獲取當(dāng)前設(shè)備的IMEI值
*/
+ (NSString *)getDeviceIMEIValue;
/**
* 獲取當(dāng)前設(shè)備的MacId值
*/
+ (NSString *)getDeviceMacIdValue;
/**
* 獲取當(dāng)前設(shè)備的通訊運營商名稱
*/
+ (NSString *)getDeviceCarrierName;
/**
* 獲取當(dāng)前設(shè)備的網(wǎng)絡(luò)通訊名稱值
*/
+ (NSString *)getDeviceNetworkName;
/**
* 獲取當(dāng)前設(shè)備的橫向最大值
*/
+ (NSNumber *)getDeviceXMaxValue;
/**
* 獲取當(dāng)前設(shè)備的縱向最大值
*/
+ (NSNumber *)getDeviceYMaxValue;
/**
* 獲取當(dāng)前設(shè)備的橫向分辨率值
*/
+ (NSNumber *)getDeviceXResolution;
/**
* 獲取當(dāng)前設(shè)備的縱向分辨率值
*/
+ (NSNumber *)getDeviceYResolution;
/**
* 獲取當(dāng)前設(shè)備的型號名稱
*/
+ (NSString *)getDeviceModel;
/**
* 獲取當(dāng)前設(shè)備的操作系統(tǒng)名稱
*/
+ (NSString *)getDeviceOSName;
/**
* 獲取當(dāng)前設(shè)備的操作系統(tǒng)版本號
*/
+ (NSString *)getDeviceOSVersion;
/**
* 獲取當(dāng)前設(shè)備的唯一編號
*/
+ (NSString *)getDeviceTerminalId;
//DeviceUtils.m中實現(xiàn)
#pragma mark - About Device Config Info Method
/*獲取當(dāng)前設(shè)備的IMSI值*/
+ (NSString *)getDeviceIMSIValue
{
return nil;
}
/*獲取當(dāng)前設(shè)備的IMEI值*/
+ (NSString *)getDeviceIMEIValue
{
return nil;
}
/*獲取當(dāng)前設(shè)備的MacId值*/
+ (NSString *)getDeviceMacIdValue
{
return nil;
}
/*獲取當(dāng)前設(shè)備的通訊運營商名稱*/
+ (NSString *)getDeviceCarrierName
{
CTTelephonyNetworkInfo *info = [CTTelephonyNetworkInfo new];
CTCarrier *carrier = [info subscriberCellularProvider];
return [carrier carrierName];
}
/*獲取當(dāng)前設(shè)備的網(wǎng)絡(luò)通訊名稱值*/
+ (NSString *)getDeviceNetworkName
{
/*
CTRadioAccessTechnologyGPRS //介于2G和3G之間(2.5G)
CTRadioAccessTechnologyEdge //GPRS到第三代移動通信的過渡(2.75G)
CTRadioAccessTechnologyWCDMA
CTRadioAccessTechnologyHSDPA //亦稱為3.5G(3?G)
CTRadioAccessTechnologyHSUPA //3G到4G的過度技術(shù)
CTRadioAccessTechnologyCDMA1x //3G
CTRadioAccessTechnologyCDMAEVDORev0 //3G標(biāo)準(zhǔn)
CTRadioAccessTechnologyCDMAEVDORevA
CTRadioAccessTechnologyCDMAEVDORevB
CTRadioAccessTechnologyeHRPD //電信一種3G到4G的演進(jìn)技術(shù)(3.75G)
CTRadioAccessTechnologyLTE //接近4G
*/
CTTelephonyNetworkInfo *info = [CTTelephonyNetworkInfo new];
return [info currentRadioAccessTechnology];
}
/*獲取當(dāng)前設(shè)備的橫向最大值*/
+ (NSNumber *)getDeviceXMaxValue
{
CGFloat xoffset = CGRectZero.origin.x;
xoffset = CGRectGetWidth([[UIScreen mainScreen] bounds]);
return [NSNumber numberWithFloat:xoffset];
}
/*獲取當(dāng)前設(shè)備的縱向最大值*/
+ (NSNumber *)getDeviceYMaxValue
{
CGFloat yoffset = CGRectZero.origin.x;
yoffset = CGRectGetHeight([[UIScreen mainScreen] bounds]);
return [NSNumber numberWithFloat:yoffset];
}
/*獲取當(dāng)前設(shè)備的橫向分辨率值*/
+ (NSNumber *)getDeviceXResolution
{
CGFloat width = CGRectZero.size.width;
CGFloat scale = [[UIScreen mainScreen] scale];
width = [[[self class] getDeviceXMaxValue] floatValue];
return [NSNumber numberWithFloat:(width * scale)];
}
/*獲取當(dāng)前設(shè)備的縱向分辨率值*/
+ (NSNumber *)getDeviceYResolution
{
CGFloat height = CGRectZero.size.height;
CGFloat scale = [[UIScreen mainScreen] scale];
height = [[[self class] getDeviceYMaxValue] floatValue];
return [NSNumber numberWithFloat:(height * scale)];
}
/*獲取當(dāng)前設(shè)備的型號名稱*/
+ (NSString *)getDeviceModel
{
NSString *platform = nil;
struct utsname systemInfo;
uname(&systemInfo);
platform = [NSString stringWithCString:systemInfo.machine
encoding:NSUTF8StringEncoding];
return [NSString stringWithFormat:@"%@",platform];
}
/*獲取當(dāng)前設(shè)備的操作系統(tǒng)名稱*/
+ (NSString *)getDeviceOSName
{
return @"ios";
}
/*獲取當(dāng)前設(shè)備的操作系統(tǒng)版本號*/
+ (NSString *)getDeviceOSVersion
{
return [[UIDevice currentDevice] systemVersion];
}
/*獲取當(dāng)前設(shè)備的唯一編號*/
+ (NSString *)getDeviceTerminalId
{
UIDevice *device = [UIDevice currentDevice];
NSString *package = [[self class] getAppBundleId];
NSString *vendor = [[device identifierForVendor] UUIDString];
return [NSString stringWithFormat:@"%@%@",package,vendor];
}