iOS 获取设备的一些信息

由于各个前端系统的权限设置,很多设备信息都不能得到有效的获取;所以,公司后台同学经常询问前端同学,你们都能获取到一些什么字段?发现自己也很长一段时间没有记录技术上的知识点了,借此时机,将能获取设备的信息来统一记录。

对于收集设备信息来说分成两大块,第一当然是设备的一些私有和唯一的信息,第二就是App的信息,我们先从简单的App的信息来说。

第一部分:App的信息

关于App的信息,我们大概就需要获取App的版本号、App的build版本号、包名、App显示名称等等。

//DeviceUtils.h中定义
#pragma mark - About App Config Info Method
/**
 *  获取当前App的版本号信息
 */
+ (NSString *)getAppVersion;

/**
 *  获取当前App的build版本号信息
 */
+ (NSString *)getAppBuildVersion;

/**
 *  获取当前App的包名信息
 */
+ (NSString *)getAppBundleId;

/**
 *  获取当前App的名称信息
 */
+ (NSString *)getAppDisplayName;
//DeviceUtils.m中实现
#pragma mark - About App Config Info Method
/*获取当前App的版本号信息*/
+ (NSString *)getAppVersion
{
    NSBundle *currentBundle = [NSBundle mainBundle];
    NSDictionary *infoDictionary = [currentBundle infoDictionary];
    return [infoDictionary objectForKey:@"CFBundleShortVersionString"];
}

/*获取当前App的build版本号信息*/
+ (NSString *)getAppBuildVersion
{
    NSBundle *currentBundle = [NSBundle mainBundle];
    NSDictionary *infoDictionary = [currentBundle infoDictionary];
    return [infoDictionary objectForKey:@"CFBundleVersion"];
}

/*获取当前App的包名信息*/
+ (NSString *)getAppBundleId
{
    NSBundle *currentBundle = [NSBundle mainBundle];
    NSDictionary *infoDictionary = [currentBundle infoDictionary];
    return [infoDictionary objectForKey:@"CFBundleIdentifier"];
}

/*获取当前App的名称信息*/
+ (NSString *)getAppDisplayName
{
    NSBundle *currentBundle = [NSBundle mainBundle];
    NSDictionary *infoDictionary = [currentBundle infoDictionary];
    return [infoDictionary objectForKey:@"CFBundleDisplayName"];
}

第二部分:设备的一些私有和唯一的信息

关于获取设备各种标识符,大概统计了一下。基本上有IDFA、IDFV、IMEI、IMSI、UUID、UDID、MAC地址等等。但随着对用户隐私信息的保护,苹果系统对信息的获取进行权限设置,譬如IMEI、IMSI等的获取都明确禁止了,除非你发布的App不通过苹果商店的渠道。不管获取权限,先来介绍下这些字段的含义。

1、IMEI、IMSI、UUID、UDID、MAC地址
  • IMEI:英文名称是:International Mobile Equipment Identity,是国际移动设备身份码的缩写,国际移动装备辨识码,是由15位数字组成的”电子串号”,它与每台手机一一对应,而且该码是全世界唯一的。每一部手机在组装完成后都将被赋予一个全球唯一的一组号码,这个号码从生产到交付使用都将被制造生产的厂商所记录。手机用户可以在手机中查到自己手机的IMEI码。因为隐私问题,苹果用户在iOS5以后不能再获取IMEI的值了。如果开发的App不上架苹果商店,又想获取IMEI值,可参考此链接,获取IMEI值。

  • IMSI:英文名称是:International Mobile Subscriber Identification Number,是国际移动用户识别码的缩写,IMSI分为两部分:一部分叫MCC(Mobile Country Code移动国家码),MCC的资源由国际电联(ITU)统一分配,唯一识别移动用户所属的国家,MCC共3位,中国地区的MCC为460;另一部分叫MNC(Mobile Network Code 移动网络号码),MNC用于识别移动客户所属的移动网络运营商。MNC由二到三个十进制数组成,例如中国移动MNC为00、02、07,中国联通的MNC为01、06、09,中国电信的MNC为03、05、11。

  • UUID:英文名称是:Universally Unique Identifier,翻译过来就是通用唯一标识符。UUID是指在一台机器上生成的数字,它保证对在同一时空中的所有机器都是唯一的。通常平台会提供生成的API,是一个32位的十六进制序列,使用小横线来连接:8-4-4-4-12。由于UUID的本身特性,它保证对在同一时空中的所有机器都是唯一的。所以,需要作为唯一标识码的话,你可以通过保存在keychain或者NSUserDefaults中。

  • UDID:所谓UDID指的是设备的唯一设备识别符,移动广告商和游戏网络运营商往往需要通过UDID用来识别玩家用户,并对用户活动进行跟踪。UDID 在iOS5.0 的时候已经被抛弃使用了。因为隐私问题,苹果宣称如果第三方应用开发者继续分享或者使用iPhone、Mac、AppleWatch的UDID的话,那么他们的应用将会禁止上架。比如我开发了5款App,很多用户都下载了这5款App并使用。如果我能轻易的获取这些用户的UDID,其实我能拼凑出用户的很多信息。由于UDID本身的隐私属性,之前常常用来做第三方统计和其他的目的。苹果就推出了一个UDID的替代品identifierForVendor的属性,关于IDFV的详细内容在下一点中查看。UDID目前主要用于配置真机调试证书。

  • MAC地址:Mac地址是唯一的,unix有系统调用可以获取Mac地址。iPhone可能有多个Mac地址,wifi的地址、以及SIM卡的地址。一般来讲,我们取en0的地址,因为它是iPhone的wifi的地址,是肯定存在的(例外情况依然有:市面上依然存在一部分联通的阉割版无wifi的iPhone)。Mac地址涉及到隐私,不应该胡乱将用户的Mac地址传播,所以我们需要将Mac地址进行hash之后再去使用。同样因为隐私问题,在iOS7以后,苹果禁止获取MAC地址,系统现在只会返回02:00:00:00:00:00虚拟的地址。

