继续创造,加速成长!这是我参加「日新方案 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(设备仅有标识符)
如何仅有标识一台iOS设备?
原文:kunnan.blog.csdn.net/article/det…
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/…