AndroidインターネットにアクセスできないWiFiネットワークで通信する必要があるアプリを作成しています。問題は、WiFiが接続されていてもAndroid = Wi-Fiネットワークにインターネットが接続されていない場合、携帯電話/モバイルデータの使用を選択します。
私はこの問題に関する多くの投稿を読みましたが、その多くはデバイスのルート化に関係していますが、実稼働アプリでは不可能です(デバイスのルート化はnotオプションです)。他のソリューション(私のコードのように)は、Sony Z2で完全に動作しますが、テストした他のデバイスでは動作しないbindProcessToNetwork()
の使用を推奨します(すべて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);
}
});
}
}
グローバル設定captive_portal_detection_enabledを0(false)に設定してみてください。
実際に起こっていることは、デフォルトでは、wifiに接続するたびに、FWはサーバー(通常はgoogle)に対してテストを実行し、キャプティブwifi(ログインが必要)かどうかを確認します。したがって、wifiがGoogleに接続されていない場合、このチェックは失敗します。その後、デバイスはwifiにインターネット接続がないことを認識し、wifiに自動的に接続しません。
この設定を0に設定すると、このチェックが回避されます。
プログラム的に:Settings.Global.putInt(getContentResolver(), Settings.Global.CAPTIVE_PORTAL_DETECTION_ENABLED, 0);
編集:Androidバージョンによっては表示されない定数の代わりに、文字列 "captive_portal_detection_enabled"を直接使用する必要がある場合があります。
あなたは正しい道を進んでいます、解決策は確かに ConnectivityManager.bindProcessToNetwork(network) です。この情報は、この記事のAndroid Developers Blog: アプリをWi-Fiデバイスに接続する 。
コードを見ると、このbarCodeData.getSsid()
は、現在接続されているwifiネットワークのSSIDを取得しているようには見えません。その場合、コードはネットワークに正常にバインドされません。
ifステートメントを置き換えてみてください
if (barCodeData.getSsid().contains("screenspace"))
と
if (getNetworkSsid(context).equals("screenspace"))
kotlinのヘルパーメソッドは、接続された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でテストしました。
[設定]でモバイルデータを無効にする必要があります(これをプログラムで実行できるかどうかは不明ですが、可能性のあるオプションです)-USIMを削除します。
それ以外の一般的な動作は、常に利用可能な最適な接続にフォールバックすることです(ほとんどのアプリケーションで使用されるため、インターネットゲートウェイとの接続が優先される場合があります)。
こちらもご覧ください answer 。
Wi-Fiが接続されているかどうかを確認してから、Wi-Fiネットワークへの接続をユーザーに求めるダイアログを表示します。
メソッドNetworkInfo.isConnected()はAPI-23で非推奨になったため、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
}
}
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)
}