翻譯:從iOS7及更高版本往後,如果你向ios設備請求獲取mac地址,系統將返回一個固定值“02:00:00:00:00:00”,如果你需要識別設備的 唯一性,請使用UIDevice的identifierForVendor屬性。(因廣告目的而需要識別設備的應用,請考慮使用 ASIdentifierManager的advertisingIdentifier屬性作爲替代)
這個MAC地址是指什麼?有什麼用?
MAC(Medium/Media Access Control)地址,用來表示互聯網上每一個站點的標識符,採用十六進制數表示,共六個字節(48位)。其中,前三個字節是由IEEE的註冊管理機構 RA負責給不同廠家分配的代碼(高位24位),也稱爲“編制上唯一的標識符” (Organizationally Unique Identifier),後三個字節(低位24位)由各廠家自行指派給生產的適配器接口,稱爲擴展標識符(唯一性)。
MAC地址在網絡上用來區分設備的唯一性,接入網絡的設備都有一個MAC地址,他們肯定都是不同的,是唯一的。一部iPhone上可能有多個MAC地址,包括WIFI的、SIM的等,但是iTouch和iPad上就有一個WIFI的,因此只需獲取WIFI的MAC地址就好了,也就是en0的地址。
形象的說,MAC地址就如同我們身份證上的身份證號碼,具有全球唯一性。這樣就可以非常好的標識設備唯一性,類似與蘋果設備的UDID號,通常的用途有:1)用於一些統計與分析目的,利用用戶的操作習慣和數據更好的規劃產品;2)作爲用戶ID來唯一識別用戶,可以用遊客身份使用app又能在服務器端保存相應的信息,省去用戶名、密碼等註冊過程。
那麼,如何使用Mac地址生成設備的唯一標識呢?主要分三種:
1、直接使用“MAC Address”
2、使用“MD5(MAC Address)”
3、使用“MD5(Mac Address+bundle_id)”獲得“機器+應用”的唯一標識(bundle_id 是應用的唯一標識)
iOS7之前,因爲Mac地址是唯一的, 一般app開發者會採取第3種方式來識別安裝對應app的設備。爲什麼會使用它?在iOS5之前,都是使用UDID的,後來被禁用。蘋果推薦使用UUID 但是也有諸多問題,從而使用MAC地址。而MAC地址跟UDID一樣,存在隱私問題,現在蘋果新發布的iOS7上,如果請求Mac地址都會返回一個固定 值,那麼Mac Address+bundle_id這個值大家的設備都變成一致的啦,跟UDID一樣相當於被禁用。那麼,要怎麼標識設備唯一呢?
在iOS系統中,獲取設備唯一標識的方法有很多:
一.UDID(Unique Device Identifier)
二.UUID(Universally Unique Identifier)
三.MAC Address
四.OPEN UDID
五.廣告標示符(IDFA-identifierForIdentifier)
六.Vindor標示符 (IDFV-identifierForVendor)
七.推送token+bundle_id
UDID的全稱是Unique Device Identifier,它就是蘋果IOS設備的唯一識別碼,它由40個字符的字母和數字組成(越獄的設備通過某些工具可以改變設備的UDID)。移動網絡可利用UDID來識別移動設備,但是,從IOS5.0(2011年8月份)開始,蘋果宣佈將不再支持用uniqueIdentifier方法獲取設備的UDID,iOS5以下是可以用的。在2013年3月21日蘋果已經通知開發者:從2013年5月1日起,訪問UIDIDs的程序將不再被審覈通過,替代的方案是開發者應該使用“在iOS 6中介紹的Vendor或Advertising標示符”。所以UDID是絕對不能用啦。
OPEN UDID,沒有用到MAC地址,同時能保證同一臺設備上的不同應用使用同一個OpenUDID,只要用戶設備上有一個使用了OpenUDID的應用存在時,其他後續安裝的應用如果獲取OpenUDID,都將會獲得第一個應用生成的那個。但是根據貢獻者的代碼和方法,和一些開發者的經驗,如果把使用了OpenUDID方案的應用全部都刪除,再重新獲取OpenUDID,此時的OpenUDID就跟以前的不一樣。可見,這種方法還是不保險。
推送token+bundle_id的方法:
1、應用中增加推送用來獲取token
2、獲取應用bundle_id
3、根據token+bundle_id進行散列運算
apple push token保證設備唯一,但必須有網絡情況下才能工作,該方法不依賴於設備本身,但依賴於apple push,而蘋果push有時候會抽風的。
UUID是Universally Unique Identifier的縮寫,中文意思是通用唯一識別碼。它是讓分佈式系統中的所有元素,都能有唯一的辨識資訊,而不需要透過中央控制端來做辨識資訊的指定。這樣,每個人都可以建立不與其它人衝突的 UUID。在此情況下,就不需考慮數據庫建立時的名稱重複問題。蘋果公司建議使用UUID爲應用生成唯一標識字符串。
- iOS中獲取UUID的代碼如下:
- -(NSString*) uuid {
- CFUUIDRef puuid = CFUUIDCreate( nil );
- CFStringRef uuidString = CFUUIDCreateString( nil, puuid );
- NSString * result = (NSString *)CFStringCreateCopy( NULL, uuidString);
- CFRelease(puuid);
- CFRelease(uuidString);
- return [result autorelease];
- }
- iOS中獲取網卡mac的代碼如下:
- #include <sys/socket.h> // Per msqr
- #include <sys/sysctl.h>
- #include <net/if.h>
- #include <net/if_dl.h>
- #pragma mark MAC addy
- // Return the local MAC addy
- // Courtesy of FreeBSD hackers email list
- // Accidentally munged during previous update. Fixed thanks to mlamb.
- - (NSString *) macaddress
- {
- int mib[6];
- size_t len;
- char *buf;
- unsigned char *ptr;
- struct if_msghdr *ifm;
- struct sockaddr_dl *sdl;
- mib[0] = CTL_NET;
- mib[1] = AF_ROUTE;
- mib[2] = 0;
- mib[3] = AF_LINK;
- mib[4] = NET_RT_IFLIST;
- if ((mib[5] = if_nametoindex("en0")) == 0) {
- printf("Error: if_nametoindex error/n");
- return NULL;
- }
- if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0) {
- printf("Error: sysctl, take 1/n");
- return NULL;
- }
- if ((buf = malloc(len)) == NULL) {
- printf("Could not allocate memory. error!/n");
- return NULL;
- }
- if (sysctl(mib, 6, buf, &len, NULL, 0) < 0) {
- printf("Error: sysctl, take 2");
- return NULL;
- }
- ifm = (struct if_msghdr *)buf;
- sdl = (struct sockaddr_dl *)(ifm + 1);
- ptr = (unsigned char *)LLADDR(sdl);
- // NSString *outstring = [NSString stringWithFormat:@"%02x:%02x:%02x:%02x:%02x:%02x", *ptr, *(ptr+1), *(ptr+2), *(ptr+3), *(ptr+4), *(ptr+5)];
- NSString *outstring = [NSString stringWithFormat:@"%02x%02x%02x%02x%02x%02x", *ptr, *(ptr+1), *(ptr+2), *(ptr+3), *(ptr+4), *(ptr+5)];
- free(buf);
- return [outstring uppercaseString];
- }
一個解決的辦法是:UUID一般只生成一次,保存在iOS系統裏面,如果應用刪除了,重裝應用之後它的UUID還是一樣的,除非系統重置 。但是不能保證在以後的系統升級後還能用(如果系統保存了該信息就能用).
由於IOS系統存儲的數據都是在sandBox裏面,一旦刪除App,sandBox也不復存在。好在有一個例外,那就是keychain(鑰匙串)。
通常情況下,IOS系統用NSUserDefaults存儲數據信息,但是對於一些私密信息,比如密碼、證書等等,就需要使用更爲安全的keychain了。
keychain裏保存的信息不會因App被刪除而丟失。所以,可以利用這個keychain這個特點來保存設備唯一標識。
那麼,如何在應用裏使用使用keyChain呢,我們需要導入Security.framework ,keychain的操作接口聲明在頭文件SecItem.h裏。
直接使用SecItem.h裏方法操作keychain,需要寫的代碼較爲複雜,我們可以使用已經封裝好了的工具類KeychainItemWrapper來對keychain進行操作。
KeychainItemWrapper是apple官方例子“GenericKeychain”裏一個訪問keychain常用操作的封裝類,在官網上下載了GenericKeychain項目後,
只需要把“KeychainItemWrapper.h”和“KeychainItemWrapper.m”拷貝到我們項目,並導入Security.framework 。KeychainItemWrapper的用法:
/** 初始化一個保存用戶帳號的KeychainItemWrapper */
KeychainItemWrapper *wrapper = [[KeychainItemWrapper alloc] initWithIdentifier:@"Account Number"
accessGroup:@"YOUR_APP_ID_HERE.com.yourcompany.AppIdentifier"];
//保存數據
[wrapper setObject:@"<帳號>" forKey:(id)kSecAttrAccount];
[wrapper setObject:@"<帳號密碼>" forKey:(id)kSecValueData];
//從keychain裏取出帳號密碼
NSString *password = [wrapper objectForKey:(id)kSecValueData];
//清空設置
[wrapper resetKeychainItem];
其中方法“- (void)setObject:(id)inObject forKey:(id)key;”裏參數“forKey”的值應該是Security.framework 裏頭文件“SecItem.h”裏定義好的key,用其他字符串做key程序會出錯!
原文地址:http://blog.csdn.net/iitvip/article/details/10064167