当前位置: 首页 > article >正文

Android打造易用的 WiFi 工具类:WifiUtils 封装实践

Android在全局范围内使用WifiUtils工具类,我们可以将其设计为一个单例,并通过Application类进行初始化。这样可以确保在整个应用程序中只有一个WifiUtils实例,并且可以在任何地方访问它。以下是实现全局使用的步骤和代码示例:

记得在AndroidManifest.xml配置文件中配置权限:

<!--    网络权限-->
    <uses-permission android:name="android.permission.INTERNET"/>
<!--    wifi权限-->
    <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_NETWORK_STATE"/>
    <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE"/>

1. 创建自定义Application

首先,创建一个自定义的Application类,用于初始化WifiUtils

import android.app.Application;

public class MyApplication extends Application {

    private static MyApplication instance;
    private WifiUtils wifiUtils;

    @Override
    public void onCreate() {
        super.onCreate();
        instance = this;
        wifiUtils = WifiUtils.getInstance(this);
    }

    public static MyApplication getInstance() {
        return instance;
    }

    public WifiUtils getWifiUtils() {
        return wifiUtils;
    }
}

  1. AndroidManifest.xml中注册Application

AndroidManifest.xml中,将MyApplication类设置为应用程序的Application类。

 <application
        android:name=".MyApplication"
        android:allowBackup="true"
        android:dataExtractionRules="@xml/data_extraction_rules"
        android:fullBackupContent="@xml/backup_rules"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/Theme.MyPagerViewDemo"
        tools:targetApi="31">
    ...
</application>

3. 修改WifiUtils工具类

确保WifiUtils是一个单例类,并且可以通过Application类访问。

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.wifi.ScanResult;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import android.net.wifi.WifiNetworkSuggestion;
import android.os.Build;
import android.os.Handler;
import android.os.Looper;
import android.text.TextUtils;
import android.util.Log;
import androidx.annotation.NonNull;
import androidx.annotation.RequiresApi;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;

public class WifiUtils {

    private static final String TAG = "WifiUtils";
    private static final int CONNECTION_TIMEOUT = 30000; // 30秒超时
    private static final int MAX_RETRY_COUNT = 3; // 最大重试次数

    private static WifiUtils instance;
    private WifiManager wifiManager;
    private Context context;
    private Handler mainHandler;
    private Set<ScanResult> cachedScanResults;
    private WifiStateReceiver wifiStateReceiver;
    private AtomicBoolean isConnecting = new AtomicBoolean(false);
    private Runnable connectionTimeoutTask;
    private int retryCount = 0;

    // 回调接口
    public interface WifiConnectionListener {
        void onConnectionSuccess();
        void onConnectionFailure(String errorMessage);
    }

    public interface WifiScanListener {
        void onScanResultsReceived(List<ScanResult> scanResults);
        void onScanFailure(String errorMessage);
    }

    // 单例模式
    public static synchronized WifiUtils getInstance(Context context) {
        if (instance == null) {
            instance = new WifiUtils(context.getApplicationContext());
        }
        return instance;
    }

    private WifiUtils(Context context) {
        this.context = context;
        this.wifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
        this.mainHandler = new Handler(Looper.getMainLooper());
        this.cachedScanResults = new HashSet<>();
        registerWifiStateReceiver();
    }

    // 注册WiFi状态监听
    private void registerWifiStateReceiver() {
        wifiStateReceiver = new WifiStateReceiver();
        IntentFilter filter = new IntentFilter();
        filter.addAction(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION);
        filter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
        context.registerReceiver(wifiStateReceiver, filter);
    }

    // 注销WiFi状态监听
    public void unregisterWifiStateReceiver() {
        if (wifiStateReceiver != null) {
            context.unregisterReceiver(wifiStateReceiver);
            wifiStateReceiver = null;
        }
    }

    // 检查WiFi是否启用
    public boolean isWifiEnabled() {
        return wifiManager != null && wifiManager.isWifiEnabled();
    }

    // 启用WiFi
    public boolean enableWifi() {
        if (wifiManager != null) {
            return wifiManager.setWifiEnabled(true);
        }
        return false;
    }

    // 扫描WiFi
    public void startScan(@NonNull WifiScanListener listener) {
        if (wifiManager == null) {
            listener.onScanFailure("WifiManager is not available");
            return;
        }

        new Thread(() -> {
            boolean scanSuccess = wifiManager.startScan();
            if (!scanSuccess) {
                mainHandler.post(() -> listener.onScanFailure("Failed to start scan"));
            }
        }).start();
    }

    // 获取扫描结果
    public List<ScanResult> getScanResults() {
        return new ArrayList<>(cachedScanResults);
    }