2、IDFA、IDFV
  • IDFA:广告标示符,iOS6及以后使用。用户可以在设置中控制IDFA是否允许获取以及重置,虽然一般用户都不知道有这个权限设置,所以IDFA是不能拿来当做设备唯一标识(UUID)的替代品。

关闭IDFA获取权限操作:设置 → 隐私 → 广告 → 选择禁止获取IDFA值
重新生成IDFA操作:
操作一:设置程序 → 通用 → 还原 → 还原位置与隐私
操作二:设置程序 → 通用 → 关于本机 → 广告 → 还原广告标示符

//导入获取IDFA的头文件
#import <AdSupport/ASIdentifierManager.h>

- (NSString *)getDeviceIDFAValue
{
    ASIdentifierManager *object = nil;
    object = [ASIdentifierManager sharedManager];
    return [[object advertisingIdentifier] UUIDString];
}

关于IDFA的一张很好的图解:

  • IDFV:iOS6.0及以后使用,是给Vendor标识用户用的,主要用于公司内部统计用户。如果隶属一个相同的组织下的App获取到的IDFV是同一个值。例如:
编号 包名 IDFV
1 com.test.app1 与2相同,与3、4不同
2 com.test.app2 与1相同,与3、4不同
3 com.test.develop.app1 与4相同,与1、2不同
4 com.test.develop.app2 与3相同,与1、2不同

准确点说,就是通过BundleID的反转的前两部分进行匹配,如果相同就是同一个Vender,共享同一个IDFV的值。

NSString *idfv = [[UIDevice currentDevice].identifierForVendor UUIDString];
3、设备运营商名称、运营商网络
  • 设备运营商名称:当前设备上的SIM卡代理商名称。

  • 运营商网络:当前设备上的蜂窝网络名称或WiFi。

4、设备型号、设备的系统名称、设备的系统版本号
  • 设备型号:主要用来区分设备是iPhone 3gs、iPhone 4、iPhone 4s、iPhone 5、iPhone 5s、iPhone 6、iPhone 6s、iPhone 7、iPhone 8、iPhone X等,还有iPad、iWatch等苹果产品型号。苹果没有提供直接获取型号名称的API方法,所以这个值获取出来后,需要在后台进行映射成对应的设备型号。

  • 设备的系统名称:苹果设备(手机以及平板)目前只有iOS系统,苹果电脑是Mac OS系统等。

  • 设备的系统版本号:苹果设备的系统版本号,可通过UIDevice类直接获取到一个浮点值。

5、设备的尺寸、设备的分辨率
  • 设备的尺寸:苹果设备的物理尺寸,可通过UIScreen类直接获取到bounds属性进行读取。

  • 设备的分辨率:苹果设备的分辨率,可通过UIScreen类直接获取到bounds属性和scale属性进行计算。

下面直接上代码:

//DeviceUtils.h中定义
#pragma mark - About Device Config Info Method
/**
 *  获取当前设备的IMSI值
 */
+ (NSString *)getDeviceIMSIValue;

/**
 *  获取当前设备的IMEI值
 */
+ (NSString *)getDeviceIMEIValue;

/**
 *  获取当前设备的MacId值
 */
+ (NSString *)getDeviceMacIdValue;

/**
 *  获取当前设备的通讯运营商名称
 */
+ (NSString *)getDeviceCarrierName;

/**
 *  获取当前设备的网络通讯名称值
 */
+ (NSString *)getDeviceNetworkName;

/**
 *  获取当前设备的横向最大值
 */
+ (NSNumber *)getDeviceXMaxValue;

/**
 *  获取当前设备的纵向最大值
 */
+ (NSNumber *)getDeviceYMaxValue;

/**
 *  获取当前设备的横向分辨率值
 */
+ (NSNumber *)getDeviceXResolution;

/**
 *  获取当前设备的纵向分辨率值
 */
+ (NSNumber *)getDeviceYResolution;

/**
 *  获取当前设备的型号名称
 */
