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;
}
}
- 在
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
在任何Activity
或Fragment
中,都可以通过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
工具类的全局使用。它具有以下优点:
- 单例模式:确保全局只有一个实例。
- 全局访问:通过
Application
类在任何地方访问WifiUtils
。 - 高性能:后台线程执行耗时操作,避免阻塞主线程。
- 健壮性:详细的错误处理和状态检查。
- 易用性:模块化设计,接口清晰,易于扩展和维护。
在实际开发中,建议根据具体需求进一步调整和扩展功能。