zoukankan      html  css  js  c++  java
  • SvUDID实现设备唯一标示

    //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
    
  • 相关阅读:
    LeetCode "Palindrome Partition II"
    LeetCode "Longest Substring Without Repeating Characters"
    LeetCode "Wildcard Matching"
    LeetCode "Best Time to Buy and Sell Stock II"
    LeetCodeEPI "Best Time to Buy and Sell Stock"
    LeetCode "Substring with Concatenation of All Words"
    LeetCode "Word Break II"
    LeetCode "Word Break"
    Some thoughts..
    LeetCode "Longest Valid Parentheses"
  • 原文地址:https://www.cnblogs.com/levy/p/5027205.html
Copyright © 2011-2022 走看看