獲取iOS設(shè)備唯一標(biāo)識(UUID)并保存到鑰匙串

前言:

1 .為了統(tǒng)計和檢測應(yīng)用的使用數(shù)據(jù)落萎,幾乎每家公司都有獲取唯一標(biāo)識的業(yè)務(wù)需求,在iOS5以前獲取唯一標(biāo)識翩肌,可以獲取到系統(tǒng)提供的方法UDID(Unique Device Identifier)模暗,后來被出于用戶隱私的考慮被Apple官方禁止掉了。于是念祭,大家開始在iOS6中使用 MAC 地址(Medium/Media Access Control) ,后來又被Apple官方在iOS7中禁止掉了碍侦。蘋果及其國外的IT公司都會比較注重用戶隱私粱坤,所以今后一但有比較靠譜的獲取唯一標(biāo)示的方法放出,蘋果肯定會封堵瓷产。

2.**  ** 在非越獄的手機上獲取某個硬件信息生成唯一標(biāo)識站玄,第一只能找到蘋果的漏洞,第二就是調(diào)用一些私有接口濒旦,顯然這兩條路都比較艱難株旷,并不可持續(xù)發(fā)展,所以網(wǎng)上大部分的唯一標(biāo)識都是從操作系統(tǒng)層面獲取的尔邓,在重置手機系統(tǒng)的時候都會被清除晾剖,在系統(tǒng)升級、卸載重裝梯嗽、備份恢復(fù)都可以保留齿尽,現(xiàn)在本人尚未發(fā)現(xiàn)可以使用嚴(yán)格意義上的唯一標(biāo)識。接下來我想跟大家探討的是如何通過“合法”的手段來盡量拿到不會輕易發(fā)生變化的“唯一標(biāo)識”灯节。

3.**  **在2013年3月21日蘋果已經(jīng)通知開發(fā)者循头,從2013年5月1日起绵估,訪問UIDID的應(yīng)用將不再能通過審核,替代的方案是開發(fā)者應(yīng)該使用“在iOS 6中介紹的Vendor或Advertising標(biāo)示符”卡骂。

4.MAC地址不能再用來設(shè)別設(shè)備
**  **還有一個生成iOS設(shè)備唯一標(biāo)示符的方法是使用iOS設(shè)備的Media Access Control(MAC)地址国裳。一個MAC地址是一個唯一的號碼,它是物理網(wǎng)絡(luò)層級方面分配給網(wǎng)絡(luò)適配器的全跨。這個地址蘋果還有其他的名字躏救,比如說是硬件地址(Hardware Address)或是Wifi地址,都是指同樣的東西螟蒸。
  有很多工程和框架都使用這個方法來生成唯一的設(shè)備ID盒使。比如說ODIN。然而七嫌,蘋果并不希望有人通過MAC地址來分辨用戶少办,所以如果你在iOS7系統(tǒng)上查詢MAC地址,它現(xiàn)在只會返回02:00:00:00:00:00诵原。

5 **  ** 講真蘋果這傲嬌的小脾氣什么時候能能改改,不過這樣 對于用戶隱私的保護,確實起到很大作用,而且蘋果也沒有把路堵死,現(xiàn)在蘋果明確的表明你應(yīng)該使用-[UIDevice identifierForVendor]或是-[ASIdentifierManager advertisingIdentifier]來作為你框架和應(yīng)用的唯一標(biāo)示符英妓。坦白的來說,應(yīng)對這些變化也不是那么的難绍赛,見以下代碼片段:

NSString *identifierForVendor = [[UIDevice currentDevice].identifierForVendor UUIDString]; 
NSString *identifierForAdvertising = [[ASIdentifierManager sharedManager].advertisingIdentifier UUIDString]; 

但是這樣用法有個缺點,就是程序每次被刪除以后,獲取到的都是新的uuid,并不能實現(xiàn)每個手機的唯一性.
所以下面要講的就是這個問題的解決辦法.

**  **對于這個問題有一個可行的辦法,就是把獲取到的uuid保存在鑰匙串里面,這樣即使程序刪除重裝,獲取到的uuid一直是同一個,實現(xiàn)了手機的唯一標(biāo)識的作用.

保存鑰匙串 我們需要用到keychain,除此之外蔓纠,Code Signing Entitlements的創(chuàng)建方法也不夠嚴(yán)謹(jǐn)。下面教大家一種方法,簡單快速.

1.新建一個工程吗蚌,看一下自己的Bundle Id.這個Bundle Id 要和你用真機測試時的證書上面的Bundle Id相匹配腿倚。

