如何在Android Oreo系统中编程创建带SSID和密码的WiFi热点?
搞定Android Oreo及以上创建WiFi热点返回false的问题
为啥旧代码在Oreo上不好使了?
从Android 8.0(API 26)开始,谷歌收紧了对WiFi热点配置的管控,旧的反射调用setWifiApEnabled的路子在普通应用里会直接返回false——一方面是系统限制了非系统应用修改热点配置的权限,另一方面旧API的内部实现也悄悄变了。
一步步解决问题
1. 先把权限配全
首先得在AndroidManifest.xml里加上必要的权限,少一个都可能翻车:
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" /> <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" /> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> <uses-permission android:name="android.permission.WRITE_SETTINGS" /> <!-- Android 10及以上还要加这个 --> <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
划重点:WRITE_SETTINGS权限不能只在Manifest里写,得动态申请!先调用Settings.System.canWrite(context)检查有没有授权,没授权的话要引导用户跳转到系统设置页面开启。
2. 适配Oreo的反射代码
针对Oreo及以上系统,得调整反射调用的逻辑,旧方法不好使了,试试下面的代码:
private boolean createCustomHotspot(WifiManager wifiManager, String ssid, String password) { // 先构建热点配置 WifiConfiguration config = new WifiConfiguration(); config.SSID = ssid; config.preSharedKey = password; config.hiddenSSID = false; config.status = WifiConfiguration.Status.ENABLED; // 配置WPA2-PSK相关参数 config.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.OPEN); config.allowedProtocols.set(WifiConfiguration.Protocol.RSN); config.allowedProtocols.set(WifiConfiguration.Protocol.WPA); config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK); config.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.CCMP); config.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.TKIP); config.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.CCMP); config.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.TKIP); try { // 先关掉已有的热点,避免冲突 Method getApConfigMethod = wifiManager.getClass().getMethod("getWifiApConfiguration"); WifiConfiguration existingConfig = (WifiConfiguration) getApConfigMethod.invoke(wifiManager); if (existingConfig != null) { Method disableApMethod = wifiManager.getClass().getMethod("setWifiApEnabled", WifiConfiguration.class, boolean.class); disableApMethod.invoke(wifiManager, existingConfig, false); } // 尝试用旧方法设置新热点 Method setApMethod = wifiManager.getClass().getMethod("setWifiApEnabled", WifiConfiguration.class, boolean.class); boolean result = (boolean) setApMethod.invoke(wifiManager, config, true); return result; } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) { e.printStackTrace(); // 旧方法不行的话,试试Oreo可能支持的另一种反射方式 try { Method startSoftApMethod = wifiManager.getClass().getMethod("startSoftAp", WifiConfiguration.class); startSoftApMethod.invoke(wifiManager, config); return true; } catch (Exception ex) { ex.printStackTrace(); return false; } } }
3. Android 10及以上用官方API更靠谱
如果你的应用目标是Android 10(API 29)及以上,直接用官方提供的startSoftAp相关API,不用折腾反射:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { WifiManager wifiManager = (WifiManager) getSystemService(Context.WIFI_SERVICE); // 构建热点规格 WifiNetworkSpecifier.Builder specBuilder = new WifiNetworkSpecifier.Builder(); specBuilder.setSsid(ssid); specBuilder.setWpa2Passphrase(password); // 创建网络请求 NetworkRequest request = new NetworkRequest.Builder() .addTransportType(NetworkCapabilities.TRANSPORT_WIFI) .setNetworkSpecifier(specBuilder.build()) .build(); ConnectivityManager connectivityManager = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE); // 请求创建热点 connectivityManager.requestNetwork(request, new ConnectivityManager.NetworkCallback() { @Override public void onAvailable(Network network) { super.onAvailable(network); // 热点创建成功啦 } @Override public void onUnavailable() { super.onUnavailable(); // 唉,创建失败了 } }); }
注意:这种方式创建的是临时热点,应用退出或者断开网络后会自动关闭。
最后提几个坑
- 厂商限制:有些Oreo及以上的设备,就算你权限全拿了,普通应用还是没法创建自定义热点——因为厂商加了额外限制,这种情况下只能引导用户手动去系统设置里创建热点。
- 设备兼容性:不同厂商的ROM对热点API的实现不一样,记得多拿几个设备测试哦~
内容的提问来源于stack exchange,提问作者shyam002




