你好,歡迎來到IOS教程網

 Ios教程網 >> IOS編程開發 >> IOS開發綜合 >> ios設備唯一標識獲取策略

ios設備唯一標識獲取策略

編輯:IOS開發綜合

英文原文:In iOS 7 and later, if you ask for the MAC address of an iOS device, the system returns the value 02:00:00:00:00:00. If you need to identify the device, use the identifierForVendor property of UIDevice instead. (Apps that need an identifier for their own advertising purposes should consider using the advertisingIdentifier property of ASIdentifierManager instead.)
翻譯:從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就跟以前的不一樣。可見,這種方法還是不保險。

 

 

 

廣告標示符,是iOS 6中另外一個新的方法,提供了一個方法advertisingIdentifier,通過調用該方法會返回一個NSUUID實例,最後可以獲得一個UUID,由系統存儲著的。不過即使這是由系統存儲的,但是有幾種情況下,會重新生成廣告標示符。如果用戶完全重置系統((設置程序 -> 通用 -> 還原 -> 還原位置與隱私) ,這個廣告標示符會重新生成。另外如果用戶明確的還原廣告(設置程序-> 通用 -> 關於本機 -> 廣告 -> 還原廣告標示符) ,那麼廣告標示符也會重新生成。關於廣告標示符的還原,有一點需要注意:如果程序在後台運行,此時用戶“還原廣告標示符”,然後再回到程序中,此時獲取廣 告標示符並不會立即獲得還原後的標示符。必須要終止程序,然後再重新啟動程序,才能獲得還原後的廣告標示符。

 

 

 

Vindor標示符,也是在iOS 6中新增的,跟advertisingIdentifier一樣,該方法返回的是一個 NSUUID對象,可以獲得一個UUID。如果滿足條件“相同的一個程序裡面-相同的vindor-相同的設備”,那麼獲取到的這個屬性值就不會變。如果是“相同的程序-相同的設備-不同的vindor,或者是相同的程序-不同的設備-無論是否相同的vindor”這樣的情況,那麼這個值是不會相同的。


推送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]; 
} 

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

 

開發者可以在應用第一次啟動時調用一 次,然後將該串存儲起來,以便以後替代UDID來使用。但是,如果用戶刪除該應用再次安裝時,又會生成新的字符串,所以不能保證唯一識別該設備。這就需要各路高手想出各種解決方案。所以,之前很多應用就采用MAC Address。但是現在如果用戶升級到iOS7(及其以後的蘋果系統)後,他們機子的MAC Address就是一樣的,沒辦法做區分,只能棄用此方法,重新使用UUID來標識。如果使用UUID,就要考慮應用被刪除後再重新安裝時的處理。

 

一個解決的辦法是: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程序會出錯!


 

  1. 上一頁:
  2. 下一頁:
蘋果刷機越獄教程| IOS教程問題解答| IOS技巧綜合| IOS7技巧| IOS8教程
Copyright © Ios教程網 All Rights Reserved