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

Android 之wifi连接流程

一 流程描述

1.1 在Android 上连接WiFi网络主要包括以下几个步骤:

  • 打开WiFi;
  • 扫描可用的WiFi网络列表;
  • 选择要连接的WiFi网络;
  • 输入密码(如果需要);
  • 连接WiFi网络。
  • 监听网络状态

二 核心代码

2.1添加权限

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

2.2 打开wifi

WifiManager wifiManager = (WifiManager) getApplicationContext().getSystemService(Context.WIFI_SERVICE);
wifiManager.setWifiEnabled(true);

2.3 扫描可用的WiFi网络列表

wifiManager.startScan();
List<ScanResult> 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/Fragmentpublic interface WifiStateListener {void onWifiStateChanged(int state); // WiFi开关状态变化void onWifiConnected(String ssid);  // 连接到新WiFivoid onWifiDisconnected();          // WiFi断开连接void onSignalStrengthChanged(int strength); // 信号强度变化}public WifiReceiver(WifiStateListener listener) {this.listener = listener;}@Overridepublic 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已连接,获取SSIDWifiManager 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;}@Overridepublic void onAvailable(Network network) {super.onAvailable(network);Log.d(TAG, "网络可用: " + network.toString());if (listener != null) {// 延迟获取网络类型,确保信息已更新NetworkType type = getNetworkType(network);listener.onNetworkAvailable(type);}}@Overridepublic void onLost(Network network) {super.onLost(network);Log.d(TAG, "网络丢失: " + network.toString());if (listener != null) {NetworkType type = getNetworkType(network);listener.onNetworkLost(type);}}@Overridepublic 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 段可能变化)

http://www.xdnf.cn/news/18606.html

相关文章:

  • 使用 LangChain 和 Neo4j 构建知识图谱
  • 一文学会vue的动态权限控制
  • 00后AI创业者崛起与AI商业应用新玩法:从Mercor到历史人物复刻的机遇
  • 【剖析高并发秒杀】从流量削峰到数据一致性的架构演进与实践
  • MySQL GPG 密钥更新问题解决文档
  • Kubernetes网络服务全解析
  • Linux netfilter工作原理详解
  • Mac简单测试硬盘读写速度
  • 暴雨环境漏检率下降78%!陌讯动态融合算法在道路积水识别的工程突破
  • LeetCode 面试经典 150_数组/字符串_找出字符串中第一个匹配项的下标(23_28_C++_简单)(KMP 算法)
  • PyTorch 面试题及详细答案120题(71-85)-- 高级特性与工具
  • Base64 编码优化 Web 图片加载:异步响应式架构(Java 后端 + 前端全流程实现)
  • vue实现小程序oss分片上传
  • 合合信息acge模型获C-MTEB第一,文本向量化迎来新突破
  • 微前端架构核心要点对比
  • C++ 使用最新 MySQL Connector/C++(X DevAPI)+ CMake 完整教程
  • 力扣 30 天 JavaScript 挑战 第38天 (第九题)学习了 语句表达式的区别 高级函数 promise async await 节流
  • 《P3623 [APIO2008] 免费道路》
  • Redis Set 类型详解:从基础命令到实战应用
  • git实战(8)git高阶命令分析【结合使用场景】
  • 本地Docker部署开源Web相册图库Piwigo与在线远程访问实战方案
  • 如何优雅解决 OpenCV 分段错误(Segfault):子进程隔离实战
  • pig框架导入总结
  • 动手学深度学习(pytorch版):第六章节—卷积神经网络(1)从全连接层到卷积
  • 新能源汽车热管理仿真:蒙特卡洛助力神经网络训练
  • Text2SQL、ChatBI简介
  • [Vid-LLM] 功能分类体系 | 视频如何被“观看“ | LLM的主要作用
  • Flink2.0学习笔记:使用HikariCP 自定义sink实现数据库连接池化
  • 一键部署开源 Coze Studio
  • 第三阶段数据库-9:循环,编号,游标,分页