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

相关文章
相关标签/搜索