• iOS获取设备卸载后不变的UUID


    1.首先导入系统库Security.framework

    2.创建文件SFHFKeychainUtils.h如下(复制即可):

    @interface SFHFKeychainUtils : NSObject {

        

    }

    + (NSString *) getPasswordForUsername: (NSString *) username andServiceName: (NSString *) serviceName error: (NSError **) error;

    + (BOOL) storeUsername: (NSString *) username andPassword: (NSString *) password forServiceName: (NSString *) serviceName updateExisting: (BOOL) updateExisting error: (NSError **) error;

    + (BOOL) deleteItemForUsername: (NSString *) username andServiceName: (NSString *) serviceName error: (NSError **) error;

    @end

    SFHFKeychainUtils.m如下

    #import "SFHFKeychainUtils.h"

    #import

    static NSString *SFHFKeychainUtilsErrorDomain = @"SFHFKeychainUtilsErrorDomain";

    #if __IPHONE_OS_VERSION_MIN_REQUIRED < 30000 && TARGET_IPHONE_SIMULATOR

    @interface SFHFKeychainUtils (PrivateMethods)

    + (SecKeychainItemRef) getKeychainItemReferenceForUsername: (NSString *) username andServiceName: (NSString *) serviceName error: (NSError **) error;

    @end

    #endif

    @implementation SFHFKeychainUtils

    #if __IPHONE_OS_VERSION_MIN_REQUIRED < 30000 && TARGET_IPHONE_SIMULATOR

    + (NSString *) getPasswordForUsername: (NSString *) username andServiceName: (NSString *) serviceName error: (NSError **) error {

        if (!username || !serviceName) {

            *error = [NSError errorWithDomain: SFHFKeychainUtilsErrorDomain code: -2000 userInfo: nil];

            return nil;

        }

        

        SecKeychainItemRef item = [SFHFKeychainUtils getKeychainItemReferenceForUsername: username andServiceName: serviceName error: error];

        

        if (*error || !item) {

            return nil;

        }

        

        // from Advanced Mac OS X Programming, ch. 16

        UInt32 length;

        char *password;

        SecKeychainAttribute attributes[8];

        SecKeychainAttributeList list;

        

        attributes[0].tag = kSecAccountItemAttr;

        attributes[1].tag = kSecDescriptionItemAttr;

        attributes[2].tag = kSecLabelItemAttr;

        attributes[3].tag = kSecModDateItemAttr;

        

        list.count = 4;

        list.attr = attributes;

        

        OSStatus status = SecKeychainItemCopyContent(item, NULL, &list, &length, (void **)&password);

        

        if (status != noErr) {

            *error = [NSError errorWithDomain: SFHFKeychainUtilsErrorDomain code: status userInfo: nil];

            return nil;

        }

        

        NSString *passwordString = nil;

        

        if (password != NULL) {

            char passwordBuffer[1024];

            

            if (length > 1023) {

                length = 1023;

            }

            strncpy(passwordBuffer, password, length);

            

            passwordBuffer[length] = '';

            passwordString = [NSString stringWithCString:passwordBuffer];

        }

        

        SecKeychainItemFreeContent(&list, password);

        

        CFRelease(item);

        

        return passwordString;

    }

    + (void) storeUsername: (NSString *) username andPassword: (NSString *) password forServiceName: (NSString *) serviceName updateExisting: (BOOL) updateExisting error: (NSError **) error {

        if (!username || !password || !serviceName) {

            *error = [NSError errorWithDomain: SFHFKeychainUtilsErrorDomain code: -2000 userInfo: nil];

            return;

        }

        

        OSStatus status = noErr;

        

        SecKeychainItemRef item = [SFHFKeychainUtils getKeychainItemReferenceForUsername: username andServiceName: serviceName error: error];

        

        if (*error && [*error code] != noErr) {

            return;

        }

        

        *error = nil;

        

        if (item) {

            status = SecKeychainItemModifyAttributesAndData(item,

                                                            NULL,

                                                            strlen([password UTF8String]),

                                                            [password UTF8String]);

            

            CFRelease(item);

        }

        else {

            status = SecKeychainAddGenericPassword(NULL,

                                                   strlen([serviceName UTF8String]),

                                                   [serviceName UTF8String],

                                                   strlen([username UTF8String]),

                                                   [username UTF8String],

                                                   strlen([password UTF8String]),

                                                   [password UTF8String],

                                                   NULL);

        }

        

        if (status != noErr) {

            *error = [NSError errorWithDomain: SFHFKeychainUtilsErrorDomain code: status userInfo: nil];

        }

    }

    + (void) deleteItemForUsername: (NSString *) username andServiceName: (NSString *) serviceName error: (NSError **) error {

        if (!username || !serviceName) {

            *error = [NSError errorWithDomain: SFHFKeychainUtilsErrorDomain code: 2000 userInfo: nil];

            return;

        }

        

        *error = nil;

        

        SecKeychainItemRef item = [SFHFKeychainUtils getKeychainItemReferenceForUsername: username andServiceName: serviceName error: error];

        

        if (*error && [*error code] != noErr) {

            return;

        }

        

        OSStatus status;

        

        if (item) {

            status = SecKeychainItemDelete(item);

            

            CFRelease(item);

        }

        

        if (status != noErr) {

            *error = [NSError errorWithDomain: SFHFKeychainUtilsErrorDomain code: status userInfo: nil];

        }

    }

    + (SecKeychainItemRef) getKeychainItemReferenceForUsername: (NSString *) username andServiceName: (NSString *) serviceName error: (NSError **) error {

        if (!username || !serviceName) {

            *error = [NSError errorWithDomain: SFHFKeychainUtilsErrorDomain code: -2000 userInfo: nil];

            return nil;

        }

        

        *error = nil;

        

        SecKeychainItemRef item;

        

        OSStatus status = SecKeychainFindGenericPassword(NULL,

                                                         strlen([serviceName UTF8String]),

                                                         [serviceName UTF8String],

                                                         strlen([username UTF8String]),

                                                         [username UTF8String],

                                                         NULL,

                                                         NULL,

                                                         &item);

        

        if (status != noErr) {

            if (status != errSecItemNotFound) {

                *error = [NSError errorWithDomain: SFHFKeychainUtilsErrorDomain code: status userInfo: nil];

            }

            

            return nil;

        }

        

        return item;

    }

    #else

    + (NSString *) getPasswordForUsername: (NSString *) username andServiceName: (NSString *) serviceName error: (NSError **) error {

        if (!username || !serviceName) {

            if (error != nil) {

                *error = [NSError errorWithDomain: SFHFKeychainUtilsErrorDomain code: -2000 userInfo: nil];

            }

            return nil;

        }

        

        if (error != nil) {

            *error = nil;

        }

        

        // Set up a query dictionary with the base query attributes: item type (generic), username, and service

        

        NSArray *keys = [[[NSArray alloc] initWithObjects: (NSString *) kSecClass, kSecAttrAccount,kSecAttrService, nil] autorelease];

        NSArray *objects = [[[NSArray alloc] initWithObjects: (NSString *) kSecClassGenericPassword, username, serviceName, nil] autorelease];

        

        NSMutableDictionary *query = [[[NSMutableDictionary alloc] initWithObjects: objects forKeys: keys] autorelease];

        

        // First do a query for attributes, in case we already have a Keychain item with no password data set.

        // One likely way such an incorrect item could have come about is due to the previous (incorrect)

        // version of this code (which set the password as a generic attribute instead of password data).

        

        NSDictionary *attributeResult = NULL;

        NSMutableDictionary *attributeQuery = [query mutableCopy];

        [attributeQuery setObject: (id) kCFBooleanTrue forKey:(id) kSecReturnAttributes];

        OSStatus status = SecItemCopyMatching((CFDictionaryRef) attributeQuery, (CFTypeRef *) &attributeResult);

        

        [attributeResult release];

        [attributeQuery release];

        

        if (status != noErr) {

            // No existing item found--simply return nil for the password

            if (error != nil && status != errSecItemNotFound) {

                //Only return an error if a real exception happened--not simply for "not found."

                *error = [NSError errorWithDomain: SFHFKeychainUtilsErrorDomain code: status userInfo: nil];

            }

            

            return nil;

        }

        

        // We have an existing item, now query for the password data associated with it.

        

        NSData *resultData = nil;

        NSMutableDictionary *passwordQuery = [query mutableCopy];

        [passwordQuery setObject: (id) kCFBooleanTrue forKey: (id) kSecReturnData];

        

        status = SecItemCopyMatching((CFDictionaryRef) passwordQuery, (CFTypeRef *) &resultData);

        

        [resultData autorelease];

        [passwordQuery release];

        

        if (status != noErr) {

            if (status == errSecItemNotFound) {

                // We found attributes for the item previously, but no password now, so return a special error.

                // Users of this API will probably want to detect this error and prompt the user to

                // re-enter their credentials.  When you attempt to store the re-entered credentials

                // using storeUsername:andPassword:forServiceName:updateExisting:error

                // the old, incorrect entry will be deleted and a new one with a properly encrypted

                // password will be added.

                if (error != nil) {

                    *error = [NSError errorWithDomain: SFHFKeychainUtilsErrorDomain code: -1999 userInfo:nil];

                }

            }

            else {

                // Something else went wrong. Simply return the normal Keychain API error code.

                if (error != nil) {

                    *error = [NSError errorWithDomain: SFHFKeychainUtilsErrorDomain code: status userInfo:nil];

                }

            }

            

            return nil;

        }

        

        NSString *password = nil;

        

        if (resultData) {

            password = [[NSString alloc] initWithData: resultData encoding: NSUTF8StringEncoding];

        }

        else {

            // There is an existing item, but we weren't able to get password data for it for some reason,

            // Possibly as a result of an item being incorrectly entered by the previous code.

            // Set the -1999 error so the code above us can prompt the user again.

            if (error != nil) {

                *error = [NSError errorWithDomain: SFHFKeychainUtilsErrorDomain code: -1999 userInfo: nil];

            }

        }

        

        return [password autorelease];

    }

    + (BOOL) storeUsername: (NSString *) username andPassword: (NSString *) password forServiceName: (NSString *) serviceName updateExisting: (BOOL) updateExisting error: (NSError **) error

    {

        if (!username || !password || !serviceName)

        {

            if (error != nil)

            {

                *error = [NSError errorWithDomain: SFHFKeychainUtilsErrorDomain code: -2000 userInfo: nil];

            }

            return NO;

        }

        

        // See if we already have a password entered for these credentials.

        NSError *getError = nil;

        NSString *existingPassword = [SFHFKeychainUtils getPasswordForUsername: username andServiceName: serviceName error:&getError];

        

        if ([getError code] == -1999)

        {

            // There is an existing entry without a password properly stored (possibly as a result of the previous incorrect version of this code.

            // Delete the existing item before moving on entering a correct one.

            

            getError = nil;

            

            [self deleteItemForUsername: username andServiceName: serviceName error: &getError];

            

            if ([getError code] != noErr)

            {

                if (error != nil)

                {

                    *error = getError;

                }

                return NO;

            }

        }

        else if ([getError code] != noErr)

        {

            if (error != nil)

            {

                *error = getError;

            }

            return NO;

        }

        

        if (error != nil)

        {

            *error = nil;

        }

        

        OSStatus status = noErr;

        

        if (existingPassword)

        {

            // We have an existing, properly entered item with a password.

            // Update the existing item.

            

            if (![existingPassword isEqualToString:password] && updateExisting)

            {

                //Only update if we're allowed to update existing.  If not, simply do nothing.

                

                NSArray *keys = [[[NSArray alloc] initWithObjects: (NSString *) kSecClass,

                                  kSecAttrService,

                                  kSecAttrLabel,

                                  kSecAttrAccount,

                                  nil] autorelease];

                

                NSArray *objects = [[[NSArray alloc] initWithObjects: (NSString *) kSecClassGenericPassword,

                                     serviceName,

                                     serviceName,

                                     username,

                                     nil] autorelease];

                

                NSDictionary *query = [[[NSDictionary alloc] initWithObjects: objects forKeys: keys] autorelease];

                

                status = SecItemUpdate((CFDictionaryRef) query, (CFDictionaryRef) [NSDictionarydictionaryWithObject: [password dataUsingEncoding: NSUTF8StringEncoding] forKey: (NSString *)kSecValueData]);

            }

        }

        else

        {

            // No existing entry (or an existing, improperly entered, and therefore now

            // deleted, entry).  Create a new entry.

            

            NSArray *keys = [[[NSArray alloc] initWithObjects: (NSString *) kSecClass,

                              kSecAttrService,

                              kSecAttrLabel,

                              kSecAttrAccount,

                              kSecValueData,

                              nil] autorelease];

            

            NSArray *objects = [[[NSArray alloc] initWithObjects: (NSString *) kSecClassGenericPassword,

                                 serviceName,

                                 serviceName,

                                 username,

                                 [password dataUsingEncoding: NSUTF8StringEncoding],

                                 nil] autorelease];

            

            NSDictionary *query = [[[NSDictionary alloc] initWithObjects: objects forKeys: keys] autorelease];

            

            status = SecItemAdd((CFDictionaryRef) query, NULL);

        }

        

        if (status != noErr) 

        {

            // Something went wrong with adding the new item. Return the Keychain error code.

            if (error != nil) {

                *error = [NSError errorWithDomain: SFHFKeychainUtilsErrorDomain code: status userInfo: nil];

            }

            

            return NO;

        }

        

        return YES;

    }

    + (BOOL) deleteItemForUsername: (NSString *) username andServiceName: (NSString *) serviceName error: (NSError **) error 

    {

        if (!username || !serviceName) 

        {

            if (error != nil) 

            {

                *error = [NSError errorWithDomain: SFHFKeychainUtilsErrorDomain code: -2000 userInfo: nil];

            }

            return NO;

        }

        

        if (error != nil) 

        {

            *error = nil;

        }

        

        NSArray *keys = [[[NSArray alloc] initWithObjects: (NSString *) kSecClass, kSecAttrAccount,kSecAttrService, kSecReturnAttributes, nil] autorelease];

        NSArray *objects = [[[NSArray alloc] initWithObjects: (NSString *) kSecClassGenericPassword, username, serviceName, kCFBooleanTrue, nil] autorelease];

        

        NSDictionary *query = [[[NSDictionary alloc] initWithObjects: objects forKeys: keys] autorelease];

        

        OSStatus status = SecItemDelete((CFDictionaryRef) query);

        

        if (status != noErr) 

        {

            if (error != nil) {

                *error = [NSError errorWithDomain: SFHFKeychainUtilsErrorDomain code: status userInfo: nil];

            }

            

            return NO;

        }

        

        return YES;

    }

    #endif

    @end

     
    这里才是重要的代码iOS获取设备卸载后不变的UUID <wbr>udid很简单,一步成功,最简单的方法
    3.在获取uuid类里导入头文件#import"SFHFKeychainUtils.h"
    下面是获取方法每次调用此方法即可

    +(NSString*) GetIOSUUID

    {

       NSError *error;

        

        NSString * string = [SFHFKeychainUtils getPasswordForUsername:@"UUID" andServiceName:@"com.china.TestKeyChain" error:&error];

        

        if (!string) {

           

        }

        

        if(error || !string){

            NSLog(@"❌从Keychain里获取密码出错:%@", error);

            [self saveUUID];//保存

            string = [SFHFKeychainUtils getPasswordForUsername:@"UUID" andServiceName:@"com.china.TestKeyChain" error:&error];

           

            

        }

        else{

            NSLog(@"✅从Keychain里获取密码成功!密码为%@",string);

        }

        return string;

        

    }

    保存uuid方法(此方法不必自己调用)

    +(void)saveUUID

    {

        CFUUIDRef puuid = CFUUIDCreate( nil );

        CFStringRef uuidString = CFUUIDCreateString( nil, puuid );

        NSString * result = (NSString *)CFBridgingRelease(CFStringCreateCopy( NULL, uuidString));

        CFRelease(puuid);

        CFRelease(uuidString);

        

        NSError *error;

        

        BOOL saved = [SFHFKeychainUtils storeUsername:@"UUID" andPassword:result

                                       forServiceName:@"com.china.TestKeyChain" updateExisting:YESerror:&error];

        

        if (!saved) {

            NSLog(@"❌Keychain保存密码时出错:%@", error);

        }else{

            NSLog(@"✅Keychain保存密码成功!%@",result);

        }

    }

    4.最后就要测试了,运行时打印一下uuid,然后卸载了重新运行打印,发现一样就OK了
     
    原文  http://blog.sina.com.cn/s/blog_15383d4e60102w5fv.html  谢谢分享
  • 相关阅读:
    解读AppIcon图标设置置信息和App内存警告临界值
    我在外包公司做增删改查有前途么?
    浅议Grpc传输机制和WCF中的回调机制的代码迁移
    2019.NET Conf China(中国.NET开发者峰会)活动全纪录:.NET技术之崛起,已势不可挡
    一位年轻而优秀的.NET开发者的成长点滴
    领域驱动设计-让程序员心中有码(九)
    2019.NET Conf,我们在共同期待
    码农的技术小世界
    .NET Core使用gRPC打造服务间通信基础设施
    坚持写了一年的博客,我有哪些收获
  • 原文地址:https://www.cnblogs.com/isItOk/p/6363698.html
Copyright © 2020-2023  润新知