完整教程:Android 之wifi连接流程
一 流程描述
1.1 在Android 上连接WiFi网络主要包括以下几个步骤:
- 打开WiFi;
- 扫描可用的WiFi网络列表;
- 选择要连接的WiFi网络;
- 输入密码(如果需要);
- 连接WiFi网络。
- 监听网络状态
二 核心代码
2.1添加权限
2.2 打开wifi
WifiManager wifiManager = (WifiManager) getApplicationContext().getSystemService(Context.WIFI_SERVICE);
wifiManager.setWifiEnabled(true);
2.3 扫描可用的WiFi网络列表
wifiManager.startScan();
List scanResults = wifiManager.getScanResults();
2.4 选择要连接的WiFi网络,如果需要密码还要输入密码
String ssid = "WiFi名称";
String password = "WiFi密码";
WifiConfiguration wifiConfig = new WifiConfiguration();
wifiConfig.SSID = "\"" + ssid + "\"";
wifiConfig.preSharedKey = "\"" + password + "\"";
int netId = wifiManager.addNetwork(wifiConfig);
wifiManager.enableNetwork(netId, true);
2.5 连接WiFi网络
wifiManager.reconnect();
2.6 监听网络状态,不同版本可能有所变化:
Android8.0之前使用广播形式监听网络状态:
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.net.wifi.WifiManager;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.Build;
import android.util.Log;
public class WifiReceiver extends BroadcastReceiver {
private static final String TAG = "WifiReceiver";
private WifiStateListener listener;
// 定义回调接口,用于将事件传递给Activity/Fragment
public interface WifiStateListener {
void onWifiStateChanged(int state); // WiFi开关状态变化
void onWifiConnected(String ssid); // 连接到新WiFi
void onWifiDisconnected(); // WiFi断开连接
void onSignalStrengthChanged(int strength); // 信号强度变化
}
public WifiReceiver(WifiStateListener listener) {
this.listener = listener;
}
@Override
public void onReceive(Context context, Intent intent) {
if (intent == null) return;
String action = intent.getAction();
if (action == null) return;
// 处理WiFi开关状态变化
if (action.equals(WifiManager.WIFI_STATE_CHANGED_ACTION)) {
handleWifiStateChanged(intent);
}
// 处理WiFi连接状态变化
else if (action.equals(ConnectivityManager.CONNECTIVITY_ACTION)) {
handleConnectivityChanged(context, intent);
}
// 处理WiFi信号强度变化(需注册特定广播)
else if (action.equals(WifiManager.RSSI_CHANGED_ACTION)) {
handleRssiChanged(context);
}
}
/**
* 处理WiFi开关状态变化
*/
private void handleWifiStateChanged(Intent intent) {
int state = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE, WifiManager.WIFI_STATE_UNKNOWN);
if (listener != null) {
listener.onWifiStateChanged(state);
}
switch (state) {
case WifiManager.WIFI_STATE_ENABLED:
Log.d(TAG, "WiFi已开启");
break;
case WifiManager.WIFI_STATE_DISABLED:
Log.d(TAG, "WiFi已关闭");
break;
case WifiManager.WIFI_STATE_ENABLING:
Log.d(TAG, "WiFi正在开启");
break;
case WifiManager.WIFI_STATE_DISABLING:
Log.d(TAG, "WiFi正在关闭");
break;
}
}
/**
* 处理WiFi连接状态变化
*/
private void handleConnectivityChanged(Context context, Intent intent) {
ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
if (cm == null) return;
NetworkInfo networkInfo;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
networkInfo = cm.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
} else {
// 旧版本兼容
networkInfo = intent.getParcelableExtra(ConnectivityManager.EXTRA_NETWORK_INFO);
}
if (networkInfo != null && networkInfo.getType() == ConnectivityManager.TYPE_WIFI) {
if (networkInfo.isConnected()) {
// WiFi已连接,获取SSID
WifiManager wifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
String ssid = wifiManager.getConnectionInfo().getSSID();
if (listener != null) {
listener.onWifiConnected(ssid);
}
Log.d(TAG, "已连接到WiFi: " + ssid);
} else {
if (listener != null) {
listener.onWifiDisconnected();
}
Log.d(TAG, "WiFi已断开");
}
}
}
/**
* 处理WiFi信号强度变化
*/
private void handleRssiChanged(Context context) {
WifiManager wifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
if (wifiManager == null) return;
int rssi = wifiManager.getConnectionInfo().getRssi();
if (listener != null) {
listener.onSignalStrengthChanged(rssi);
}
Log.d(TAG, "WiFi信号强度变化: " + rssi + " dBm");
}
}
Android8.0之后推荐使用 ConnectivityManager.NetworkCallback 来监听网络连接状态,它能更准确地反映网:
import android.content.Context;
import android.net.ConnectivityManager;
import android.net.Network;
import android.net.NetworkCapabilities;
import android.net.NetworkRequest;
import android.os.Build;
import android.util.Log;
public class NetworkMonitor {
private static final String TAG = "NetworkMonitor";
private Context context;
private ConnectivityManager connectivityManager;
private NetworkCallback callback;
private NetworkRequest networkRequest;
// 回调接口,对外提供网络状态事件
public interface NetworkListener {
void onNetworkAvailable(NetworkType type); // 网络可用
void onNetworkLost(NetworkType type); // 网络丢失
void onNetworkCapabilitiesChanged(NetworkType type, NetworkCapabilities capabilities); // 网络能力变化
}
// 网络类型枚举
public enum NetworkType {
WIFI, MOBILE, ETHERNET, OTHER, NONE
}
public NetworkMonitor(Context context, NetworkListener listener) {
this.context = context.getApplicationContext();
this.connectivityManager = (ConnectivityManager) this.context
.getSystemService(Context.CONNECTIVITY_SERVICE);
this.callback = new NetworkCallback(listener);
// 构建网络请求(可指定监听的网络类型)
this.networkRequest = new NetworkRequest.Builder()
// 监听所有具备互联网访问能力的网络
.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
// 可选:指定监听的网络类型(如只监听WiFi)
// .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
.build();
}
/**
* 开始监听网络状态
*/
public void startMonitoring() {
if (connectivityManager == null || networkRequest == null || callback == null) {
return;
}
// 注册网络回调(适配Android 10+的参数变化)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
connectivityManager.registerNetworkCallback(networkRequest, callback, null);
} else {
connectivityManager.registerNetworkCallback(networkRequest, callback);
}
}
/**
* 停止监听网络状态(必须调用,避免内存泄漏)
*/
public void stopMonitoring() {
if (connectivityManager != null && callback != null) {
connectivityManager.unregisterNetworkCallback(callback);
}
}
/**
* 网络回调实现类
*/
private static class NetworkCallback extends ConnectivityManager.NetworkCallback {
private NetworkListener listener;
public NetworkCallback(NetworkListener listener) {
this.listener = listener;
}
@Override
public void onAvailable(Network network) {
super.onAvailable(network);
Log.d(TAG, "网络可用: " + network.toString());
if (listener != null) {
// 延迟获取网络类型,确保信息已更新
NetworkType type = getNetworkType(network);
listener.onNetworkAvailable(type);
}
}
@Override
public void onLost(Network network) {
super.onLost(network);
Log.d(TAG, "网络丢失: " + network.toString());
if (listener != null) {
NetworkType type = getNetworkType(network);
listener.onNetworkLost(type);
}
}
@Override
public void onCapabilitiesChanged(Network network, NetworkCapabilities capabilities) {
super.onCapabilitiesChanged(network, capabilities);
Log.d(TAG, "网络能力变化: " + capabilities.toString());
if (listener != null) {
NetworkType type = getNetworkType(network, capabilities);
listener.onNetworkCapabilitiesChanged(type, capabilities);
}
}
/**
* 判断网络类型
*/
private NetworkType getNetworkType(Network network) {
return getNetworkType(network, null);
}
private NetworkType getNetworkType(Network network, NetworkCapabilities capabilities) {
if (capabilities == null) {
ConnectivityManager cm = (ConnectivityManager)
MyApplication.getContext().getSystemService(Context.CONNECTIVITY_SERVICE);
if (cm != null) {
capabilities = cm.getNetworkCapabilities(network);
}
}
if (capabilities == null) return NetworkType.NONE;
if (capabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)) {
return NetworkType.WIFI;
} else if (capabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)) {
return NetworkType.MOBILE;
} else if (capabilities.hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET)) {
return NetworkType.ETHERNET;
} else {
return NetworkType.OTHER;
}
}
}
}
三 拓展:根据 IP 地址获取对应的国家信息,通常需要借助IP 地址解析服务(第三方 API 或本地数据库),因为 IP 地址本身并不直接包含国家信息,而是需要通过 IP 与地理位置的映射关系来查询
3.1 方案一:IP-API 的免费接口
无需注册,直接通过 URL 调用:
http://ip-api.com/json/[IP地址](若不填 IP,默认查询本机公网 IP)
// 线程中执行
new Thread(() -> {
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url("http://ip-api.com/json/") // 查询本机IP的国家信息
.build();
try {
Response response = client.newCall(request).execute();
if (response.isSuccessful() && response.body() != null) {
String jsonData = response.body().string();
// 解析JSON数据
parseCountryInfo(jsonData);
}
} catch (IOException e) {
e.printStackTrace();
}
}).start();
IP-API 返回的 JSON 格式示例:
{
"status": "success",
"country": "China",
"countryCode": "CN",
"region": "BJ",
"regionName": "Beijing",
"city": "Beijing",
"zip": "",
"lat": 39.9042,
"lon": 116.4074,
"timezone": "Asia/Shanghai",
"isp": "China Unicom Beijing",
"org": "",
"as": "AS4837 China169 Backbone",
"query": "114.114.114.114"
}
解析代码:
private void parseCountryInfo(String jsonData) {
try {
JSONObject jsonObject = new JSONObject(jsonData);
String status = jsonObject.getString("status");
if ("success".equals(status)) {
String country = jsonObject.getString("country"); // 国家名(如"China")
String countryCode = jsonObject.getString("countryCode"); // 国家简写(如"CN")
// 处理结果(如保存到变量,用于后续语言适配)
Log.d("IPCountry", "国家:" + country + ",简写:" + countryCode);
}
} catch (JSONException e) {
e.printStackTrace();
}
}
3.2 方案 二:本地数据库方案(适合无网络场景)
下载免费的 GeoIP2 数据库(如GeoLite2-Country.mmdb
),放入assets
目录。
使用官方 SDK(如geoip2-java
)读取数据库,根据 IP 查询国家。
// 加载本地数据库
File database = new File(context.getFilesDir(), "GeoLite2-Country.mmdb");
// 从assets复制数据库到本地(首次启动时)
copyAssetToFile(context, "GeoLite2-Country.mmdb", database);
// 查询IP对应的国家
DatabaseReader reader = new DatabaseReader.Builder(database).build();
InetAddress ipAddress = InetAddress.getByName("114.114.114.114");
CountryResponse response = reader.country(ipAddress);
String countryCode = response.getCountry().getIsoCode(); // 国家简写(如"CN")
String countryName = response.getCountry().getName(); // 国家名(如"China")
注意:本地数据库体积较大(约几十 MB),且需要定期更新(IP 段可能变化)