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;@Overridepublic void onCreate() {super.onCreate();instance = this;wifiUtils = WifiUtils.getInstance(this);}public static MyApplication getInstance() {return instance;}public WifiUtils getWifiUtils() {return wifiUtils;}
}
- 在
AndroidManifest.xml
中注册Application
类
在AndroidManifest.xml
中,将MyApplication
类设置为应用程序的Application
类。
<applicationandroid: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();}// 启用WiFipublic boolean enableWifi() {if (wifiManager != null) {return wifiManager.setWifiEnabled(true);}return false;}// 扫描WiFipublic 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);}// 连接到指定WiFipublic 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);}// 创建WifiConfigurationprivate 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 {@Overridepublic 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
在任何Activity
或Fragment
中,都可以通过MyApplication
类获取WifiUtils
实例,并调用其方法。
public class MainActivity extends AppCompatActivity {private WifiUtils wifiUtils;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);// 获取WifiUtils实例wifiUtils = ((MyApplication) getApplication()).getWifiUtils();// 检查并启用WiFiif (!wifiUtils.isWifiEnabled()) {wifiUtils.enableWifi();}// 扫描WiFiwifiUtils.startScan(new WifiUtils.WifiScanListener() {@Overridepublic void onScanResultsReceived(List<ScanResult> scanResults) {for (ScanResult result : scanResults) {Log.d("WifiScan", "SSID: " + result.SSID);}}@Overridepublic void onScanFailure(String errorMessage) {Log.e("WifiScan", "Scan failed: " + errorMessage);}});// 连接到指定WiFiString ssid = "YourWiFiSSID";String password = "YourWiFiPassword";wifiUtils.connectToWifi(ssid, password, new WifiUtils.WifiConnectionListener() {@Overridepublic void onConnectionSuccess() {Log.d("WifiConnect", "Connected to " + ssid);}@Overridepublic 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");}}@Overrideprotected void onDestroy() {super.onDestroy();wifiUtils.unregisterWifiStateReceiver();}
}
5. 总结
通过以上步骤,我们实现了WifiUtils
工具类的全局使用。它具有以下优点:
- 单例模式:确保全局只有一个实例。
- 全局访问:通过
Application
类在任何地方访问WifiUtils
。 - 高性能:后台线程执行耗时操作,避免阻塞主线程。
- 健壮性:详细的错误处理和状态检查。
- 易用性:模块化设计,接口清晰,易于扩展和维护。
在实际开发中,建议根据具体需求进一步调整和扩展功能。