安卓手機已保存WiFi密碼查看助手(開源)


一、需求分析

   最近電腦需要連接WiFi,卻發現WiFi密碼給忘記了。而手機里有保存過的WiFi密碼,但是在手機的設置界面看不到。

   雖然已經有一些可以查看WiFi密碼的app,但是主要還是擔心密碼被那些app傳到后台去。還是自己寫一個比較放心。而且用app查看只需要點擊一下,要比直接查找系統里保存了密碼的文件更加方便。

二、主要功能實現

2.1 讀取系統文件

   Android系統保存了WiFi密碼的文件保存在/data/misc/wifi/wpa_supplicant.conf中[1],通過在代碼中運行命令行程序‘cat’來讀取文件[3][4]。

String commandResult=commandForResult("cat /data/misc/wifi/wpa_supplicant.conf");
public String commandForResult(String command) { try { Process process = Runtime.getRuntime().exec("su"); DataOutputStream outputStream = null; outputStream = new DataOutputStream(process.getOutputStream()); outputStream.writeBytes(command+"\n"); outputStream.flush(); outputStream.writeBytes("exit\n"); outputStream.flush(); BufferedReader in = new BufferedReader(new InputStreamReader(process.getInputStream())); StringBuilder total = new StringBuilder(); String line; while ((line = in.readLine()) != null) { total.append(line); total.append("\n"); } return total.toString(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); return "error"; } }

2.2 對WiFi信息按照priority由大到小排序

   wpa_supplicant.conf文件中保存的Wifi信息主要采用如下格式,每個網絡信息以network開頭。key_mgmt=NONE表示網絡不需要密碼。當key_mgmt=WPA-PSK時,會通過psk字段來標識密碼信息。

   目前看到的手機里wpa_supplicant.conf文件中並沒有對不同的網絡按照priority的值進行排序。而那些經常用的網絡priority比較高,被放在了文件的后面,因此考慮對網絡信息按照priority由大到小進行排序。

    String sortByPriority(String input){
        String [] stringPerLine=input.split("\n");
        ArrayList<NetworkPara> list=new ArrayList<MainActivity.NetworkPara>();
        int start=0,end=0;
        NetworkPara networkPara = null;
        for (int i = 0; i < stringPerLine.length; i++) {
            if (stringPerLine[i].contains("network={")) {
                start=1;
                end=0;
                networkPara=new NetworkPara();
                networkPara.paraString="";
            }
            if (start==1) {
                if (networkPara!=null) {
                    networkPara.paraString=networkPara.paraString.concat(stringPerLine[i])+"\n";    
                }
                if (stringPerLine[i].contains("priority")) {
                    String []prioSplit=stringPerLine[i].split("=");
                    networkPara.priority=Integer.parseInt(prioSplit[prioSplit.length-1]);
                }
                if (stringPerLine[i].contains("}")) {
                    start=0;
                    end=1;
                }
            }
            if (end==1) {
                list.add(networkPara);
            }
        }
         Collections.sort(list, new Comparator() {
             public int compare(Object o1, Object o2) {
                     return ((Comparable) ((NetworkPara) (o2)).priority)
                             .compareTo(((NetworkPara) (o1)).priority);
                     }
             });
        
        String result="";
        for (int i = 0; i < list.size(); i++) {
            result=result.concat(list.get(i).paraString);
        }
        return result;
    }

2.3 支持按照字符串進行搜索

   字符串搜索的入口選擇采用在actionar上增加搜索按鈕,根據輸入字符串進行逐行匹配。當有多個匹配結果時,在界面中顯示前進后退按鈕,以支持前后內容的選擇。

2.3.1 Actionbar中顯示搜索按鈕

首先在menu item生成時增加搜索按鈕,然后主activity implements OnQueryTextListener並實現onQueryTextChange和onQueryTextSubmit方法[2]。

    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.main, menu);
        
        searchView = (SearchView) MenuItemCompat.getActionView(menu.findItem(R.id.menu_search)); 
        searchView.setOnQueryTextListener(this);
        return true; 
    }