注意這個Bundle identifier

2.Target - Capabilities - Keychain Sharing - ON

注意圓圈里面的保持一致

這步主要目的是打開Keychain Sharing,將它由灰色狀態(tài)的OFF改為藍色狀態(tài)的ON。

會自動生成這個

左側(cè)的目錄會自動生成Entitlements文件蚯妇,不需要自己創(chuàng)建了敷燎。

也就是說,Bundle Identifier箩言、Keychain Sharing的Keychain Groups硬贯、Entitlements文件的Keychain Access Groups的第一個元素,它們要保持上圖所示的一致性陨收。
設(shè)置好了以后可以運行下程序饭豹,沒問題可以進行下一步。

.傳說中的uuid類和keychain類來啦
既然蘋果的keychain方法會崩潰而且有些復(fù)雜务漩,我們只保存一個uuid的話可以用下面的簡單方法:


KeyChainStore.h

#import <Foundation/Foundation.h>

@interface KeyChainStore : NSObject

+ (void)save:(NSString *)service data:(id)data;
+ (id)load:(NSString *)service;
+ (void)deleteKeyData:(NSString *)service;

@end



KeyChainStore.m

//
//  KeyChainStore.m
//  getUUID
//
//  Created by ckl@pmm on 16/9/18.
//  Copyright ? 2016年 CKLPronetway. All rights reserved.
//

#import "KeyChainStore.h"

@implementation KeyChainStore

+ (NSMutableDictionary *)getKeychainQuery:(NSString *)service {
    return [NSMutableDictionary dictionaryWithObjectsAndKeys:
            (id)kSecClassGenericPassword,(id)kSecClass,
            service, (id)kSecAttrService,
            service, (id)kSecAttrAccount,
            (id)kSecAttrAccessibleAfterFirstUnlock,(id)kSecAttrAccessible,
            nil];
}

+ (void)save:(NSString *)service data:(id)data {
    //Get search dictionary
    NSMutableDictionary *keychainQuery = [self getKeychainQuery:service];
    //Delete old item before add new item
    SecItemDelete((CFDictionaryRef)keychainQuery);
    //Add new object to search dictionary(Attention:the data format)
    [keychainQuery setObject:[NSKeyedArchiver archivedDataWithRootObject:data] forKey:(id)kSecValueData];
    //Add item to keychain with the search dictionary
    SecItemAdd((CFDictionaryRef)keychainQuery, NULL);
}


+ (id)load:(NSString *)service {
    id ret = nil;
    NSMutableDictionary *keychainQuery = [self getKeychainQuery:service];
    //Configure the search setting
    //Since in our simple case we are expecting only a single attribute to be returned (the password) we can set the attribute kSecReturnData to kCFBooleanTrue
    [keychainQuery setObject:(id)kCFBooleanTrue forKey:(id)kSecReturnData];
    [keychainQuery setObject:(id)kSecMatchLimitOne forKey:(id)kSecMatchLimit];
    CFDataRef keyData = NULL;
    if (SecItemCopyMatching((CFDictionaryRef)keychainQuery, (CFTypeRef *)&keyData) == noErr) {
        @try {
            ret = [NSKeyedUnarchiver unarchiveObjectWithData:(__bridge NSData *)keyData];
        } @catch (NSException *e) {
            NSLog(@"Unarchive of %@ failed: %@", service, e);
        } @finally {
        }
    }
    if (keyData)
        CFRelease(keyData);
    return ret;
}

+ (void)deleteKeyData:(NSString *)service {
    NSMutableDictionary *keychainQuery = [self getKeychainQuery:service];
    SecItemDelete((CFDictionaryRef)keychainQuery);
}
@end
getUUID.h

#import <Foundation/Foundation.h>

@interface getUUID : NSObject
+(NSString *)getUUID;
@end
getUUID.m

//
//  getUUID.m
//  getUUID
//
//  Created by ckl@pmm on 16/9/18.
//  Copyright ? 2016年 CKLPronetway. All rights reserved.
//

#import "getUUID.h"
#import "KeyChainStore.h"
#define  KEY_USERNAME_PASSWORD @"com.company.app.usernamepassword"
#define  KEY_USERNAME @"com.company.app.username"
#define  KEY_PASSWORD @"com.company.app.password"

@implementation getUUID

