1. 程式人生 > >Android開發——WiFi訊號檢測

Android開發——WiFi訊號檢測

1.首先在AndroidManifest.xml檔案中新增如下程式碼以開啟許可權:

<!-- 獲取WiFi狀態的許可權 -->
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
<!-- 改變網路狀態的許可權 -->
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE"/>
<!-- 獲取網路許可權 -->
<uses-permission android:name
="android.permission.INTERNET"/> <!-- 往SDCard寫入資料許可權 --> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> <!-- 在SDCard中建立與刪除檔案許可權 --> <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>
2.Android有三個跟獲取WiFi資訊相關的類:WifiManager,WifiInfo,ScanResult
  • WifiManage
 1 // 獲取系統wifi服務
 2 WifiManage wm = (WifiManager) getApplicationContext().getSystemService(WIFI_SERVICE);
 3 // 獲取當前所連線wifi的資訊
 4 WifiInfo wi = wm.getConnectionInfo();
 5 // 獲取掃描到的所有wifi資訊
 6 List<ScanResult> scanResults = wm.getScanResults();
 7 // 獲取當前手機wifi網絡卡狀態
 8 int state = wm.getWifiState();    //
state值為以下巨集定義 9 WifiManager.WIFI_STATE_ENABLED wifi網絡卡可用 10 WifiManager.WIFI_STATE_DISABLED wifi網絡卡不可用 11 WifiManager.WIFI_STATE_DISABLING wifi網絡卡正關閉 12 WifiManager.WIFI_STATE_ENABLING wifi網絡卡正開啟 13 WifiManager.WIFI_STATE_UNKNOWN 狀態未知
  • WifiInfo
1 WifiInfo wifiInfo = wifi_service.getConnectionInfo();    // 獲取當前所連線wifi的資訊
2 wi.getSSID();        // 獲取當前連線wifi的名詞
3 wi.getBSSID();       // 獲取路由器Mac地址,String型別
4 wi.getMacAddress();  // 獲取本機Mac地址
5 wi.getRssi();        // 獲取當前連線wifi的訊號強度,返回一個0~-100之間的int型資料
6 wi.getLinkSpeed();   // 獲取連線速度
7 WifiInfo.LINK_SPEED_UNITS; // 連線速度單位

注:RSSI,得到的值是一個0到-100的區間值,是一個int型資料,其中0到-50表示訊號最好,-50到-70表示訊號偏差,小於-70表示最差,有可能連線不上或者掉線,一般Wifi已斷則值為-200。

  • ScanResult
scanResult.SSID();
scanResult.BSSID();
scanResult.level;    // 訊號強度(原始資料)
WifiManager.calculateSignalLevel(scanResult.level(),5); // 計算強度等級,此處分5級。

3.程式碼

  • activity_main.xml資原始檔
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
    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"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.lee.rss_collector.MainActivity">

    <RelativeLayout
        android:id="@+id/relative_layout"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_margin="30dp"
        android:gravity="start|center_vertical">

        <Button
            android:id="@+id/start_button"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentStart="true"
            android:layout_marginStart="20dp"
            android:text="@string/start_scan" />

        <Button
            android:id="@+id/stop_button"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginStart="10dp"
            android:layout_toEndOf="@+id/start_button"
            android:text="@string/stop_scan" />

        <Button
            android:id="@+id/save_button"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginStart="10dp"
            android:layout_toEndOf="@+id/stop_button"
            android:text="@string/save_button" />

        <LinearLayout
            android:id="@+id/curr_connected"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_below="@+id/start_button"
            android:layout_marginTop="10dp"
            android:orientation="vertical">

            <TextView
                android:id="@+id/text_view_curr_connected"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:text="@string/curConnectWiFi" />

            <EditText
                android:id="@+id/edit_text_curr_connected"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:cursorVisible="false"
                android:focusable="false"
                android:focusableInTouchMode="false" />
        </LinearLayout>

        <LinearLayout
            android:id="@+id/scan_result"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical"
            android:layout_below="@+id/curr_connected">

            <TextView
                android:id="@+id/text_view_scan_result"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginBottom="20dp"
                android:text="@string/scanResult" />
            <ScrollView
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:fadingEdge="vertical"
                android:scrollbars="vertical">

                <LinearLayout
                    android:id="@+id/list_wifi"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:orientation="vertical">

                    <EditText
                        android:id="@+id/edit_view_scan_result"
                        android:layout_width="match_parent"
                        android:layout_height="wrap_content"
                        android:cursorVisible="false"
                        android:focusable="false"
                        android:focusableInTouchMode="false" />
                </LinearLayout>
            </ScrollView>
        </LinearLayout>

    </RelativeLayout>

    <android.support.constraint.Guideline
        android:id="@+id/guideline"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        app:layout_constraintGuide_begin="20dp" />

    <android.support.constraint.Guideline
        android:id="@+id/guideline2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        app:layout_constraintGuide_begin="20dp" />

    <android.support.constraint.Group
        android:id="@+id/group"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />
</android.support.constraint.ConstraintLayout>
  • MainActivity.java主程式
package com.lee.rss_collector;

import android.content.Context;
import android.net.wifi.ScanResult;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import android.os.Environment;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.EditText;
import android.widget.Toast;

import java.io.FileOutputStream;
import java.util.List;

public class MainActivity extends AppCompatActivity {

    // private Context mContext = getApplicationContext();  // 加這一句會閃退
    public boolean mFlag = true;    // 控制執行緒終止
    private String mCurrentConnect; // 儲存當前所連WiFi資訊
    private StringBuilder mListInfo;// 儲存掃描的WiFi列表資訊
    private ScanThread mScanThread; // WiFi掃描的執行緒

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // 顯示主頁面
        setContentView(R.layout.activity_main);

        // 監聽三個按鈕
        findViewById(R.id.start_button).setOnClickListener(mOnClickListener);
        findViewById(R.id.stop_button).setOnClickListener(mOnClickListener);
        findViewById(R.id.save_button).setOnClickListener(mOnClickListener);
    }

    public View.OnClickListener mOnClickListener = new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            switch (v.getId()){
                case R.id.start_button:
                    mFlag = true;   // 標誌位置為true,允許執行緒執行
                    mScanThread = new ScanThread(); // 新建WiFi掃描執行緒
                    mScanThread.start();    // 啟動執行緒
                    break;
                case R.id.stop_button:
                    mFlag = false;  // 標誌位置為false,終止執行緒
                    break;
                case R.id.save_button:
                    String filename = "wifi_data.txt";
                    String fileContent = mListInfo.toString();
                    try{
                        savaFileToSD(filename,fileContent);
                        Toast.makeText(getApplicationContext(), "資料寫入成功", Toast.LENGTH_SHORT).show();
                    }catch (Exception e){
                        e.printStackTrace();
                        Toast.makeText(getApplicationContext(), "資料寫入失敗", Toast.LENGTH_SHORT).show();
                    }
                    break;
            }
        }
    };

    private class ScanThread extends Thread {
        @Override
        public void run() {
            while (mFlag) {
                // 在UI執行緒中獲取WiFi資訊,並更新UI
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        obtainListInfo();
                    }
                });
                // 取樣頻率500ms
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    private void obtainListInfo(){

        WifiManager wm = (WifiManager) getApplicationContext().getSystemService(WIFI_SERVICE);
        WifiInfo wi = wm.getConnectionInfo();
        String ssid = wi.getSSID();
        String bssid = wi.getBSSID();
        int rssi = wi.getRssi();
        int speed = wi.getLinkSpeed();

        // 記錄當前所連WiFi資訊
        mCurrentConnect = "SSID: " + ssid +
                                "\nMAC Address: " + bssid +
                                "\nSignal Strength(dBm): " + rssi +
                                "\nspeed: " + speed + " " + WifiInfo.LINK_SPEED_UNITS;
        // 記錄掃描的WiFi列表資訊
        if (wm.getWifiState() == WifiManager.WIFI_STATE_ENABLED) {
            mListInfo = new StringBuilder();
            List<ScanResult> scanResults = wm.getScanResults();
            for (ScanResult sr:scanResults){
                mListInfo.append("SSID: ");
                mListInfo.append(sr.SSID);
                mListInfo.append("\nMAC Address: ");
                mListInfo.append(sr.BSSID);
                mListInfo.append("\nSignal Strength(dBm): ");
                mListInfo.append(sr.level);
                mListInfo.append("\n\n");
            }

            // 更新UI上顯示的WiFi資訊
            EditText editTextCurr = findViewById(R.id.edit_text_curr_connected);
            EditText editTextList = findViewById(R.id.edit_view_scan_result);
            editTextCurr.setText(mCurrentConnect);
            editTextList.setText(mListInfo.toString());
        }
    }
    //往SD卡寫入檔案的方法
    public void savaFileToSD(String filename,String fileContent) throws Exception {
        // 先判斷是否有SD卡以及是否有讀取SD卡的許可權
        if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
            // 設定檔案路徑
            String filePath = Environment.getExternalStorageDirectory().getCanonicalPath() + "/" + filename;
            // new一個檔案輸出流物件
            FileOutputStream output = new FileOutputStream(filePath);
            //將String字串以位元組流的形式寫入到輸出流中
            output.write(fileContent.getBytes());
            output.close();     //關閉輸出流
        } else {
            Toast.makeText(MainActivity.this, "SD卡不存在或者不可讀寫", Toast.LENGTH_SHORT).show();
        }
    }
}