适配IPV6
在WWDC2015上苹果公司宣布iOS9将支持纯IPV6的网络服务。自从5月初Apple明文规定所有开发者在6月1号以后提交新版本需要支持IPV6-Only的网络,什么是IPV6 ? Apple如何审核IPV6?如何支持IPV6?应用中哪些模块目前不支持IPV6?为确保现有的应用兼容,我们又应该注意那些东西呢?如果我要进行本地测试,应该如何搭建IPV6环境?
关键词:WWDC2015 IPV6-Only
一、什么是IPV6
首先IPV6,是对IPV4地址空间的扩充。目前当我们用iOS设备连接上Wifi、4G、3G等网络时,设备被分配的地址均是IPV4地址,但是随着运营商和企业逐渐部署IPV6 DNS64/NAT64网络之后,设备被分配的地址会变成IPV6的地址,而这些网络就是所谓的IPV6-Only网络,并且仍然可以通过此网络去获取IPV4地址提供的内容。客户端向服务器端请求域名解析,首先通过DNS64 Server查询IPv6的地址,如果查询不到,再向DNS Server查询IPv4地址,通过DNS64 Server合成一个IPV6的地址,最终将一个IPV6的地址返回给客户端。
二、Apple如何审核支持IPV6-Only
1、简单来讲让应用能够在IPv6 DNS64/NAT64网络环境下仍然能够正常运行,即为应用支持了IPV6-Only网络。但目前我们所能使用到的网络环境仍然是IPV4网络,所以应用需要同时支持IPV4以及IPV6网络环境。
2、Apple官方规定iOS9开始向IPV6过度,并在iOS9.2+上支持IPV4地址合成IPV6地址。目前苹果官方提供的Reachability库在iOS8系统下无法实现IPV4与IPV6之间的相互切换,所以苹果官方声明只需要在苹果最新的系统上保证支持IPV6的兼容即可。
3、由于目前4G网络的IPV6部署还不够完善,所以应用只需要支持主流程兼容IPV6,通过苹果审核即可。对于不支持IPV6的模块段时间内不会影响用户使用,但是后期仍需要进行支持。
三、如何支持IPV6
Apple官方给出以下支持IPV6的标准:
1.UseHigh-LevelNetworking Frameworks;
2. Don’tUseIP Address Literals;
3.CheckSourceCodeforIPv6 DNS64/NAT64Incompatibilities;
4.UseSystemAPIstoSynthesize IPv6 Addresse;
3.1 NSURLConnection是否支持IPV6?
官方给出的声明只说NSURLSession和CFNetwork的API不需要改变,但是并没有提及到NSURLConnection相关信息。从NSURLSession、NSURLConnection同属于Cocoa的url loading system,可以猜测NSURLConnection在iOS9上支持IPV6。但是目前AFNetwroking库已经推出支持IPV6的3.0版本,使得开发者必须升级AFNetworking并重写网络请求。
3.2 Reachability是否需要支持IPV6?
根据实际应用中开发者提出的各种网络切换问题(通过ZeroAddress开启网络监控)苹果官方给出的相关解释说明Reachability不需要做任何修改,并且苹果审核时不关心在iOS9一下Reachability存在的BUG,只关心iOS9以上是否支持。
四、底层的socket API如何同时支持IPV4和IPV6?
应用中大量使用了包含底层的socket API的网络诊断组件,所以支持IPV6十分重。应用的长连接需要支持IPV6,对于Socket如何同时支持IPV4和IPV6,可以参考谷歌的开源库CocoaAsyncSocket.
4.1、IP地址从二进制到符号的转化
话不多说直接上代码:
//for IPV6
+(NSString*)formatIPV6Address:(structin6_addr)ipv6Addr
{
NSString*address =nil;
chardstStr[INET6_ADDRSTRLEN];
charsrcStr[INET6_ADDRSTRLEN];
memcpy(srcStr, &ipv6Addr,sizeof(structin6_addr));
if(inet_ntop(AF_INET6, srcStr,dstStr,INET6_ADDRSTRLEN)!=NULL){
address = [NSStringstringWithUTF8String:dstStr];
}
returnaddress;
}
//for IPV4
+(NSString*)formatIPV4Address:(structin_addr)ipv4Addr{
NSString*address =nil;
chardstStr[INET_ADDRSTRLEN];
charsrcStr[INET_ADDRSTRLEN];memcpy(srcStr, &ipv4Addr,sizeof(structin_addr));
if(inet_ntop(AF_INET, srcStr, dstStr,INET_ADDRSTRLEN) !=NULL){
address = [NSStringstringWithUTF8String:dstStr];
}
returnaddress;
}
4.2、本机IP获取支持IPV6
类似于终端输入ifconfig命令获取字符串,然后解析获取其中的en0(Wifi)、padp_ip0(移动网络)的IP地址。
注意:
1、在模拟器和真机上都会出现以FE80开头的IPV6单播地址响应我们的判断,所以要注意第一次遇到不是单播地址的IP即为本机IP地址。
2、在IPV6环境下,真机测试时第一个出现的是IPV4地址,所以在IPV4条件下第一次遇到单播地址不退出。
代码;
+ (NSString *)deviceIPAdress
{
while(temp_addr !=NULL) {
NSLog(@"ifa_name===%@",[NSStringstringWithUTF8String:temp_addr->ifa_name]);
// 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 = [selfformatIPV4Address:((structsockaddr_in *)temp_addr->ifa_addr)->sin_addr];
}
//如果是IPV6地址
elseif(temp_addr->ifa_addr->sa_family == AF_INET6){
address = [selfformatIPV6Address:((struct sockaddr_in6*)temp_addr->ifa_addr)->sin6_addr];
if(address && ![address
isEqualToString:@""] && ![address.uppercaseString hasPrefix:@"FE80"])break;
}
}
temp_addr = temp_addr->ifa_next;
}
}
}
4.3更多方法
更多支持IPV6的方法请移步支持IPV6方法总结
五、对于兼容IPV6需要注意的事项
5.1、最好不要使用底层的API。
下图展示的蓝色部分的这些API都是不存在兼容性问题的,而我们平时自己用的包括那些第三方的网络库大部分都是用的这些API。
Networking frameworks and API layers
大部分情况下我们用高级的API完全能实现需求,而且高级的API封装的很好,并且方便使用,对于IPV6的适配也帮我们做好了,例如ShareSDK等。就像之前提到的哪有,使用底层AIP会有大量的工作需要我们自己完成,所以可能更容易出现BUG。
5.2不要用IP地址
比如下面这个API,nodename这个参数不要传IP地址,而应该用域名。
这个方法会在Reachability中用到。常用的网络请求库AFNetworking最近刚更新版本就是使用了这个方法。如果使用AFNetworking且应用需要提交到App store上需要尽快更新版本并做好相关适配。
5.3检查不兼容IPV6的代码
全局搜一下工程里有没有如下这些API,这些都是针对IPv4做处理的,有的话就删除。
inet_addr()
inet_aton()
inet_lnaof()
inet_makeaddr()
inet_netof()
inet_network()
inet_ntoa()
inet_ntoa_r()
bindresvport()
getipv4sourcefilter()
setipv4sourcefilter()
对应IPV4做IPV6处理
IPV4
IPV6
AF_INET
AF_INET6
PE_INET
PE_INET6
struct in_addr
Struct in_addr6
struct sockadd_in
struct sockaddr_in6
kDNSServiceProtocol_IPv4
kDNSServiceProtocol_IPv6
IPv4--IPv6
六、本地搭建IPv6测试环境
最后我们如何搭建一个测试的IPv6环境呢?其实很简单,我们可以通过Mac做一个热点,然后让iPhone连接这个Wifi。区别是这次我们产生的是一个本地的IPv6 DNS64/NAT64网络,这项功能是OS X 10.11新加的。和我们以前开启热点方式不一样的地方在于,我们在“System
Preferences”界面选中“Sharing”的同时,要按住“Option”键。
之后在“Sharing”界面中,我们会看到和之前不一样的地方,就是红框所标的地方,多了一个叫“Create NAT64 Network”的选框,选中它。
之后就是按照正常的创建热点的流程走完就行了。
现在我们用iPhone连接上这个刚创建好的热点就可以测试了,注意此时要把iPhone设成飞行模式,以保证只用Wi-Fi上网。
七、iOS IPv6最新升级攻略
苹果商店6月1日起,强制app需要支持IPv6-only的网络。
iOS IPv6最新升级攻略:
1,官方Reachability
2,微信SDK
iOS平台微信SDK下载地址:https://res.wx.qq.com/open/zh_CN/htmledition/res/dev/download/sdk/WeChatSDK1.7.zip
微信SDK已支持IPv6,请iOS开发者及时升级
由于苹果App Store政策调整,所有iOS应用必须支持IPv6。iOS平台微信SDK最新的1.7版已支持IPv6,请开发者及时升级App中的微信SDK。
微信团队
2016年05月12日
3,微博SDK
https://github.com/sinaweibosdk/weibo_ios_sdk
关于ipv6支持的问题
由于苹果商店6月1日起,强制app需要支持ipv6-only的网络。微博sdk这边也做了支持,更新了使用的底层网络代码,包括reachability库。
附录:
百度百科对IPV6解释:http://baike.baidu.com/view/5228.htm