什么是UUID
UUID即Unique Device Identifier,唯一设备识别符。iOS上的IDFA/IDFV/OpenUDID/macho-uuid,都采用UUID4格式。UUID是RFC定义的高随机性的标识字符串,结构说明在https://www.ietf.org/rfc/rfc4122.txt
struct rfc_uuid {
uint32_t time_low;
uint16_t time_mid;
uint16_t time_hi_and_version; // v=(v&0xfff)|0x400
uint8_t clock_seq_hi_and_reserved; // v=(v&0x3f)|0x80
uint8_t clock_seq_low;
uint8_t node[6];
};
UUID目前有多个版本,包括UUID1/UUID3/UUID4/UUID5,一个典型的UUID4串ef9cbf1e-3560-4555-b1aa-81bf4773cd9e
。注意uuid4的结构和其他类型不同,有些bit位固定为0或1,其他bit位完全随机(********-****-4***-(8|9|a|b)***-************
),因此如果用上面的结构体解析UUID4串是没有意义的。正如rfc所述:
4.4. Algorithms for Creating a UUID from Truly Random or
Pseudo-Random Numbers
The version 4 UUID is meant for generating UUIDs from truly-random or
pseudo-random numbers.
The algorithm is as follows:
o Set the two most significant bits (bits 6 and 7) of the
clock_seq_hi_and_reserved to zero and one, respectively.
o Set the four most significant bits (bits 12 through 15) of the
time_hi_and_version field to the 4-bit version number from
Section 4.1.3.
o Set all the other bits to randomly (or pseudo-randomly) chosen
values.
使用ObjC和Python生成uuid4
// Objective-C生成UUID
NSString* myuuid = NSUUID.UUID.UUIDString;
// Python生成UUID
import uuid
myuuid = str(uuid.uuid4())
讲一个趣事,之前一个朋友不知道IDFA用UUID4格式生成,用Hook修改系统IDFA获取的部分,改为纯随机,结果跑起来莫名其妙就是崩。。。。改机软件模拟的UUID均为上述方式生成。
怎样生成相对固定的uuid4
此需求看似有点奇怪,但是其实是有用的。在模拟参数的时候如果uuid需要和其他参数配套,那么固定一个参数去生成uuid就十分必要了。这里提供一个使用时间戳生成uuid4的实例
void uuid4_format(unsigned char* buf) { // bufsize=16
struct rfc_uuid* uuid = (struct rfc_uuid*)buf;
uuid->time_hi_and_version = (uuid->time_hi_and_version & 0xff0f) | 0x0040;
uuid->clock_seq_hi_and_reserved = (uuid->clock_seq_hi_and_reserved & 0x3f) | 0x80;
}
NSString* uuid4_init_with_ts(time_t ts) {
unsigned char uuid[16];
if (ts == 0) {
ts = time(0);
}
((uint32_t*)uuid)[0] = crc32_for_byte(ts & 0xff);
((uint32_t*)uuid)[1] = crc32_for_byte((ts >> 8) & 0xff);
((uint32_t*)uuid)[2] = crc32_for_byte((ts >> 16) & 0xff);
((uint32_t*)uuid)[3] = crc32_for_byte((ts >> 24) & 0xff);
uuid4_format(uuid);
NSUUID* nsuuid = [[NSUUID alloc] initWithUUIDBytes:uuid];
return nsuuid.UUIDString;
}