iOS獲取當前裝置的資訊-網路相關

ppsheep發表於2016-12-16

最近在搞網路相關的SDK,將自己在專案中能夠開放出來的,記錄下來,其中很多用到了C,相當於一個工具。後期還會選擇開放一些ping網路的工具,找鏈路節點的工具,最近就在搞這個。

歡迎大家關注我的公眾號,我會定期分享一些我在專案中遇到問題的解決辦法和一些iOS實用的技巧,現階段主要是整理出一些基礎的知識記錄下來



文章也會同步更新到我的部落格:
ppsheep.com

獲取當前裝置的IP地址

對於公網的IP當然,在我們本地裝置上是不能夠獲取到的,至少我沒有找到方法獲取到出口IP地址,但是區域網的IP還是能夠獲取到的,這裡ipv4和ipv6 都能夠獲取出來

+ (NSString *)deviceIPAdress
{
    NSString *address = @"";
    struct ifaddrs *interfaces = NULL;
    struct ifaddrs *temp_addr = NULL;
    int success = 0;

    success = getifaddrs(&interfaces);

    if (success == 0) {  // 0 表示獲取成功

        temp_addr = interfaces;
        while (temp_addr != NULL) {

            if ([[NSString stringWithUTF8String:temp_addr->ifa_name] isEqualToString:@"en0"] || [[NSString stringWithUTF8String:temp_addr->ifa_name] isEqualToString:@"pdp_ip0"])
                {
                //如果是IPV4地址,直接轉化
                if (temp_addr->ifa_addr->sa_family == AF_INET){

                    // Get NSString from C String
                    address = [self formatIPV4Address:((struct sockaddr_in *)temp_addr->ifa_addr)->sin_addr];
                }

                //如果是IPV6地址
                else if (temp_addr->ifa_addr->sa_family == AF_INET6){
                    address = [self formatIPV6Address:((struct sockaddr_in6 *)temp_addr->ifa_addr)->sin6_addr];
                    if (address && ![address isEqualToString:@""] && ![address.uppercaseString hasPrefix:@"FE80"]) break;
                }
                }

            temp_addr = temp_addr->ifa_next;
        }
    }

    freeifaddrs(interfaces);

    //以FE80開始的地址是單播地址
    if (address && ![address isEqualToString:@""] && ![address.uppercaseString hasPrefix:@"FE80"]) {
        return address;
    } else {
        return @"127.0.0.1";
    }
}複製程式碼

獲取當前裝置閘道器地址

閘道器地址,通俗點 就是路由器的地址,也是相對於區域網 這裡需要區分一下ipv4和ipv6,兩種獲取閘道器地址的方法是不一樣

