//SvUDIDTools : https://github.com/smileEvday/SvUDID

//将生成的UDID保存到钥匙串中,用户卸载app再重新安装UDID也不会改变.

/* 用法1:(摘于网上的使用方法)
在工程目录下新建一个KeychainAccessGroups.plist文件,该文件的结构中最顶层的节点必须是一个名为“keychain-access-groups”的Array,
并且该Array中每一项都是一个描述分组的NSString。yourAppID.com.yourCompany.whatever就是你要起的公共区名称,除了whatever字段可以随便定之外,
其 他的都必须如实填写。这个文件的路径要配置 在 Project->build setting->Code Signing Entitlements里,否则公共区无效,配置好后, 须用你正式的证书签名编译才可通过,
否则xcode会弹框告诉你code signing有问题。所以,苹果限制了你只能同公司的产品共享 KeyChain数据,别的公司访问不了你公司产品的KeyChain。
如果拷贝:则将UID文件夹下面的KeychainAccessGroups.plist拷贝到同级于工程目录,并拖曳到xcode工程窗口修改响应的yourAppID.com.yourCompany.whatever 追加Build Phases->Compile Sources下面的SvUDIDTools.m文件配置信息字符串“-fno-objc-arc” 修改Build Setting->Code Signing->Code Signing Entitlements属性为KeychainAccessGroups.plist */ /*用法2:自己实际操作
Project -> Capabilities -> Keychain Sharing -> on, 会弹出提示框请求Fetching list of teams from the Developer Portal....,选择开发账号,确认. 生成entitlements文件, 网络不好时,可手动添加 KeychainAccessGroups.plist 用法类似 用法1.
自动生成的entitlements 已经将Keychain Access Groups 补充好, 不需再更改,Keychain Access Groups分组中会出现 $(AppIdentifierPrefix)com.moule.Utils-iOS ( $(AppIdentifierPrefix)开头的字段 ), Build Phases->Compile Sources下面的SvUDIDTools.m文件配置信息字符串“-fno-objc-arc” //获取开发账号的appID
+ (NSString *)bundleSeedID {
NSDictionary *query = [NSDictionary dictionaryWithObjectsAndKeys:kSecClassGenericPassword, kSecClass,@"bundleSeedID", kSecAttrAccount,@"", kSecAttrService,(id)kCFBooleanTrue, kSecReturnAttributes,nil];
CFDictionaryRef result = nil;
OSStatus status = SecItemCopyMatching((CFDictionaryRef)query, (CFTypeRef *)&result);
if (status == errSecItemNotFound)
status = SecItemAdd((CFDictionaryRef)query, (CFTypeRef *)&result);
if (status != errSecSuccess)
return nil;
NSString *accessGroup = [(__bridge NSDictionary *)result objectForKey:kSecAttrAccessGroup];
NSArray *components = [accessGroup componentsSeparatedByString:@"."];
NSString *bundleSeedID = [[components objectEnumerator] nextObject];
CFRelease(result);
return bundleSeedID;
} kKeyChainUDIDAccessGroup 是应用的bundle ID */
.h文件

#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
@interface SvUDIDTools : NSObject /*
* @brief obtain Unique Device Identity
*/
+ (NSString*)UDID; @end
.m文件

