我正在构建一个需要通过无法访问互联网的WiFi网络进行通信的Android应用程序。问题是即使连接WiFi,当wifi网络上没有连接互联网时,机器人选择使用蜂窝/移动数据。
我已经阅读了很多关于这个问题的帖子,其中许多涉及生根设备,但生产应用程序无法实现(生根设备不是一个选项)。其他解决方案(比如我的代码吼叫)建议使用bindProcessToNetwork()
,它在我的Sony Z2上完美运行,但在我测试的其他设备上没有(所有运行6.0.1)
private void bindToNetwork() {
final ConnectivityManager connectivityManager = (ConnectivityManager) mActivity.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkRequest.Builder builder;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
builder = new NetworkRequest.Builder();
//set the transport type do WIFI
builder.addTransportType(NetworkCapabilities.TRANSPORT_WIFI);
connectivityManager.requestNetwork(builder.build(), new ConnectivityManager.NetworkCallback() {
@Override
public void onAvailable(Network network) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
connectivityManager.bindProcessToNetwork(null);
if (barCodeData.getSsid().contains("screenspace")) {
connectivityManager.bindProcessToNetwork(network);
}
} else {
//This method was deprecated in API level 23
ConnectivityManager.setProcessDefaultNetwork(null);
if (barCodeData.getSsid().contains("screenspace")) {
ConnectivityManager.setProcessDefaultNetwork(network);
}
}
connectivityManager.unregisterNetworkCallback(this);
}
});
}
}
答案 0 :(得分:2)
您可以尝试将全局设置captive_portal_detection_enabled设置为0(false)。
实际发生的事情是,默认情况下,每次连接到wifi时,FW都会针对服务器(通常是google)进行测试,看看它是否是强制性wifi(需要登录)。因此,如果您的wifi未连接到谷歌,此检查将失败。之后,设备知道wifi没有互联网连接,并且根本不会自动连接到它。
将此设置设为0将避免此检查。
编程方式:
Settings.Global.putInt(getContentResolver(), Settings.Global.CAPTIVE_PORTAL_DETECTION_ENABLED, 0);
编辑:您可能需要使用字符串" captive_portal_detection_enabled"直接,而不是根据Android版本不可见的常数。
答案 1 :(得分:1)
您需要在“设置”中禁用移动数据(不确定,如果可以通过编程方式完成,这可能是一种可能的选项) - 或取出USIM;
否则常见的行为是,它将始终回归到最佳可用连接(而与Internet网关的连接可能是首选,因为它被大多数应用程序使用)。
另见answer。
答案 2 :(得分:1)
您可以检查wifi是否已连接,然后继续向用户显示一个对话框,要求他连接到wifi网络
由于现在在API-23中不推荐使用NetworkInfo.isConnected()方法,因此这里有一种方法可以检测Wi-Fi适配器是否已打开并使用WifiManager连接到接入点:
private boolean checkWifiOnAndConnected() {
WifiManager wifiMgr = (WifiManager) getSystemService(Context.WIFI_SERVICE);
if (wifiMgr.isWifiEnabled()) { // Wi-Fi adapter is ON
WifiInfo wifiInfo = wifiMgr.getConnectionInfo();
if( wifiInfo.getNetworkId() == -1 ){
return false; // Not connected to an access point
}
return true; // Connected to an access point
}
else {
return false; // Wi-Fi adapter is OFF
}
}
答案 3 :(得分:1)
您走的路正确,ConnectivityManager.bindProcessToNetwork(network)的确是解决方案。此信息已发布在Android开发者博客上的这篇文章中:Connecting your App to a Wi-Fi Device。
此代码barCodeData.getSsid()
看起来并没有获得当前连接的wifi网络的SSID。如果是这种情况,您的代码将永远无法成功绑定到网络。
尝试替换您的 if语句
if (barCodeData.getSsid().contains("screenspace"))
使用
if (getNetworkSsid(context).equals("screenspace"))
kotlin 中的Helper方法来检索连接的wifi网络的SSID
private fun getNetworkSsid(context: Context?): String {
// WiFiManager must use application context (not activity context) otherwise a memory leak can occur
val mWifiManager = context?.applicationContext?.getSystemService(Context.WIFI_SERVICE) as WifiManager
val wifiInfo: WifiInfo? = mWifiManager.connectionInfo
if (wifiInfo?.supplicantState == SupplicantState.COMPLETED) {
return wifiInfo.ssid.removeSurrounding("\"")
}
return ""
}
如果仍然无法使用,请遵循my complete solution,在该方法中我使用了相同的方法,但进行了一些额外的检查。我在Android版本5.1.1、6.0、6.0.1、7.1.1和8.1.0中进行了测试。
答案 4 :(得分:0)
关于Kotlin的解决方案
class ConnectWithoutInternetTest constructor(
private val mContext: Context,
private val connectivityManager: ConnectivityManager,
private val wifiManager: WifiManager
) {
private val mWifiBroadcastReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
when (intent.action) {
WifiManager.NETWORK_STATE_CHANGED_ACTION -> {
val info = intent.getParcelableExtra<NetworkInfo>(WifiManager.EXTRA_NETWORK_INFO)
val isConnected = info.isConnected
val ssid: String? = normalizeAndroidWifiSsid(wifiManager.connectionInfo?.ssid)
if (isConnected) {
val builder = NetworkRequest.Builder()
builder.addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
connectivityManager.registerNetworkCallback(
builder.build(),
object : ConnectivityManager.NetworkCallback() {
override fun onAvailable(network: Network) {
super.onAvailable(network)
val networkInfo = connectivityManager.getNetworkInfo(network)
val networkSsid = networkInfo.extraInfo
if (networkSsid == ssid) {
connectivityManager.unregisterNetworkCallback(this)
}
}
})
}
}
}
}
}
private fun init() {
val intentFilter = IntentFilter()
intentFilter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION)
mContext.registerReceiver(mWifiBroadcastReceiver, intentFilter)
}
private fun destroy() {
mContext.unregisterReceiver(mWifiBroadcastReceiver)
}
private fun normalizeAndroidWifiSsid(ssid: String?): String? {
return ssid?.replace("\"", "") ?: ssid
}
fun connectToWifi(ssidParam: String, password: String?) {
init()
val ssid = "\"$ssidParam\""
val config = wifiManager.configuredNetworks.find { it.SSID == ssid }
val netId = if (config != null) {
config.networkId
} else {
val wifiConfig = WifiConfiguration()
wifiConfig.SSID = ssid
password?.let { wifiConfig.preSharedKey = "\"$password\"" }
wifiConfig.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE)
wifiManager.addNetwork(wifiConfig)
}
wifiManager.disconnect()
val successful = wifiManager.enableNetwork(netId, true)
}