android wifi(一)

龙永思
2023-12-01

最近一直在做盒子上的setting,涉及到wifi设置。

android源生的wifi设置代码很复杂,我所工作的项目是在盒子上,不需要那么复杂的功能。

首先注册广播,这一部分直接使用源生的代码,修改了其中的一部分。

private WifiModel(Context context) {

		mContext = context;

		mWifiManager = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE);

		mFilter = new IntentFilter();
		// 注册广播
		mFilter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
		mFilter.addAction(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION);
		mFilter.addAction(WifiManager.NETWORK_IDS_CHANGED_ACTION);
		mFilter.addAction(WifiManager.SUPPLICANT_STATE_CHANGED_ACTION);
		mFilter.addAction(WifiManager.CONFIGURED_NETWORKS_CHANGED_ACTION);
		mFilter.addAction(WifiManager.LINK_CONFIGURATION_CHANGED_ACTION);
		mFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
		mFilter.addAction(WifiManager.RSSI_CHANGED_ACTION);

		mReceiver = new BroadcastReceiver() {
			@Override
			public void onReceive(Context context, Intent intent) {
				handleEvent(context, intent);
			}
		};

		mScanner = new Scanner();

		mContext.registerReceiver(mReceiver, mFilter);
	}

// 处理广播
	private void handleEvent(Context context, Intent intent) {
		String action = intent.getAction();
		Log.i(TAG, action);
		// wifi状态改变
		if (WifiManager.WIFI_STATE_CHANGED_ACTION.equals(action)) {
			updateWifiState(intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE, WifiManager.WIFI_STATE_UNKNOWN));
		}
		// Scanner通过调用mWifiManager.startScan()处理定时扫描wifi列表
		else if (WifiManager.SCAN_RESULTS_AVAILABLE_ACTION.equals(action)
				|| WifiManager.CONFIGURED_NETWORKS_CHANGED_ACTION.equals(action)
				|| WifiManager.LINK_CONFIGURATION_CHANGED_ACTION.equals(action)) {
			updateAccessPoints();
		} else if (WifiManager.SUPPLICANT_STATE_CHANGED_ACTION.equals(action)) {
			// Ignore supplicant state changes when network is connected
			// TODO: we should deprecate SUPPLICANT_STATE_CHANGED_ACTION and
			// introduce a broadcast that combines the supplicant and network
			// network state change events so the apps dont have to worry about
			// ignoring supplicant state change when network is connected
			// to get more fine grained information.
			SupplicantState supplicantState = (SupplicantState) intent.getParcelableExtra(WifiManager.EXTRA_NEW_STATE);
			DetailedState state = WifiInfo.getDetailedStateOf(supplicantState);
			Log.i(TAG, action + "  " + WifiInfo.getDetailedStateOf(supplicantState) + "  " + mConnected.get() + "  "
					+ SupplicantState.isHandshakeState(supplicantState) + "  " + isHandshakeState(state));
			// 本来源生是使用SupplicantState.isHandshakeState(supplicantState)来判断某一wifi连接状态的,
			// 但是log显示它将DetailedState的DISCONNECTED状态过滤掉了,
			// 故自己写了一个方法isHandshakeState(state)来判断是否过滤
			// if (!mConnected.get() &&
			// SupplicantState.isHandshakeState(supplicantState)) {
			if (!mConnected.get() && isHandshakeState(state)) {
				//wifi连接状态更新
				updateConnectionState(WifiInfo.getDetailedStateOf(supplicantState));
			}
			int authState = intent.getIntExtra(WifiManager.EXTRA_SUPPLICANT_ERROR, -1);
			if (authState == WifiManager.ERROR_AUTHENTICATING) {
				updateAccessPoints();
			}
		}
		// 网络的连接状态改变
		else if (WifiManager.NETWORK_STATE_CHANGED_ACTION.equals(action)) {
			NetworkInfo info = (NetworkInfo) intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO);
			mConnected.set(info.isConnected());
			// if (!(isEthprefer && processWifiEthBothOn()))
			updateAccessPoints();
			Log.i(TAG, action + "  " + info.getDetailedState());
			updateConnectionState(info.getDetailedState());
		} else if (WifiManager.RSSI_CHANGED_ACTION.equals(action)) {
			updateConnectionState(null);
		}
	}

	private static boolean isHandshakeState(DetailedState state) {
		return state != DetailedState.IDLE && state != DetailedState.SCANNING;
	}