//
// SvUDIDTools.m
// SvUDID
//
// Created by maple on 8/18/13.
// Copyright (c) 2013 maple. All rights reserved.
// #import "SvUDIDTools.h"
#import <Security/Security.h>
#include <sys/socket.h>
#include <sys/sysctl.h>
#include <net/if.h>
#include <net/if_dl.h> // replace the identity with your company's domain
static const char kKeychainUDIDItemIdentifier[] = "UUID";
static NSString * kKeyChainUDIDAccessGroup = @"com.moule.Utils-iOS"; @implementation SvUDIDTools + (NSString *)bundleSeedID {
NSDictionary *query = [NSDictionary dictionaryWithObjectsAndKeys:
kSecClassGenericPassword, kSecClass,
@"bundleSeedID", kSecAttrAccount,
@"", kSecAttrService,
(id)kCFBooleanTrue, kSecReturnAttributes,
nil];
CFDictionaryRef result = nil;
OSStatus status = SecItemCopyMatching((CFDictionaryRef)query, (CFTypeRef *)&result);
if (status == errSecItemNotFound)
status = SecItemAdd((CFDictionaryRef)query, (CFTypeRef *)&result);
if (status != errSecSuccess)
return nil;
NSString *accessGroup = [(__bridge NSDictionary *)result objectForKey:kSecAttrAccessGroup];
NSArray *components = [accessGroup componentsSeparatedByString:@"."];
NSString *bundleSeedID = [[components objectEnumerator] nextObject];
CFRelease(result);
return bundleSeedID;
} + (NSString*)UDID
{
NSString *udid = [SvUDIDTools getUDIDFromKeyChain];
if (!udid) { NSString *sysVersion = [UIDevice currentDevice].systemVersion;
CGFloat version = [sysVersion floatValue]; if (version >= 7.0) {
udid = [SvUDIDTools _UDID_iOS7];
}
else if (version >= 2.0) {
udid = [SvUDIDTools _UDID_iOS6];
} [SvUDIDTools settUDIDToKeyChain:udid];
} return udid;
} /*
* iOS 6.0
* use wifi's mac address
*/
+ (NSString*)_UDID_iOS6
{
return [SvUDIDTools getMacAddress];
} /*
* iOS 7.0
* Starting from iOS 7, the system always returns the value 02:00:00:00:00:00
* when you ask for the MAC address on any device.
* use identifierForVendor + keyChain
* make sure UDID consistency atfer app delete and reinstall
*/
+ (NSString*)_UDID_iOS7
{
return [[UIDevice currentDevice].identifierForVendor UUIDString];
} #pragma mark -
#pragma mark Helper Method for Get Mac Address // from http://stackoverflow.com/questions/677530/how-can-i-programmatically-get-the-mac-address-of-an-iphone
+ (NSString *)getMacAddress
{
int mgmtInfoBase[6];
char *msgBuffer = NULL;
size_t length;
unsigned char macAddress[6];
struct if_msghdr *interfaceMsgStruct;
struct sockaddr_dl *socketStruct;
NSString *errorFlag = nil; // Setup the management Information Base (mib)
mgmtInfoBase[0] = CTL_NET; // Request network subsystem
mgmtInfoBase[1] = AF_ROUTE; // Routing table info
mgmtInfoBase[2] = 0;
mgmtInfoBase[3] = AF_LINK; // Request link layer information
mgmtInfoBase[4] = NET_RT_IFLIST; // Request all configured interfaces // With all configured interfaces requested, get handle index
if ((mgmtInfoBase[5] = if_nametoindex("en0")) == 0)
errorFlag = @"if_nametoindex failure";
else
{
// Get the size of the data available (store in len)
if (sysctl(mgmtInfoBase, 6, NULL, &length, NULL, 0) < 0)
errorFlag = @"sysctl mgmtInfoBase failure";
else
{
// Alloc memory based on above call
if ((msgBuffer = malloc(length)) == NULL)
errorFlag = @"buffer allocation failure";
else
{
// Get system information, store in buffer
if (sysctl(mgmtInfoBase, 6, msgBuffer, &length, NULL, 0) < 0)
errorFlag = @"sysctl msgBuffer failure";
}
}
} // Befor going any further...
if (errorFlag != NULL)
{
NSLog(@"Error: %@", errorFlag);
if (msgBuffer) {
free(msgBuffer);
} return errorFlag;
} // Map msgbuffer to interface message structure
interfaceMsgStruct = (struct if_msghdr *) msgBuffer; // Map to link-level socket structure
socketStruct = (struct sockaddr_dl *) (interfaceMsgStruct + 1); // Copy link layer address data in socket structure to an array
memcpy(&macAddress, socketStruct->sdl_data + socketStruct->sdl_nlen, 6); // Read from char array into a string object, into traditional Mac address format
NSString *macAddressString = [NSString stringWithFormat:@"%02X:%02X:%02X:%02X:%02X:%02X",
macAddress[0], macAddress[1], macAddress[2],
macAddress[3], macAddress[4], macAddress[5]];
NSLog(@"Mac Address: %@", macAddressString); // Release the buffer memory
free(msgBuffer); return macAddressString;
} #pragma mark -
#pragma mark Helper Method for make identityForVendor consistency + (NSString*)getUDIDFromKeyChain
{
NSMutableDictionary *dictForQuery = [[NSMutableDictionary alloc] init];
[dictForQuery setValue:(id)kSecClassGenericPassword forKey:(id)kSecClass]; // set Attr Description for query
[dictForQuery setValue:[NSString stringWithUTF8String:kKeychainUDIDItemIdentifier]
forKey:kSecAttrDescription]; // set Attr Identity for query
NSData *keychainItemID = [NSData dataWithBytes:kKeychainUDIDItemIdentifier
length:strlen(kKeychainUDIDItemIdentifier)];
[dictForQuery setObject:keychainItemID forKey:(id)kSecAttrGeneric]; // The keychain access group attribute determines if this item can be shared
// amongst multiple apps whose code signing entitlements contain the same keychain access group.
NSString *accessGroup =[NSString stringWithFormat:@"%@.%@",[SvUDIDTools bundleSeedID],kKeyChainUDIDAccessGroup];
if (accessGroup != nil)
{
#if TARGET_IPHONE_SIMULATOR
// Ignore the access group if running on the iPhone simulator.
//
// Apps that are built for the simulator aren't signed, so there's no keychain access group
// for the simulator to check. This means that all apps can see all keychain items when run
// on the simulator.
//
// If a SecItem contains an access group attribute, SecItemAdd and SecItemUpdate on the
// simulator will return -25243 (errSecNoAccessForItem).
#else
[dictForQuery setObject:accessGroup forKey:(id)kSecAttrAccessGroup];
#endif
} [dictForQuery setValue:(id)kCFBooleanTrue forKey:(id)kSecMatchCaseInsensitive];
[dictForQuery setValue:(id)kSecMatchLimitOne forKey:(id)kSecMatchLimit];
[dictForQuery setValue:(id)kCFBooleanTrue forKey:(id)kSecReturnData]; OSStatus queryErr = noErr;
NSData *udidValue = nil;
NSString *udid = nil;
queryErr = SecItemCopyMatching((CFDictionaryRef)dictForQuery, (CFTypeRef*)&udidValue); NSMutableDictionary *dict = nil;
[dictForQuery setValue:(id)kCFBooleanTrue forKey:(id)kSecReturnAttributes];
queryErr = SecItemCopyMatching((CFDictionaryRef)dictForQuery, (CFTypeRef*)&dict); if (queryErr == errSecItemNotFound) {
NSLog(@"KeyChain Item: %@ not found!!!", [NSString stringWithUTF8String:kKeychainUDIDItemIdentifier]);
}
else if (queryErr != errSecSuccess) {
NSLog(@"KeyChain Item query Error!!! Error code:%d", (int)queryErr);
}
if (queryErr == errSecSuccess) {
NSLog(@"KeyChain Item: %@", udidValue); if (udidValue) {
udid = [NSString stringWithUTF8String:udidValue.bytes];
[udidValue release];
}
[dict release];
} [dictForQuery release];
return udid;
} + (BOOL)settUDIDToKeyChain:(NSString*)udid
{
NSMutableDictionary *dictForAdd = [[NSMutableDictionary alloc] init]; [dictForAdd setValue:(id)kSecClassGenericPassword forKey:(id)kSecClass];
[dictForAdd setValue:[NSString stringWithUTF8String:kKeychainUDIDItemIdentifier] forKey:kSecAttrDescription]; [dictForAdd setValue:@"UUID" forKey:(id)kSecAttrGeneric]; // Default attributes for keychain item.
[dictForAdd setObject:@"" forKey:(id)kSecAttrAccount];
[dictForAdd setObject:@"" forKey:(id)kSecAttrLabel]; // The keychain access group attribute determines if this item can be shared
// amongst multiple apps whose code signing entitlements contain the same keychain access group.
NSString *accessGroup = [NSString stringWithFormat:@"%@.%@",[SvUDIDTools bundleSeedID],kKeyChainUDIDAccessGroup];
if (accessGroup != nil)
{
#if TARGET_IPHONE_SIMULATOR
// Ignore the access group if running on the iPhone simulator.
//
// Apps that are built for the simulator aren't signed, so there's no keychain access group
// for the simulator to check. This means that all apps can see all keychain items when run
// on the simulator.
//
// If a SecItem contains an access group attribute, SecItemAdd and SecItemUpdate on the
// simulator will return -25243 (errSecNoAccessForItem).
#else
[dictForAdd setObject:accessGroup forKey:(id)kSecAttrAccessGroup];
#endif
} const char *udidStr = [udid UTF8String];
NSData *keyChainItemValue = [NSData dataWithBytes:udidStr length:strlen(udidStr)];
[dictForAdd setValue:keyChainItemValue forKey:(id)kSecValueData]; OSStatus writeErr = noErr;
if ([SvUDIDTools getUDIDFromKeyChain]) { // there is item in keychain
[SvUDIDTools updateUDIDInKeyChain:udid];
[dictForAdd release];
return YES;
}
else { // add item to keychain
writeErr = SecItemAdd((CFDictionaryRef)dictForAdd, NULL);
if (writeErr != errSecSuccess) {
NSLog(@"Add KeyChain Item Error!!! Error Code:%ld", writeErr); [dictForAdd release];
return NO;
}
else {
NSLog(@"Add KeyChain Item Success!!!");
[dictForAdd release];
return YES;
}
} [dictForAdd release];
return NO;
} + (BOOL)removeUDIDFromKeyChain
{
NSMutableDictionary *dictToDelete = [[NSMutableDictionary alloc] init]; [dictToDelete setValue:(id)kSecClassGenericPassword forKey:(id)kSecClass]; NSData *keyChainItemID = [NSData dataWithBytes:kKeychainUDIDItemIdentifier length:strlen(kKeychainUDIDItemIdentifier)];
[dictToDelete setValue:keyChainItemID forKey:(id)kSecAttrGeneric]; OSStatus deleteErr = noErr;
deleteErr = SecItemDelete((CFDictionaryRef)dictToDelete);
if (deleteErr != errSecSuccess) {
NSLog(@"delete UUID from KeyChain Error!!! Error code:%ld", deleteErr);
[dictToDelete release];
return NO;
}
else {
NSLog(@"delete success!!!");
} [dictToDelete release];
return YES;
} + (BOOL)updateUDIDInKeyChain:(NSString*)newUDID
{ NSMutableDictionary *dictForQuery = [[NSMutableDictionary alloc] init]; [dictForQuery setValue:(id)kSecClassGenericPassword forKey:(id)kSecClass]; NSData *keychainItemID = [NSData dataWithBytes:kKeychainUDIDItemIdentifier
length:strlen(kKeychainUDIDItemIdentifier)];
[dictForQuery setValue:keychainItemID forKey:(id)kSecAttrGeneric];
[dictForQuery setValue:(id)kCFBooleanTrue forKey:(id)kSecMatchCaseInsensitive];
[dictForQuery setValue:(id)kSecMatchLimitOne forKey:(id)kSecMatchLimit];
[dictForQuery setValue:(id)kCFBooleanTrue forKey:(id)kSecReturnAttributes]; NSDictionary *queryResult = nil;
SecItemCopyMatching((CFDictionaryRef)dictForQuery, (CFTypeRef*)&queryResult);
if (queryResult) { NSMutableDictionary *dictForUpdate = [[NSMutableDictionary alloc] init];
[dictForUpdate setValue:[NSString stringWithUTF8String:kKeychainUDIDItemIdentifier] forKey:kSecAttrDescription];
[dictForUpdate setValue:keychainItemID forKey:(id)kSecAttrGeneric]; const char *udidStr = [newUDID UTF8String];
NSData *keyChainItemValue = [NSData dataWithBytes:udidStr length:strlen(udidStr)];
[dictForUpdate setValue:keyChainItemValue forKey:(id)kSecValueData]; OSStatus updateErr = noErr; // First we need the attributes from the Keychain.
NSMutableDictionary *updateItem = [NSMutableDictionary dictionaryWithDictionary:queryResult];
[queryResult release]; // Second we need to add the appropriate search key/values.
// set kSecClass is Very important
[updateItem setObject:(id)kSecClassGenericPassword forKey:(id)kSecClass]; updateErr = SecItemUpdate((CFDictionaryRef)updateItem, (CFDictionaryRef)dictForUpdate);
if (updateErr != errSecSuccess) {
NSLog(@"Update KeyChain Item Error!!! Error Code:%ld", updateErr); [dictForQuery release];
[dictForUpdate release];
return NO;
}
else {
NSLog(@"Update KeyChain Item Success!!!");
[dictForQuery release];
[dictForUpdate release];
return YES;
}
} [dictForQuery release];
return NO;
} @end

