美文网首页
iOS开发-获取设备号,钥匙串keychain 记录获取

iOS开发-获取设备号,钥匙串keychain 记录获取

作者: 王天琦 | 来源:发表于2016-10-28 12:07 被阅读962次

    在之前开发游戏官方渠道sdk的时候,通常会有快速登录的需求,这时候就需要获取设备的唯一标识  来当做用户的账号。

    在一些大公司,比如网易、腾讯、游久等,他们都会有自己的一套获取设备号的方法。

    之前试过一些,比如mac地址,uuid ,udid等,这些方式也都被苹果禁用了。

    当时,uuid可以获取到,但是如果用户在设置中   

    设置-隐私-广告-跟踪广告,这个如果是打开状态的话,会造成获取不到设备号(每次设备号都会重新生成)。所以,游戏玩家进入游戏,下线再次登录之后,会发现之前的游戏角色不见了。(或者变成别人的账号,发生串号问题)

    那么,我们就要获取一个永不会变的“标识符”,存在设备的钥匙串中,即使删除应用程序(游戏),这个“标识符”依然存在。

    如下:项目中实际的解决方案。

    + (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];

    }

    elseif(version >=2.0) {

    udid = [SvUDIDTools _UDID_iOS6];

    }

    [SvUDIDTools settUDIDToKeyChain:udid];

    }

    returnudid;

    }

    /*

    * 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

    // fromhttp://stackoverflow.com/questions/677530/how-can-i-programmatically-get-the-mac-address-of-an-iphone

    + (NSString *)getMacAddress

    {

    intmgmtInfoBase[6];

    char*msgBuffer =NULL;

    size_tlength;

    unsignedcharmacAddress[6];

    structif_msghdr*interfaceMsgStruct;

    structsockaddr_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);

    }

    returnerrorFlag;

    }

    // Map msgbuffer to interface message structure

    interfaceMsgStruct = (structif_msghdr *) msgBuffer;

    // Map to link-level socket structure

    socketStruct = (structsockaddr_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);

    returnmacAddressString;

    }

    #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 stringWithUTF8String: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]);

    }

    elseif(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];

    [udidValue release];

    }

    [dict release];

    }

    [dictForQuery release];

    returnudid;

    }

    + (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 stringWithUTF8String: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

    }

    constchar*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];

    returnYES;

    }

    else{// add item to keychain

    writeErr = SecItemAdd((CFDictionaryRef)dictForAdd,NULL);

    if(writeErr != errSecSuccess) {

    NSLog(@"Add KeyChain Item Error!!! Error Code:%ld", writeErr);

    [dictForAdd release];

    returnNO;

    }

    else{

    NSLog(@"Add KeyChain Item Success!!!");

    [dictForAdd release];

    returnYES;

    }

    }

    [dictForAdd release];

    returnNO;

    }

    + (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];

    returnNO;

    }

    else{

    NSLog(@"delete success!!!");

    }

    [dictToDelete release];

    returnYES;

    }

    + (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];

    constchar*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];

    returnNO;

    }

    else{

    NSLog(@"Update KeyChain Item Success!!!");

    [dictForQuery release];

    [dictForUpdate release];

    returnYES;

    }

    }

    [dictForQuery release];

    returnNO;

    }

    相关文章

      网友评论

          本文标题:iOS开发-获取设备号,钥匙串keychain 记录获取

          本文链接:https://www.haomeiwen.com/subject/bmfeuttx.html