參考:
總結(jié)
目前最佳獲取設(shè)備的唯一標(biāo)識(shí)方案:UUID+keychain
IMEI
蘋果已經(jīng)不允許APP獲取IMEI熔掺,在:設(shè)置-通用-關(guān)于本機(jī)中可以查看到IMEI。
UDID
IDFA和IDFV
- IDFA:廣告標(biāo)識(shí)符
- IDFV:APP 提供商 標(biāo)識(shí)符
IDFA和IDFV都可以通過(guò)系統(tǒng)API獲取到一個(gè)NSUUID對(duì)象置逻,二者都是6.0開(kāi)始使用。
IDFA
獲取方式:
#import <AdSupport/AdSupport.h>
NSString *idfa = [[[ASIdentifierManager sharedManager] advertisingIdentifier] UUIDString];
官方文檔
An alphanumeric string unique to each device, used only for serving advertisements.
Unlike the identifierForVendor property of the UIDevice, the same value is returned to all vendors. This identifier may change—for example, if the user erases the device—so you should not cache it.每個(gè)設(shè)備唯一的字母數(shù)字字符串努潘,僅用于提供廣告诽偷。
與UIDevice的identifierForVendor屬性不同,相同的值返回給所有供應(yīng)商疯坤。這個(gè)標(biāo)識(shí)符可能會(huì)改變——例如报慕,如果用戶擦除設(shè)備——所以您不應(yīng)該緩存它。
In iOS 10.0 and later, the value of advertisingIdentifier is all zeroes when the user has limited ad tracking.
If the value is nil, wait and get the value again later. This happens, for example, after the device has been restarted but before the user has unlocked the device.
在iOS 10.0及以后版本中压怠,當(dāng)用戶限制廣告跟蹤時(shí)眠冈,advertisingIdentifier的值都是0。如果值為nil菌瘫,則等待并稍后再次獲取該值蜗顽。例如,這發(fā)生在設(shè)備重啟之后雨让,但在用戶解鎖設(shè)備之前雇盖。
從官方文檔可總結(jié)出:
- 同個(gè)供應(yīng)商,同一個(gè)設(shè)備栖忠,值相同崔挖。
- 用戶
限制廣告跟蹤
,iOS10以上庵寞,返回的值都為0狸相,如:00000000-0000-0000-0000-000000000000
- 用戶重新關(guān)閉限制廣告跟蹤,值會(huì)改變捐川。
可重置脓鹃,可限制:
- 1、手動(dòng)重置(設(shè)置 -> 通用 -> 還原 -> 還原所有設(shè)置古沥、還原位置與隱私)
- 2瘸右、重置系統(tǒng)
- 3娇跟、設(shè)置 - 隱私 - 廣告 - 限制廣告跟蹤
對(duì)于IDFA的使用,在提審的時(shí)候尊浓,也要注意相關(guān)選項(xiàng)的勾選:
IDFV
NSUUID *idfv = [UIDevice currentDevice].identifierForVendor;
NSLog(@"%@",idfv);
The value of this property is the same for apps that come from the same vendor running on the same device. A different value is returned for apps on the same device that come from different vendors, and for apps on different devices regardless of vendor.
對(duì)于來(lái)自運(yùn)行在相同設(shè)備上的相同供應(yīng)商的應(yīng)用程序逞频,此屬性的值是相同的。對(duì)于來(lái)自不同廠商的同一設(shè)備上的應(yīng)用程序栋齿,以及對(duì)于來(lái)自不同廠商的不同設(shè)備上的應(yīng)用程序,將返回不同的值襟诸。
If the value is nil, wait and get the value again later. This happens, for example, after the device has been restarted but before the user has unlocked the device.
如果值為nil瓦堵,則等待并稍后再次獲取該值。例如歌亲,這發(fā)生在設(shè)備重啟之后菇用,但在用戶解鎖設(shè)備之前。
The value changes when the user deletes all of that vendor’s apps from the device and subsequently reinstalls one or more of them. The value can also change when installing test builds using Xcode or when installing an app on a device using ad-hoc distribution. Therefore, if your app stores the value of this property anywhere, you should gracefully handle situations where the identifier changes.
當(dāng)用戶從設(shè)備上刪除該供應(yīng)商的所有應(yīng)用程序并隨后重新安裝其中一個(gè)或多個(gè)應(yīng)用程序時(shí)陷揪,該值將發(fā)生變化惋鸥。在使用Xcode安裝測(cè)試構(gòu)建時(shí),或者在使用特別發(fā)行版在設(shè)備上安裝應(yīng)用程序時(shí)悍缠,該值也可以更改卦绣。因此,如果您的應(yīng)用程序在任何地方存儲(chǔ)此屬性的值飞蚓,那么您應(yīng)該優(yōu)雅地處理標(biāo)識(shí)符更改的情況滤港。
從官方文檔可以獲得如下的要點(diǎn):
- 來(lái)自同一個(gè)提供商的APP運(yùn)行在同一個(gè)設(shè)備上,不同APP獲取該值相同趴拧。
- 來(lái)自不同的提供商的不同APP溅漾,不管是不是同一個(gè)設(shè)備上,該值都不同著榴。
- 同一個(gè)設(shè)備上添履,刪除了該提供商的所有APP,再次安裝該提供商的其中一個(gè)或者多個(gè)APP脑又,值會(huì)改變暮胧。
- 如果獲取到該值為nil,等待并稍后再獲取該值挂谍。這種情況發(fā)生在用戶重啟設(shè)備并解鎖之前叔壤。
- 如果用戶使用xcode或者ad-hoc企業(yè)證書分發(fā)的安裝的情況,值也可能改變口叙,因此炼绘,應(yīng)該優(yōu)雅的緩存該值。(如何緩存妄田?keychain)
供應(yīng)商區(qū)分
為什么主要是由于提供商的來(lái)區(qū)分呢俺亮?因?yàn)檫@個(gè)值就是根據(jù)提供商的不用來(lái)生成的(包名 bundle identifier)驮捍。
如何區(qū)分是否是同一個(gè)提供商?其實(shí)就是看包名脚曾。
包名的格式一般都是這樣的:
com.example.app1
com.example.app2
com.example.app.app1
com.example.app.app2
從系統(tǒng)版本上來(lái)看东且,取決于不同部分
- iOS6上:取前兩部分:com.example
- iOS7以上:除了最后那部分的其他部分:com.example、com.example.app
用表格來(lái)表示如下:
Bundle ID | iOS 6.x | iOS 7.x |
---|---|---|
com.example.app1 | com.example | com.example |
com.example.app2 | com.example | com.example |
com.example.app.app1 | com.example | com.example.app |
com.example.app.app2 | com.example | com.example.app |
因此本讥,com.example.app1和com.example.app2也就屬于同一個(gè)提供商了珊泳。
既然獲取該值可能會(huì)為nil,切會(huì)改變拷沸。因?yàn)槲覀兛梢陨a(chǎn)一個(gè)色查,并且用keychain保存起來(lái)。這樣對(duì)于用一個(gè)APP提供商撞芍,同一個(gè)設(shè)備秧了,無(wú)論用戶刪除APP與否,都可以獲取到同一個(gè)值序无,相當(dāng)于設(shè)備的唯一標(biāo)識(shí)(IMEI)了验毡。
以上的值,IMEI帝嗡,UDID無(wú)法獲取
IDFA根據(jù)值會(huì)因?yàn)橛脩舻脑O(shè)置而獲取不到晶通,用戶重置手機(jī)會(huì)改變。
IDFV用戶充值手機(jī)會(huì)改變丈探。且IDFA录择,IDFV都跟bundle identifier(包名)有關(guān),不能對(duì)每個(gè)包都獲得不同值碗降,因此不合適隘竭。
生成UUID
//生成UUID
- (NSString *)uuidString{
CFUUIDRef uuid_ref = CFUUIDCreate(NULL);
CFStringRef uuid_string_ref= CFUUIDCreateString(NULL, uuid_ref);
NSString *uuid = [NSString stringWithString:(__bridge NSString *)uuid_string_ref];
CFRelease(uuid_ref);
CFRelease(uuid_string_ref);
return [uuid lowercaseString];
}
通過(guò)測(cè)試,用這種方式每次生成的值都不一樣讼渊。只能保存到keychain动看,每次獲取,先去keychain獲取爪幻,如果有則取出菱皆,沒(méi)有則插入一個(gè)新的。即使用戶刪除該APP挨稿,UUID還是會(huì)保存在keychain仇轻,保證了UUID的唯一性。
至于如何使用keychain奶甘。篷店。。等我研究后再寫。現(xiàn)在用的是一個(gè)關(guān)于keychain框架疲陕,可以很方便的操作keychain方淤。
也可以使用SSKeychain
以及別人使用來(lái)保存UUID的方式: