iOS 惟一標示用戶的設備

    衆所周知,蘋果在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;

@end

//

//  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;

}

@end



@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

相關文章
相關標籤/搜索