天天看点

Cocos2d-x iOS唯一标识解决方案

根据唯一标识来生成账号,对游戏及应用来讲是非常必要的。通常我们会使用UDID(设备唯一标识码)、UUID(通用唯一标识码)、MAC、IDFA(广告标识符)来实现。

但是随着苹果的各项政策,UDID不能用了。iOS7以后,要根据Mac地址绑定账号,不再可行,获得的Mac地址都是02:00:00:00:00:00,IDFA是可以重置的而且多半用于广告。我这里提供一个切实可行的解决方案。

目的:实现iOS设备账号唯一

实现策略:在应用首次启动的时候生成UUID,然后缓存到钥匙串。

步骤:

1、实现WWKeyChianUtils,钥匙串处理工具类。

//
//  WWKeyChianUtils.h
//  wawaGame
//
//  Created by diyal on 16/11/19.
//  Copyright (c) 2016年 GRMobile. All rights reserved.
//

#import <Foundation/Foundation.h>

@interface WWKeyChianUtils : NSObject

+ (NSMutableDictionary *)getKeychainQuery:(NSString *)service;

+ (void)save:(NSString *)service data:(id)data;

+ (id)load:(NSString *)service;

+ (void)delete:(NSString *)service;

@end
           
#import "WWKeyChianUtils.h"

@implementation WWKeyChianUtils

+ (NSMutableDictionary *)getKeychainQuery:(NSString *)service
{
    return [NSMutableDictionary dictionaryWithObjectsAndKeys:
            (__bridge_transfer id)kSecClassGenericPassword,(__bridge_transfer id)kSecClass,
            service, (__bridge_transfer id)kSecAttrService,
            service, (__bridge_transfer id)kSecAttrAccount,
            (__bridge_transfer id)kSecAttrAccessibleAfterFirstUnlock,(__bridge_transfer id)kSecAttrAccessible,
            nil];
}

+ (void)save:(NSString *)service data:(id)data
{
    //Get search dictionary
    NSMutableDictionary *keychainQuery = [self getKeychainQuery:service];
    //Delete old item before add new item
    SecItemDelete((__bridge_retained CFDictionaryRef)keychainQuery);
    //Add new object to search dictionary(Attention:the data format)
    [keychainQuery setObject:[NSKeyedArchiver archivedDataWithRootObject:data] forKey:(__bridge_transfer id)kSecValueData];
    //Add item to keychain with the search dictionary
    SecItemAdd((__bridge_retained CFDictionaryRef)keychainQuery, NULL);
}

+ (id)load:(NSString *)service
{
    id ret = nil;
    NSMutableDictionary *keychainQuery = [self getKeychainQuery:service];
    //Configure the search setting
    [keychainQuery setObject:(id)kCFBooleanTrue forKey:(__bridge_transfer id)kSecReturnData];
    [keychainQuery setObject:(__bridge_transfer id)kSecMatchLimitOne forKey:(__bridge_transfer id)kSecMatchLimit];
    CFDataRef keyData = NULL;
    if (SecItemCopyMatching((__bridge_retained CFDictionaryRef)keychainQuery, (CFTypeRef *)&keyData) == noErr) {
        @try {
            ret = [NSKeyedUnarchiver unarchiveObjectWithData:(__bridge_transfer NSData *)keyData];
        } @catch (NSException *e) {
            NSLog(@"Unarchive of %@ failed: %@", service, e);
        } @finally {
        }
    }
    return ret;
}

+ (void)delete:(NSString *)service
{
    NSMutableDictionary *keychainQuery = [self getKeychainQuery:service];
    SecItemDelete((__bridge_retained CFDictionaryRef)keychainQuery);
}

@end
           

2、实现getPhoneUDID,我们自定义为一个UDID,即自定义设备唯一标识。首次调用的时候,会在要钥匙串缓存。

static NSString * const KEY_USER_WAWAIDTENFIY = @"com.mas.wawaGame.wawaidtenfiy";

const char* WWIphoneTool::getPhoneUDID()
{

    NSString * strUUID = (NSString *)[WWKeyChianUtils load:KEY_USER_WAWAIDTENFIY];

    //首次执行该方法时,uuid为空
    if ([strUUID isEqualToString:@""] || !strUUID)
    {
        //生成一个uuid的方法
        CFUUIDRef uuidRef = CFUUIDCreate(kCFAllocatorDefault);

        strUUID = (NSString *)CFBridgingRelease(CFUUIDCreateString (kCFAllocatorDefault,uuidRef));

        //将该uuid保存到keychain
        [WWKeyChianUtils save:KEY_USER_WAWAIDTENFIY data:strUUID];

        CFRelease(uuidRef);
    }
    strUUID = [strUUID stringByReplacingOccurrencesOfString:@"-" withString:@""];
    return [strUUID UTF8String];
}