WiFi热点安卓开发
What is WiFi
Wi-Fi是无线网络协议的一个家族,基于IEEE 802.11协议。Wi-Fi与它的有线姐妹Ethernet无缝共同工作。有条件的设备能通过无线接入点互相联网,包括有线设备和互联网。基于不同的IEEE 802.11 协议标准,有不同的WiFi版本。
Wi-Fi站点通过互相发送数据包交流,这些数据包由载波的调制和解调完成。站点有48位MAC地址,MAC地址用于标识每个数据包的目的和来源。Wi-Fi建立link级别的连接,可以由目的和源地址定义。
信道(channel)是半双工的,可以被不同的网络分时使用。当交流发生在同一个信道下时,一台机器发送的任何信息都会被所有接收到,即便目的地址只有一个。网络接口卡(网卡)只在接收到合适的报文时中断CPU,忽略不是以它为目的的报文。
- Infrastructure是最常使用的模式,所有通信都经过一个基础站点。
- ad hoc模式指设备直接相互对话,不需要首先与AP对话。在更复杂的协议里,节点可能转发报文,并持续跟踪如何到达其他节点。一些设备可以通过ad hoc分享互联网连接,从而成为热点(virtual router 虚拟路由器)。
What is a WiFi hotspot
WiFi热点是可以让电脑、手机等设备可以连接WiFi的互联网接入点(Access Point, AP),通过WLAN使用路由,以连接到互联网服务提供商。热点都是通过WiFi创建的。热点是一种Tethering方式,另外的Tethering方式还有蓝牙和USB。
Wi-Fi被用在无线设备和AP之间,而热点使用连接到路由的AP设备。
Wi-Fi是WLAN的一种。
SoftAP
https://en.wikipedia.org/wiki/SoftAP
https://source.android.com/devices/tech/connect/wifi-softap-tethering
Software enabled access point 让本来不是被用作路由的设备成为一个无线接入点(wireless access point),等价于虚拟路由(virtual router)。SoftAP主要用于设置在一些没有显示或输入设备的Wi-Fi产品上,一般使用步骤如下:
- 联Wi-Fi设备开启SoftAP Wi-Fi 热点
- 用户在智能手机上下载特定产品的app,app使用底层操作系统(android或iOS)连接上SoftAP热点,或者引导用户手动连接
- app请求用户的私人Wi-Fi网络名称(SSID)和passkey
- app通过SoftAP网络向设备发送SSID和passkey
- 设备结束SoftAP网络,加入用户的私人Wi-Fi网络
需要注意的是,不同的操作系统和硬件处理SoftAP的方式不同,因此用户体验也会很大不同,尤其是对于安卓的软硬件。
在安卓开源网站中,认为安卓的Wi-Fi热点就是Soft AP。实际上在用户使用UI开启WiFi热点时,系统的startTether()函数会依次调用,其中一个步骤是Tethering.startTethering—>enableTetheringInternal—>setWifiTethering。在setWifiTethering中,调用了WifiManager的startSoftAp函数。最后调用cpp函数HostapdManager::StartHostapd()。详见安卓9.0Wifi热点开启流程梳理。
Wi-Fi Certified Passpoint (Hotspot 2.0)
https://www.everythingrf.com/community/what-is-passpoint-or-hotspot-2-0
https://developer.android.com/guide/topics/connectivity/passpoint
是由Wi-Fi Alliance (WFA)在2012年发起的技术,它让移动设备可以自动连接被Passpoint认证的WiFi热点。该技术让移动设备在用户进入热点2.0区域时自动加入Wi-Fi用户服务,以便为终端用户提供更好的带宽和按需服务,减轻运营商基础设施的流量。它基于IEEE 802.11u标准,支持802.11u的设备如果订阅了Hotspots 2 服务,就会自动连接并漫游。
Passpoint连接被WPA 2安全保护。
在Passpoint之前,用户需要在热点更换时重复登录过程。而Passpoint在连接上一个热点时,用户凭证被传送到网络中所有热点,避免用户为了连接到新的热点去找到并认证设备。
安卓2.2版本加入了wifi热点功能
Wi-Fi开启
必须权限
android.permission.INTERNET
— Allows applications to open network sockets.android.permission.ACCESS_NETWORK_STATE
— Allows applications to access information about networks.android.permission.ACCESS_WIFI_STATE
— Allows applications to access information about Wi-Fi networks.android.permission.CHANGE_WIFI_STATE
— Allows applications to change Wi-Fi connectivity state.- #
android.permission.CHANGE_WIFI_MULTICAST_STATE
— Allows applications to enter Wi-Fi Multicast mode. Drains battery faster.
这几个permission都属于normal level install-time permission,会在AndroidManifest.xml的permission中显示。
The Wi-Fi Control permission allows apps that have been granted it to “turn Wi-Fi on or off, scan and connect to Wi-Fi networks, add or remove networks, or start a local-only hotspot.”
热点开启
参考:
https://my.oschina.net/u/4382384/blog/4289594
https://www.jianshu.com/p/9dbb02c3e21f
https://blog.csdn.net/VNanyesheshou/article/details/82147110
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_MULTICAST_STATE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
Android <6.0, API<23,android.net.wifi.WifiConfiguration.setWifiApEnabled
权限
<uses-permission android:name="android.permission.WRITE_SETTINGS" >
6.0以下的手机可以用下面的代码检测权限
ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_SETTINGS) == PackageManager.PERMISSION_GRANTED;
这里不需要AndroidMainifest.xml的定位权限,和手动打开GPS权限。 这里可以设置WiFi热点的用户名ssid和密码,当然也可以设置不要密码的形式。
方法
WifiManager.getClass().getMethod(“setWifiApEnabled”, WifiConfiguration.class, boolean.class);
public static boolean configApState(Context context, String apName) {
WifiManager wifimanager = (WifiManager) context.getSystemService(context.WIFI_SERVICE);
WifiConfiguration wificonfiguration = null;
try {
wificonfiguration = new WifiConfiguration();
wificonfiguration.SSID = apName;
if (isApOn(context)) {
wifimanager.setWifiEnabled(false);
disableAp(context);
}
Method method = wifimanager.getClass().getMethod("setWifiApEnabled", WifiConfiguration.class, boolean.class);
method.invoke(wifimanager, wificonfiguration, !isApOn(context));
return true;
} catch (Exception e) {
e.printStackTrace();
}
return false;
}
6.0<=Android <=7.0, 23<=API<=24,android.net.wifi.WifiConfiguration.setWifiApEnabled
权限
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
//6.0 API>=23, 动态申请
Intent intent = new
Intent(Settings.ACTION_MANAGE_WRITE_SETTINGS);
intent.setData(Uri.