無論是移動、聯通還是電信,都至少提供了兩種類型的的APN:WAP方式和NET方式。其中NET方式跟WIFI方式一樣,無需任何設定,可自由訪問所有類型網站,而WAP方式,需要手機先設定Proxy 伺服器和連接埠號碼等資訊,並且只能訪問HTTP協議類型的網站。
1) 移動的WAP名稱是CMWAP,NET名稱是CMNET;
2) 聯通的WAP名稱是UNIWAP,NET名稱是UNINET;聯通3G的WAP名稱是3GWAP,NET名稱是3GNET;
3) 電信的WAP名稱是CTWAP,NET名稱是CTNET;
其中,移動和聯通的WAPProxy 伺服器都是10.0.0.172,連接埠號碼是80;而電信的WAPProxy 伺服器是10.0.0.200,連接埠號碼是80。
Android系統中,對於APN網路的API是隱藏的,因此擷取手機的APN設定,需要通過ContentProvider來進行資料庫查詢,查詢的URI地址是:
取得全部的APN列表:content://telephony/carriers;
取得當前設定的APN:content://telephony/carriers/preferapn;
取得current=1的APN:content://telephony/carriers/current;
下面我們的代碼就是擷取當前首選的APN設定,並繼承HttpClient,實現我們自己的代理HttpClient類。首先來看下APN的管理類的實現,這個類的主要功能是獲得APN的Proxy 伺服器和連接埠號碼,查詢用的URI如下:
由這個URI使用ContentResolver獲得遊標對象,之後就是查詢操作了,分別查處當前手機所設定的APN、Proxy和Port,而如果手機的Proxy沒有設定,則需要根據APN來決定當前應該串連的Proxy 伺服器地址和連接埠號碼,詳細代碼如下所示:
通過APNManager類擷取到當前手機的WAP設定的代理和連接埠之後,就可以構造我們自己的代理HttpClient了,這個類定義為ProxyHttpClient,在該類的建構函式中,首先獲得APNManager的執行個體,然後擷取Proxy 伺服器proxy和連接埠值port,通過這兩個參數構造HttpHost執行個體,並將host執行個體設定為ConnRouteParams.DEFAULT_PROXY的值,詳細代碼如下所示:
APNManager類完整定義如下:
package com.hust.iprai;import android.content.ContentResolver;import android.content.Context;import android.database.Cursor;import android.net.ConnectivityManager;import android.net.NetworkInfo;import android.net.Uri;public class APNManager { public static final Uri PREFERRED_APN_URI; private String mApn; // 存取點名稱 private String mPort; // 連接埠號碼 private String mProxy; // Proxy 伺服器 private boolean mUseWap; // 是否正在使用WAP static { PREFERRED_APN_URI = Uri.parse("content://telephony/carriers/preferapn"); // 取得當前設定的APN } public APNManager(Context context) { checkNetworkType(context); } /** * 獲得當前設定的APN相關參數 * @param context */ private void checkApn(Context context) { ContentResolver contentResolver = context.getContentResolver(); Uri uri = PREFERRED_APN_URI; String[] apnInfo = new String[3]; apnInfo[0] = "apn"; apnInfo[1] = "proxy"; apnInfo[2] = "port"; Cursor cursor = contentResolver.query(uri, apnInfo, null, null, null); if (cursor != null) { while (cursor.moveToFirst()) { this.mApn = cursor.getString(cursor.getColumnIndex("apn")); this.mProxy = cursor.getString(cursor.getColumnIndex("proxy")); this.mPort = cursor.getString(cursor.getColumnIndex("port")); // 代理為空白 if ((this.mProxy == null) || (this.mProxy.length() <= 0)) { String apn = this.mApn.toUpperCase(); // 中國移動WAP設定:APN:CMWAP;代理:10.0.0.172;連接埠:80 // 中國聯通WAP設定:APN:UNIWAP;代理:10.0.0.172;連接埠:80 // 中國聯通WAP設定(3G):APN:3GWAP;代理:10.0.0.172;連接埠:80 if ((apn.equals("CMWAP")) || (apn.equals("UNIWAP")) || (apn.equals("3GWAP"))) { this.mUseWap = true; this.mProxy = "10.0.0.172"; this.mPort = "80"; break; } // 中國電信WAP設定:APN(或者存取點名稱):CTWAP;代理:10.0.0.200;連接埠:80 if (apn.equals("CTWAP")) { this.mUseWap = true; this.mProxy = "10.0.0.200"; this.mPort = "80"; break; } } this.mPort = "80"; this.mUseWap = true; break; } } this.mUseWap = false; cursor.close(); } /** * 檢測當前使用的網路類型是WIFI還是WAP * @param context */ private void checkNetworkType(Context context) { NetworkInfo networkInfo = ((ConnectivityManager) context .getApplicationContext().getSystemService(Context.CONNECTIVITY_SERVICE)).getActiveNetworkInfo(); if (networkInfo != null) { if (!"wifi".equals(networkInfo.getTypeName().toLowerCase())) { checkApn(context); return; } this.mUseWap = false; } } /** * 判斷當前網路連接狀態 * @param context * @return */ public static boolean isNetworkConnected(Context context) { NetworkInfo networkInfo = ((ConnectivityManager) context .getApplicationContext().getSystemService("connectivity")) .getActiveNetworkInfo(); if (networkInfo != null) { return networkInfo.isConnectedOrConnecting(); } return false; } public String getApn() { return this.mApn; } public String getProxy() { return this.mProxy; } public String getProxyPort() { return this.mPort; } public boolean isWapNetwork() { return this.mUseWap; }}
ProxyHttpClient類完整定義如下:
package com.hust.iprai;import android.content.Context;import android.text.TextUtils;import android.util.Log;import org.apache.http.HttpHost;import org.apache.http.conn.params.ConnRouteParams;import org.apache.http.impl.client.DefaultHttpClient;import org.apache.http.params.HttpConnectionParams;import org.apache.http.params.HttpParams;import org.apache.http.params.HttpProtocolParams;public class ProxyHttpClient extends DefaultHttpClient { private static final int HTTP_TIMEOUT_MS = 30 * 1000; private static final int BUFFER_SIZE = 1024 * 8; private static final String TAG = ProxyHttpClient.class.getSimpleName(); private RuntimeException mLeakedException = new IllegalStateException("ProxyHttpClient created and never closed"); private String mPort; private String mProxy; private boolean mUseWap; public ProxyHttpClient(Context context) { this(context, null, null); } public ProxyHttpClient(Context context, APNManager manager) { this(context, null, manager); } public ProxyHttpClient(Context context, String userAgent) { this(context, userAgent, null); } public ProxyHttpClient(Context context, String userAgent, APNManager manager) { if (manager == null) { manager = new APNManager(context); } this.mUseWap = manager.isWapNetwork(); this.mProxy = manager.getProxy(); this.mPort = manager.getProxyPort(); if (this.mUseWap) { HttpHost host = new HttpHost(this.mProxy, Integer.valueOf(this.mPort).intValue()); getParams().setParameter(ConnRouteParams.DEFAULT_PROXY, host); // 設定代理 } HttpConnectionParams.setConnectionTimeout(getParams(), HTTP_TIMEOUT_MS); HttpConnectionParams.setSoTimeout(getParams(), HTTP_TIMEOUT_MS); HttpConnectionParams.setSocketBufferSize(getParams(), BUFFER_SIZE); if (!TextUtils.isEmpty(userAgent)) { HttpProtocolParams.setUserAgent(getParams(), userAgent); } } public void close() { if (this.mLeakedException != null) { getConnectionManager().shutdown(); this.mLeakedException = null; } } protected HttpParams createHttpParams() { HttpParams params = super.createHttpParams(); HttpProtocolParams.setUseExpectContinue(params, false); return params; } protected void finalize() throws Throwable { super.finalize(); if (this.mLeakedException != null) { Log.e(TAG, "Leak found", this.mLeakedException); } }}