JSAnalysis 是一款苹果设备信息静默获取的工具。它可以在用户无感知的情况下获取到尽可能多的设备信息,方便开发者对用户提供更好的体验。本工具仅限于技术学习交流使用.
- 使用AES256加入签名、敏感信息加密. 防篡改、防劫持.
- 在没有权限获取对应信息时统一设置value为@“NONE”、防止因App、系统的更新带来的crash,对用户灵感知.
- 加入缓存机制、子线程异步获取, 避免影响主线程业务
iOS设备信息获取SDK可获取信息列表 | |||||||
---|---|---|---|---|---|---|---|
特别说明:以下部分Key值是有可能为空的,本SDK的所有空值均以NONE字符串来标识 | |||||||
(一)appInfo-应用信息 | |||||||
序号 | 应用信息名称 | 参数名称 | 示例 | 可行性 | 可行性描述 | 特别说明 | |
1 | 应用名称 | appName | “应用名称” | Y | |||
2 | 应用唯一标识 | appBundle | 公司名称 | Y | |||
3 | 应用版本 | appVersion | 2.0.1 | Y | clientVersion | ||
4 | 行为数据采集SDK版本 | sdkVersion | 1.0.1 | Y | |||
5 | App启动时间 | launchTime | 4.32 | Y | |||
6 | 本应用用户id | userId | 1002231 | Y | 需要sdk接入的开发人员初始化@property (nonatomic, copy) GetUserIdBlock userIdBlock; | ||
(二)clientInfo-客户端信息 | |||||||
序号 | 基础信息名称 | 参数名称 | 备注 | 示例 | 可行性 | 可行性描述 | 特别说明 |
7 | 设备名称 | deviceName | 获取设备驱动名称 | hwG750-T01 | Y/N | 我理解是设备的昵称,就是给我自己手机设置的别名 | |
8 | 设备型号 | deviceModel | 手机的型号 | HUAWEI G750-T01 | Y | deviceModel:iPhone X | |
9 | 设备品牌 | brand | 设备品牌 | Huawei | Y | ||
10 | 系统名称 | osName | 系统名称 | Android | Y | platform:iOS | |
11 | 系统版本 | osVersion | 获取系统版本字符串 | 4.4.4 | Y | deviceOs:iOS12.1 | |
12 | 系统sdk版本 | osSDK | 系统sdk版本比如iOS11.2 | iOS11.2 | Y | ||
13 | 制造商 | manufacturer | 设备制造商 | HUAWEI | Y | ||
14 | 系统默认语言 | initialLanguage | 系统默认语言 | zh | Y | 默认语言可以修改,获取结果同15 | |
15 | 配置时区 | timeZone | 配置时区 | 北京 | Y | ||
16 | 剩余电量 | dumpEnergy | 剩余电量 | 0.15 | Y | 模拟器获取为-1.00 | |
17 | 是否充电 | charging | 是否充电 | 0、1 | Y | 0代表没有在充电,1代表正在充电 | |
18 | 电池状态 | batteryState | Unknown: 未知状态 Unplugged: 未插电 Charging: 充电中 Full: 充电中/并且已经充满 | Charging | Y | ||
19 | UUID | UUID | IOS设备唯一标识 | xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx | Y | 这个标识会在卸载应用后会改变,现在传的imei字端其实就是这个 | |
20 | IDFA | IDFA | 与device相关的唯一标识符,可以用来打通不同app之间的广告 | 1E2DFA89-496A-47FD-9941-DF1FC4E6484A | Y | ||
21 | 是否越狱 | jailbroken | 是否越狱 | 是、否、NONE | Y | 模拟器获取为NONE | |
22 | 是否为模拟器 | simulator | 是否为模拟器 | 1、0 | Y | 1代表是,0代表不是 | |
23 | 手机cpu使用率 | cpuUsage | cpu使用率 | 12.91 | Y | ||
24 | app cpu 的使用率 | appCpuUsage | app占用的cpu | 1.23 | Y | ||
25 | 系统启动时间 | bootTime | 格林威治时间 | 1549851830 | Y | ||
26 | 系统运行总时间 | upTime | 从启动到现在运行的总时长,秒为单位 | 1233360 | Y | ||
27 | 内核版本 | kernelVersion | 系统内核版本 | Darwin Kernel Version 18.2.0: Mon Nov 12 20:24:31 PST 2018; root:xnu-4903.231.4~1/RELEASE_X86_64 | Y | ||
28 | 现在时间 | nowTime | 格林威治时间 | 1551085190 | Y | ||
(三)netInfo-网络信息 | |||||||
序号 | 网络信息名称 | 参数名称 | 备注 | 示例 | 可行性 | 可行性描述 | 特别说明 |
29 | 网络类型 | networkType | WIFI、WWAN、NONE | WIFI | Y | ||
30 | 网络名称 | SSID | 网络名/wifi名/ | YOUXIN_WIFI/NONE | Y | 模拟器获取为NONE iOS13后值固定为“WLAN” | |
31 | mac地址 | mac | 无线局域网mac地址 | 00:08:02:a4:fb | N | 如果没有连接到WiFi,获取到固定值0x020000000000 | 模拟器获取为NONE |
32 | 路由器地址 | routerAddress | 无线路由器地址 | 192.168.1.1 | Y | ||
33 | 路由器mac | routerMac | wifi的mac地址 | 10:76:93:2c:a0 | Y | bssid/ ssid | 模拟器获取为NONE |
34 | 网速 | link_speed | 网速 | 135mbps | Y | 目前有这个功能,但是都没有获取 | |
35 | cell_ip | cellIp | 蜂窝网络ip | 192.168.1.105 | Y | 模拟器获取为NONE | |
36 | wifi_ip | wifiIp | 无线局域网ip | 192.168.1.12 | Y | ||
37 | 代理ip | proxyIp | 代理ip | Y | |||
38 | 蓝牙名称 | bluetoothName | 蓝牙名称 | HUAWEI TAG-TL00 | Y | 和iPhone本身的别名相同 | |
39 | VOIP状态 | voipStatus | 0、1 | Y | |||
40 | 网络制式 | radioType | 移动网络制式 | LET | Y | ||
41 | 路由广播地址 | routerDstaddr | 10.255.17.255 | Y | |||
42 | 路由网关 | routerGateway | 160.197.64.113 | Y | |||
43 | 路由名称 | routerName | 112.50.112.48 | Y | |||
44 | 路由子网掩码 | routerNetmask | 255.255.254.0 | Y | |||
(四)phoneCardInfo-手机卡信息 | |||||||
序号 | 手机卡信息名称 | 参数名称 | 备注 | 示例 | 可行性 | 可行性描述 | 特别说明 |
45 | 手机卡国家 | simCountryIso | 手机卡国家iso代码 | cn | Y | 模拟器获取为NONE | |
46 | 运营商名字 | simOperatorName | 运营商名字 | 中国联通 | Y | 模拟器获取为NONE | |
47 | 运营商id | simOperator | 运营商id | 46001 | Y/N | 能获取国家代码和网络代码,运营商id,没有直接获取的api | 模拟器获取为NONE |
48 | 手机卡状态 | simState | SIM_STATE_UNKNO | UNKNOW、INSTALL、NONE | Y/N | 只能获取到是否插入sim卡 | |
49 | 移动国家代码 | mobileCountryCode | 移动国家代码 | NONE,1 | Y | ||
(五)screenInfo-屏幕信息 | |||||||
序号 | 屏幕信息名称 | 参数名称 | 备注 | 示例 | 可行性 | 可行性描述 | 特别说明 |
50 | 屏幕高度 | screenWidth | 屏幕高度 | 4.960638 | Y | ||
51 | 屏幕宽度 | screenHeight | 屏幕宽度 | 2.795277 | Y | ||
52 | 屏幕密度 | density | 屏幕密度 | 2 | Y | ||
53 | 屏幕亮度值 | screenBrightness | 屏幕亮度值 0--255 | Y | Y | 模拟器获取为0 | |
(六)sensorInfo-传感器信息 | |||||||
序号 | 传感信息名称 | 参数名称 | 备注 | 示例 | 可行性 | 可行性描述 | 特别说明 |
54 | 定位经度 | gpsLongitude | 定位经度 | Y | 需要用户授权位置权限 | 在没有权限的情况下为NONE | |
55 | 定位纬度 | gpsLatitude | 定位纬度 | Y | 需要用户授权位置权限 | ||
56 | GPS认证状态 | gpsStatus | GPS认证状态 | NotDetermined、Restricted、Denied、Always、WhenInUse、NONE | Y | ||
57 | GPS开关 | gpsSwitch | gps开关是否打开 | 0、1 | Y | ||
(七)storageInfo-存储/内存信息 | |||||||
序号 | 存储信息名称 | 参数名称 | 备注 | 示例 | 可行性 | 可行性描述 | 特别说明 |
58 | 内存总大小 | totalMemory | bytes为单位 | 8589934592 | Y | ||
59 | 内部存储 | totalSpace | bytes为单位 | 501580873728 | Y | ||
60 | 物理内存当前占用 | usedMemory | bytes为单位 | 14700544 | Y | ||
61 | app占用内存 | appUsedMemory | bytes为单位 | 48287744 | Y | ||
62 | 空闲的总内存 | freeSpace | bytes为单位 | 18707865600 | Y |
#import "JSAnalysis.h"
[JSAnalysis standardAnalysis].appKey = @"你的AppJKey";
//手动获取
[[JSAnalysis standardAnalysis] getAnalysisBoxWithOption:JSAnalysisGetAnalysisBoxOptionManual responseBlock:^(NSDictionary * _Nonnull analysisBoxInfo) {
NSLog(@"%@",analysisBoxInfo);
}];
更改JSAnalysisGetAnalysisBoxOptionManual 为 JSAnalysisGetAnalysisBoxOptionIntelligentAuto 可以在特定的条件下自动上传到信息收集的服务器,用户可根据 jsBox去查询数据的解密结果。
- (void)getAnalysisBoxWithOption:(JSAnalysisGetAnalysisBoxOption)option responseBlock:(void(^)(NSDictionary *analysisBoxInfo))block
API 每次被调用都会执行重新获取动作,如果需要重新获取,在每个合适的节点重新调用即可。
提供了设备信息的缓存:cacheBoxInfo
在JSAnalysis
的单例对象中可获取。
** 如果需要不加密的数据可以参考 JSAnalysis.m
中的getAllInfo
方法实现. **
{
// app 标识
"appBundle" = "com.analysisi.show";
// 信息加密后的结果
"jsBox" = "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";
// 数据签名
"sign" = 377dce9785fc41c5e502cefa3082531b;
// 获取时间
"timestamp" = 1551237554589;
// 设备标识 IDFA
clientId = "9047090B-1140-4A66-8503-A76B7698C113";
// sdk版本
sdkVersion = "1.0.0";
// 签名
sign = 84ec561739fe2ce531e3ce8c8cba427d;
timestamp = 1552977734417;
}
举例: 两个关键的key
- AES256 key: 0f607264fc6318a92b9e13c65db7cd3c (用于AES256将敏感数据加密)
JSAnalysisEncryptionTool.m
的static const char JSEncryptionToolAES256Key[] = "xxxxxxxxxxxxxxxx";
修改AES256的密钥- sign key : appkey_test (用于将加密后的数据做签名,防篡改)
- 签名默认加密私钥使用的是
JSAnalysis.h
中@property (nonatomic, copy, nonnull) NSString *appKey;
请自行更改.
- 一个map,将其中的key:value对,按照key升序排列,如 app、baby、brand、cos、design...
- 使用 AES256 key 以及 AES256加密方式对步骤1中的结果map进行加密。
-
map = { app_bundle : 当前应用标识, jsBox : 加密后的结果值, timestamp :当前时间的时间戳 } (同样按key升序)
-
以sign key为盐 做md5.
步骤1中的加密数据解密结果:
{
appInfo = {
appBundle = "com.ucredit.sales";
appName = AnalysisDemo;
appVersion = "1.0.0";
launchTime = "0.51";
sdkVersion = "1.0.0";
userId = NONE;
};
clientInfo = {
IDFA = "9047090B-1140-4A66-8503-A76B7698C113";
UUID = "2F0CB187-60A6-48EE-8DAE-C8C97FC1B186";
appCpuUsage = "61.80";
batteryState = Unknown;
bootTime = 1552914866;
brand = Apple;
charging = 0;
cpuUsage = "16.50";
deviceModel = "x86_64";
deviceName = "iPhone XR";
dumpEnergy = "-1.00";
initialLanguage = en;
jailbroken = NONE;
kernelVersion = "Darwin Kernel Version 18.2.0: Mon Nov 12 20:24:31 PST 2018; root:xnu-4903.231.4~1/RELEASE_X86_64";
manufacturer = Apple;
nowTime = 1552977730;
osName = iOS;
osSDK = "12.1";
osVersion = "12.1";
simulator = 1;
timeZone = "Asia/Shanghai (GMT+8d) offset 28800";
upTime = 62864;
};
netInfo = {
SSID = NONE;
bluetoothName = "iPhone XR";
cellIp = NONE;
mac = NONE;
networkType = WiFi;
proxyIp = NONE;
radioType = NONE;
routerAddress = "10.255.16.152";
routerDstaddr = "10.255.17.255";
routerGateway = "16.44.60.99";
routerMac = NONE;
routerName = "112.50.112.48";
routerNetmask = "255.255.254.0";
voipStatus = 0;
wifiIp = "10.255.16.152";
};
phoneCardInfo = {
mobileCountryCode = NONE;
simCountryIso = NONE;
simOperator = NONE;
simOperatorName = NONE;
simState = UNKNOW;
};
screenInfo = {
density = 2;
screenBrightness = 0;
screenHeight = 480;
screenWidth = 320;
};
sensorInfo = {
gpsLatitude = "0.000000";
gpsLongitude = "0.000000";
gpsStatus = NotDetermined;
gpsSwitch = 1;
};
storageInfo = {
appUsedMemory = 48046080;
freeSpace = 12156682240;
totalMemory = 8589934592;
totalSpace = 501580873728;
usedMemory = "-147644416";
};
}