持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第27天,点击查看活动详情
引言
设备唯一标识符获取方案:
- 使用idfa、idfv
- 使用Keychain 存储UUID
- 通过Safari与mobileconfig获取
关于设备ID的心得: 通过逆向研究,发现大部分的app设备ID以及OpenUDID都是基于CFUUIDCreate、CFUUIDCreateString 进行创建。
+ (NSString*) value {
return [OpenUDID valueWithError:nil];
}
+ (NSString*) valueWithError:(NSError **)error {
NSString * appUID = [defaults objectForKey:kOpenUDIDAppUIDKey];
if(appUID == nil)
{
// generate a new uuid and store it in user defaults
CFUUIDRef uuid = CFUUIDCreate(NULL);
appUID = (NSString *) CFUUIDCreateString(NULL, uuid);
CFRelease(uuid);
[appUID autorelease];
}
....
}
I 预备知识
1.1 什么是Keychain?
Keychain是OS X和iOS都提供的一种安全存储敏感信息工具:可以在Keychain中存储用户名、密码等信息;iOS16新增 LARightStore 用于存储与获取 keychain 中的数据。 Keychain的安全机制从系统层面保证了存储的敏感信息不会被非法读取或者窃取。
Keychain的特点如下:
- 保存在Keychain中的数据,即使应用程序被卸载,数据仍然存在;重新安装应用程序,我们也可以从Keychain中读取这些数据。
- Keychain中的数据可以通过Group的方式实现应用程序之间共享,只要应用程序具有相同的TeamID即可。
- 保存在Keychain中的数据都是经过加密的,因此非常安全。
1.2 OpenUDID的使用
在ARC工程中集成非ARC的第三方代码,编译库里面的文件需要使用-fno-objc-arc
// E192DF9B1F68C4AB00509A7D /* OpenUDID.m in Sources / = {isa = PBXBuildFile; fileRef = E192DF9A1F68C4AB00509A7D / OpenUDID.m */; settings = {COMPILER_FLAGS = “-fno-objc-arc”; }; };
- (NSString *)openUDID{
if (_openUDID == nil || [_openUDID isEqualToString:@""]) {
CMPayKeychainItemWrapper *wrapper = [[CMPayKeychainItemWrapper alloc] initWithIdentifier:@"weiliu.openUdid"accessGroup:nil];
// 读测试
NSString *openUDID = [wrapper objectForKey:(__bridge id)kSecValueData];
NSLog(@"读出_openUDID:%@",openUDID);
if (openUDID == nil || [openUDID isEqualToString:@""])
{
openUDID = [OpenUDID value];
// 如果是模拟器
if (TARGET_IPHONE_SIMULATOR){
}else{
[wrapper setObject:openUDID forKey:(__bridge id)kSecValueData];
}
NSLog(@"写入_openUDID:%@",openUDID);
}
_openUDID = openUDID;
NSLog(@"_openUDID:%@", openUDID);
}
return _openUDID;
}
II 设备唯一标识符获取方案
2.1 通过Safari浏览器获取iOS设备UDID(设备唯一标识符)
2.2 替代方案:使用Keychain 存储UUID
从CSDN下载Demo:https://download.csdn.net/download/u011018979/16751837
1、应用场景:签名函数 2、原理:为了提高代码的安全性,可以采用把把函数名隐藏在结构体里,以函数指针成员的形式存储。 编译后,只留了下地址,去掉了名字和参数表,提高了逆向成本和攻击门槛. 3、文章:kunnan.blog.csdn.net/article/det…
- (NSString *)strUUID{
if (_strUUID == nil || [_strUUID isEqualToString:@""]) {
CMPayKeychainItemWrapper *wrapper = [[CMPayKeychainItemWrapper alloc] initWithIdentifier:@"https://kunnan.blog.csdn.net/"accessGroup:nil];
// 读测试
NSString *strMD5 = [wrapper objectForKey:(__bridge id)kSecAttrAccount];
NSLog(@"读出md5:%@",strMD5);
if (strMD5 == nil || [strMD5 isEqualToString:@""])
{
strMD5 = [MD5Generator MD5];
// 如果是模拟器
if (TARGET_IPHONE_SIMULATOR){
}else{
[wrapper setObject:strMD5 forKey:(__bridge id)kSecAttrAccount];
}
NSLog(@"写入MD5:%@",strMD5);
}
_strUUID = strMD5;
NSLog(@"strUUID:%@", strMD5);
}
return _strUUID;
}
- (NSString *)openUDID{
if (_openUDID == nil || [_openUDID isEqualToString:@""]) {
CMPayKeychainItemWrapper *wrapper = [[CMPayKeychainItemWrapper alloc] initWithIdentifier:@"weiliu.openUdid"accessGroup:nil];
// 读测试
NSString *openUDID = [wrapper objectForKey:(__bridge id)kSecValueData];
NSLog(@"读出_openUDID:%@",openUDID);
if (openUDID == nil || [openUDID isEqualToString:@""])
{
openUDID = [OpenUDID value];
// 如果是模拟器
if (TARGET_IPHONE_SIMULATOR){
}else{
[wrapper setObject:openUDID forKey:(__bridge id)kSecValueData];
}
NSLog(@"写入_openUDID:%@",openUDID);
}
_openUDID = openUDID;
NSLog(@"_openUDID:%@", openUDID);
}
return _openUDID;
}
III IDFA(Identifier For Advertising,广告标识符)
在同一个iOS设备上,同一时刻,所有的应用程序获取到的IDFA都是相同的。从iOS 6开始,我们可以利用AdSupport.framework库提供的方法来获取IDFA,
#import <AdSupport/AdSupport.h>;
NSString *idfa = [[[ASIdentifierManager sharedManager] advertisingIdentifier] UUIDString];
但是,IDFA的值并不是固定不变的.目前,以下操作均会改变IDFA的值:
- 通过设置→通用→还原→抹掉所有内容和设置
- 通过iTunes还原设备
- 通过设置→隐私→广告→限制广告追踪(一旦用户限制了广告追踪,我们获取到的IDFA将是一个固定的IDFA,即一连串零:00000000-0000-0000-0000-000000000000)
判断是否限制了广告追踪
BOOL isLimitAdTracking = [[ASIdentifierManager sharedManager] isAdvertisingTrackingEnabled];
IDFA能解决应用程序卸载重装唯一标识设备的问题。因此,IDFA目前来说比较适合作为iOS设备ID属性。
IV IDFV (Identifier For Vendor,应用开发商标识符)
NSString *idfv = [[[UIDevice currentDevice] identifierForVendor] UUIDString];
是为了便于应用开发商(Vendor)标识用户,适用于分析用户在应用内的行为等。它也是一个由32位十六进制组成的序列,格式与UUID一致。
每一个iOS设备在所属同一个Vendor的应用里,获取到的IDFV是相同的。Vendor是通过反转后的BundleID的前两部分进行匹配的,如果相同就属于同一个Vendor。(比如,对于com.apple.example1和com.apple.example2这两个BundleID来说,它们就属于同一个Vendor,将共享同一个IDFV。)
-
和IDFA相比,IDFV不会出现获取不到的场景。
-
但IDFV也有一个很大的缺点:
如果用户将属于此Vendor的所有应用程序都卸载,IDFV的值也会被系统重置。即使重装该Vendor的应用程序,获取到的也是一个全新的IDFV。
以下操作也会重置IDFV:
- 通过设置→通用→还原→抹掉所有内容和设置。
- 通过iTunes还原设备。
- 卸载设备上某个开发者账号下的所有应用程序。
V iOS设备指纹大全
5.1 iPhone型号认知
- 要查看A/B型
打开手机的 设置-通用-关于,型号那一行默认显示的就是B型号 双击型号所在的行可以切换A/B型号信息
- A型号(表示对应的大版本,比如全网通版本、中国特供版)
下载固件的时候,就是参考A型号
- B型号(表示的是具体的型号,前五位数字才是真正的型号,其余的表示不同地区而已)
1、不同地区不同颜色甚至不同容量的 iOS 设备,他的B型号都是不同的 2、首字母表示设备的类型 F:官方翻新机 M:零售,通常我们买到的就是这种 N:更换机,售后等更换后的机子 P:镌刻机,购买时镌刻了自定义文字
5.2 iOS设备指纹大全
VI 、 通过UIDevice获取设备信息的汇总
iOS16隐私权限增强,通过 UIDevice 获取设备名称时,无法获取用户的信息,只能获取设备对应的名称。UIDevice 不再支持通过setValue()方法设置设备的方向,替换为 UIWindowScene 的requestGeometryUpdate()方法。
let name = UIDevice.current.name
// iOS16之前:XXX iPhone 13 Pro Max
// iOS16之后:iPhone 13 Pro Max,不再包含用户信息
let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene
// 通过UIWindowScene的requestGeometryUpdate()设置
windowScene?.requestGeometryUpdate(.iOS(interfaceOrientations: .landscapeLeft))
更多内容请查看原文:blog.csdn.net/z929118967/…
今天的文章iOS小技能:获取设备唯一标识符(idfa、idfv 、使用Keychain 存储UUID及通过Safari获取)分享到此就结束了,感谢您的阅读。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/19427.html