//ipv4閘道器地址
+ (NSString *)getGatewayIPV4Address
{

    NSString *address = nil;

    /* net.route.0.inet.flags.gateway */
    int mib[] = {CTL_NET, PF_ROUTE, 0, AF_INET, NET_RT_FLAGS, RTF_GATEWAY};

    size_t l;
    char *buf, *p;
    struct rt_msghdr *rt;
    struct sockaddr *sa;
    struct sockaddr *sa_tab[RTAX_MAX];
    int i;

    if (sysctl(mib, sizeof(mib) / sizeof(int), 0, &l, 0, 0) < 0) {
        address = @"192.168.0.1";
    }

    if (l > 0) {
        buf = malloc(l);
        if (sysctl(mib, sizeof(mib) / sizeof(int), buf, &l, 0, 0) < 0) {
            address = @"192.168.0.1";
        }

        for (p = buf; p < buf + l; p += rt->rtm_msglen) {
            rt = (struct rt_msghdr *)p;
            sa = (struct sockaddr *)(rt + 1);
            for (i = 0; i < RTAX_MAX; i++) {
                if (rt->rtm_addrs & (1 << i)) {
                    sa_tab[i] = sa;
                    sa = (struct sockaddr *)((char *)sa + ROUNDUP(sa->sa_len));
                } else {
                    sa_tab[i] = NULL;
                }
            }

            if (((rt->rtm_addrs & (RTA_DST | RTA_GATEWAY)) == (RTA_DST | RTA_GATEWAY)) &&
                sa_tab[RTAX_DST]->sa_family == AF_INET &&
                sa_tab[RTAX_GATEWAY]->sa_family == AF_INET) {
                unsigned char octet[4] = {0, 0, 0, 0};
                int i;
                for (i = 0; i < 4; i++) {
                    octet[i] = (((struct sockaddr_in *)(sa_tab[RTAX_GATEWAY]))->sin_addr.s_addr >>
                                (i * 8)) &
                    0xFF;
                }
                if (((struct sockaddr_in *)sa_tab[RTAX_DST])->sin_addr.s_addr == 0) {
                    in_addr_t addr =
                    ((struct sockaddr_in *)(sa_tab[RTAX_GATEWAY]))->sin_addr.s_addr;
                    address = [self formatIPV4Address:*((struct in_addr *)&addr)];
                    //                    NSLog(@"IPV4address%@", address);
                    break;
                }
            }
        }
        free(buf);
    }

    return address;
}複製程式碼
//ipv6閘道器地址
+ (NSString *)getGatewayIPV6Address
{

    NSString *address = nil;

    /* net.route.0.inet.flags.gateway */
    int mib[] = {CTL_NET, PF_ROUTE, 0, AF_INET6, NET_RT_FLAGS, RTF_GATEWAY};

    size_t l;
    char *buf, *p;
    struct rt_msghdr *rt;
    struct sockaddr_in6 *sa;
    struct sockaddr_in6 *sa_tab[RTAX_MAX];
    int i;

    if (sysctl(mib, sizeof(mib) / sizeof(int), 0, &l, 0, 0) < 0) {
        address = @"192.168.0.1";
    }

    if (l > 0) {
        buf = malloc(l);
        if (sysctl(mib, sizeof(mib) / sizeof(int), buf, &l, 0, 0) < 0) {
            address = @"192.168.0.1";
        }

        for (p = buf; p < buf + l; p += rt->rtm_msglen) {
            rt = (struct rt_msghdr *)p;
            sa = (struct sockaddr_in6 *)(rt + 1);
            for (i = 0; i < RTAX_MAX; i++) {
                if (rt->rtm_addrs & (1 << i)) {
                    sa_tab[i] = sa;
                    sa = (struct sockaddr_in6 *)((char *)sa + sa->sin6_len);
                } else {
                    sa_tab[i] = NULL;
                }
            }

            if( ((rt->rtm_addrs & (RTA_DST|RTA_GATEWAY)) == (RTA_DST|RTA_GATEWAY))
               && sa_tab[RTAX_DST]->sin6_family == AF_INET6
               && sa_tab[RTAX_GATEWAY]->sin6_family == AF_INET6)
                {
                address = [self formatIPV6Address:((struct sockaddr_in6 *)(sa_tab[RTAX_GATEWAY]))->sin6_addr];
                //                NSLog(@"IPV6address%@", address);
                break;
                }
        }
        free(buf);
    }

    return address;
}複製程式碼

我們在獲取的時候判斷一下

/*!
 * 獲取當前裝置閘道器地址
 */
+ (NSString *)getGatewayIPAddress{
    NSString *address = nil;

    NSString *gatewayIPV4 = [self getGatewayIPV4Address];
    NSString *gatewayIPV6 = [self getGatewayIPV6Address];

    if (gatewayIPV6 != nil) {
        address = gatewayIPV6;
    } else {
        address = gatewayIPV4;
    }

    return address;
}複製程式碼

通過域名拿到域名對應的IP地址(CDN)

通過域名拿到的IP地址,一般來說,如果買了CDN的話,拿到的Ip都會是多個IP


/*!
 * 通過hostname獲取ip列表 DNS解析地址
 */
+ (NSArray *)getDNSsWithDormain:(NSString *)hostName{
    NSMutableArray *result = [[NSMutableArray alloc] init];
    NSArray *IPDNSs = [self getDNSWithHostName:hostName];
    if (IPDNSs && IPDNSs.count > 0) {
        [result addObjectsFromArray:IPDNSs];
    }

    return [NSArray arrayWithArray:result];
}


