Android Wifi连接控制、TCP、UDP通信,6.0以上
2018-03-23 本文已影响456人
进击的包籽
本文章包含内容
- Wifi连接控制、Wifi广播接收,适配了Android6.0以上的版本
- Wifi下的TCP通信
- Wifi下的UDP通信
- Github项目地址
- 码云项目地址
最近公司要开发智能家居,APP要作为遥控器和控制中心,其中的原理就是智能设备开机先作为一个热点,发射Wifi信号,然后手机连上这个热点(Wifi控制),手机和智能设备建立了连接后,将家里路由器wifi的账号密码通过TCP协议,Socket通信发送给智能设备,最后智能设备收到后就能连上家里的路由器了。
第一步当然就是Wifi控制了,网上资料挺多的,但是Andorid6.0以上的版本,由于权限问题,不能连上指定Wifi,这就把解决方法分享出来,有一些简单的代码,我用Kotlin来练手了,关键的还是用Java (#^.^#)。
- Manifest里面添加权限
<!-- wifi控制和状态权限 -->
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<!-- 网络状态改变的权限 -->
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
<!-- 6.0以上打开蓝牙和wifi最好加上定位权限,获取wifi列表要用 -->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<!-- 获取IP地址 -->
<uses-permission android:name="android.permission.INTERNET"/>
-
Andorid 6.0以上要动态权限
参考资料是严振杰的动态权限方法
Github
Android 6.0 运行时权限管理最佳实践 -
Wifi广播,用于监听Wifi的状态,demo动态注册广播
参考资料
Android-WiFi开发之 WiFi广播监听
Android SupplicantState
/**
* Created by bao on 2018/3/21.
* wifi状态广播
*/
public class WifiBroadcastReceiver extends BroadcastReceiver
{
private WifiControlUtils wifiControlUtils;
@Override
public void onReceive(Context context, Intent intent)
{
wifiControlUtils = new WifiControlUtils(context);
//wifi正在改变状态
if (WifiManager.WIFI_STATE_CHANGED_ACTION.equals(intent.getAction()))
{
//获取wifi状态
int wifiState = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE, WifiManager.WIFI_STATE_DISABLING);
switch (wifiState)
{
case WifiManager.WIFI_STATE_DISABLED:
//wifi已经关闭
break;
case WifiManager.WIFI_STATE_DISABLING:
//wifi正在关闭
break;
case WifiManager.WIFI_STATE_ENABLED:
//wifi已经开启
break;
case WifiManager.WIFI_STATE_ENABLING:
//wifi正在开启
break;
}
} else if (WifiManager.NETWORK_STATE_CHANGED_ACTION.equals(intent.getAction()))
{
//网络状态改变
NetworkInfo info = intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO);
if (NetworkInfo.State.DISCONNECTED.equals(info.getState()))
{
//wifi网络连接断开
} else if (NetworkInfo.State.CONNECTED.equals(info.getState()))
{
//获取当前网络,wifi名称
ToastUtils.showLong(context.getString(R.string.wifi_connected, wifiControlUtils.getWifiInfo().getSSID()));
}
} else if (WifiManager.SUPPLICANT_STATE_CHANGED_ACTION.equals(intent.getAction()))
{
//wifi密码错误广播
SupplicantState netNewState = intent.getParcelableExtra(WifiManager.EXTRA_NEW_STATE);
//错误码
int netConnectErrorCode = intent.getIntExtra(WifiManager.EXTRA_SUPPLICANT_ERROR, WifiManager.ERROR_AUTHENTICATING);
}
}
}
public class WifiControlActivity extends AppCompatActivity
{
private WifiBroadcastReceiver wifiBroadcastReceiver;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.wifi_control_activity);
ButterKnife.bind(this);
//动态注册wifi状态广播
wifiBroadcastReceiver = new WifiBroadcastReceiver();
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
intentFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
intentFilter.addAction(WifiManager.SUPPLICANT_STATE_CHANGED_ACTION);
registerReceiver(wifiBroadcastReceiver, intentFilter);
}
@Override
protected void onDestroy()
{
super.onDestroy();
//注销广播
unregisterReceiver(wifiBroadcastReceiver);
}
}
- Wifi控制工具,网上别人的资料在Andorid6.0 以上不能连接,对其工具进行改进一下,马上解决。
参考资料 Android中自动连接到指定SSID的Wi-Fi
- 获取WifiManager,这里注意的就是context.getApplicationContext()获取,防止内存泄漏。
public WifiControlUtils(Context context)
{
//获取wifiManager对象
mWifiManager = (WifiManager) context.getApplicationContext().getSystemService(Context.WIFI_SERVICE);
}
wifimanager.jpg
2.Wifi 的信息 WifiInfo,获取之前,要先判断 WifiManager 是否为空,因为 Wifi 状态会经常改变,所以获取之前判断一下是否为空,而且每次都重新获取,拿最新的 Wifi 信息。
/**
* 获取wifi连接信息
**/
public WifiInfo getWifiInfo()
{
if (mWifiManager != null)
{
return mWifiManager.getConnectionInfo();
}
return null;
}
wifiinfo.jpg
3.Andorid 6.0以上的版本,权限改变,连接Wifi不一样。
- 对于6.0以上,如果你要连接不是自己创建的配置,只需要在mWifiManager.getConfiguredNetworks(),翻出以前连接过的的Wifi 配置,获取对应的netId,就能重新连接上。
- 如果以前连接过的 Wifi 密码改了,但是名称没变,你是连不上的,也没权限去修改密码和删除(可能就是为了安全吧),你就要手动去处理这个Wifi 信息了。
- APP没有权限删除之前的连接过的 Wifi ,包括APP以前本身创建的 Wifi(先创建了,重装或者更新后,都不算是自己创建了)。
-
对于从来都没连接过的 Wifi,或者是删除过的 Wifi(相当于没连接过),和以前一样,只要用 SSID (Wifi名)、密码、加密方式创建新的 WifiConfiguration,无密码的就是要 SSID;然后 mWifiManager.enableNetwork 就连上了。
不可移除wifi.jpg
- 我的改进后的处理方式就是这样的。
/**
* 连接指定wifi
* 6.0以上版本,直接查找时候有连接过,连接过的拿出wifiConfiguration用
* 不要去创建新的wifiConfiguration,否者失败
*/
public void addNetWork(String SSID, String password, int Type)
{
int netId = -1;
/*先执行删除wifi操作,1.如果删除的成功说明这个wifi配置是由本APP配置出来的;
2.这样可以避免密码错误之后,同名字的wifi配置存在,无法连接;
3.wifi直接连接成功过,不删除也能用, netId = getExitsWifiConfig(SSID).networkId;*/
if (removeWifi(SSID))
{
//移除成功,就新建一个
netId = mWifiManager.addNetwork(createWifiInfo(SSID, password, Type));
} else
{
//删除不成功,要么这个wifi配置以前就存在过,要么是还没连接过的
if (getExitsWifiConfig(SSID) != null)
{
//这个wifi是连接过的,如果这个wifi在连接之后改了密码,那就只能手动去删除了
netId = getExitsWifiConfig(SSID).networkId;
} else
{
//没连接过的,新建一个wifi配置
netId = mWifiManager.addNetwork(createWifiInfo(SSID, password, Type));
}
}
//这个方法的第一个参数是需要连接wifi网络的networkId,第二个参数是指连接当前wifi网络是否需要断开其他网络
//无论是否连接上,都返回true。。。。
mWifiManager.enableNetwork(netId, true);
}
/**
* 获取配置过的wifiConfiguration
*/
public WifiConfiguration getExitsWifiConfig(String SSID)
{
wifiConfigurationList = mWifiManager.getConfiguredNetworks();
for (WifiConfiguration wifiConfiguration : wifiConfigurationList)
{
if (wifiConfiguration.SSID.equals("\"" + SSID + "\""))
{
return wifiConfiguration;
}
}
return null;
}
/**
* 移除wifi,因为权限,无法移除的时候,需要手动去翻wifi列表删除
* 注意:!!!只能移除自己应用创建的wifi。
* 删除掉app,再安装的,都不算自己应用,具体看removeNetwork源码
*
* @param netId wifi的id
*/
public boolean removeWifi(int netId)
{
return mWifiManager.removeNetwork(netId);
}
/**
* 移除wifi
*
* @param SSID wifi名
*/
public boolean removeWifi(String SSID)
{
if (getExitsWifiConfig(SSID) != null)
{
return removeWifi(getExitsWifiConfig(SSID).networkId);
} else
{
return false;
}
}
- 到这里基本结束了,TCP、UDP、Wifi更多详情,就下载源码看看吧,测试机小米6(Android8.0),三星S7edge(Andorid7.0),魅蓝note3(Android7.0),oppoR9s(Android7.0)均可以使用。小米6可以收wifi和把这个wifi热点分享出去,所以测试方便。
TCP通信
UDP通信
1.gif 2.gif 3.gif tcp.gif udp.gif