如何以编程方式连接到 Android API 级别 29 (>= 29) 及以上的其他 Wi-fi 网络
How to connect to Other Wi-fi Network Programmatically in and above Android API level 29 (>= 29)
Usecase: 成功连接到其他指定的Wi-fi网络,并断开与现有Wi-fi网络的连接。
我尝试 WifiNetworkSpecifier 和 WifiNetworkSuggestion 在 Android 中以编程方式连接到其他 Wi-fi。当我尝试使用 WifiNetworkSpecifier 时,我可以看到要求用户连接到指定网络的对话框。但是,在单击连接后,我 无法访问互联网 并且当我 close/kill 我的应用程序时 从 Wi-fi 网络断开连接 。而 WifiNetworkSuggestion 不适用于我的以下代码(位置权限已保证)。
用于 WifiNetworkSpecifier 的代码:
WifiNetworkSpecifier.Builder builder = new WifiNetworkSpecifier.Builder();
builder.setSsid(MY_SSID);
builder.setWpa2Passphrase(MY_PASSWORD);
WifiNetworkSpecifier wifiNetworkSpecifier = builder.build();
NetworkRequest.Builder networkRequestBuilder1 = new NetworkRequest.Builder();
networkRequestBuilder1.addTransportType(NetworkCapabilities.TRANSPORT_WIFI);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
networkRequestBuilder1.setNetworkSpecifier(wifiNetworkSpecifier);
}
NetworkRequest networkRequest = networkRequestBuilder1.build();
ConnectivityManager cm = (ConnectivityManager)
getApplicationContext().getSystemService(Context.CONNECTIVITY_SERVICE);
ConnectivityManager.NetworkCallback networkCallback = new
ConnectivityManager.NetworkCallback() {
@Override
public void onAvailable(Network network) {
super.onAvailable(network);
Log.d(TAG, "onAvailable:" + network);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
cm.bindProcessToNetwork(network);
}
}
};
cm.requestNetwork(networkRequest, networkCallback);
用于 WifiNetworkSuggestion 的代码(我认为对于我的用例,我需要根据 android 文档使用这个代码):
WifiNetworkSuggestion suggestion1 = new WifiNetworkSuggestion.Builder()
.setSsid(MY_SSID)
.setWpa2Passphrase(MY_PASSWORD)
.setIsAppInteractionRequired(true) // Optional (Needs location permission)
.build();
List<WifiNetworkSuggestion> suggestionsList = new ArrayList<WifiNetworkSuggestion>();
suggestionsList.add(suggestion1);
int status = wifiManager.addNetworkSuggestions(suggestionsList);
if (status != WifiManager.STATUS_NETWORK_SUGGESTIONS_SUCCESS) {
showToast("Failure");
} else {
showToast("Success");
}
final IntentFilter intentFilter = new IntentFilter(WifiManager.ACTION_WIFI_NETWORK_SUGGESTION_POST_CONNECTION);
final BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if (!intent.getAction().equals(WifiManager.ACTION_WIFI_NETWORK_SUGGESTION_POST_CONNECTION)) {
return;
}
// Post connection
showToast("post connection");
}
};
getApplicationContext().registerReceiver(broadcastReceiver, intentFilter);
使用权限:
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<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.CHANGE_NETWORK_STATE" />
非常感谢任何建议或帮助。谢谢!
您需要注册NetworkCallbck()
onResume:
override fun onResume() {
super.onResume()
getConnectivityManager().registerDefaultNetworkCallback(networkCallback)
}
和网络回调:
private val networkCallback: NetworkCallback = object : NetworkCallback() {
override fun onAvailable(network: Network) {
super.onAvailable(network)
getConnectivityManager().bindProcessToNetwork(network)
if (wifiManager.connectionInfo.ssid == "\"" + MY_SSID + "\"") { //take note of this string
//connection succesfull. todo
}
}
override fun onUnavailable() {
super.onUnavailable()
}
override fun onLost(network: Network) {
super.onLost(network)
}
}
至于 wifiManager.addNetworkSuggestions
请添加这些:
private fun checkNetworkSuggestion() {
when (wifiManager.addNetworkSuggestions(getWifiSuggestionList()!!)) {
WifiManager.STATUS_NETWORK_SUGGESTIONS_SUCCESS -> {
//all ok so wait for network callback
}
WifiManager.STATUS_NETWORK_SUGGESTIONS_ERROR_ADD_DUPLICATE -> {
//there is a duplicate. remove the suggestion
wifiManager.removeNetworkSuggestions(getWifiSuggestionList()!!)
checkNetworkSuggestion()
}
else -> //todo error
}
}
如果一切顺利,将显示通知以允许您的应用程序连接到网络。单击是并等待网络回调到 return。这可能要花点时间。就我而言,我必须等待 1 分钟才能连接 wifi。此外,imo 也不需要注册广播接收器。最后取消注册您的网络回调。
override fun onDestroy() {
try {
getConnectivityManager().unregisterNetworkCallback(networkCallback)
} catch (e: Exception) {
e.printStackTrace()
}
super.onDestroy()
}
一定要试试这些。
在我的例子中,上面的代码可以正常工作,但我断开了与 wifi picker 的网络连接,所以它阻止了我 24 小时。这就是上面那个时候对我不起作用的原因。我观察到的一些限制。
- 位置权限是强制性的
- 拒绝网络建议通知的用户会从应用程序中删除CHANGE_WIFI_STATE权限,即;当用户在通知中单击“否”时。他们无法连接到 Wi-fi。用户稍后可以通过进入 Wi-Fi 控制菜单(设置>应用和通知>特殊应用访问>Wi-Fi 控制>应用名称)- Android 文档来授予此批准。
- wifi连接成功后卸载app会导致wifi网络断开
Usecase: 成功连接到其他指定的Wi-fi网络,并断开与现有Wi-fi网络的连接。
我尝试 WifiNetworkSpecifier 和 WifiNetworkSuggestion 在 Android 中以编程方式连接到其他 Wi-fi。当我尝试使用 WifiNetworkSpecifier 时,我可以看到要求用户连接到指定网络的对话框。但是,在单击连接后,我 无法访问互联网 并且当我 close/kill 我的应用程序时 从 Wi-fi 网络断开连接 。而 WifiNetworkSuggestion 不适用于我的以下代码(位置权限已保证)。
用于 WifiNetworkSpecifier 的代码:
WifiNetworkSpecifier.Builder builder = new WifiNetworkSpecifier.Builder();
builder.setSsid(MY_SSID);
builder.setWpa2Passphrase(MY_PASSWORD);
WifiNetworkSpecifier wifiNetworkSpecifier = builder.build();
NetworkRequest.Builder networkRequestBuilder1 = new NetworkRequest.Builder();
networkRequestBuilder1.addTransportType(NetworkCapabilities.TRANSPORT_WIFI);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
networkRequestBuilder1.setNetworkSpecifier(wifiNetworkSpecifier);
}
NetworkRequest networkRequest = networkRequestBuilder1.build();
ConnectivityManager cm = (ConnectivityManager)
getApplicationContext().getSystemService(Context.CONNECTIVITY_SERVICE);
ConnectivityManager.NetworkCallback networkCallback = new
ConnectivityManager.NetworkCallback() {
@Override
public void onAvailable(Network network) {
super.onAvailable(network);
Log.d(TAG, "onAvailable:" + network);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
cm.bindProcessToNetwork(network);
}
}
};
cm.requestNetwork(networkRequest, networkCallback);
用于 WifiNetworkSuggestion 的代码(我认为对于我的用例,我需要根据 android 文档使用这个代码):
WifiNetworkSuggestion suggestion1 = new WifiNetworkSuggestion.Builder()
.setSsid(MY_SSID)
.setWpa2Passphrase(MY_PASSWORD)
.setIsAppInteractionRequired(true) // Optional (Needs location permission)
.build();
List<WifiNetworkSuggestion> suggestionsList = new ArrayList<WifiNetworkSuggestion>();
suggestionsList.add(suggestion1);
int status = wifiManager.addNetworkSuggestions(suggestionsList);
if (status != WifiManager.STATUS_NETWORK_SUGGESTIONS_SUCCESS) {
showToast("Failure");
} else {
showToast("Success");
}
final IntentFilter intentFilter = new IntentFilter(WifiManager.ACTION_WIFI_NETWORK_SUGGESTION_POST_CONNECTION);
final BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if (!intent.getAction().equals(WifiManager.ACTION_WIFI_NETWORK_SUGGESTION_POST_CONNECTION)) {
return;
}
// Post connection
showToast("post connection");
}
};
getApplicationContext().registerReceiver(broadcastReceiver, intentFilter);
使用权限:
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<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.CHANGE_NETWORK_STATE" />
非常感谢任何建议或帮助。谢谢!
您需要注册NetworkCallbck()
onResume:
override fun onResume() {
super.onResume()
getConnectivityManager().registerDefaultNetworkCallback(networkCallback)
}
和网络回调:
private val networkCallback: NetworkCallback = object : NetworkCallback() {
override fun onAvailable(network: Network) {
super.onAvailable(network)
getConnectivityManager().bindProcessToNetwork(network)
if (wifiManager.connectionInfo.ssid == "\"" + MY_SSID + "\"") { //take note of this string
//connection succesfull. todo
}
}
override fun onUnavailable() {
super.onUnavailable()
}
override fun onLost(network: Network) {
super.onLost(network)
}
}
至于 wifiManager.addNetworkSuggestions
请添加这些:
private fun checkNetworkSuggestion() {
when (wifiManager.addNetworkSuggestions(getWifiSuggestionList()!!)) {
WifiManager.STATUS_NETWORK_SUGGESTIONS_SUCCESS -> {
//all ok so wait for network callback
}
WifiManager.STATUS_NETWORK_SUGGESTIONS_ERROR_ADD_DUPLICATE -> {
//there is a duplicate. remove the suggestion
wifiManager.removeNetworkSuggestions(getWifiSuggestionList()!!)
checkNetworkSuggestion()
}
else -> //todo error
}
}
如果一切顺利,将显示通知以允许您的应用程序连接到网络。单击是并等待网络回调到 return。这可能要花点时间。就我而言,我必须等待 1 分钟才能连接 wifi。此外,imo 也不需要注册广播接收器。最后取消注册您的网络回调。
override fun onDestroy() {
try {
getConnectivityManager().unregisterNetworkCallback(networkCallback)
} catch (e: Exception) {
e.printStackTrace()
}
super.onDestroy()
}
一定要试试这些。
在我的例子中,上面的代码可以正常工作,但我断开了与 wifi picker 的网络连接,所以它阻止了我 24 小时。这就是上面那个时候对我不起作用的原因。我观察到的一些限制。
- 位置权限是强制性的
- 拒绝网络建议通知的用户会从应用程序中删除CHANGE_WIFI_STATE权限,即;当用户在通知中单击“否”时。他们无法连接到 Wi-fi。用户稍后可以通过进入 Wi-Fi 控制菜单(设置>应用和通知>特殊应用访问>Wi-Fi 控制>应用名称)- Android 文档来授予此批准。
- wifi连接成功后卸载app会导致wifi网络断开