Reachability在iOS7.0能正常工作么?Absolutely Not!

在WWDC2015上苹果宣布iOS9将支持纯IPv6的网络服务。2016年初开始所有提交到App Store的应用必须支持IPv6。这早已不是新鲜事,网上也出了大部分博文供我们参考怎么支持IPv6,关于Reachability,苹果也推出了Version 5.0,用来支持IPv6,但细心的小伙伴可能会发现,最新版的Reachability最低的系统要求是iOS 8.0。

Reachability在iOS7.0能正常工作么?Absolutely Not!_第1张图片
Paste_Image.png

这个对于大部分开发者来说是没有问题的,但是客户非要支持iOS7.0怎么办?小弟我就遇到了这样的客户,赶紧在iOS7.0系统上测试最新的Reachability,希望不要有错,测试代码如下:

Reachability *reachability = [Reachability reachabilityForInternetConnection];
NSLog(@"status:%ld",(long)[reachability currentReachabilityStatus]);

测试结果往往不如所愿,如下图,分别在IPv6、IPv4网络环境下使用iOS9.0以及iOS7.0手机测试,iOS7.0系统的手机在IPv6网络环境下是无法得到这确结果的。(IPv6网络环境搭建请看这里)

Paste_Image.png

故我开始了对Reachability的改造之路,目的是想让它在iOS7上同样支持IPv6。
改造方法认为为:

+ (instancetype)reachabilityForInternetConnection
{
 struct sockaddr_in zeroAddress;
 bzero(&zeroAddress, sizeof(zeroAddress));
 zeroAddress.sin_len = sizeof(zeroAddress);
 zeroAddress.sin_family = AF_INET;
 return [self reachabilityWithAddress: (const struct sockaddr *) &zeroAddress];
}

修改的思路为:

  • 获取设备IP地址
  • 通过IP地址判断当前设备所处的网络环境
  • 如果是IPv6网络环境,则使用struct sockaddr_in6来构造zeroAddress。
+ (instancetype)reachabilityForInternetConnection
{
    // IPv4
    struct sockaddr_in zeroAddress;
    bzero(&zeroAddress, sizeof(zeroAddress));
    zeroAddress.sin_len = sizeof(zeroAddress);
    zeroAddress.sin_family = AF_INET;
    
    // 获取IP地址
    NSString *ipStr = [self getIPAddress];
    NSLog(@"ip address:%@",ipStr);
    if ([ipStr rangeOfString:@"."].location == NSNotFound) {
        // IPv6
        struct sockaddr_in6 zeroAddress;
        bzero(&zeroAddress, sizeof(zeroAddress));
        zeroAddress.sin6_len = sizeof(zeroAddress);
        zeroAddress.sin6_family = AF_INET6;
        return [self reachabilityWithAddress:(const struct sockaddr *)&zeroAddress];
    }
    
    return [self reachabilityWithAddress:(const struct sockaddr *)&zeroAddress];
}

+ (NSString *)getIPAddress {
    NSString *address = @"error";
    struct ifaddrs *interfaces = NULL;
    struct ifaddrs *temp_addr = NULL;
    int success = getifaddrs(&interfaces);    // retrieve the current interfaces - returns 0 on success
    if (success == 0) {
        // Loop through linked list of interfaces
        temp_addr = interfaces;
        while (temp_addr != NULL) {
            // Check if interface is en0 which is the wifi connection on the iPhone
            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;
        }
    }
    // Free memory
    freeifaddrs(interfaces);
    return address;
}

//for IPV6
+ (NSString *)formatIPV6Address:(struct in6_addr)ipv6Addr{
    NSString *address = nil;
    
    char dstStr[INET6_ADDRSTRLEN];
    char srcStr[INET6_ADDRSTRLEN];
    memcpy(srcStr, &ipv6Addr, sizeof(struct in6_addr));
    if(inet_ntop(AF_INET6, srcStr, dstStr, INET6_ADDRSTRLEN) != NULL){
        address = [NSString stringWithUTF8String:dstStr];
    }
    return address;
}

//for IPV4
+ (NSString *)formatIPV4Address:(struct in_addr)ipv4Addr{
    NSString *address = nil;
    
    char dstStr[INET_ADDRSTRLEN];
    char srcStr[INET_ADDRSTRLEN];
    memcpy(srcStr, &ipv4Addr, sizeof(struct in_addr));
    if(inet_ntop(AF_INET, srcStr, dstStr, INET_ADDRSTRLEN) != NULL){
        address = [NSString stringWithUTF8String:dstStr];
    }
    return address;
}

修改好之后再次测试(iOS7系统,IPv6环境):

Paste_Image.png

大功告成。
总结:如果你的项目也需要适配iOS7.0,那么这个博客可能有些许帮助,有这个要求的客户应该少数。如代码有问题,希望给予指点。

你可能感兴趣的:(Reachability在iOS7.0能正常工作么?Absolutely Not!)