    // 连接到指定WiFi
    public void connectToWifi(@NonNull String ssid, @NonNull String password, WifiConnectionListener listener) {
        if (isConnecting.get()) {
            listener.onConnectionFailure("A connection attempt is already in progress");
            return;
        }

        if (TextUtils.isEmpty(ssid) || TextUtils.isEmpty(password)) {
            listener.onConnectionFailure("SSID or password is empty");
            return;
        }

        if (!isWifiEnabled()) {
            listener.onConnectionFailure("WiFi is not enabled");
            return;
        }

        isConnecting.set(true);
        startConnectionTimeout(listener);

        new Thread(() -> {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
                connectToWifiWithSuggestion(ssid, password, listener);
            } else {
                connectToWifiLegacy(ssid, password, listener);
            }
        }).start();
    }

    // 传统方式连接WiFi(Android 9及以下)
    private void connectToWifiLegacy(String ssid, String password, WifiConnectionListener listener) {
        WifiConfiguration config = createWifiConfig(ssid, password);
        if (config == null) {
            handleConnectionFailure(listener, "Failed to create WifiConfiguration");
            return;
        }

        int netId = wifiManager.addNetwork(config);
        if (netId == -1) {
            handleConnectionFailure(listener, "Failed to add network");
            return;
        }

        boolean isDisconnected = wifiManager.disconnect();
        if (!isDisconnected) {
            handleConnectionFailure(listener, "Failed to disconnect from current network");
            return;
        }

        boolean isEnabled = wifiManager.enableNetwork(netId, true);
        if (!isEnabled) {
            handleConnectionFailure(listener, "Failed to enable network");
            return;
        }

        boolean isReconnected = wifiManager.reconnect();
        if (!isReconnected) {
            handleConnectionFailure(listener, "Failed to reconnect");
            return;
        }

        handleConnectionSuccess(listener);
    }

    // 使用WifiNetworkSuggestion连接WiFi(Android 10及以上)
    @RequiresApi(api = Build.VERSION_CODES.Q)
    private void connectToWifiWithSuggestion(String ssid, String password, WifiConnectionListener listener) {
        WifiNetworkSuggestion suggestion = new WifiNetworkSuggestion.Builder()
                .setSsid(ssid)
                .setWpa2Passphrase(password)
                .setIsHiddenSsid(false)
                .build();

        List<WifiNetworkSuggestion> suggestionsList = new ArrayList<>();
        suggestionsList.add(suggestion);

        int status = wifiManager.addNetworkSuggestions(suggestionsList);
        if (status == WifiManager.STATUS_NETWORK_SUGGESTIONS_SUCCESS) {
            handleConnectionSuccess(listener);
        } else {
            handleConnectionFailure(listener, "Failed to add network suggestion");
        }
    }

    // 处理连接成功
    private void handleConnectionSuccess(WifiConnectionListener listener) {
        isConnecting.set(false);
        retryCount = 0;
        mainHandler.removeCallbacks(connectionTimeoutTask);
        mainHandler.post(listener::onConnectionSuccess);
    }

    // 处理连接失败
    private void handleConnectionFailure(WifiConnectionListener listener, String errorMessage) {
        if (retryCount < MAX_RETRY_COUNT) {
            retryCount++;
            Log.d(TAG, "Retrying connection attempt " + retryCount);
            connectToWifi(ssid, password, listener);
        } else {
            isConnecting.set(false);
            retryCount = 0;
            mainHandler.removeCallbacks(connectionTimeoutTask);
            mainHandler.post(() -> listener.onConnectionFailure(errorMessage));
        }
    }

    // 启动连接超时任务
    private void startConnectionTimeout(WifiConnectionListener listener) {
        connectionTimeoutTask = () -> handleConnectionFailure(listener, "Connection timed out");
        mainHandler.postDelayed(connectionTimeoutTask, CONNECTION_TIMEOUT);
    }

    // 创建WifiConfiguration
    private WifiConfiguration createWifiConfig(String ssid, String password) {
        try {
            WifiConfiguration config = new WifiConfiguration();
            config.SSID = String.format("\"%s\"", ssid);
            config.preSharedKey = String.format("\"%s\"", password);
            config.status = WifiConfiguration.Status.ENABLED;
            config.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.TKIP);
            config.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.CCMP);
            config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
            config.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.TKIP);
            config.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.CCMP);
            config.allowedProtocols.set(WifiConfiguration.Protocol.RSN);
            return config;
        } catch (Exception e) {
            Log.e(TAG, "Failed to create WifiConfiguration: " + e.getMessage());
            return null;
        }
    }

    // 获取当前连接的WiFi信息
    public WifiInfo getConnectedWifiInfo() {
        if (wifiManager != null) {
            return wifiManager.getConnectionInfo();
        }
        return null;
    }

    // 断开当前WiFi连接
    public boolean disconnectFromWifi() {
        if (wifiManager != null) {
            return wifiManager.disconnect();
        }
        return false;
    }

    // WiFi状态监听器
    private class WifiStateReceiver extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent) {
            if (WifiManager.SCAN_RESULTS_AVAILABLE_ACTION.equals(intent.getAction())) {
                // 更新缓存扫描结果
                if (wifiManager != null) {
                    cachedScanResults = new HashSet<>(wifiManager.getScanResults());
                }
            } else if (WifiManager.NETWORK_STATE_CHANGED_ACTION.equals(intent.getAction())) {
                // 处理网络状态变化
                WifiInfo wifiInfo = getConnectedWifiInfo();
                if (wifiInfo != null) {
                    Log.d(TAG, "Connected to: " + wifiInfo.getSSID());
                }
            }
        }
    }
}

