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

在WWDC2015上蘋果宣布iOS9將支持純IPv6的網(wǎng)絡(luò)服務(wù)。2016年初開始所有提交到App Store的應(yīng)用必須支持IPv6。這早已不是新鮮事,網(wǎng)上也出了大部分博文供我們參考怎么支持IPv6,關(guān)于Reachability,蘋果也推出了Version 5.0,用來支持IPv6,但細(xì)心的小伙伴可能會(huì)發(fā)現(xiàn),最新版的Reachability最低的系統(tǒng)要求是iOS 8.0。

Paste_Image.png

這個(gè)對(duì)于大部分開發(fā)者來說是沒有問題的,但是客戶非要支持iOS7.0怎么辦?小弟我就遇到了這樣的客戶,趕緊在iOS7.0系統(tǒng)上測(cè)試最新的Reachability,希望不要有錯(cuò),測(cè)試代碼如下:

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

測(cè)試結(jié)果往往不如所愿,如下圖,分別在IPv6、IPv4網(wǎng)絡(luò)環(huán)境下使用iOS9.0以及iOS7.0手機(jī)測(cè)試,iOS7.0系統(tǒng)的手機(jī)在IPv6網(wǎng)絡(luò)環(huán)境下是無法得到這確結(jié)果的。(IPv6網(wǎng)絡(luò)環(huán)境搭建請(qǐng)看這里

Paste_Image.png

故我開始了對(duì)Reachability的改造之路,目的是想讓它在iOS7上同樣支持IPv6。
改造方法認(rèn)為為:

+ (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];
}

修改的思路為:

  • 獲取設(shè)備IP地址
  • 通過IP地址判斷當(dāng)前設(shè)備所處的網(wǎng)絡(luò)環(huán)境
  • 如果是IPv6網(wǎng)絡(luò)環(huán)境,則使用struct sockaddr_in6來構(gòu)造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;
}

修改好之后再次測(cè)試(iOS7系統(tǒng),IPv6環(huán)境):

Paste_Image.png

大功告成。
總結(jié):如果你的項(xiàng)目也需要適配iOS7.0,那么這個(gè)博客可能有些許幫助,有這個(gè)要求的客戶應(yīng)該少數(shù)。如代碼有問題,希望給予指點(diǎn)。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 研究IPv6 socket編程原因: Supporting IPv6 in iOS 9 WWDC2015蘋果宣布在...
    li大鵬閱讀 7,624評(píng)論 7 15
  • 一、IPV6-Only支持是啥? 首先IPV6,是對(duì)IPV4地址空間的擴(kuò)充。目前當(dāng)我們用iOS設(shè)備連接上Wifi、...
    一字碼閱讀 891評(píng)論 0 0
  • 生活平平淡淡,少有浪花和色彩。反倒是夢(mèng),因?yàn)榻M合的奇異,有了新奇的效果。醒來總是讓人難以忘記。既然老是回味...
    梅影映雪閱讀 206評(píng)論 0 3
  • iOS常用的數(shù)據(jù)持久化方案主要有四種:NSUserDefault、File、Keychain、FMDB。 NSUs...
    簡(jiǎn)潔的想法閱讀 501評(píng)論 0 0
  • 5月23日,我這天也和往常一樣早起上班,每天習(xí)慣性地看看公司的公眾號(hào),前一天已經(jīng)有幕天捐書,為山區(qū)學(xué)生捐了六...
    梨樹花開閱讀 586評(píng)論 0 0

友情鏈接更多精彩內(nèi)容