衆所周知,蘋果在iOS7禁用了 [UIDevice uniqueIdentifier] 也拋棄MAC 地址git
如今蘋果明確的代表你應該使用-[UIDevice identifierForVendor]或是-[ASIdentifierManager advertisingIdentifier]來做爲你框架和應用的惟一標示符。github
見如下代碼片斷:app
NSString *identifierForVendor = [[UIDevice currentDevice].identifierForVendor UUIDString]; 框架
NSString *identifierForAdvertising = [[ASIdentifierManager sharedManager].advertisingIdentifier UUIDString]; ide
每種方法都適配一種特別的用法:ui
identifierForVendor對供應商來講是惟一的一個值,也就是說,由同一個公司發行的的app在相同的設備上運行的時候都會有這個相同的標識符。然而,若是用戶刪除了這個供應商的app而後再從新安裝的話,這個標識符就會不一致。spa
identifierForAdvertising會返回給在這個設備上全部軟件供應商相同的 一個值,因此只能在廣告的時候使用。這個值會由於不少狀況而有所變化,好比說用戶初始化設備的時候便會改變。.net
因爲identifierForVendor刪除了這個供應商的app而後再從新安裝的話,這個標識符就會不一致,因此要解決這個問題能夠把第一次生成的惟一標示符,保存到keyChain(鑰匙串)中,當應用被刪除後keyChain中的數據還在,下次在從keyChain中取就OK了提供兩種方式解決這個問題內存
資源文件 https://git.oschina.net/jiangwenjun/IdentificationTool 資源
git地址: git@git.oschina.net:jiangwenjun/IdentificationTool.git
方法一:直接上代碼
#import <Foundation/Foundation.h>
#import "Singleton.h"
@interface APPIdentificationManager : NSObject
single_interface(APPIdentificationManager) // 聲明一個單例 你能夠本身寫
- (NSString*)readUDID;
//
// APPIdentificationManager.m
// Ayibang
//
// Created by 小胖的Mac on 15/11/25.
// Copyright (c) 2015年 ayibang. All rights reserved.
//
#import "APPIdentificationManager.h"
#import <Security/Security.h>
#define KEY_UDID @"KEY_UDID"
#define KEY_IN_KEYCHAIN @"KEY_IN_KEYCHAIN"
@interface APPIdentificationManager (){
NSString *_uuid;
}
@implementation APPIdentificationManager
single_implementation(APPIdentificationManager)
#pragma mark 獲取UUID
/**
*此uuid在相同的一個程序裏面-相同的vindor-相同的設備下是不會改變的
*此uuid是惟一的,但應用刪除再從新安裝後會變化,採起的措施是:只獲取一次保存在鑰匙串中,以後就從鑰匙串中獲取
**/
- (NSString *)openUDID
{
NSString *identifierForVendor = [[UIDevice currentDevice].identifierForVendor UUIDString];
return identifierForVendor;
}
#pragma mark 保存UUID到鑰匙串
- (void)saveUDID:(NSString *)udid
{
NSMutableDictionary *udidKVPairs = [NSMutableDictionary dictionary];
[udidKVPairs setObject:udid forKey:KEY_UDID];
[[APPIdentificationManager sharedAPPIdentificationManager] save:KEY_IN_KEYCHAIN data:udidKVPairs];
}
#pragma mark 讀取UUID
/**
*先從內存中獲取uuid,若是沒有再從鑰匙串中獲取,若是尚未就生成一個新的uuid,並保存到鑰匙串中供之後使用
**/
- (NSString*)readUDID
{
if (_uuid == nil || _uuid.length == 0) {
NSMutableDictionary *udidKVPairs = (NSMutableDictionary *)[[APPIdentificationManager sharedAPPIdentificationManager] load:KEY_IN_KEYCHAIN];
NSString *uuid = [udidKVPairs objectForKey:KEY_UDID];
if (uuid == nil || uuid.length == 0) {
uuid = [self openUDID];
[self saveUDID:uuid];
}
_uuid = uuid;
}
return _uuid;
}
#pragma mark 刪除UUID
- (void)deleteUUID
{
[APPIdentificationManager delete:KEY_IN_KEYCHAIN];
}
#pragma mark 查詢鑰匙串
- (NSMutableDictionary *)getKeychainQuery:(NSString *)service {
return [NSMutableDictionary dictionaryWithObjectsAndKeys:
(__bridge_transfer id)kSecClassGenericPassword,(__bridge_transfer id)kSecClass,
service, (__bridge_transfer id)kSecAttrService,
service, (__bridge_transfer id)kSecAttrAccount,
(__bridge_transfer id)kSecAttrAccessibleAfterFirstUnlock,(__bridge_transfer id)kSecAttrAccessible,
nil];
}
#pragma mark 將數據保存到鑰匙串
- (void)save:(NSString *)service data:(id)data {
NSMutableDictionary *keychainQuery = [self getKeychainQuery:service];
SecItemDelete((__bridge_retained CFDictionaryRef)keychainQuery);
[keychainQuery setObject:[NSKeyedArchiver archivedDataWithRootObject:data] forKey:(__bridge_transfer id)kSecValueData];
SecItemAdd((__bridge_retained CFDictionaryRef)keychainQuery, NULL);
}
#pragma mark 加載鑰匙串中數據
- (id)load:(NSString *)service {
id ret = nil;
NSMutableDictionary *keychainQuery = [self getKeychainQuery:service];
[keychainQuery setObject:(id)kCFBooleanTrue forKey:(__bridge_transfer id)kSecReturnData];
[keychainQuery setObject:(__bridge_transfer id)kSecMatchLimitOne forKey:(__bridge_transfer id)kSecMatchLimit];
CFDataRef keyData = NULL;
if (SecItemCopyMatching((__bridge_retained CFDictionaryRef)keychainQuery, (CFTypeRef *)&keyData) == noErr) {
@try {
ret = [NSKeyedUnarchiver unarchiveObjectWithData:(__bridge_transfer NSData *)keyData];
} @catch (NSException *e) {
NSLog(@"Unarchive of %@ failed: %@", service, e);
} @finally {
}
}
return ret;
}
#pragma mark 刪除鑰匙串中數據
- (void)delete:(NSString *)service {
NSMutableDictionary *keychainQuery = [self getKeychainQuery:service];
SecItemDelete((__bridge_retained CFDictionaryRef)keychainQuery);
}
@end
方法二
對keyChain的操做網上比較流行的的 SSKeychain (https://github.com/soffes/sskeychain)經過這個第三方框架能夠很好地操做鑰匙串
第一步:導入 SSKeychain 能夠用cocopods導入
第二步:上代碼
#import <Foundation/Foundation.h>
#import "Singleton.h"
#import "SSKeychain.h"
@interface AYBIdentificationTool : NSObject
single_interface(AYBIdentificationTool)
/**
* 獲取用戶設備的惟一標示
*
* @return 若是鑰匙串中有identifierForVendor 返回identifierForVendor
若是鑰匙串中沒有identifierForVendor 建立identifierForVendor 存於鑰匙串中
用戶刪除、升級應用 或者升級系統identifierForVendor 不會被刪除用來標示設備
*/
- (NSString*)readUDID;
@end
#import "AYBIdentificationTool.h"
#define KEY_UDID @"KEY_UDID"
#define KEY_IN_KEYCHAIN @"KEY_IN_KEYCHAIN"
@interface AYBIdentificationTool (){
NSString *_udid;
}
@end
@implementation AYBIdentificationTool
single_implementation(AYBIdentificationTool)
- (NSString *)readUDID{
// 從鑰匙串中讀取 _uuid
_udid = [SSKeychain passwordForService:KEY_UDID account:KEY_IN_KEYCHAIN];
if (_udid == nil || _udid.length == 0) {
NSString * udid = [self openUDID];
[SSKeychain setPassword:udid forService:KEY_UDID account:KEY_IN_KEYCHAIN];
_udid = udid;
}
return _udid?_udid:@"";
}
- (NSString *)openUDID
{
NSString *identifierForVendor = [[UIDevice currentDevice].identifierForVendor UUIDString];
return identifierForVendor;
}
@end