Android WiFi(一)

Android WiFi

WiFi相关的知识点,我是第一次接触,所以比较零碎

Wifi基础知识

WiFi Scan

官方文档对WiFi扫描的说明:

比较完整的例子,可参考:

按照官方文档,大致的步骤:

1.为 SCAN_RESULTS_AVAILABLE_ACTION 注册一个广播监听器,系统会在完成扫描请求时调用此监听器,提供其成功/失败状态

2.使用 WifiManager.startScan() 请求扫描

3.使用 WifiManager.getScanResults() 获取扫描结果

在使用之前,需要下面的相关权限:

<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
  • ACCESS_WIFI_STATE - Allows applications to access information about Wi-Fi networks.
  • CHANGE_WIFI_STATE - Allows applications to change Wi-Fi connectivity state.

ACCESS_FINE_LOCATIONACCESS_COARSE_LOCATION属于危险权限,需要运行时权限

android.permission.ACCESS_NETWORK_STATEandroid.permission.ACCESS_WIFI_STATE的区别

参考:

android.permission.ACCESS_NETWORK_STATE is needed for accessing ConnectivityManager (mainly for monitoring network connections in general), while android.permission.ACCESS_WIFI_STATE grants access to WifiManager (for managing all aspects of Wi-Fi connectivity in particular).

例子如下:

public class MainActivity extends AppCompatActivity {
    private static final String TAG = "MainActivity-TAG";
    //需要先申请的权限
    String[] permissions = new String[] {
            Manifest.permission.ACCESS_FINE_LOCATION,
            Manifest.permission.ACCESS_COARSE_LOCATION
    };

    private WifiManager mWifiManager;
    private ListView mListView;
    private Button mScanBtn;
    private List<ScanResult> mResults;
    private ArrayList<String> mArrayList = new ArrayList<>();
    private ArrayAdapter mAdapter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        requestPermissions();

        mScanBtn = findViewById(R.id.scanBtn);
        mListView = findViewById(R.id.wifiList);



        mScanBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                scanWiFi();
            }
        });

        mWifiManager = (WifiManager) getSystemService(Context.WIFI_SERVICE);
        if (!mWifiManager.isWifiEnabled()) {
            Toast.makeText(MainActivity.this, "WiFi is disabled... we need enable it", Toast.LENGTH_SHORT).show();
            //Enable or disable Wi-Fi.
            //Applications must have the android.Manifest.permission.CHANGE_WIFI_STATE permission to toggle wifi.
            mWifiManager.setWifiEnabled(true);
        }

        mAdapter = new ArrayAdapter(this, android.R.layout.simple_list_item_1, mArrayList);
        mListView.setAdapter(mAdapter);

        scanWiFi();


    }

    //扫描WiFi
    private void scanWiFi() {
        mArrayList.clear();

        registerReceiver(wifiReceiver, new IntentFilter(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION));
        mWifiManager.startScan();
        Toast.makeText(this, "Scanning WiFi...", Toast.LENGTH_SHORT).show();
    }

    // 请求权限
    private void requestPermissions() {
        for (String permission : permissions) {
            if (checkSelfPermission(permission) != PackageManager.PERMISSION_GRANTED) {
                ActivityCompat.requestPermissions(MainActivity.this, permissions, 100);
            }
        }
    }

    BroadcastReceiver wifiReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            if (intent != null) {
                String action = intent.getAction();
                Log.d(TAG, "onReceive:" + action);

                if (action.equals(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION)) {
                    unregisterReceiver(this);

                    boolean success = intent.getBooleanExtra(WifiManager.EXTRA_RESULTS_UPDATED, false);
                    if (success) {
                        Toast.makeText(MainActivity.this, "Scan success", Toast.LENGTH_SHORT).show();

                        mResults = mWifiManager.getScanResults();
                        for (ScanResult scanResult : mResults) {
                            mArrayList.add(scanResult.SSID + " - " + scanResult.capabilities);
                            mAdapter.notifyDataSetChanged();
                        }

                    } else {
                        Toast.makeText(MainActivity.this, "Scan fail", Toast.LENGTH_SHORT).show();
                    }

                }
            }
        }
    };

}