<menu xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    tools:context="com.zhigao.all_connect.MainActivity" >
    
        <item android:id="@+id/menu_search" 
            android:title="Search" 
            app:showAsAction="always"  
            app:actionViewClass="android.support.v7.widget.SearchView"
              />
</menu>

2.3.2 字符串匹配與結果保存

   用戶輸入完待搜索的字符點擊搜索之后,執行onQueryTextSubmit函數。采用stringSplit[i].toLowerCase().contains(arg0.toLowerCase())進行不區分大小寫的匹配操作。使用scrollTo函數進行scrollview的跳轉[5]。

    public boolean onQueryTextSubmit(String arg0) {
        // TODO Auto-generated method stub
        Log.v(TAG, "querysubmit"+arg0);
        matchedLine.clear();
        String []stringSplit=sortedResult.split("\n");
        for (int i = 0; i < stringSplit.length; i++) {
            //case insensitive match
            if (stringSplit[i].toLowerCase().contains(arg0.toLowerCase())) {
                matchedLine.add(i);
            }
        }

        if (matchedLine.size()==0) {
            Toast.makeText(getApplicationContext(), "no match!", Toast.LENGTH_SHORT).show();
            return false;
        }else if (matchedLine.size()==1) {
            
        }
        else {
            forwardButton.setVisibility(View.VISIBLE);
            backwardButton.setVisibility(View.VISIBLE);
        }
        scrollView.post(new Runnable() {
            @Override
            public void run() {
                int y = textView.getLayout().getLineTop(matchedLine.get(0));
                scrollView.scrollTo(0, y);
            }
        });
        searchView.clearFocus();
        return false;
    }

 

2.3.3 當有多個字符串可以匹配時的結果顯示

   基於relativelayout構造出button浮在textview上的效果,實現了當用戶向下滑動scrollview時,button能夠始終保持在右下方的位置[6]。用戶點擊按鈕進行向前或者向后的搜索操作。點擊textview之后取消按鈕的顯示。

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">
<ScrollView
    android:id="@+id/scrollView"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    >
     <TextView
        android:id="@+id/ssidTextView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
      />
 </ScrollView>

     <Button
         android:id="@+id/backwardButton"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:layout_alignParentBottom="true"
         android:layout_alignParentRight="true"
         android:background="@drawable/backward"
         />
           <Button
         android:id="@+id/forwardButton"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:layout_toLeftOf="@id/backwardButton"
         android:layout_alignParentBottom="true"
         android:background="@drawable/forward"
      />
</RelativeLayout>

2.4 生成有簽名apk時遇到的問題及目前解決方案

2.4.1 Duplicate id @+id/image問題[7]

 生成簽名apk運行lint檢查時,提示由Duplicate id @+id/image問題。即使是將android support library更新到23.0.1之后仍然出現。目前先將abc_activity_chooser_view.xml中的第二個@+id/image修改為@+id/image2。

2.4.2 This class should be public (android.support.v7.internal.widget.ActionBarView.HomeView)問題

   修改lint,讓其將這個問題從error判斷為warning。window->preferences -> Android Lint Preferences,搜索Instantiatable。將其設置為warning。

2.4.3 "abc_action_bar_home_description_format" is not translated in "mk-rMK" 問題

   因為目前不考慮支持過多語言,而且android這個包之后有可能再會更新。因此目前考慮先將lint的missing chanslation設置為warning。

三、完整源碼共享

https://github.com/jue-jiang/wifiAssist

四、apk下載

 https://github.com/jue-jiang/wifiAssist/blob/master/wifiAssist.apk

五、參考材料

[1]安卓手機如何查看WIFI密碼_百度經驗

[2]searchView.setOnQueryTextListener(this);

[3]java - Android Reading from an Input stream efficiently - Stack Overflow

[4]java - execute shell command from android - Stack Overflow

[5]java - How to scroll to a given line number, TextView inside ScrollView - Stack Overflow

[6]How to add a floating button on scrolling in android? - Stack Overflow

[7]Issue 73197 - android - abc_activity_chooser_view_include.xml uses android:id="@+id/image" twice - Android Open Source Project - Issue Tracker - Google Project Hosting


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM