iOS 獲取唯一標(biāo)識(shí)

目前獲取唯一標(biāo)識(shí)一般采用UUID+keychain來(lái)使用,實(shí)測(cè)可以做到,不過(guò)還沒(méi)上架AppStore不確定能不能通過(guò)審核。


NSString *SERVICE_NAME = @"com.xinliao.dongneng";//最好用程序的bundle id

NSString * str =? [SFHFKeychainUtils getPasswordForUsername:@"UUID" andServiceName:SERVICE_NAME error:nil];? // 從keychain獲取數(shù)據(jù)

if ([str length]<=0)

{

str? = [[[UIDevice currentDevice] identifierForVendor] UUIDString];? // 保存UUID作為手機(jī)唯一標(biāo)識(shí)符

[SFHFKeychainUtils storeUsername:@"UUID"

andPassword:str

forServiceName:SERVICE_NAME

updateExisting:1

error:nil];? // 往keychain添加數(shù)據(jù)

}




創(chuàng)建文件 SFHFKeychainUtils


//.h文件

#import@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



//.m文件

////? SFHFKeychainUtils.m////? Created by Buzz Andersen on 10/20/08.//? Based partly on code by Jonathan Wight, Jon Crosby, and Mike Malone.//? Copyright 2008 Sci-Fi Hi-Fi. All rights reserved.////? Permission is hereby granted, free of charge, to any person//? obtaining a copy of this software and associated documentation//? files (the "Software"), to deal in the Software without//? restriction, including without limitation the rights to use,//? copy, modify, merge, publish, distribute, sublicense, and/or sell//? copies of the Software, and to permit persons to whom the//? Software is furnished to do so, subject to the following//? conditions:////? The above copyright notice and this permission notice shall be//? included in all copies or substantial portions of the Software.////? THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,//? EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES//? OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND//? NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT//? HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,//? WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING//? FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR//? OTHER DEALINGS IN THE SOFTWARE.//#import "SFHFKeychainUtils.h"#importstatic 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] = '\0';

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) [NSDictionary dictionaryWithObject: [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





最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容

  • 最近搞環(huán)信聊天,需求是游客身份也可以進(jìn)行聊天,當(dāng)用戶注冊(cè)了我們的APP后也需要把游客身份切換過(guò)來(lái)進(jìn)行聊天,首先我們...
    EncourageMan閱讀 2,012評(píng)論 2 3
  • /**ios常見(jiàn)的幾種加密方法: 普通的加密方法是講密碼進(jìn)行加密后保存到用戶偏好設(shè)置( [NSUserDefaul...
    彬至睢陽(yáng)閱讀 3,017評(píng)論 0 7
  • iOS開(kāi)發(fā)系列--網(wǎng)絡(luò)開(kāi)發(fā) 概覽 大部分應(yīng)用程序都或多或少會(huì)牽扯到網(wǎng)絡(luò)開(kāi)發(fā),例如說(shuō)新浪微博、微信等,這些應(yīng)用本身可...
    lichengjin閱讀 3,721評(píng)論 2 7
  • 蘋(píng)果官方文檔地址 keychain保護(hù) /* 設(shè)置keychain項(xiàng)保護(hù)等級(jí) */ NSDictionary *q...
    GeniusLi閱讀 1,185評(píng)論 0 0
  • 今天天氣晴好,早上上班便從家里步行到單位,途中,小區(qū)一位鄰居開(kāi)電動(dòng)車(chē)從我身邊經(jīng)過(guò),停下來(lái)問(wèn):要帶你嗎?如今出入都...
    趣趣1閱讀 364評(píng)論 1 3