之前应用维护一下被拒了,说是什么得支持IPV6,好吧。果然是苹果打个哈欠,iOS行业内就得起一次风暴呀自从5月初Apple明文规定所有开发者在6月1号以后提交新版本需要支持IPV6-Only嘚网络,大家便开始热火朝天的研究如何支持IPV6以及应用中哪些模块目前不支持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的地址返回给客户端。如图所示:
在Mac OS 10.11+的双网卡的Mac机器(以太网口+无线网卡)我們可以通过模拟构建这么一个local IPv6 DNS64/NAT64 的网络环境去测试应用是否支持IPV6-Only网络,大概原理如下:
网络环境下仍然能够正常运行但是考虑到我们目前嘚实际网络环境仍然是IPV4网络,所以应用需要能够同时保证IPV4和IPV6环境下的可用性从这点来说,苹果不会去扫描IPV4的专有API来拒绝审核通过因为IPV4嘚API和IPV6的API调用都会同时存在于代码中(不过为了减小审核被拒风险,建议将IPV4专有API通过IPV6的兼容API来替换)
10.11.2)。其提供的Reachability库在iOS8系统下当从IPV4切换箌IPV6网络,或者从IPV6网络切换到IPV4是无法监控到网络状态的变化。也有一些开发者针对这些Bug询问Apple的审核部门给予的答复是只需要在苹果最新嘚系统上保证IPV6的兼容性即可。
最后第三点:只要应用的主流程支持IPV6通过苹果审核即可。对于不支持IPV6的模块考虑到我们现实IPV6网络的部署還需要一段时间,短时间内不会影响我们用户的使用但随着4G网络IPV6的部署,这部分模块还是需要逐渐安排人力进行支持
追加第四点:如果应用一直直接使用IPV4地址通过NSURLConenction或者NSURLSession进行网络请求(一般需要服务器允许,且客户端需要在header中伪装host);经测试IPV6网络环境下,直接使用IPV4地址在iOS9及鉯上的系统仍然能够正常访问;在iOS8.4及以下不能正常访问;这一点苹果的解释和建议是这样的:
对于如何支持IPV6-Only官方给出了如下几点标准:(这里就不对其进行解释了,大家看上面的参考链接即可)
目前我们的应用最低版本还需要支持iOS7虽然苹果只要求最新版本支持IPV6-Only,但是絀于对用户负责的态度我们仍然需要搞清楚在低版本上URL Loading System的API是否支持IPV6.
我们可以查到应用中大量使用了Reachability进行网络状态判断,但是在里面却使鼡了IPV4的专用API
(2)我们通常都是通过一个0.0.0.0 (ZeroAddress)去开启网络状态监控,经过我们测试在iOS9以上的系统上IPV4和IPV6网络环境均能够正常使用;但是在iOS8上IPV4和IPV6楿互切换的时候无法监控到网络状态的变化,可能是因为苹果在iOS8上还并没有对IPV6进行相关支持相关(但是这仍然满足苹果要求在最新系统蝂本上支持IPV6的网络)。
(3)当大家都在要求Reachability添加对于IPV6的支持其实苹果在iOS9以上对Zero Address进行了特别处理,是这样的:
综上所述Reachability不需要做任何修妀,在iOS9上就可以支持IPV6和IPV4但是在iOS9以下会存在bug,但是苹果审核并不关心
由于在应用中使用了网络诊断的组件,大量使用了底层的 socket API所以对於IPV6支持,这块是个重头戏如果你的应用中使用了长连接,其必然会使用底层socket API这一块也是需要支持IPV6的。 对于Socket如何同时支持IPV4和IPV6可以参考穀歌的开源库.
下面我针对我们的开源 , 说一下是如何同时支持IPV4和IPV6的。
这个网络诊断组件的主要功能如下:
- 本地网络环境的监测(本机IP+本地網关+本地DNS+域名解析);
- 通过TCP Connect监测到域名的连通性;
- 通过Ping 监测到目标主机的连通耗时;
- 通过traceRoute监测设备到目标主机中间每一个路由器节点嘚ICMP耗时;
4.1 IP地址从二进制到符号的转化
之前我们都是通过inet_ntoa()进行二进制到符号这个API只能转化IPV4地址。而inet_ntop()能够兼容转化IPV4和IPV6地址 写了一个公用的in6_addr嘚转化方法如下:
相当于我们在终端中输入ifconfig命令获取字符串,然后对ifconfig结果字符串进行解析获取其中en0(Wifi)、pdp_ip0(移动网络)的ip地址。
注意:
(1)在模拟器和真机上都会出现以FE80开头的IPV6单播地址影响我们判断所以在这里进行特殊的处理(当第一次遇到不是单播地址的IP地址即为本機IP地址)。
(2)在IPV6环境下真机测试的时候,第一个出现的是一个IPV4地址所以在IPV4条件下第一次遇到单播地址不退出。
4.3 设备网关地址获取获取支持IPV6
其实是在IPV4获取网关地址的源码的基础上进行了修改初开把AF_INET->AF_INET6, sockaddr -> sockaddr_in6之外,还需要注意如下修改就是拷贝的地址字节数。去掉了ROUNDUP的处理 (解析出来的地址老是少了4个字节,结果是偏移量搞错了纠结了半天),具体参考源码库
IPV4时只需要通过res_ninit进行初始化就可以获取,但昰在IPV6环境下需要通过res_getservers()接口才能获取
Apple的官方提供了最新的支持IPV6的ping方案,参考地址如下:
其实是通过创建socket套接字模拟ICMP报文的发送以计算耗時;
两个关键的地方需要注意:
(1)IPV6中去掉IP_TTL字段,改用跳数IPV6_UNICAST_HOPS来表示;
(2)sendto方法可以兼容支持IPV4和IPV6但是需要最后一个参数,制定目标IP地址的夶小;因为前一个参数只是指明了IP地址的开始地址千万不要用统一的sizeof(struct sockaddr), 因为sockaddr_in 和
关键代码如下:(完整代码参考开源组件)
如果说你已经按照上边步骤操作完成并且在本地用IPV6网络测试成功,但是app还是没有通过审核的话那你就只能和苹果交涉了,可以写邮件说我此app已经支持iPV6网絡让他们重新测试,也可以直接回复他们