前言
最近在研究WiFi,順便看了一下WiFi的API文件,然後衍生出一系列的腦洞大開,不過這篇文章不打算講它的API,感興趣的可以直接去看它的文件
android.net.wifi 。
既然能獲取到手機連線到的WiFi資訊,那麼自然也能獲取得到連線過的WiFi密碼啦,不過前提是你的手機必須有root許可權。
先貼個最終的效果圖片~~~
1.獲取手機root許可權
現在有很多軟體都可以獲取root,不過我在獲取root的時候是真的心塞,可能是手機太low了,機型不適配,試過很多軟體都不行,最後下載了KingRoot,然後看著它不停的關機開機再關機再開機最後才root成功的(不過過了5分鐘後又打回原形了,對這手機真的無語),不過這5分鐘也已經夠我測試的啦。所以大家如果一直失敗的話也可以嘗試一下KingRoot,當然這也不是百分百成功的。
2.獲取本地已連線過的WiFi資料
當手機連線過WiFi時,連線的資訊會儲存在手機的/data/misc/wifi/wpa_supplicant.conf檔案裡,但是這個檔案並不能直接開啟,而是需要靠命令列的方式來列印出來,不多說,直接上程式碼~~~
MainActivity.java
//讀取WiFi配置檔案
private static final String CAT_WIFI_CONF = "cat /data/misc/wifi/wpa_supplicant.conf\n";
//退出
private static final String EXIT = "exit\n";
Process process;
DataOutputStream dataOutputStream;
DataInputStream dataInputStream;
StringBuffer wifiConf = new StringBuffer();
private void getWiFiInfo() {
try {
//使當前程式獲得root許可權
process = Runtime.getRuntime().exec("su");
dataOutputStream = new DataOutputStream(process.getOutputStream());
dataInputStream = new DataInputStream(process.getInputStream());
//使用cat來列印該檔案的資料
dataOutputStream.writeBytes(CAT_WIFI_CONF);
//列印完後退出
dataOutputStream.writeBytes(EXIT);
dataOutputStream.flush();
//讀取位元組並解碼成指定格式的字元
InputStreamReader inputStreamReader = new InputStreamReader(dataInputStream, "UTF-8");
//讀取字元流
BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
String line = null;
//每讀取一行則拼接一次
while ((line = bufferedReader.readLine()) != null) {
wifiConf.append(line);
}
//關閉流並釋放資源
bufferedReader.close();
inputStreamReader.close();
process.waitFor();
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
if (TextUtils.isEmpty(wifiConf.toString())) {
tips.setVisibility(View.VISIBLE);
Toast.makeText(getApplicationContext(), "您還未獲取Root許可權", Toast.LENGTH_LONG).show();
}
try {
if (dataOutputStream != null) {
dataOutputStream.close();
}
if (dataInputStream != null) {
dataInputStream.close();
}
process.destroy();
} catch (Exception e) {
e.printStackTrace();
}
}
//新增WiFi資訊
addWifiList();
}
複製程式碼
我們通過Runtime.getRuntime().exec("su")
為當前程式獲得root環境後,當你執行開啟APP後,會彈出一個框,提示你是否允許當前應用使用root,這裡點選允許,反正是自己寫的程式碼,也不怕它會幹什麼壞事是吧~
我們通過cat /data/misc/wifi/wpa_supplicant.conf列印出來的資料正是我們想得到的WiFi資訊,但是由於裡面的資訊包含很多個欄位,所以我們要篩選出我們需要的內容來。 wpa_supplicant.conf包含的欄位為:
network={
ssid="wifi_SU"
psk="Su1ddsfs235sdf82"
key_mgmt=WPA-PSK
priority=117
disabled=1
id_str="%7B%22creatorUid%22%3A%221000%22%2C%22configKey%22%3A%22%fi_SU%5C%22WPA_PSK%22%7D"
}
其中ssid為WiFi名稱,psk為WiFi密碼,key_mgmt為WiFi的加密型別
我們需要的最重要資料就是前兩個欄位了
複製程式碼
3.建立儲存的物件並新增資料
當知道我們想要的資訊後,就可以新增進我們的列表裡的,首先需要建立一個bean類儲存我們要新增的內容,這個很簡單,就直接貼程式碼了:
WiFiInfo.java
public class WiFiInfo {
private String name;
private String pwd;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPwd() {
return pwd;
}
public void setPwd(String pwd) {
this.pwd = pwd;
}
}
複製程式碼
然後就可以往裡面新增資料啦~~
private List<WiFiInfo> lists;
//通過建立一個正規表示式來匹配是否有需要的欄位,有則進行下一步操作,慢慢看就能懂,不作解釋
private void addWifiList() {
Pattern network = Pattern.compile("network=\\{([^\\}]+)\\}", Pattern.DOTALL);
Matcher networkMatcher = network.matcher(wifiConf.toString());
WiFiInfo wifiInfo;
while (networkMatcher.find()) {
String networkBlock = networkMatcher.group();
Pattern ssid = Pattern.compile("ssid=\"([^\"]+)\"");
Matcher ssidMatcher = ssid.matcher(networkBlock);
if (ssidMatcher.find()) {
wifiInfo = new WiFiInfo();
wifiInfo.setName(ssidMatcher.group(1));
Pattern psk = Pattern.compile("psk=\"([^\"]+)\"");
Matcher pskMatcher = psk.matcher(networkBlock);
if (pskMatcher.find()) {
wifiInfo.setPwd(pskMatcher.group(1));
} else {
wifiInfo.setPwd("無密碼");
}
lists.add(wifiInfo);
}
}
// 列表倒序,看著方便~
Collections.reverse(lists);
adapter.notifyDataSetChanged();
}
複製程式碼
4.顯示資料
新增完之後就可以顯示資料了,我這裡的activity_main.xml使用的是recyclerview,比較簡單,然後adapter我使用的是BaseRecyclerViewAdapterHelper,當然我的重點是獲取WiFi密碼,所以其他程式碼能簡單就簡單啦~下面我就直接貼出這些程式碼了:
activity_main.xml
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<android.support.v7.widget.RecyclerView
android:id="@+id/wifi_list"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<!--當未獲取root許可權時的tips-->
<TextView
android:id="@+id/tips"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="請先獲取Root許可權"
android:layout_centerInParent="true"
android:visibility="gone"/>
</RelativeLayout>
複製程式碼
WiFiAdapter.java
public class WiFiAdapter extends BaseQuickAdapter<WiFiInfo, BaseViewHolder> {
public WiFiAdapter(int layoutResId, @Nullable List<WiFiInfo> data) {
super(layoutResId, data);
}
@Override
protected void convert(BaseViewHolder helper, WiFiInfo item) {
helper.setText(R.id.item_name, "名稱:" + item.getName())
.setText(R.id.item_pwd, "密碼:" + item.getPwd());
}
}
複製程式碼
item_wifi.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="10dp">
<TextView
android:id="@+id/item_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/wifi_name" />
<TextView
android:id="@+id/item_pwd"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="4dp"
android:text="@string/wifi_pwd" />
</LinearLayout>
<View
android:layout_width="match_parent"
android:layout_height="0.5dp"
android:background="#30000000" />
</LinearLayout>
複製程式碼
然後剩下的就是在MainActivity中配置adapter啦,這些就不貼了,比較簡單。當你手機未獲得root許可權時,則列表會為空,因為你無法讀取wpa_supplicant.conf檔案。
好啦,以後再也不怕忘記密碼啦,只要是你的WiFi萬能鑰匙能連得上的WiFi,就都能知道別人的密碼了~