+(NSString *)getUUID
{
    NSString * strUUID = (NSString *)[KeyChainStore load:@"com.company.app.usernamepassword"];
    
    //首次執(zhí)行該方法時拄衰,uuid為空
    if ([strUUID isEqualToString:@""] || !strUUID)
    {
        //生成一個uuid的方法
        CFUUIDRef uuidRef = CFUUIDCreate(kCFAllocatorDefault);
        
        strUUID = (NSString *)CFBridgingRelease(CFUUIDCreateString (kCFAllocatorDefault,uuidRef));
        
        //將該uuid保存到keychain
        [KeyChainStore save:KEY_USERNAME_PASSWORD data:strUUID];
        
    }
    return strUUID;
}

@end

在Viewcontroller里面執(zhí)行如下代碼

#import "ViewController.h"
#import "getUUID.h"
@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    NSLog(@" uuid  is  ---> %@",[getUUID getUUID]);
    
    // Do any additional setup after loading the view, typically from a nib.
}

打印出來類似于以下的長串字符:

獲取到的uuid.png

把程序卸載掉然后重新運行一次,獲取到的還是上次保存的uuid.
不知道手機越獄以后,會不會改變,因為樓主手機版本是最新的9.3.5,身邊還沒相關(guān)越獄設(shè)備,希望大家可以自行測試一下.并告知樓主.聯(lián)系方式 : QQ :576484150

參考地址:
:http://blog.sina.com.cn/s/blog_5971cdd00102vqgy.html
:http://blog.csdn.net/chy555chy/article/details/51628079

自己寫了一個demo,已經(jīng)放在gitHub上了,有興趣的同學(xué)可以下載下來瞅瞅.
demo 地址 :https://github.com/chengkunlun/getUUID

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市菲饼,隨后出現(xiàn)的幾起案子肾砂,更是在濱河造成了極大的恐慌,老刑警劉巖宏悦,帶你破解...
    沈念sama閱讀 216,591評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件镐确,死亡現(xiàn)場離奇詭異包吝,居然都是意外死亡,警方通過查閱死者的電腦和手機源葫,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,448評論 3 392
  • 文/潘曉璐 我一進店門诗越,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人息堂,你說我怎么就攤上這事嚷狞。” “怎么了荣堰?”我有些...
    開封第一講書人閱讀 162,823評論 0 353
  • 文/不壞的土叔 我叫張陵床未,是天一觀的道長。 經(jīng)常有香客問我振坚,道長薇搁,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,204評論 1 292
  • 正文 為了忘掉前任渡八,我火速辦了婚禮啃洋,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘屎鳍。我一直安慰自己宏娄,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,228評論 6 388
  • 文/花漫 我一把揭開白布逮壁。 她就那樣靜靜地躺著孵坚,像睡著了一般。 火紅的嫁衣襯著肌膚如雪貌踏。 梳的紋絲不亂的頭發(fā)上十饥,一...
    開封第一講書人閱讀 51,190評論 1 299
  • 那天,我揣著相機與錄音祖乳,去河邊找鬼。 笑死秉氧,一個胖子當(dāng)著我的面吹牛眷昆,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播汁咏,決...
    沈念sama閱讀 40,078評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼亚斋,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了攘滩?” 一聲冷哼從身側(cè)響起帅刊,我...
    開封第一講書人閱讀 38,923評論 0 274
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎漂问,沒想到半個月后赖瞒,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體女揭,經(jīng)...
    沈念sama閱讀 45,334評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,550評論 2 333
  • 正文 我和宋清朗相戀三年栏饮,在試婚紗的時候發(fā)現(xiàn)自己被綠了吧兔。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,727評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡袍嬉,死狀恐怖境蔼,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情伺通,我是刑警寧澤箍土,帶...
    沈念sama閱讀 35,428評論 5 343
  • 正文 年R本政府宣布,位于F島的核電站罐监,受9級特大地震影響吴藻,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜笑诅,卻給世界環(huán)境...
    茶點故事閱讀 41,022評論 3 326
  • 文/蒙蒙 一调缨、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧吆你,春花似錦弦叶、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,672評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至者祖,卻和暖如春立莉,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背七问。 一陣腳步聲響...
    開封第一講書人閱讀 32,826評論 1 269
  • 我被黑心中介騙來泰國打工蜓耻, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人械巡。 一個月前我還...
    沈念sama閱讀 47,734評論 2 368
  • 正文 我出身青樓刹淌,卻偏偏與公主長得像,于是被迫代替她去往敵國和親讥耗。 傳聞我的和親對象是個殘疾皇子有勾,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,619評論 2 354

推薦閱讀更多精彩內(nèi)容