蘋果的規定:2016年6月1日提交到App Store必須支持IPv6-only網路。 官方說明:https://developer.apple.com/library/mac/documentation/NetworkingInternetWeb/Conceptual/NetworkingOver ...
蘋果的規定:2016年6月1日提交到App Store必須支持IPv6-only網路。
官方文檔:https://developer.apple.com/library/mac/documentation/NetworkingInternetWeb/Conceptual/NetworkingOverview/UnderstandingandPreparingfortheIPv6Transition/UnderstandingandPreparingfortheIPv6Transition.html#//apple_ref/doc/uid/TP40010220-CH213-SW1
大多數應用APP 不需要任何改變,因為IPv6的已經被NSURLSession、CFNetwork、NSURLConnection 支持。
一、是否需要修改代碼
1、如果線上環境的APP 只使用功能變數名稱訪問,沒有使用IP地址,並且沒有使用底層socket API ,就不用修改代碼。
直接訪問IP地址 主要是用在測試環境中。
大多數app使用的:NSURLSession、NSURLConnection、UIWebView、WKWebView、CFNetwork。所以可以不用修改網路代碼,AFNetworking2.x、reachability 這些 都 不用做任何的改變。
不過還是 推薦 大家升級AFNetworking到最新版本,畢竟NSURLConnection遲早要被淘汰。
用Swift寫的 就直接用 Alamofire吧。
2、Reachability不用IP地址,可以固定寫死為 線上功能變數名稱。也可以用 AFNetworking 的Reachability來判斷網路連接狀態(是非同步的,不用輸入功能變數名稱或IP)。
Reachability 最新版本 官方 聲明iOS8以上系統可以使用,經測試,iOS 7.0以上系統都可以使用。
3、iOS 9.0、OS X 10.11 以上的系統 在IPv6的環境下 是支持IP地址訪問網路的。所以大家測試機如果是 iOS9.0以上的系統,可以直接通過IP訪問。這是因為iOS 9.0之後 NSURLSession和CFNetwork能把IPv4的地址 合成IPv6的地址(在DNS64/NAT64網路環境中)。
iOS 9.0以下的系統 就會報錯,這和是否升級 AFNetworking 沒有關係。就算升級AFNetworking到3.x,也是一樣會報:Error Domain=NSURLErrorDomain Code=-1001 等錯誤。
官方圖片:
4、分享SDK
微信SDK、新浪微博SDK 都更新了版本,並聲明支持IPv6。
但是因為微信本身不支持IPv6,所以即使更新SDK到最新版本,分享到微信時,在微信的APP 還是會一直顯示網路無法連接。
測試發現,不更新 這些分享的SDK,也能相容IPv6。(等微信支持IPv6後,是否必須更新SDK 還不清楚)
友盟分享 官網建議升級SDK,個人也是推薦升級,如果實在不想升,應該也沒問題。
來個小插曲:
上星期友盟新發的5.2版本 的SDK 有 郵件、簡訊分享崩潰的bug,給他們提出了。他們昨天下午進行了升級。
二、現有APP支持IPv6的情況:
1、絕大多數 都是支持IPv6的,比如:QQ,淘寶、大眾點評。
1.1、因為絕大多數的app 都使用的功能變數名稱,而不是ip地址。
1.2、並且沒有調用底層的socket api。
1.3、不需要進行DNS查找。
2、極少數app不支持IPv6,比如:微信。
三、DNS64/ NAT64
DNS64/ NAT64過渡工作流程:
1、提供獨立的IPv4和IPv6連接 的 蜂窩網路,把IPv4的網路升級到IPv6
上圖只是理想狀態下,升級到IPv6的情況,但是現在絕大多數都是IPv4的伺服器,所以一些大的供應商開始實施DNS64/NAT64 的過度 來支持IPv6.
2、部署DNS64/NAT64 IPv6的蜂窩網路
客戶端請求 網站功能變數名稱,首先會通過DNS64伺服器 查詢該功能變數名稱是否存在 IPv6的地址,如果存在,就返回IPv6的地址。如果不存在,就去查找該功能變數名稱對應的IPv4地址,並返回。
下麵是詳細流程圖:
3、DNS64/NAT64 轉換 流程:
DNS64/NAT64 可以 將IPv4地址 轉換為IPv6,將IPv6地址解析成IPv4。
IPv4地址 轉換為IPv6:
客戶端訪問網站功能變數名稱 ,如果網站只有 IPv4 地址:56.111.211.22,轉成16進位: 38 6F D3 16,該16進位為IPv6的最後2位: 64:ff9b::386F:D316
四、搭建 IPv6 環境
MAC 的系統為 OS 10.11 及以上系統。
1、進入MAC 電腦的 “系統偏好設置”--》按住option/alt 鍵--》 點擊 “共用”
2、選中“創建NAT64網路”,然後打開熱點。
3、手機 連接 熱點後,查看網路的 DNS 為:XX:XX:XX:XX:XX:XX ,說明網路為IPv6。
下圖為MAC搭建IPv6 的原理圖:
目前,一個網卡會同時使用這兩張地址;以後 一個網卡僅有IPv6 地址。 兩種設備不能直接訪問,需要DNS64/NAT64 這種 過渡技術才能 互相訪問。
五、升級AFNetworking2.X到最新版本
1、將 AFHTTPRequestOperationManager 替換為: AFHTTPSessionManager
2、將 AFHTTPRequestOperation 替換為:NSURLSessionTask
3、如果通過IP訪問,或者允許https證書之外的功能變數名稱訪問,需要設置 validatesDomainName 為false:
AFHTTPSessionManager * manager = [AFHTTPSessionManager manager]; manager.securityPolicy = [AFSecurityPolicy defaultPolicy]; manager.securityPolicy.allowInvalidCertificates = YES; //忽略https證書 manager.securityPolicy.validatesDomainName = NO; //是否驗證功能變數名稱
六、系統相容IPv6代碼
1、下麵的方法 只適用於IPv4,不能相容IPv6:
-
inet_addr()
-
inet_aton()
-
inet_lnaof()
-
inet_makeaddr()
-
inet_netof()
-
inet_network()
-
inet_ntoa()
-
inet_ntoa_r()
-
bindresvport()
-
getipv4sourcefilter()
-
setipv4sourcefilter()
2、如果有以下代碼處理IPv4類型,要確保IPv6的形式也被處理過:
IPv4 |
IPv6 |
---|---|
|
|
|
|
|
|
|
|
|
|
3、使用系統API合成IPv6:
如果你的APP需要連接的伺服器 只有IPv4地址,沒有功能變數名稱,可以用 getaddrinfo 來解決。下麵的代碼,將IPv4地址(如:192.0.2.1) 地址轉換為IPv6地址(如:包含 64:ff9b::192.0.2.1 的struct sockaddr_in6 )
#include <sys/socket.h> #include <netdb.h> #include <arpa/inet.h> #include <err.h> uint8_t ipv4[4] = {192, 0, 2, 1}; struct addrinfo hints, *res, *res0; int error, s; const char *cause = NULL; char ipv4_str_buf[INET_ADDRSTRLEN] = { 0 }; const char *ipv4_str = inet_ntop(AF_INET, &ipv4, ipv4_str_buf, sizeof(ipv4_str_buf)); memset(&hints, 0, sizeof(hints)); hints.ai_family = PF_UNSPEC; hints.ai_socktype = SOCK_STREAM; hints.ai_flags = AI_DEFAULT; error = getaddrinfo(ipv4_str, "http", &hints, &res0); if (error) { errx(1, "%s", gai_strerror(error)); /*NOTREACHED*/ } s = -1; for (res = res0; res; res = res->ai_next) { s = socket(res->ai_family, res->ai_socktype, res->ai_protocol); if (s < 0) { cause = "socket"; continue; } if (connect(s, res->ai_addr, res->ai_addrlen) < 0) { cause = "connect"; close(s); s = -1; continue; } break; /* okay we got one */ } if (s < 0) { err(1, "%s", cause); /*NOTREACHED*/ } freeaddrinfo(res0);