Android WiFi 許可權、廣播、連線、踩坑相關記錄
emmm…最近專案首頁重構,UI重新弄,邏輯拆分重新寫,變成我來寫了…寫完了,踩了好幾個坑,好幾個都忘記了,趕緊記一下防止都忘記了…
1.許可權請求…
既然是WiFi連線,當然首先考慮到的是開啟WiFi啊什麼的,現在基本都是targetSdkVersion >=23了吧,這些就會有涉及到許可權請求的問題.
主要是分為2個部分的許可權:
1. 開啟WIFI開關
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name ="android.permission.CHANGE_WIFI_STATE" />
這些許可權僅僅是普通許可權,直接寫在清單檔案裡面即可…
2. 掃描WIFI訊號
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
這個許可權是隸屬於 LOCATION 許可權組,需要手動申請該許可權.
至於許可權請求處理的第三方庫,工具類大家自個找吧,多得是…
我這邊因為除了常規的開啟關閉WiFi,掃描WiFi訊號還涉及到實際的業務邏輯,需要檢測當前連線的是否為硬體對應的WiFi訊號,同時頁面和邏輯作不同的處理.撇開業務邏輯,說說常規流程和遇到的坑吧.
1.
工欲善其事必先利其器,先封裝一個WifiManager對應的工具類吧,否則操作起來實在麻煩.
2.
判斷WiFi是否開啟(剛剛進入Activity/Fragment進行判斷…)
mWifiManager.isWifiEnabled();
3.
WiFi關閉,點選申請開啟WiFi,請求Manifest.permission.ACCESS_FINE_LOCATION許可權.
該許可權涉及到掃描WiFi列表.
4.
開啟WiFi
if (!mWifiManager.isWifiEnabled()) {
mWifiManager.setWifiEnabled(true );
}
重點來了!!!
程式碼在執行到這一步的時候,小米/華為手機會彈窗出來(沒有三喪,藍綠廠的測試機,估計也差不多),是否允許開啟WiFi開關,WTF…
這和許可權有毛線關係,你們吃多了吧…
小米彈窗只需10秒鐘,10秒鐘沒點選就會自動選擇拒絕
華為更狠,15秒…
程式碼邏輯直接就在這裡
試了下MOTO X的 類似於原生Google的ROM…好好地,說開就開.
所以一切邏輯請放在這個後面執行,同時以WiFi開關是否開啟作為判斷使用者點選彈窗的結果,順帶加個延時(考慮到有的手機配置低,4系U,甚至還有”良心”諾基亞的2系U),我是延時2000毫秒.發現紅米夠用,能夠在2000毫秒內成功開啟WiFi.
在實際過程中,摻雜著業務邏輯,需要一定時間的連線動畫,請務必在動畫執行完以後再次判斷WiFi當前狀態,畢竟在連線動畫中,一個手勢下拉狀態列,WiFi關掉就1,2秒就搞定,否則執行動畫結束後,發現邏輯繼續執行,但是WiFi是關閉的就尷尬了.
5.獲得WiFi列表
mWifiManager.startScan();
// 得到掃描結果
mWifiList = mWifiManager.getScanResults();
// 得到配置好的網路連線
mWifiConfiguration = mWifiManager.getConfiguredNetworks();
遍歷去重,建立制定WiFi名稱規則的list進行展示和連線.
連不上就直接跳轉設定手動連線吧
startActivity(new Intent(Settings.ACTION_WIFI_SETTINGS));
以上僅僅是普通流程,主要問題還是在請求許可權和開啟WiFi,國內ROM設定的彈窗問題…
實際摻雜了業務邏輯後要麻煩的多,得考慮不同WiFi狀態頁面的顯示情況和連線動畫執行情況.
2.廣播監聽…
part.1主要涉及的是WiFi連線狀態和業務邏輯.
這部分主要是對於切換WiFi開關後,通過監聽對應廣播後進行處理的一些情況和坑.
1.
註冊廣播和登出廣播
/**
* 註冊wifi廣播監聽
*/
private void sendReceiver() {
IntentFilter filter = new IntentFilter(WifiManager.WIFI_STATE_CHANGED_ACTION);
filter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
mWiFiReceiver = new WifiStateReceiver();
mContext.registerReceiver(mWiFiReceiver, filter);
}
/**
* 登出wifi廣播監聽
*/
private void stopReceiver() {
if (mWiFiReceiver != null) {
mContext.unregisterReceiver(mWiFiReceiver);
mWiFiReceiver = null;
}
}
這個沒什麼好說的,將註冊和登出放在對應的生命週期方法內即可.
2.廣播部分
首先是WiFi開啟關閉的廣播
WifiManager.WIFI_STATE_CHANGED_ACTION
//WIFI開啟和關閉...
if (WifiManager.WIFI_STATE_CHANGED_ACTION.equals(action)) {
int wifiState = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE, -1);
switch (wifiState) {
case WifiManager.WIFI_STATE_DISABLED:
//這裡處理WiFi關閉以後的邏輯
break;
case WifiManager.WIFI_STATE_ENABLED:
break;
default:
break;
}
}
EXTRA_WIFI_STATE 對應的State有5種,分別是DISABLING、DISABLED、ENABLING、ENABLED、UNKNOWN.
我記得之前我是直接通過這個廣播狀態來處理整個WiFi變化的邏輯處理,但是後來發現有坑,具體什麼坑,抱歉,我忘記了,2333.反正別用就對了,繼續往下看.
後來對於EXTRA_WIFI_STATE,主要使用的就是 DISABLED來處理WiFi關閉的情況.至於WiFi開啟則是通過 WifiManager.NETWORK_STATE_CHANGED_ACTION
當WifiManager.WIFI_STATE_ENABLED時,就能接收到NETWORK_STATE_CHANGED_ACTION.
它有6種情況,分別是CONNECTING、CONNECTED、SUSPENDED、DISCONNECTING、DISCONNECTED、UNKNOWN.
主要監聽的是DISCONNECTED和CONNECTED.
它們代表的狀態是 我WiFi開關是開著,但是我沒有連線和我WiFi開關是開著,且我已經連線上.
需要注意的是
1.注意新增flag,防止在剛剛進入Activity/Fragment時,切換WiFi開關連線狀態,同時執行廣播邏輯
2.NetworkInfo.State.CONNECTED內邏輯新增延時處理(針對連線制定裝置WiFi訊號進行鑑權,認證邏輯處理).
在切換WiFi,且WiFi自動連線時,邏輯會先走DISCONNECTED然後才是CONNECTED,會出現當前已經獲得到WIFI是對的,但是實際還沒有連線上的這種情況,會導致DISCONNECTED和CONNECTED邏輯衝突,還是建議給CONNECTED邏輯進行延時處理.
3.廣播接收去重的問題
每次切換WiFi時,都會重複傳送,重複接收到WiFi,需要進行去重.
我這邊的辦法是通過判斷時間來進行去重
private static final int WIFI_DISABLED = 0;
private static final int WIFI_DISCONNECTED = 1;
private static final int WIFI_CONNECTED = 2;
private boolean forOnceByStatus(int index) {
long nowTime = TimeUtils.getCurrentTimeInLong();
if ((nowTime - (index == 0 ? timeForDisabled : (index == 1 ? timeForDisconnect : timeForConnect))) > 800) {
if (index == WIFI_DISABLED) {
timeForDisabled = nowTime;
} else if (index == WIFI_DISCONNECTED) {
timeForDisconnect = nowTime;
} else if (index == WIFI_CONNECTED) {
timeForConnect = nowTime;
}
return true;
} else {
return false;
}
}
分別在DISABLED,DISCONNECTED,CONNECTED進行呼叫,為true才允許執行相關邏輯.
當關閉WiFi:
WIFI關閉我進來了DISCONNECTED,時間是====1509342281409
WIFI關閉我進來了DISABLED,時間是====1509342281589
當開啟WiFi:
WIFI開啟我進來了DISCONNECTED,時間是====1509342288210
WIFI開啟我進來了CONNECTED,時間是====1509342289212
總結
總體來說,WiFi開啟/關閉,掃描,連線,廣播監聽.API還是挺簡單的,當涉及摻雜實際的業務邏輯時,就會變得賊雞兒麻煩.
需要考慮的情況特別多,什麼手動給你關WiFi,許可權拒絕,彈窗拒絕,連到一半關,連線的不是指定WiFi……
還是多注意,多測試下各種情況吧.