在WWDC2015上蘋果宣布iOS9將支持純IPv6的網(wǎng)絡(luò)服務(wù)靴患。2016年初開始所有提交到App Store的應(yīng)用必須支持IPv6。這早已不是新鮮事豁状,網(wǎng)上也出了大部分博文供我們參考怎么支持IPv6,關(guān)于Reachability捉偏,蘋果也推出了Version 5.0,用來支持IPv6,但細(xì)心的小伙伴可能會發(fā)現(xiàn)泻红,最新版的Reachability最低的系統(tǒng)要求是iOS 8.0夭禽。
這個(gè)對于大部分開發(fā)者來說是沒有問題的,但是客戶非要支持iOS7.0怎么辦谊路?小弟我就遇到了這樣的客戶讹躯,趕緊在iOS7.0系統(tǒng)上測試最新的Reachability,希望不要有錯(cuò)缠劝,測試代碼如下:
Reachability *reachability = [Reachability reachabilityForInternetConnection];
NSLog(@"status:%ld",(long)[reachability currentReachabilityStatus]);
測試結(jié)果往往不如所愿蜀撑,如下圖,分別在IPv6剩彬、IPv4網(wǎng)絡(luò)環(huán)境下使用iOS9.0以及iOS7.0手機(jī)測試酷麦,iOS7.0系統(tǒng)的手機(jī)在IPv6網(wǎng)絡(luò)環(huán)境下是無法得到這確結(jié)果的。(IPv6網(wǎng)絡(luò)環(huán)境搭建請看這里)
故我開始了對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;
}
修改好之后再次測試(iOS7系統(tǒng)糊肤,IPv6環(huán)境):
大功告成。
總結(jié):如果你的項(xiàng)目也需要適配iOS7.0,那么這個(gè)博客可能有些許幫助氓鄙,有這個(gè)要求的客戶應(yīng)該少數(shù)馆揉。如代碼有問題,希望給予指點(diǎn)抖拦。