SvUDID实现设备唯一标示的更多相关文章

  1. iOS 获取设备唯一标示符的方法

    在开发中会遇到应用需要记录设备标示,即使应用卸载后再安装也可重新识别的情况,在这写一种实现方式--读取设备的UUID(Universally Unique Identifier)并通过KeyChain ...

  2. android获取设备唯一标示

    概述 有时需要对用户设备进行标识,所以希望能够得到一个稳定可靠并且唯一的识别码.虽然Android系统中提供了这样设备识别码,但是由于Android系统版本.厂商定制系统中的Bug等限制,稳定性和唯一 ...

  3. [转]iOS设备唯一标识探讨

    转自:http://www.jianshu.com/p/b83b0240bd0e iOS设备唯一标识探讨 为了统计和检测应用的使用数据,几乎每家公司都有获取唯一标识的业务需求,在iOS5以前获取唯一标 ...

  4. 获取iOS设备唯一标识

    [获取iOS设备唯一标识] 1.已禁用-[UIDevice uniqueIdentifier] 苹果总是把用户的隐私看的很重要.-[UIDevice uniqueIdentifier]在iOS5实际在 ...

  5. iOS编程——经过UUID和KeyChain来代替Mac地址实现iOS设备的唯一标示(OC版)

    iOS编程——通过UUID和KeyChain来代替Mac地址实现iOS设备的唯一标示(OC版) 很多的应用都需要用到手机的唯一标示,而且要求这个唯一标示不能因为应用app的卸载或者改变而变化. 在iO ...

  6. iOS开发之 -- 获取设备的唯一标示符

    各种获取设备唯一标识的方法介绍 一.UDID(Unique Device Identifier) UDID的全称是Unique Device Identifier,它就是苹果iOS设备的唯一识别码,它 ...

  7. iOS获取设备唯一标识的8种方法

    8种iOS获取设备唯一标识的方法,希望对大家有用. UDID UDID(Unique Device Identifier),iOS 设备的唯一识别码,是一个40位十六进制序列(越狱的设备通过某些工具可 ...

  8. ios 唯一标示符

    大家知道苹果每部 iOS 设备都有一个 UDID,它就像设备的身份证一样,记录着设备的名称.类型甚至一些关于用户的私人信息.通常情况下,UDID 的一个最大功能就是帮助广告发布商向特定用户推送定向广告 ...

  9. 获得iOS设备唯一标识

    使用-[UIDevice identifierForVendor]或是-[ASIdentifierManager advertisingIdentifier]来作为你框架和应用的唯一标示符.坦白的来说 ...

随机推荐

  1. Android gingerbread eMMC booting

    Android gingerbread eMMC booting This page is currently under construction. The content of this page ...

  2. SQL[连载1]简介

    SQL[连载1]简介 SQL 教程 SQL 是用于访问和处理数据库的标准的计算机语言. 在本教程中,您将学到如何使用 SQL 访问和处理数据系统中的数据,这类数据库包括:MySQL.SQL Serve ...

  3. shader复杂与深入:Normal Map(法线贴图)1

    转自:http://www.zwqxin.com/archives/shaderglsl/review-normal-map-bump-map.htmlNormal Map法线贴图,想必每个学习计算机 ...

  4. Android开源库--PhotoView图片查看

    如果说我比别人看得更远些,那是因为我站在了巨人的肩上. github地址:https://github.com/chrisbanes/PhotoView 介绍 在一般的应用中,总会遇到查看图片的功能, ...

  5. SHOI2008 题目总结

    感觉还是上海人出题水平高?这套题写得心旷神怡的...总之很难就是啦 由于我实在不适应博客园这种排版和字体..所以我的文章可能会特别难看大家见谅..说不定回头开发一个支持全局LaTeX的博客也不错?23 ...

  6. [ionic开源项目教程] - 第5讲 如何在项目中使用全局配置

    第5讲 如何在项目中使用全局配置? Q:ionic开发,说纯粹一点,用的就是html+css+js,那么无疑跟web开发的方式是类似的.在这里给大家分享一个小技巧,如何在项目中使用全局配置? A:我的 ...

  7. Qt之国际化(系统文本-QMessageBox按钮、QLineEdit右键菜单等)

    简介 使用Qt的时候,经常会遇到英文问题,例如:QMessageBox中的按钮.QLineEdit.QSpinBox.QScrollBar中的右键菜单等.通常情况下,我们软件都不会是纯英文的,那么如何 ...

  8. XML中对特殊字符的处置

    str = str.replaceAll("‘", "‘"); str = str.replaceAll("’", "‘" ...

  9. LA 3602 DNA Consensus String

    最近审题老是一错再错,Orz 题目中说求一个Hamming值总和最小的字符串,而不是从所给字符中找一个最小的 这样的话,我们逐列处理,所求字符串当前位置的字符应该是该列中出现次数最多其次ASCII值最 ...

  10. UVa 10891 (博弈+DP) Game of Sum

    最开始的时候思路就想错了,就不说错误的思路了. 因为这n个数的总和是一定的,所以在取数的时候不是让自己尽可能拿的最多,而是让对方尽量取得最少. 记忆化搜索(时间复杂度O(n3)): d(i, j)表示 ...