ios7之后暂时代替MAC地址的作为唯一标识的方法!

来源:互联网 发布:阿里云 io hang 编辑:程序博客网 时间:2024/06/05 13:29

该方法缺陷:刷机-还原设备时重新获取!




#import <Foundation/Foundation.h>


@interface SvUDIDTools : NSObject



/*

 * @brief obtain Unique Device Identity

 */

+ (NSString*)UDID;


@end





//

//  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 constchar kKeyChainUDIDAccessGroup[] ="YOURAPPID.com.cnblogs.smileEvday";


@implementation SvUDIDTools


+ (NSString*)UDID

{

    NSString *sysVersion = [UIDevicecurrentDevice].systemVersion;

    CGFloat version = [sysVersion floatValue];

    

    if (version >= 7.0) {

        return [SvUDIDTools_UDID_iOS7];

    }

    else if (version >=6.0) {

        return [SvUDIDTools_UDID_iOS6];

    }

    else if (version >=2.0) {

        return [SvUDIDTools_UDID_iOS5];

    }

    

    return nil;

}


/* 

 * iOS Prior to 6.0

 * use uniqueIdentifier

 */

+ (NSString*)_UDID_iOS5

{

    return [[UIDevicecurrentDevice] performSelector:@selector(uniqueIdentifier)];

}


/*

 * iOS 6.0

 * use wifi's mac address

 */

+ (NSString*)_UDID_iOS6

{

    return [SvUDIDToolsgetMacAddress];

}


/*

 * 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

{

    NSString *udid = [SvUDIDToolsgetUDIDFromKeyChain];

    if (!udid) {

        udid = [[UIDevice currentDevice].identifierForVendor UUIDString];

        [SvUDIDTools settUDIDToKeyChain:udid];

    }


    return udid;

}



#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 = [NSStringstringWithFormat:@"%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 = [[NSMutableDictionaryalloc] init];

    [dictForQuery setValue:(id)kSecClassGenericPasswordforKey:(id)kSecClass];

    

    // set Attr Description for query

    [dictForQuery setValue:[NSStringstringWithUTF8String:kKeychainUDIDItemIdentifier]

                    forKey:kSecAttrDescription];

    

    // set Attr Identity for query

    NSData *keychainItemID = [NSDatadataWithBytes: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 = [NSStringstringWithUTF8String: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)kCFBooleanTrueforKey:(id)kSecMatchCaseInsensitive];

    [dictForQuery setValue:(id)kSecMatchLimitOneforKey:(id)kSecMatchLimit];

    [dictForQuery setValue:(id)kCFBooleanTrueforKey:(id)kSecReturnData];

    

    OSStatus queryErr   = noErr;

    NSData   *udidValue = nil;

    NSString *udid      = nil;

    queryErr = SecItemCopyMatching((CFDictionaryRef)dictForQuery, (CFTypeRef*)&udidValue);

    

    NSMutableDictionary *dict =nil;

    [dictForQuery setValue:(id)kCFBooleanTrueforKey:(id)kSecReturnAttributes];

    queryErr = SecItemCopyMatching((CFDictionaryRef)dictForQuery, (CFTypeRef*)&dict);

    

    if (queryErr == errSecItemNotFound) {

        NSLog(@"KeyChain Item: %@ not found!!!", [NSStringstringWithUTF8String:kKeychainUDIDItemIdentifier]);

    }

    else if (queryErr !=errSecSuccess) {

        NSLog(@"KeyChain Item query Error!!! Error code:%ld", queryErr);

    }

    if (queryErr == errSecSuccess) {

        NSLog(@"KeyChain Item: %@", udidValue);

        

        if (udidValue) {

            udid = [NSString stringWithUTF8String:udidValue.bytes];

        }

    }

    

    [dictForQuery release];

    return udid;

}


+ (BOOL)settUDIDToKeyChain:(NSString*)udid

{

    NSMutableDictionary *dictForAdd = [[NSMutableDictionaryalloc] init];

    

    [dictForAdd setValue:(id)kSecClassGenericPasswordforKey:(id)kSecClass];

    [dictForAdd setValue:[NSStringstringWithUTF8String: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 = [NSStringstringWithUTF8String: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 = [udidUTF8String];

    NSData *keyChainItemValue = [NSDatadataWithBytes:udidStr length:strlen(udidStr)];

    [dictForAdd setValue:keyChainItemValue forKey:(id)kSecValueData];

    

    OSStatus writeErr = noErr;

    if ([SvUDIDToolsgetUDIDFromKeyChain]) {        // 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 = [[NSMutableDictionaryalloc] init];

    

    [dictToDelete setValue:(id)kSecClassGenericPasswordforKey:(id)kSecClass];

    

    NSData *keyChainItemID = [NSDatadataWithBytes:kKeychainUDIDItemIdentifierlength: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 = [[NSMutableDictionaryalloc] init];

    

    [dictForQuery setValue:(id)kSecClassGenericPasswordforKey:(id)kSecClass];

   

    NSData *keychainItemID = [NSDatadataWithBytes:kKeychainUDIDItemIdentifier

                                            length:strlen(kKeychainUDIDItemIdentifier)];

    [dictForQuery setValue:keychainItemID forKey:(id)kSecAttrGeneric];

    [dictForQuery setValue:(id)kCFBooleanTrueforKey:(id)kSecMatchCaseInsensitive];

    [dictForQuery setValue:(id)kSecMatchLimitOneforKey:(id)kSecMatchLimit];

    [dictForQuery setValue:(id)kCFBooleanTrueforKey:(id)kSecReturnAttributes];

    

    NSDictionary *queryResult = nil;

    SecItemCopyMatching((CFDictionaryRef)dictForQuery, (CFTypeRef*)&queryResult);

    if (queryResult) {

        

        NSMutableDictionary *dictForUpdate = [[NSMutableDictionaryalloc] init];

        [dictForUpdate setValue:[NSStringstringWithUTF8String:kKeychainUDIDItemIdentifier]forKey:kSecAttrDescription];

        [dictForUpdate setValue:keychainItemIDforKey:(id)kSecAttrGeneric];

        

        const char *udidStr = [newUDIDUTF8String];

        NSData *keyChainItemValue = [NSDatadataWithBytes:udidStr length:strlen(udidStr)];

        [dictForUpdate setValue:keyChainItemValueforKey:(id)kSecValueData];

        

        OSStatus updateErr = noErr;

        

        // First we need the attributes from the Keychain.

        NSMutableDictionary *updateItem = [NSMutableDictionarydictionaryWithDictionary:queryResult];

        

        // Second we need to add the appropriate search key/values.

        // set kSecClass is Very important

        [updateItem setObject:(id)kSecClassGenericPasswordforKey:(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



原创粉丝点击