+ (NSString *)getDeviceModel;

/**
 *  获取当前设备的操作系统名称
 */
+ (NSString *)getDeviceOSName;

/**
 *  获取当前设备的操作系统版本号
 */
+ (NSString *)getDeviceOSVersion;

/**
 *  获取当前设备的唯一编号
 */
+ (NSString *)getDeviceTerminalId;
//DeviceUtils.m中实现
#pragma mark - About Device Config Info Method
/*获取当前设备的IMSI值*/
+ (NSString *)getDeviceIMSIValue
{
    return nil;
}

/*获取当前设备的IMEI值*/
+ (NSString *)getDeviceIMEIValue
{
    return nil;
}

/*获取当前设备的MacId值*/
+ (NSString *)getDeviceMacIdValue
{
    return nil;
}

/*获取当前设备的通讯运营商名称*/
+ (NSString *)getDeviceCarrierName
{
    CTTelephonyNetworkInfo *info = [CTTelephonyNetworkInfo new];
    CTCarrier *carrier = [info subscriberCellularProvider];
    return [carrier carrierName];
}

/*获取当前设备的网络通讯名称值*/
+ (NSString *)getDeviceNetworkName
{
    /*
        CTRadioAccessTechnologyGPRS             //介于2G和3G之间(2.5G)
        CTRadioAccessTechnologyEdge             //GPRS到第三代移动通信的过渡(2.75G)
        CTRadioAccessTechnologyWCDMA
        CTRadioAccessTechnologyHSDPA            //亦称为3.5G(3?G)
        CTRadioAccessTechnologyHSUPA            //3G到4G的过度技术
        CTRadioAccessTechnologyCDMA1x           //3G
        CTRadioAccessTechnologyCDMAEVDORev0     //3G标准
        CTRadioAccessTechnologyCDMAEVDORevA
        CTRadioAccessTechnologyCDMAEVDORevB
        CTRadioAccessTechnologyeHRPD            //电信一种3G到4G的演进技术(3.75G)
        CTRadioAccessTechnologyLTE              //接近4G
     */
    CTTelephonyNetworkInfo *info = [CTTelephonyNetworkInfo new];
    return [info currentRadioAccessTechnology];
}

/*获取当前设备的横向最大值*/
+ (NSNumber *)getDeviceXMaxValue
{
    CGFloat xoffset = CGRectZero.origin.x;
    xoffset = CGRectGetWidth([[UIScreen mainScreen] bounds]);
    return [NSNumber numberWithFloat:xoffset];
}

/*获取当前设备的纵向最大值*/
+ (NSNumber *)getDeviceYMaxValue
{
    CGFloat yoffset = CGRectZero.origin.x;
    yoffset = CGRectGetHeight([[UIScreen mainScreen] bounds]);
    return [NSNumber numberWithFloat:yoffset];
}

/*获取当前设备的横向分辨率值*/
+ (NSNumber *)getDeviceXResolution
{
    CGFloat width = CGRectZero.size.width;
    CGFloat scale = [[UIScreen mainScreen] scale];
    width = [[[self class] getDeviceXMaxValue] floatValue];
    return [NSNumber numberWithFloat:(width * scale)];
}

/*获取当前设备的纵向分辨率值*/
+ (NSNumber *)getDeviceYResolution
{
    CGFloat height = CGRectZero.size.height;
    CGFloat scale = [[UIScreen mainScreen] scale];
    height = [[[self class] getDeviceYMaxValue] floatValue];
    return [NSNumber numberWithFloat:(height * scale)];
}

/*获取当前设备的型号名称*/
+ (NSString *)getDeviceModel
{
    NSString *platform = nil;
    struct utsname systemInfo;
    uname(&systemInfo);
    platform = [NSString stringWithCString:systemInfo.machine
                                  encoding:NSUTF8StringEncoding];
    return [NSString stringWithFormat:@"%@",platform];
}

/*获取当前设备的操作系统名称*/
+ (NSString *)getDeviceOSName
{
    return @"ios";
}

/*获取当前设备的操作系统版本号*/
+ (NSString *)getDeviceOSVersion
{
    return [[UIDevice currentDevice] systemVersion];
}

/*获取当前设备的唯一编号*/
+ (NSString *)getDeviceTerminalId
{
    UIDevice *device = [UIDevice currentDevice];
    NSString *package = [[self class] getAppBundleId];
    NSString *vendor = [[device identifierForVendor] UUIDString];
    return [NSString stringWithFormat:@"%@%@",package,vendor];
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 157,012评论 4 359
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 66,589评论 1 290
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 106,819评论 0 237
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,652评论 0 202
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 51,954评论 3 285
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,381评论 1 210
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,687评论 2 310
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,404评论 0 194
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,082评论 1 238
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,355评论 2 241
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,880评论 1 255
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,249评论 2 250
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,864评论 3 232
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,007评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,760评论 0 192
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,394评论 2 269
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,281评论 2 259

推荐阅读更多精彩内容