4. 在全局范围内使用WifiUtils

在任何ActivityFragment中,都可以通过MyApplication类获取WifiUtils实例,并调用其方法。

public class MainActivity extends AppCompatActivity {

    private WifiUtils wifiUtils;

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

        // 获取WifiUtils实例
        wifiUtils = ((MyApplication) getApplication()).getWifiUtils();

        // 检查并启用WiFi
        if (!wifiUtils.isWifiEnabled()) {
            wifiUtils.enableWifi();
        }

        // 扫描WiFi
        wifiUtils.startScan(new WifiUtils.WifiScanListener() {
            @Override
            public void onScanResultsReceived(List<ScanResult> scanResults) {
                for (ScanResult result : scanResults) {
                    Log.d("WifiScan", "SSID: " + result.SSID);
                }
            }

            @Override
            public void onScanFailure(String errorMessage) {
                Log.e("WifiScan", "Scan failed: " + errorMessage);
            }
        });

        // 连接到指定WiFi
        String ssid = "YourWiFiSSID";
        String password = "YourWiFiPassword";
        wifiUtils.connectToWifi(ssid, password, new WifiUtils.WifiConnectionListener() {
            @Override
            public void onConnectionSuccess() {
                Log.d("WifiConnect", "Connected to " + ssid);
            }

            @Override
            public void onConnectionFailure(String errorMessage) {
                Log.e("WifiConnect", "Failed to connect: " + errorMessage);
            }
        });

        // 获取当前连接的WiFi信息
        WifiInfo wifiInfo = wifiUtils.getConnectedWifiInfo();
        if (wifiInfo != null) {
            Log.d("WifiInfo", "Connected to: " + wifiInfo.getSSID());
        }

        // 断开当前WiFi连接
        boolean isDisconnected = wifiUtils.disconnectFromWifi();
        if (isDisconnected) {
            Log.d("WifiDisconnect", "Disconnected from current WiFi");
        }
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        wifiUtils.unregisterWifiStateReceiver();
    }
}

5. 总结

通过以上步骤,我们实现了WifiUtils工具类的全局使用。它具有以下优点:

  1. 单例模式:确保全局只有一个实例。
  2. 全局访问:通过Application类在任何地方访问WifiUtils
  3. 高性能:后台线程执行耗时操作,避免阻塞主线程。
  4. 健壮性:详细的错误处理和状态检查。
  5. 易用性:模块化设计,接口清晰,易于扩展和维护。

在实际开发中,建议根据具体需求进一步调整和扩展功能。


http://www.kler.cn/a/579253.html

相关文章:

  • Oracle数据恢复:闪回表
  • 网络安全高级软件编程技术 网络安全 软件开发
  • laravel es 相关代码 ElasticSearch
  • olmOCR:高效精准的 PDF 文本提取工具
  • Deeplabv3+改进5:在主干网络中添加EMAattention|助力涨点!
  • WIFI ESP8266以及基础功能介绍
  • Python与SQL深度融合实战案例:打造你的数据处理秘籍
  • firewalld富规则配置黑名单
  • 小程序事件系统 —— 34 事件传参 - mark - 自定义数据
  • NXP MPC574x EE模拟-数据结构
  • VBA信息获取与处理第五节:如何在单个工作表中查找某个给定值
  • JAVA入门——网络编程简介
  • 游戏引擎学习第141天
  • 蓝桥杯 砍柴
  • 2025科技项目申报预测月历来啦!
  • 【AI】AI开源IDE:CLine源码分析报告
  • 达梦数据库导入数据,通过命令的方式
  • Windows 11下Git Bash执行cURL脚本400问题、CMD/PowerShell不能执行多行文本等问题记录及解决方案
  • V8引擎中的垃圾回收机制如何工作?
  • 删除或替换 Word 中的首页、尾页以及其它指定范围的页