+ (NSArray *)getDNSWithHostName:(NSString *)hostName
{
    const char *hostN = [hostName UTF8String];
    Boolean result = false;
    Boolean bResolved = false;
    CFHostRef hostRef;
    CFArrayRef addresses = NULL;

    CFStringRef hostNameRef = CFStringCreateWithCString(kCFAllocatorDefault, hostN, kCFStringEncodingASCII);

    hostRef = CFHostCreateWithName(kCFAllocatorDefault, hostNameRef);
    if (hostRef) {
        result = CFHostStartInfoResolution(hostRef, kCFHostAddresses, NULL);
        if (result == true) {
            addresses = CFHostGetAddressing(hostRef, &result);
        }
    }
    bResolved = result;
    NSMutableArray *ipAddresses = [NSMutableArray array];
    if(bResolved)
        {
        struct sockaddr_in* remoteAddr;

        for(int i = 0; i < CFArrayGetCount(addresses); i++)
            {
            CFDataRef saData = (CFDataRef)CFArrayGetValueAtIndex(addresses, i);
            remoteAddr = (struct sockaddr_in*)CFDataGetBytePtr(saData);

            if(remoteAddr != NULL)
                {
                //獲取IP地址
                const char *strIP41 = inet_ntoa(remoteAddr->sin_addr);
                NSString *strDNS =[NSString stringWithCString:strIP41 encoding:NSASCIIStringEncoding];
                [ipAddresses addObject:strDNS];
                }
            }
        }
    CFRelease(hostNameRef);
    if (hostRef) {
        CFRelease(hostRef);
    }

    return [NSArray arrayWithArray:ipAddresses];
}複製程式碼

獲取當前的網路狀況

如果是WIFI環境,直接返回wifi 如果是蜂窩網路環境,那麼還可以區分到底是那個運營商,還可以區分是使用的什麼網路,4G 3G 2G等 運營商暫時區分了國內的三大運營商,如果還需要區分國外的,可以維基百科上查對應的code


+(NSString *)currentNetInfo{

    NSString *returnName = nil;

    PPSNetWorkType type = [PPSGetAppEnvironment getNetworkTypeFromStatusBar];
    if (type == PPSNetWorkTypeWiFi) {
        returnName = @"WIFI";
        return returnName;
    }

    NSString *carrierName = nil;
    CTTelephonyNetworkInfo *netInfo = [[CTTelephonyNetworkInfo alloc] init];
    CTCarrier *carrier = [netInfo subscriberCellularProvider];
    if (carrier != NULL) {
        NSArray *chinaMobileMics = @[@"0",@"2",@"7"];//移動code
        NSArray *chinaTelecomMics = @[@"3",@"5",@"11"];//電信code
        NSArray *chinaUnicomMics = @[@"1",@"6"];//聯通code
        NSString *mobileNetworkCode = [carrier mobileNetworkCode];
        if ([chinaMobileMics containsObject:mobileNetworkCode]) {
            carrierName = @"chinamobile";
        }else if ([chinaTelecomMics containsObject:mobileNetworkCode]){
            carrierName = @"chinatelecom";
        }else if ([chinaUnicomMics containsObject:mobileNetworkCode]){
            carrierName = @"chinaunicom";
        }else{
            carrierName = @"unknown";
        }
    } else {
        carrierName = @"unknown";
    }

    switch (type) {
        case PPSNetWorkType2G:
            returnName = [NSString stringWithFormat:@"%@_%@",carrierName,@"2G"];
            break;
        case PPSNetWorkType3G:
            returnName = [NSString stringWithFormat:@"%@_%@",carrierName,@"3G"];
            break;
        case PPSNetWorkType4G:
            returnName = [NSString stringWithFormat:@"%@_%@",carrierName,@"4G"];
            break;
        case PPSNetWorkType5G:
            returnName = [NSString stringWithFormat:@"%@_%@",carrierName,@"5G"];
            break;
        case PPSNetWorkTypeNone:
            returnName = [NSString stringWithFormat:@"%@_%@",carrierName,@"unknown"];
            break;
        default:
            returnName = [NSString stringWithFormat:@"%@_%@",carrierName,@"unknown"];
            break;
    }
    return returnName;
}複製程式碼

獲取當前的裝置資訊

獲取當前裝置的資訊,是iPhone 4 5 6 7還是 等等 還有系統的版本號 手機、平板
之類的都能夠去區分出來


/**
 獲取裝置的型別

 @return 裝置型別
 */
+ (NSString *)deviceInfo {
    struct utsname systemInfo;

    uname(&systemInfo);

    NSString* code = [NSString stringWithCString:systemInfo.machine
                                        encoding:NSUTF8StringEncoding];

    static NSDictionary* deviceNamesByCode = nil;

    if (!deviceNamesByCode) {

        deviceNamesByCode = @{@"i386"      :@"Simulator",
                              @"x86_64"    :@"Simulator",
                              @"iPod1,1"   :@"iPod Touch",        // (Original)
                              @"iPod2,1"   :@"iPod Touch",        // (Second Generation)
                              @"iPod3,1"   :@"iPod Touch",        // (Third Generation)
                              @"iPod4,1"   :@"iPod Touch",        // (Fourth Generation)
                              @"iPod7,1"   :@"iPod Touch",        // (6th Generation)
                              @"iPhone1,1" :@"iPhone",            // (Original)
                              @"iPhone1,2" :@"iPhone",            // (3G)
                              @"iPhone2,1" :@"iPhone",            // (3GS)
                              @"iPad1,1"   :@"iPad",              // (Original)
                              @"iPad2,1"   :@"iPad 2",            //
                              @"iPad3,1"   :@"iPad",              // (3rd Generation)
                              @"iPhone3,1" :@"iPhone 4",          // (GSM)
                              @"iPhone3,3" :@"iPhone 4",          // (CDMA/Verizon/Sprint)
                              @"iPhone4,1" :@"iPhone 4S",         //
                              @"iPhone5,1" :@"iPhone 5",          // (model A1428, AT&T/Canada)
                              @"iPhone5,2" :@"iPhone 5",          // (model A1429, everything else)
                              @"iPad3,4"   :@"iPad",              // (4th Generation)
                              @"iPad2,5"   :@"iPad Mini",         // (Original)
                              @"iPhone5,3" :@"iPhone 5c",         // (model A1456, A1532 | GSM)
                              @"iPhone5,4" :@"iPhone 5c",         // (model A1507, A1516, A1526 (China), A1529 | Global)
                              @"iPhone6,1" :@"iPhone 5s",         // (model A1433, A1533 | GSM)
                              @"iPhone6,2" :@"iPhone 5s",         // (model A1457, A1518, A1528 (China), A1530 | Global)
                              @"iPhone7,1" :@"iPhone 6 Plus",     //
                              @"iPhone7,2" :@"iPhone 6",          //
                              @"iPhone8,1" :@"iPhone 6S",         //
                              @"iPhone8,2" :@"iPhone 6S Plus",    //
                              @"iPhone8,4" :@"iPhone SE",         //
                              @"iPhone9,1" :@"iPhone 7",          //
                              @"iPhone9,3" :@"iPhone 7",          //
                              @"iPhone9,2" :@"iPhone 7 Plus",     //
                              @"iPhone9,4" :@"iPhone 7 Plus",     //

                              @"iPad4,1"   :@"iPad Air",          // 5th Generation iPad (iPad Air) - Wifi
                              @"iPad4,2"   :@"iPad Air",          // 5th Generation iPad (iPad Air) - Cellular
                              @"iPad4,4"   :@"iPad Mini",         // (2nd Generation iPad Mini - Wifi)
                              @"iPad4,5"   :@"iPad Mini",         // (2nd Generation iPad Mini - Cellular)
                              @"iPad4,7"   :@"iPad Mini",         // (3rd Generation iPad Mini - Wifi (model A1599))
                              @"iPad6,7"   :@"iPad Pro (12.9\")", // iPad Pro 12.9 inches - (model A1584)
                              @"iPad6,8"   :@"iPad Pro (12.9\")", // iPad Pro 12.9 inches - (model A1652)
                              @"iPad6,3"   :@"iPad Pro (9.7\")",  // iPad Pro 9.7 inches - (model A1673)
                              @"iPad6,4"   :@"iPad Pro (9.7\")"   // iPad Pro 9.7 inches - (models A1674 and A1675)
                              };
    }

    NSString* deviceName = [deviceNamesByCode objectForKey:code];

    if (!deviceName) {
        // Not found on database. At least guess main device type from string contents:

        if ([code rangeOfString:@"iPod"].location != NSNotFound) {
            deviceName = @"iPod Touch";
        }
        else if([code rangeOfString:@"iPad"].location != NSNotFound) {
            deviceName = @"iPad";
        }
        else if([code rangeOfString:@"iPhone"].location != NSNotFound){
            deviceName = @"iPhone";
        }
        else {
            deviceName = @"Unknown";
        }
    }

    UIDevice *device = [UIDevice currentDevice];
    NSString *systemVersion = [device systemVersion];

    return [NSString stringWithFormat:@"iOS#%@#%@",deviceName,systemVersion];
}複製程式碼

效果:

iOS獲取當前裝置的資訊-網路相關

原專案地址:

github.com/yangqian111…

相關文章