Android中的WIFI模块开发思路

来源:互联网 发布:红蜘蛛软件年费 编辑:程序博客网 时间:2024/05/22 23:59

最近有做机顶盒的设置APK,特地将WIFI模块相关的开发思路分享下,

文章中广播的说明参考:http://blog.csdn.net/wuqingyidongren/article/details/50903090

其它参考(含三篇):http://blog.csdn.net/whuthm/article/details/40347465
以及(含三篇):http://blog.csdn.net/zrf1335348191/article/details/51351895

感谢上面几位博主的共享~


开启WIFI的扫描:
WifiManager.startScan()


返回一个配置列表,获取到配置好的网络连接,该列表存放了关于已经连接过的接入点WiFi的信息,返回的列表中包括如下字段,当WiFi 关闭时会返回null  
wifiManager.getConfiguredNetworks()


获取到WiFi扫描结果,返回附近可用WiFi,包括已经连接的或者已经保存的WiFi  
wifiManager.getScanResults()


WIFI热点对象
AccessPoint 


WIFI热点的加密方式
目前常用的加密方式有NONE,WEB,WPA/WPA2 PSK,802.1xEAP四种,最后一种是企业级的应用(需要指定的参数比较多,较为繁杂)
AccessPoint.security


根据wifi加密方式以及密码来创建WifiConfiguration对象
WifiConfiguration config = new WifiConfiguration();
config.enterpriseConfig 企业级的加密方式所需参数


为网络设置IP的获取方式有DHCP服务器和静态IP两种
config.ipAssignment = IpAssignment.DHCP; 
config.ipAssignment = IpAssignment.STATIC; 


网络地址类
InetAddress inetIp = NetworkUtils.numericToInetAddress(ip);

NetworkUtils帮助类相关的API
将整型转换为网络地址(通过DHCP的API得到的IP地址是一个整型的数值)
NetworkUtils.intToInetAddress(int arg0)
设置子网掩码时用得到(根据子网掩码的长度返回网络地址的长度)
NetworkUtils.prefixLengthToNetmaskInt(int prefixLength) 
设置子网掩码时用得到(根据子网掩码的网络地址返回子网掩码的长度)
NetworkUtils.netmaskIntToPrefixLength(int netmask)

子网掩码通过代码获取的往往不准确,因此一般是写固定,转换的时候

8位即是(255.0.0.0)16位(255.255.0.0)24位(255.255.255.0)32位(255.255.255.255)


将整型转换为一个网络地址
NetworkUtils.numericToInetAddress(String addrString)
将一个网络地址转换为整型
NetworkUtils.inetAddressToInt(Inet4Address inetAddr)

未被保存的网络需要连接时调用
WifiManager.connect(WifiConfiguration config, ActionListener listener)

已保存的网络需要连接时调用
WifiManager.connect(int networkId, ActionListener listener)

添加新的网络
WifiManager.save(WifiConfiguration config, ActionListener listener)

忽略网络
WifiManager.forget(int netId, ActionListener listener)


===============与WIFI相关的几个重要的系统广播以及说明==========


WifiManager.WIFI_STATE_CHANGED_ACTION
wifi功能所对应状态的变化监听
intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE,WifiManager.WIFI_STATE_UNKNOWN)获取;
WIFI_STATE_DISABLED(wifi已经被关闭),
WIFI_STATE_DISABLING(wifi正在关闭);
WIFI_STATE_ENABLED(wifi已经被打开);
WIFI_STATE_ENABLING(wifi正在被打开);
WIFI_STATE_UNKNOWN(wifi状态未知)。


WifiManager.NETWORK_STATE_CHANGED_ACTION
表示wifi的连接状态发生了变化。其携带的信息是一个NetworkInfo对象;可以通过NetworkInfo info = (NetworkInfo)intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO);获取



WifiManager.SCAN_RESULTS_AVAILABLE_ACTION

WifiManager.CONFIGURED_NETWORKS_CHANGED_ACTION

WifiManager.LINK_CONFIGURATION_CHANGED_ACTION
该广播表示无线网络扫描完毕,可以从WPAS中获取扫描结果。一般做法收到该广播更新wifi列表

WifiManager.NETWORK_IDS_CHANGED_ACTIO
所配置的网络的网络ID可能已经改变(用的不多,当然在这里也可以更新下WIFI热点的状态)

WifiManager.RSSI_CHANGED_ACTION
WIFI的信号强度发生变化

获取wifi信号的强度,分为N个等级**0,1,2,3....N-1**
WifiInfo mWifiInfo = mWifiManager.getConnectionInfo();
int wifi_rssi = mWifiInfo.getRssi();
wifi_level = WifiManager.calculateSignalLevel(wifi_rssi, **N**);


其它可能会用到的广播:

ConnectivityManager.CONNECTIVITY_ACTION
 监听网络状态的变化,如从wifi->有线。

ConnectivityManager.ACTION_TETHER_STATE_CHANGED

监听网线的插拔


// android.net.ethernet.ETHERNET_STATE_CHANGED
 EthernetDataTracker.ETHERNET_STATE_CHANGED_ACTION);

该广播在插拔网线的时候会各收到一次



// android.net.conn.CONNECTIVITY_CHANGE
      ConnectivityManager.CONNECTIVITY_ACTION 
有线-》wifi,会收到两次,一次是拔出网线有线->不可用;另一次是不可用->wifi;
有线-》不可用则会收到一次
不可用-》有线,该广播会收到1次。
wifi-》有线会收到3次,具体原因目前还不清楚;


// android.net.conn.TETHER_STATE_CHANGED
 ConnectivityManager.ACTION_TETHER_STATE_CHANGED);
由wifi->有线的时候。会收到一次
由有线-》wifi的时候会收到3次。原因未解
无网络连接-》有线 ,收不到该广播
有线-》无网络:收到2次


开发的大致思路是:

第一步:注册系统的广播,启动WIFI的扫描

第二步:接受系统广播,获取WIFI热点,添加到WIFI列表中

第三步:选择WIFI热点,点击连接WIFI热点

第四步:根据WIFI状态的变化及时更新UI(连接或者断开,信号强度变化等)


1:开启WIFI 关闭WIFI(之前有连接过的WIFI需要自动连接)
?有时候再次开启WIFI时 之前连接过的热点不自动重连了,并且提示“为检测到互联网连接,因此不会自动重连.”
http://blog.csdn.net/w6980112/article/details/45843129
据说系统是在访问Android的一个URL地址,如果不能访问则返回402 并出现以上的提示信息


2:获取WIFI热点列表并及时刷新(上次已保存的网络和新扫描的网络)

3:添加新的WIFI热点(说明要添加的热点是隐藏的)

4:选择WIFI热点点击连接(已保存的网络 和 未保存的网络);可以在两个连接的WIFI热点之间自由切换
???在两个热点之间切换时 已经输入过密码了,切换时还是需要再次输入
可以翻阅一下标准版本 该版本的系统设置是不需要再次输入的


初始化热点的时候有两种情况一是通过扫描到的结果,而是通过连接过的热点的配置信息 最大不同之处在于networkId不同
连接过的热点networkId系统会为该热点分配一个networkId,不会是默认的-1  扫描到的热点才会是-1
wifiManager.getConfiguredNetworks()
wifiManager.getScanResults()
返回的结果有重叠的 造成每次连接过的热点的networkId被重置为了-1,因此每次连接的时候都需要输入密码

解决方案是:获取连接过的热点后 如果再在扫描到的热点的结果中含有 则跳过该热点 不更新该热点的networkId

5:忽略热点(不保存)

6:编辑WIFI热点的网络信息,为热点设置一个静态IP


7:连接WIFI热点后,输入的密码错误后给出提示(同一个WIFI热点仅且提示一次)
可监听WifiManager.SUPPLICANT_STATE_CHANGED_ACTION广播 但是会多次提示
int result=intent.getIntExtra(WifiManager.EXTRA_SUPPLICANT_ERROR, -2);
if(result==WifiManager.ERROR_AUTHENTICATING)  即是密码错误


另外遇到一个问题 为网络设置动态的DNS和网关的时候没有相应的API,网上搜到一个通过反射设置的方法,亲测有效
public static void setStaticIpConfiguration(WifiConfiguration config, InetAddress ipAddress, int prefixLength, InetAddress gateway, InetAddress[] dns) throws ClassNotFoundException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, NoSuchFieldException, InstantiationException
{
   // First set up IpAssignment to STATIC.
   Object ipAssignment = getEnumValue("android.net.IpConfiguration$IpAssignment", "STATIC");
   callMethod(config, "setIpAssignment", new String[] { "android.net.IpConfiguration$IpAssignment" }, new Object[] { ipAssignment });


   // Then set properties in StaticIpConfiguration.
   Object staticIpConfig = newInstance("android.net.StaticIpConfiguration");
   Object linkAddress = newInstance("android.net.LinkAddress", new Class<?>[] { InetAddress.class, int.class }, new Object[] { ipAddress, prefixLength });


   setField(staticIpConfig, "ipAddress", linkAddress);
   setField(staticIpConfig, "gateway", gateway);
   getField(staticIpConfig, "dnsServers", ArrayList.class).clear();
   for (int i = 0; i < dns.length; i++)
   {
       getField(staticIpConfig, "dnsServers", ArrayList.class).add(dns[i]);
   }
   callMethod(config, "setStaticIpConfiguration", new String[] { "android.net.StaticIpConfiguration" }, new Object[] { staticIpConfig });  
}

注意对于已经连接上的WIFI是可以编辑IP地址的,可以为WIFI网络设置一个静态的IP地址(类似于有线网络一样)