Android NDK 層發起 HTTP 請求的問題及解決
前言
新的一年,大家新年快樂~~雞年大吉!
本次給大家帶來何老師的最新文章~雖然何老師還在過節,但依然放心不下廣大開發者,在此佳節還未結束之際,給大家帶來最新的技術分享~
NDK層網絡請求
事件的起因不說了,總之是需要實現一個 NDK 層的網絡請求。為了多端適用,還是選擇了 CodeTyphon 作為跨平臺方案。關于 CodeTyphon 此處不述,感興趣的可以直接去其官網查看(傳送門:http://www.pilotlogic.com/sitejoom/)。
CodeTyphon 自帶的 fcl-web 庫可以直接完成對于 HTTP 請求的支持,雖然我很想這么說... 在實際使用中,的確可以通過引入 fcl-web 來完成跨平臺的網絡請求,然而在 Android 端實際測試時,卻發生了奇怪的錯誤。
比如說請求我自己的服務器 www.rarnu.com ,會發生以下錯誤:
而當我換用 IP 地址來請求時,卻是可以成功的。
輸入的域名是實際存在的,可以排除掉域名本身的問題。而使用 adb shell 連入設備,并使用 ping 命令訪問該域名,也是正常的。
那么問題可能就出在,找不到 nameserver 。我們都知道,在 Linux 下, nameserver 由 resolv.conf 決定,這個文件通常保存在 /etc 下。于是看了一下,Android 里并沒有這個文件,應該就是這個原因引起的了,因為讀不到 resolv.conf 所以才導致了無法解釋域名。接下來就是去找 Android 下,原本該是 resolv.conf 的東西保存在哪里。
不賣關子了,其實 Android 很早就把 resolv.conf 的內容改成了 key-value 的形式,采用 SystemProperties 進行存儲,而其關鍵的 key 是 net.dns1 和 net.dns2 。
嘗試使用 adb 連接手機,并對以上兩個 key 進行取值:
我的手機上取出來的是 OpenDNS 的值,自己設置過。好了,既然已經知道了 nameserver 的所在,接下去就是修改代碼以使程序識別和加載。
在 CodeTyphon 中,有一個基礎庫文件叫 netdb.pp ,其中包含了 resolveName 方法,其具體代碼如下:
其實這段代碼很明確,關鍵變量是 DNSServers ,打印一下看看是個什么值:
程序執行后打出來 -1 ,也就是說在 Android 下,由于 DNSServers 變量中沒有任何的數據,導致了完全無法解析域名,在其他平臺下,在此處打日志均顯示 0 ,表示在這個數組里有一個下標為 0 的數據。
那事情就變得簡單了,我們可以直接去找加載了 DNSServers 的地方,很容易的,找到了 InitResolver 函數,由于該函數比較長,此處只截取加載 DNSServer 的部分:
沒有比這更明確的了,就是去找有沒有 /etc/resolv.conf 嘛,找到就加載,沒找到那就啥都不做了,而剛才說過了 Android 端并沒有這么一個文件,于是直接就導致了 nameserver 缺失,間接引起域名無法解析。
好了,那么簡易的解決方案也就有了,只需要重建 GetDNsservers 函數,使其能夠適應 Android 端的情況即可。
下面給出代碼:
里面還有一個關鍵代碼,是 GetNetDNS ,它用于從 Android 內讀取 net.dns1 變量:
最后,把上面的 InitResolver 改一下,使其可以正常加載工作于 Android 端的這段代碼:
編譯運行程序, Error resolving host 的問題即得到了解決。
來自:http://mp.weixin.qq.com/s/O2APsNzYqjPGAp9sDo-MyA