Wifi AP主要分为四种类型 NONE(无密码),WEP加密,PSK(WAP-PSK和WAP2-PSK),EAP(此种wifi网络过滤),获取wifi列表如下,并且已过滤EAP网络。

//此方法是获取wifi列表
	/** Returns sorted list of access points */
	private List<AccessPoint> constructAccessPoints() {
		ArrayList<AccessPoint> accessPoints = new ArrayList<AccessPoint>();
		/**
		 * Lookup table to more quickly update AccessPoints by only considering
		 * objects with the correct SSID. Maps SSID -> List of AccessPoints with
		 * the given SSID.
		 */
		Multimap<String, AccessPoint> apMap = new Multimap<String, AccessPoint>();

		//
		final List<WifiConfiguration> configs = mWifiManager.getConfiguredNetworks();
		if (configs != null) {
			for (WifiConfiguration config : configs) {
				AccessPoint accessPoint = new AccessPoint(config);
				accessPoint.update(mLastInfo, mLastState);
				accessPoints.add(accessPoint);
				apMap.put(accessPoint.ssid, accessPoint);

			}
		}

		final List<ScanResult> results = mWifiManager.getScanResults();
		if (results != null) {
			for (ScanResult result : results) {
				// Ignore hidden and ad-hoc networks.
				// [WPA-EAP-TKIP] : Ignore EAP WIFI.
				//过滤ssid为空的wifi以及EAP加密网络
				if (result.SSID == null || result.SSID.length() == 0 || result.capabilities.contains("[IBSS]")
						|| result.capabilities.contains("[WPA-EAP-TKIP]")) {
					continue;
				}

				boolean found = false;
				for (AccessPoint accessPoint : apMap.getAll(result.SSID)) {
					if (accessPoint.update(result))
						found = true;
				}
				if (!found) {
					AccessPoint accessPoint = new AccessPoint(result);
					accessPoints.add(accessPoint);
					apMap.put(accessPoint.ssid, accessPoint);
				}
			}
		}

		// Pre-sort accessPoints to speed preference insertion
		Collections.sort(accessPoints);
		return accessPoints;
	}

连接网络:分为两种,一种已保存的网络,一种未保存的网络。

已保存网络连接很简单,通过WifiConfiguration的networkId连接即可。

mWifiManager.connect(networkId, l);

未保存的网络,需要先创建一个WifiConfiguration对象,调用mWifiManager.connect(configuration, l);

根据wifi加密方式以及密码来创建WifiConfiguration对象(只有三种,EAP未写出来):

public WifiConfiguration getNewConfig(AccessPoint accessPoint, String password) {
		if (accessPoint == null) {
			return null;
		}

		if (TextUtils.isEmpty(password) && accessPoint.security != AccessPoint.SECURITY_NONE) {
			return null;
		}

		if (accessPoint.networkId != WifiConfiguration.INVALID_NETWORK_ID) {
			return null;
		}

		WifiConfiguration config = new WifiConfiguration();
		config.SSID = AccessPoint.convertToQuotedString(accessPoint.ssid);

		switch (accessPoint.security) {
		case AccessPoint.SECURITY_NONE:
			config.allowedKeyManagement.set(KeyMgmt.NONE);
			break;

		case AccessPoint.SECURITY_WEP:
			config.allowedKeyManagement.set(KeyMgmt.NONE);
			config.allowedAuthAlgorithms.set(AuthAlgorithm.OPEN);
			config.allowedAuthAlgorithms.set(AuthAlgorithm.SHARED);
			int length = password.length();
			// WEP-40, WEP-104, and 256-bit WEP (WEP-232?)
			if ((length == 10 || length == 26 || length == 58) && password.matches("[0-9A-Fa-f]*")) {
				config.wepKeys[0] = password;
			} else {
				config.wepKeys[0] = '"' + password + '"';
			}
			break;

		case AccessPoint.SECURITY_PSK:
			config.allowedKeyManagement.set(KeyMgmt.WPA_PSK);
			if (password.matches("[0-9A-Fa-f]{64}")) {
				config.preSharedKey = password;
			} else {
				config.preSharedKey = '"' + password + '"';
			}
			break;

		default:
			return null;
		}
		return config;
	}

(1)使用很多android hide api,需要在源码下编译或者将源码编译后的classes.jar包导进工程项目中。

(2)WEP加密网络的使用:测试时一直连不上此种类型的网络,是路由器WEP加密网络设置错误,将密码设置后,会生成十位长度的密钥1,此为密码。


下次介绍wifi网络的自动配置以及设置静态ip。

 类似资料: