Android開發之WIFI與網路連線處理
網路連線處理
在說WiFi之前,先來說說網路連線處理。
在Android開發過程中,對於一個需要連線網路的Android裝置,對裝置的網路狀態檢測是很有必要的!有很多的App都需要連線網路。判斷裝置是否已經連線網路,並且在連線網路的狀態下判斷是wifi無線連線還是GPRS手機網路連線,這樣就可以在不同的網路連線下去呼叫不同的方法,處理不同的事情。
現在app大多都需要從網路上獲得資料。所以訪問網路是在所難免。但是在訪問網路之前,我們應該先做一下網路的狀態判斷。其實在訪問網路之前我們要做一些狀態判斷,對應一些狀態判斷來做處理,並不是直接使用Http訪問網路即可。很多人在開發就經常把網路這塊直接跳過,直接訪問網路,一旦斷網,各種體驗效果不好,不是說app沒法用,只是體驗效果差。還有,就是我們可能為使用者考慮,因為現在一般連網是wifi和手機流量,都知道後者收費是比較高的。假如我們的app載入的圖片或者有大的資料下載操作,可是使用者的本意是要是在流量下的話就不要操作這些很費流量的的操作,這樣就必須要我們做一些連網狀態的判斷。網路是否連線良好,連線的wifi還是流量,斷網或者網路改變了的時候怎麼做,這都是一些細節,但是要注意處理。
檢視當前網路狀態需要的許可權:
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
允許檢視當前網路狀態,比如是3G還是WIFI上網。
連線管理
涉及的常用類
ConnectivityManager
翻譯成中文即:網路連線管理者
主要作用:
- 監聽手機網路狀態(包括GPRS,WIFI, UMTS等)
- 手機狀態發生改變時,傳送廣播
- 當一個網路連線失敗時進行故障切換
- 為應用程式提供可以獲取可用網路的高精度和粗糙的狀態
獲取ConnectivityManager
ConnectivityManager connMgr = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo
翻譯成中文即:網路的狀態資訊
獲取NetworkInfo
通過ConnectivityManager獲取
ConnectivityManager connMgr = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo networkInfo = connMgr.getActiveNetworkInfo();
主要方法:
- getDetailedState():獲取詳細狀態。
- isAvailable():判斷該網路是否可用,是否可以尋找到網路
- isConnected():判斷是否已經連線
- isConnectedOrConnecting():判斷是否已經連線或正在連線。
- getState() 獲取連線狀態
- getExtraInfo():獲取附加資訊。
- getType():獲取網路型別(一般為移動(0)或Wi-Fi(1))。
- getTypeName():獲取網路型別名稱(一般取值“WIFI”或“MOBILE”)。
- getReason():獲取連線失敗的原因。
- isFailover():判斷是否連線失敗。
- isRoaming():判斷是否漫遊
注意:
1.當用wifi上的時候
getType是WIFI
getExtraInfo是空的
2.當用手機上的時候
getType是MOBILE
3.用移動CMNET方式
getExtraInfo的值是cmnet
4.用移動CMWAP方式
getExtraInfo的值是cmwap,但是不在代理的情況下訪問普通的網站訪問不了
5.用聯通3gwap方式
getExtraInfo的值是3gwap
6.用聯通3gnet方式
getExtraInfo的值是3gnet
7.用聯通uniwap方式
getExtraInfo的值是uniwap
8.用聯通uninet方式
getExtraInfo的值是uninet
TelephonyManager
TelephonyManager類主要提供了一系列用於訪問與手機通訊相關的狀態和資訊的get方法。其中包括手機SIM的狀態和資訊、電信網路的狀態及手機使用者的資訊。在應用程式中可以使用這些get方法獲取相關資料。
需要新增許可權:
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
第一步,也要像ConnectivityManager一樣獲取管理器:
TelephonyManager tm = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
常用方法:
- getCallState()
CALL_STATE_IDLE 無任何狀態時
CALL_STATE_OFFHOOK 接起電話時
CALL_STATE_RINGING 電話進來時 - getDataActivity()
DATA_ACTIVITY_IN 資料連線狀態:活動,正在接受資料
DATA_ACTIVITY_OUT 資料連線狀態:活動,正在傳送資料
DATA_ACTIVITY_INOUT 資料連線狀態:活動,正在接受和傳送資料
DATA_ACTIVITY_NONE 資料連線狀態:活動,但無資料傳送和接受 - getDataState()
DATA_CONNECTED 資料連線狀態:已連線
DATA_CONNECTING 資料連線狀態:正在連線
DATA_DISCONNECTED 資料連線狀態:斷開
DATA_SUSPENDED 資料連線狀態:暫停 - getDeviceSoftwareVersion() 移動終端的軟體版本,例如:GSM手機的IMEI/SV碼
- getLine1Number() 手機號碼,對於GSM網路來說即MSISDN(不一定能拿到)
- getNetworkCountryIso() ISO標準的國家碼,即國際長途區號
- getDeviceId() GSM網路,返回IMEI;如果是CDMA網路,返回MEID
IMEI是International Mobile Equipment Identity (國際移動裝置標識)的簡稱
IMEI由15位數字組成的”電子串號”,它與每臺手機一一對應,而且該碼是全世界唯一的,其組成為:- 前6位數(TAC)是”型號核准號碼”,一般代表機型
- 接著的2位數(FAC)是”最後裝配號”,一般代表產地
- 之後的6位數(SNR)是”串號”,一般代表生產順序號
- 最後1位數(SP)通常是”0″,為檢驗碼,目前暫備用
MEID 移動裝置識別碼(Mobile Equipment Identifier)是CDMA手機的身份識別碼,也是每臺CDMA手機或通訊平板唯一的識別碼。
MEID由14個十六進位制字元標識,第15位為校驗位,不參與空中傳輸。
RR:範圍A0-FF,由官方分配
XXXXXX:範圍 000000-FFFFFF,由官方分配
ZZZZZZ:範圍 000000-FFFFFF,廠商分配給每臺終端的流水號
C/CD:0-F,校驗碼
- getNetworkOperator() MCC+MNC程式碼 (SIM卡運營商國家程式碼和運營商網路程式碼)(IMSI)
IMSI是國際移動使用者識別碼的簡稱(International Mobile Subscriber Identity)
IMSI共有15位,其結構如下:
MCC+MNC+MIN
MCC:Mobile Country Code,移動國家碼,共3位,中國為460;
MNC:Mobile NetworkCode,行動網路碼,共2位
在中國,移動的程式碼為電00和02,聯通的程式碼為01,電信的程式碼為03
合起來就是(也是Android手機中APN配置檔案中的程式碼):
中國移動:46000 46002
中國聯通:46001
中國電信:46003
舉例,一個典型的IMSI號碼為460030912121001 - getNetworkOperatorName() 行動網路運營商的名字(SPN)
- getNetworkType() 行動網路型別
int NETWORK_TYPE_CDMA 網路型別為CDMA
int NETWORK_TYPE_EDGE 網路型別為EDGE
int NETWORK_TYPE_EVDO_0 網路型別為EVDO0
int NETWORK_TYPE_EVDO_A 網路型別為EVDOA
int NETWORK_TYPE_GPRS 網路型別為GPRS
int NETWORK_TYPE_HSDPA 網路型別為HSDPA
int NETWORK_TYPE_HSPA 網路型別為HSPA
int NETWORK_TYPE_HSUPA 網路型別為HSUPA
int NETWORK_TYPE_UMTS 網路型別為UMTS
在中國,聯通的3G為UMTS或HSDPA,移動和聯通的2G為GPRS或EGDE,電信的2G為CDMA,電信的3G為EVDO - getPhoneType() 手機制式型別
int PHONE_TYPE_CDMA 手機制式為CDMA,電信
int PHONE_TYPE_GSM 手機制式為GSM,移動和聯通
int PHONE_TYPE_NONE 手機制式未知 - getSimState()
int SIM_STATE_ABSENT SIM卡未找到
int SIM_STATE_NETWORK_LOCKED SIM卡網路被鎖定,需要Network PIN解鎖
int SIM_STATE_PIN_REQUIRED SIM卡PIN被鎖定,需要User PIN解鎖
int SIM_STATE_PUK_REQUIRED SIM卡PUK被鎖定,需要User PUK解鎖
int SIM_STATE_READY SIM卡可用
int SIM_STATE_UNKNOWN SIM卡未知 - getSimCountryIso() SIM卡提供商的國家程式碼
- getSimOperator(),getSimOperatorName() MCC+MNC程式碼 (SIM卡運營商國家程式碼和運營商網路程式碼)(IMSI)
- getSimSerialNumber() SIM卡的序列號(IMEI)
- getSubscriberId() 使用者唯一標識,比如GSM網路的IMSI編號
- getVoiceMailAlphaTag() 語音信箱號碼關聯的字母標識
- getVoiceMailNumber() 語音郵件號碼
- isNetworkRoaming() 手機是否處於漫遊狀態
網路連線處理方式
獲取單個網路是否連線
貼程式碼:
ConnectivityManager connMgr = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
//WiFi是否連線
NetworkInfo networkInfo = connMgr.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
boolean isWifiConn = networkInfo.isConnected();
//手機網路是否連線
networkInfo = connMgr.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
boolean isMobileConn = networkInfo.isConnected();
獲取網路是否連線
ConnectivityManager connMgr = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo networkInfo = connMgr.getActiveNetworkInfo();
通過廣播獲取連線狀態改變(常用方式)
- 註冊廣播,監聽ConnectivityManager.CONNECTIVITY_ACTION頻道
IntentFilter filter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION);
context.registerReceiver(mReceiver, filter);
- 網路狀態廣播
BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if (intent.getBooleanExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, false)) {
Log.i(TAG, "netWork has lost");
}
NetworkInfo tmpInfo = (NetworkInfo)
intent.getExtras().get(ConnectivityManager.EXTRA_NETWORK_INFO);
Log.i(TAG, tmpInfo.toString() + " {isConnected = " + tmpInfo.isConnected() + "}");
}
};
- 清單檔案註冊(Demo寫內部類了)
<receiver android:name=".ConnectionReceiver" >
<intent-filter>
<action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
</intent-filter>
</receiver>
無網路連線處理
提示無網路,或跳轉到網路設定介面:
/**
* 判斷手機系統的版本!如果API大於10 就是3.0+
* 因為3.0以上的版本的設定和3.0以下的設定不一樣,呼叫的方法不同
*/
Intent intent ;
if (Build.VERSION.SDK_INT > 10) {
intent = new Intent(android.provider.Settings.ACTION_WIFI_SETTINGS);
} else {
intent = new Intent();
ComponentName component = new ComponentName("com.android.settings","com.android.settings.WirelessSettings");
intent.setComponent(component);
intent.setAction("android.intent.action.VIEW");
}
startActivity(intent);
不同Rom可能不同。
下面來說WiFi
WiFi
WIFI是一種無線聯網技術,常見的是使用無線路由器,在這個無線路由器的訊號覆蓋的範圍內都可以採用WIFI連線的方式進行聯網。如果無線路由器連線了一個ADSL線路或其他的聯網線路,則又被稱為“熱點”。
首先,要操作WiFi,先要加入許可權
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE"/>
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
Android中對於Wifi操作本身提供了一些有用的包android.net.wifi
WiFi常用相關類
WifiManager用來管理我們的wifi連線
取得WifiManager物件
WifiManager mWifiManager=(WifiManager) context.getSystemService(Context.WIFI_SERVICE);
開啟wifi
if(!mWifiManager.isWifiEnabled())
{
mWifiManager.setWifiEnabled(true);
}
關閉wifi
if(mWifiManager.isWifiEnabled())
{
mWifiManager.setWifiEnabled(false);
}
檢查當前wifi狀態
mWifiManager.getWifiState()
WIFI網絡卡狀態
- WifiManager.WIFI_STATE_DISABLING : WIFI網絡卡正在關閉(0)
- WifiManager.WIFI_STATE_DISABLED : WIFI網絡卡不可用(1)
- WifiManager.WIFI_STATE_ENABLING : WIFI網正在開啟(2) (WIFI啟動需要一段時間)
- WifiManager.WIFI_STATE_ENABLED : WIFI網絡卡可用(3)
- WifiManager.WIFI_STATE_UNKNOWN : 未知網絡卡狀態
WifiInfo
wifi無線連線的資訊,包括接入點,網路連線狀態,隱藏的接入點,IP地址,連線速度,MAC地址,網路ID,訊號強度等資訊
WifiInfo mWifiInfo=mWifiManager.getConnectionInfo();
- getBSSID() 獲取BSSID,在手機WIFI中,就是MAC地址
- getSSID() 獲取SSID
- getDetailedStateOf() 獲取客戶端的連通性
- getHiddenSSID() 獲得SSID是否被隱藏
- getIpAddress() 獲取IP地址
- getLinkSpeed() 獲得連線的速度
- getMacAddress() 獲得Mac地址
- getRssi() 獲得802.11n網路的訊號
- getSupplicanState() 返回具體客戶端狀態的資訊
ScanResult
主要用來描述已經檢測出的接入點,包括接入點的地址,接入點的名稱,
身份認證,頻率,訊號強度等資訊。
開始掃描
mWifiManager.startScan()
得到掃描結果
List<ScanResult> mWifiList=mWifiManager.getScanResults();
WifiConfiguration
Wifi網路的配置,包括安全設定等。
得到配置好的網路連線
List<WifiConfiguration> mWifiConfigurations=mWifiManager.getConfiguredNetworks()
連線配置好指定ID的網路
mWifiManager.enableNetwork(mWifiConfigurations.get(index).networkId, true)
處理網路
動態處理WiFi網路
//新增一個網路並連線
public void addNetWork(WifiConfiguration configuration){
int wcgId=mWifiManager.addNetwork(configuration);
mWifiManager.enableNetwork(wcgId, true);
}
//斷開指定ID的網路
public void disConnectionWifi(int netId){
mWifiManager.disableNetwork(netId);
mWifiManager.disconnect();
}
連線到對應WiFi網路
建立WifiConfiguration配置物件
String ssid = "Rair";
String pwd = "88888888";
WifiConfiguration localWifiConfiguration = new WifiConfiguration();
//公認的IEEE 802.11驗證演算法。
localWifiConfiguration.allowedAuthAlgorithms.clear();
localWifiConfiguration.allowedAuthAlgorithms.set(0);
//公認的的公共組密碼。
localWifiConfiguration.allowedGroupCiphers.clear();
localWifiConfiguration.allowedGroupCiphers.set(2);
//公認的金鑰管理方案。
localWifiConfiguration.allowedKeyManagement.clear();
localWifiConfiguration.allowedKeyManagement.set(1);
//密碼為WPA。
localWifiConfiguration.allowedPairwiseCiphers.clear();
localWifiConfiguration.allowedPairwiseCiphers.set(1);
localWifiConfiguration.allowedPairwiseCiphers.set(2);
//公認的安全協議。
localWifiConfiguration.allowedProtocols.clear();
localWifiConfiguration.SSID = ("\"" + ssid + "\"");
localWifiConfiguration.preSharedKey = ("\"" + pwd + "\"");
//不廣播其SSID的網路
localWifiConfiguration.hiddenSSID = true;
WifiConfiguration對應的配置值可到文件中檢視,不知道怎麼翻譯描述。O(∩_∩)O~
新增WIFI網路
wcnetworkid = mWifiManager.addNetwork(localWifiConfiguration);
使WIFI網路有效
mWifiManager.enableNetwork(wcnetworkid,true);
鎖定網路
手機螢幕關閉之後,並且其他的應用程式沒有在使用wifi的時候,系統大概在兩分鐘之後,會關閉wifi,使得wifi處於睡眠狀態,有利於電源能量的節省和延長電池壽命。
android為wifi提供了一種叫WifiLock的鎖,能夠阻止wifi進入睡眠狀態,使wifi一直處於活躍狀態。這種鎖,在下載一個較大的檔案的時候,比較適合使用。
新增許可權
<uses-permission android:name="android.permission.WAKE_LOCK"/>
建立wifiLock
方式1:
// lockName為鎖的名稱
WifiLock wifiLock = wifiManager.createWifiLock(lockName);
方式2:
wifiLock = wifiManager.createWifiLock(lockType, lockName);
lockType可以取以下值:
- WIFI_MODE_FULL == 1 //掃描,自動的嘗試去連線一個曾經配置過的熱點
- WIFI_MODE_SCAN_ONLY == 2 //只剩下掃描
- WIFI_MODE_FULL_HIGH_PERF = 3 //在第一種模式的基礎上,保持最佳效能
wifi新增鎖
wifiLock.acquire();
wifi釋放鎖
//判斷wifi是否被lock鎖持用
if (wifiLock.isHeld())
{
// 釋放鎖
wifiLock.release();
}
一般到了這個時候就該給個Demo了
ConnectivityManagerDemo:連線管理的Demo,裡面帶一個NetworkConnUtil(網路連線幫助類),Demo都是以log形式顯示結果。懶得寫介面啦 (∇*)4
WifiDemo: 裡面帶一個WifiUtil(Wifi連線幫助類)
Demo已上傳:RairDemo
GitHub:https://github.com/Rairmmd/RairDemo
Coding:https://coding.net/u/Rair/p/RairDemo/git