Some Android Issues
最近写了些代码,遇到一些Android的坑…真的坑
1.Android HttpURLConnection response code 204/200
Android中HttpURLConnection 的response code好像并不可靠,譬如服务器明明返回了HTTP 204,然而你调用urlConnection.getResponseCode得到的却是 HTTP 200…(如果用Java SE运行得到的是正常的204)
查看了一下Android源码中isCaptivePortal函数(/frameworks/base/services/core/java/com/android/server/connectivity/NetworkMonitor.java),其中处理到了HTTP response code,
580 /** 581 * Do a URL fetch on a known server to see if we get the data we expect. 582 * Returns HTTP response code. 583 */ 584 private int isCaptivePortal() { 585 if (!mIsCaptivePortalCheckEnabled) return 204; 586 587 HttpURLConnection urlConnection = null; 588 int httpResponseCode = 599; 589 try { 590 URL url = new URL("http", mServer, "/generate_204"); 591 if (DBG) { 592 log("Checking " + url.toString() + " on " + 593 mNetworkAgentInfo.networkInfo.getExtraInfo()); 594 } 595 urlConnection = (HttpURLConnection) mNetworkAgentInfo.network.openConnection(url); 596 urlConnection.setInstanceFollowRedirects(false); 597 urlConnection.setConnectTimeout(SOCKET_TIMEOUT_MS); 598 urlConnection.setReadTimeout(SOCKET_TIMEOUT_MS); 599 urlConnection.setUseCaches(false); 600 601 // Time how long it takes to get a response to our request 602 long requestTimestamp = SystemClock.elapsedRealtime(); 603 604 urlConnection.getInputStream(); 605 606 // Time how long it takes to get a response to our request 607 long responseTimestamp = SystemClock.elapsedRealtime(); 608 609 httpResponseCode = urlConnection.getResponseCode(); 610 if (DBG) { 611 log("isCaptivePortal: ret=" + httpResponseCode + 612 " headers=" + urlConnection.getHeaderFields()); 613 } 614 // NOTE: We may want to consider an "HTTP/1.0 204" response to be a captive 615 // portal. The only example of this seen so far was a captive portal. For 616 // the time being go with prior behavior of assuming it's not a captive 617 // portal. If it is considered a captive portal, a different sign-in URL 618 // is needed (i.e. can't browse a 204). This could be the result of an HTTP 619 // proxy server. 620 621 // Consider 200 response with "Content-length=0" to not be a captive portal. 622 // There's no point in considering this a captive portal as the user cannot 623 // sign-in to an empty page. Probably the result of a broken transparent proxy. 624 // See http://b/9972012. 625 if (httpResponseCode == 200 && urlConnection.getContentLength() == 0) { 626 if (DBG) log("Empty 200 response interpreted as 204 response."); 627 httpResponseCode = 204; 628 } 629 630 sendNetworkConditionsBroadcast(true /* response received */, httpResponseCode == 204, 631 requestTimestamp, responseTimestamp); 632 } catch (IOException e) { 633 if (DBG) log("Probably not a portal: exception " + e); 634 if (httpResponseCode == 599) { 635 // TODO: Ping gateway and DNS server and log results. 636 } 637 } finally { 638 if (urlConnection != null) { 639 urlConnection.disconnect(); 640 } 641 } 642 return httpResponseCode; 643 }
从第625行可以看出,Android源码中判断当response code=200且content-length为0时,手动将response code置为204。嗯,我也这样做,然后该问题就解决了。
除此之外,Android中HttpURLConnection总之和Java SE中运行不大一致,譬如如果你是POST请求,却设置了urlConnection.setDoOutput(false);将会影响响应头。
但是,至于为什么出现这些情况,暂时并没细究,改日有空再看看Android相关源码。
2.Android 21+ Network bind with using vpn cause operating not permitted exception
Android 21+因为开始支持网络多连接,因此在android.net.ConnectivityManager中新增了绑定网络到当前线程或者绑定到具体socket的方法,
API21 connectivityManager.setProcessDefaultNetwork(network)
API23 connectivityManager.bindProcessToNetwork(network)然而使用时,
对于某type为ConnectivityManager.TYPE_WIFI的network调用以上方法绑定后,手机再连接VPN时,网络请求将会出现java.net.SocketException “operating not permitted”翻阅Android API文档发现,Android 21中新增了一种网络类型VPN,想必与此有关,继续翻阅Android源码,发现了Android在处理网络类型时,把vpn作为优先处理的网络类型,一旦连接了vpn,系统将会将其作为当前活跃网络。此时类型为wifi的network对象将会被限制socket创建。
API21 connectivityManager.setProcessDefaultNetwork(network)
API23 connectivityManager.bindProcessToNetwork(network)然而使用时,
对于某type为ConnectivityManager.TYPE_WIFI的network调用以上方法绑定后,手机再连接VPN时,网络请求将会出现java.net.SocketException “operating not permitted”翻阅Android API文档发现,Android 21中新增了一种网络类型VPN,想必与此有关,继续翻阅Android源码,发现了Android在处理网络类型时,把vpn作为优先处理的网络类型,一旦连接了vpn,系统将会将其作为当前活跃网络。此时类型为wifi的network对象将会被限制socket创建。
共有 0 条评论