1.开启手机WLAN,扫描结果如下:

005

2.如果未开启WLAN,调用mWifiManager.setWifiEnabled(true)后,在本人的oppo手机上有如下的弹窗出现

006

如果选择了允许,WiFi扫描也会成功,列表中也会有扫描结果

我原本以为mWifiManager.setWifiEnabled(true)会把手机的WLAN开关打开,但是却并非如此,WLAN还是关闭状态

007

还需要注意的是setWifiEnabled (boolean enabled)方法已废弃

Starting with Build.VERSION_CODES#Q, applications are not allowed to enable/disable Wi-Fi. Compatibility Note: For applications targeting Build.VERSION_CODES.Q or above, this API will always fail and return false. If apps are targeting an older SDK (Build.VERSION_CODES.P or below), they can continue to use this API.

Deprecation Exemptions:(废弃豁免)

  • Device Owner (DO), Profile Owner (PO) and system apps.

Enable or disable Wi-Fi.

Applications must have the Manifest.permission.CHANGE_WIFI_STATE permission to toggle wifi.

如何解决这个废弃的问题,可参考:

Intent panelIntent = new Intent(Settings.Panel.ACTION_INTERNET_CONNECTIVITY);
startActivityForResult(panelIntent, 100);

此时如果WLAN被关闭,将会打开如下的界面

008

连接WiFi

原来连接WiFi大概要使用如下的方法和类

  • WifiConfiguration
  • WifiManager#addNetwork
  • WifiManager#enableNetwork
  • WifiManager#disableNetwork

按如下的方式来连接WiFi

    private void connectWiFi(String networkCapabilities, String networkSSID) {

        Toast.makeText(this, "Connecting to network: "+ networkSSID, Toast.LENGTH_SHORT).show();

        String networkPass = "password";

        WifiConfiguration wifiConfig = new WifiConfiguration();
        wifiConfig.SSID =  "\"" + networkSSID + "\"";

        if(networkCapabilities.toUpperCase().contains("WEP")) { // WEP Network.
            Toast.makeText(this, "WEP Network", Toast.LENGTH_SHORT).show();

            wifiConfig.wepKeys[0] = "\"" + networkPass + "\"";
            wifiConfig.wepTxKeyIndex = 0;
            wifiConfig.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
            wifiConfig.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.WEP40);
        } else if(networkCapabilities.toUpperCase().contains("WPA")) { // WPA Network
            Toast.makeText(this, "WPA Network", Toast.LENGTH_SHORT).show();
            wifiConfig.preSharedKey = "\""+ networkPass +"\"";
        } else  { // OPEN Network.
            Toast.makeText(this, "OPEN Network", Toast.LENGTH_SHORT).show();
            wifiConfig.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
        }

        int result =  mWifiManager.addNetwork(wifiConfig);

        List<WifiConfiguration> list = this.mWifiManager.getConfiguredNetworks();
        for( WifiConfiguration config : list ) {
            if(config.SSID != null && config.SSID.equals("\"" + networkSSID + "\"")) {
                this.mWifiManager.disconnect();
                this.mWifiManager.enableNetwork(config.networkId, true);
                this.mWifiManager.reconnect();
                break;
            }
        }
    }

但由于mWifiManager.addNetwork(wifiConfig)该方法一直返回的是-1,所以一直没有成功

009

addNetwork方法有如下的介绍:

010

在Android 10 及以上中,一直返回-1

而我手机的版本为Android 11,我估计是这个问题造成的,该怎么处理了?

在网上找到了如下的方法

    //连接WiFi
    private void connectWiFi(String networkCapabilities, String networkSSID) {

        Toast.makeText(this, "Connecting to network: "+ networkSSID, Toast.LENGTH_SHORT).show();

        String networkPass = "xingxing_password";

        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.Q) {
            NetworkSpecifier specifier =
                    new WifiNetworkSpecifier.Builder()
                            .setSsidPattern(new PatternMatcher(networkSSID, PatternMatcher.PATTERN_PREFIX))
                            .setWpa2Passphrase(networkPass)
                            .build();

            NetworkRequest request =
                    new NetworkRequest.Builder()
                            .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
                            .removeCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
                            .setNetworkSpecifier(specifier)
                            .build();

            ConnectivityManager connectivityManager = (ConnectivityManager) this.getSystemService(Context.CONNECTIVITY_SERVICE);

            ConnectivityManager.NetworkCallback networkCallback = new ConnectivityManager.NetworkCallback() {
                @Override
                public void onAvailable(Network network) {
                    // do success processing here..
                    Log.d(TAG, "onAvailable " + network.toString());
                }

                @Override
                public void onUnavailable() {
                    // do failure processing here..

                    Log.d(TAG, "onUnavailable ");
                }
            };
            connectivityManager.requestNetwork(request, networkCallback);
            // Release the request when done.
            // connectivityManager.unregisterNetworkCallback(networkCallback);
        }
    }

在我oppo Android11手机上,当通过上面的方法连接某个WiFi时,会跳转到如下的页面:

011

点击要连接的WiFi后,会自动连接上对应的WiFi,不需要输入密码

注意

1.需要申请如下的权限

<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
<uses-permission android:name="android.permission.WRITE_SETTINGS" />

否则可能会有如下的提示:

java.lang.SecurityException: com.example.wifidemo was not granted  either of these permissions: android.permission.CHANGE_NETWORK_STATE, android.permission.WRITE_SETTINGS.

2.测试的时候,WLAN要开启

可参考:

其它方法

1.getWifiState()

public int getWifiState ()

Gets the Wi-Fi enabled state.

检查当前wifi状态.

  • WIFI_STATE_DISABLING - Wi-Fi is currently being disabled. The state will change to WIFI_STATE_DISABLED if it finishes successfully. 值为0
  • WIFI_STATE_DISABLED - Wi-Fi is disabled. 值为1
  • WIFI_STATE_ENABLING - Wi-Fi is currently being enabled. The state will change to WIFI_STATE_ENABLED if it finishes successfully. 值为2
  • WIFI_STATE_ENABLED - Wi-Fi is enabled. 值为3
  • WIFI_STATE_UNKNOWN - Wi-Fi is in an unknown state. This state will occur when an error happens while enabling or disabling. 值为4
// 获取WiFi状态
private void getWiFiState() {
    int wifiState = mWifiManager.getWifiState();
    switch (wifiState) {
        case WifiManager.WIFI_STATE_ENABLED:
            Log.d(TAG, "wifiState = " + wifiState + " WIFI_STATE_ENABLED");
            break;
        case WifiManager.WIFI_STATE_DISABLED:
            Log.d(TAG, "wifiState = " + wifiState + " WIFI_STATE_DISABLED");
            break;
        default:
            break;
    }
}

如果打开WLAN开关,WiFi状态为WIFI_STATE_ENABLED

2021-08-17 15:08:10.602 10282-10282/com.example.wifidemo D/MainActivity-TAG: wifiState = 3 WIFI_STATE_ENABLED

如果关闭WLAN,WiFi状态为WIFI_STATE_DISABLED

2021-08-17 15:10:36.497 13093-13093/com.example.wifidemo D/MainActivity-TAG: wifiState = 1 WIFI_STATE_DISABLED

2.getConnectionInfo

public WifiInfo getConnectionInfo ()

Return dynamic information about the current Wi-Fi connection, if any is active.

当前wifi连接信息

注意这个方法在最新的版本中也是废弃了

This method was deprecated in API level 31.
Starting with Build.VERSION_CODES#S, WifiInfo retrieval is moved to ConnectivityManager API surface. WifiInfo is attached in NetworkCapabilities#getTransportInfo() which is available via callback in NetworkCallback#onCapabilitiesChanged(Network, NetworkCapabilities) or on-demand from ConnectivityManager#getNetworkCapabilities(Network).

如下的例子:

WifiInfo wifiInfo = mWifiManager.getConnectionInfo();
int ip = wifiInfo.getIpAddress();
String macAddress = wifiInfo.getMacAddress();
String bssid = wifiInfo.getBSSID();
int rssi = wifiInfo.getRssi();
int linkspeed = wifiInfo.getLinkSpeed();
String ssid = wifiInfo.getSSID();
int networkId = wifiInfo.getNetworkId();
String ipAddress = Formatter.formatIpAddress(ip);

Log.d(TAG, "macAddress = " + macAddress);
Log.d(TAG, "bssid = " + bssid);
Log.d(TAG, "rssi = " + rssi);
Log.d(TAG, "linkspeed = " + linkspeed);
Log.d(TAG, "ssid = " + ssid);
Log.d(TAG, "networkId = " + networkId);
Log.d(TAG, "ipAddress = " + ipAddress);

当前本人手机连接信息

2021-08-17 14:23:41.086 30534-30534/com.example.wifidemo D/MainActivity-TAG: macAddress = 02:00:00:00:00:00
2021-08-17 14:23:41.086 30534-30534/com.example.wifidemo D/MainActivity-TAG: bssid = ec:26:ca:c9:7d:3e
2021-08-17 14:23:41.086 30534-30534/com.example.wifidemo D/MainActivity-TAG: rssi = -33
2021-08-17 14:23:41.086 30534-30534/com.example.wifidemo D/MainActivity-TAG: linkspeed = 72
2021-08-17 14:23:41.086 30534-30534/com.example.wifidemo D/MainActivity-TAG: ssid = "xingxing"
2021-08-17 14:23:41.086 30534-30534/com.example.wifidemo D/MainActivity-TAG: networkId = 6
2021-08-17 14:23:41.086 30534-30534/com.example.wifidemo D/MainActivity-TAG: ipAddress = 192.168.2.102

3.另一种监测WiFi是否开启的方法

在网络上看到了另一种监测WiFi状态的方codinginflow/AndroidManifest.xml

通过注册广播WifiManager.WIFI_STATE_CHANGED_ACTION

IntentFilter intentFilter = new IntentFilter(WifiManager.WIFI_STATE_CHANGED_ACTION);
registerReceiver(wifiStateReceiver, intentFilter);
    private BroadcastReceiver wifiStateReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            int wifiStateExtra = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE,
                    WifiManager.WIFI_STATE_UNKNOWN);

            switch (wifiStateExtra) {
                case WifiManager.WIFI_STATE_ENABLED:
                    wifiSwitch.setChecked(true);
                    wifiSwitch.setText("WiFi is ON");
                    break;
                case WifiManager.WIFI_STATE_DISABLED:
                    wifiSwitch.setChecked(false);
                    wifiSwitch.setText("WiFi is OFF");
                    break;
            }
        }
    };

4.WifiManager.NETWORK_STATE_CHANGED_ACTION

Broadcast intent action indicating that the state of Wi-Fi connectivity has changed. An extra provides the new state in the form of a NetworkInfo object. No network-related permissions are required to subscribe to this broadcast.

This broadcast is not delivered to manifest receivers in applications that target API version 26 or later.

表示的是 Wi-Fi连接状态改变

可参考:

        // 监听wifi的连接状态即是否连上了一个有效无线路由
        if (WifiManager.NETWORK_STATE_CHANGED_ACTION.equals(intent.getAction())) {
            Parcelable parcelableExtra = intent
                    .getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO);
            if (null != parcelableExtra) {
                // 获取联网状态的NetWorkInfo对象
                NetworkInfo networkInfo = (NetworkInfo) parcelableExtra;
                //获取的State对象则代表着连接成功与否等状态
                NetworkInfo.State state = networkInfo.getState();
                //判断网络是否已经连接
                boolean isConnected = state == NetworkInfo.State.CONNECTED;
                Log.e("TAG", "isConnected:" + isConnected);
                if (isConnected) {
                } else {

                }
            }
        }

参考资料

其它可参考的资料:

Github上有封装的类,可以参考下:

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值