web-dev-qa-db-ja.com

Androidを同時に使用してデバイスと通信し、モバイルデータを使用してサーバーと通信しますか?

私はAndroidアプリケーションを開発しており、アプリは速度、RPM、エンジン冷却水温度の詳細などを読み取ることができます。したがって、wifiはOBD2デバイスとの接続にのみ使用されます(インターネットに接続する機能がなく、ローカルクライアントとの通信のみです。Webサービスにもインターネット接続が必要ですが、wifiに接続した後、Androidのモバイルデータネットワーク経由でインターネットに接続できません。

同様のアプリケーションはiOS用にも開発されています。 iOSでは、Wifi(静的Wifi設定)を介してデバイスを使用し、セルラーネットワークからインターネット接続を使用できます。これは、iOSのインターネット接続にモバイルデータネットワークを使用できる静的IPを使用してwifiを構成することを意味します。

しかし、Androidでは、静的なWi-Fiを使用してインターネット接続を確認すると、利用できません。

Android)でwifi設定を構成することにより、Wifiとインターネット接続の両方を並列またはその他の方法で使用するにはどうすればよいですか?

17
ArchFever

まず、ここで直面する可能性のある問題は、WiFiネットワークにインターネット接続がないため、HTTPデータがその接続を通過しないことです。解決策については、Android Mでモバイルデータがオン(接続あり)の場合でも WiFi経由でリクエストを送信(接続なし)を参照してください

ただし、HTTPリクエストが成功しない場合があるという問題に直面しました。この問題を解決するには、 ConnectivityManager.requestNetwork() および Network.openConnection() を使用してこれを実現します。

モバイルデータとWiFiネットワークが有効になっていて、Androidマニフェストが適切に接続されていることを確認してください:

_<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_NETWORK_STATE" />
<uses-permission Android:name="Android.permission.CHANGE_NETWORK_STATE" />
_

変数:

_private ConnectivityManager.NetworkCallback mWifiNetworkCallback, mMobileNetworkCallback;
private Network mWifiNetwork, mMobileNetwork;
_

接続マネージャーを取得します:

_final ConnectivityManager manager = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
_

ネットワークコールバックを構築する:

_if(mWifiNetworkCallback == null){
    //Init only once
    mWifiNetworkCallback = new ConnectivityManager.NetworkCallback() {
        @Override
        public void onAvailable(final Network network) {
            try {
                //Save this network for later use
                mWifiNetwork = network;
            } catch (NullPointerException npe) {
                npe.printStackTrace();
            }
        }
    };
}

if(mMobileNetworkCallback == null){
    //Init only once
    mMobileNetworkCallback = new ConnectivityManager.NetworkCallback() {
        @Override
        public void onAvailable(final Network network) {
            try {
                //Save this network for later use
                mMobileNetwork = network;
            } catch (NullPointerException npe) {
                npe.printStackTrace();
            }
        }
    };
}
_

ネットワークのリクエスト:

_NetworkRequest.Builder wifiBuilder;
wifiBuilder = new NetworkRequest.Builder();
//set the transport type do WIFI
wifiBuilder.addTransportType(NetworkCapabilities.TRANSPORT_WIFI);
manager.requestNetwork(wifiBuilder.build(), mWifiNetworkCallback);

NetworkRequest.Builder mobileNwBuilder;
mobileNwBuilder = new NetworkRequest.Builder();
//set the transport type do Cellular
mobileNwBuilder.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR);
manager.requestNetwork(mobileNwBuilder.build(), mMobileNetworkCallback);
_

次のように適切なリクエストを行います:

_public void makeHTTPRequest(final String httpUrl, final String payloadJson, final int timeout,
                          final boolean hasHeaders, final String header1, final String header2) {

    try {
        URL url = new URL(httpUrl);
        HttpURLConnection conn = null;
        if (Android.os.Build.VERSION.SDK_INT >= Android.os.Build.VERSION_CODES.Lollipop) {
            conn = (HttpURLConnection) mWifiNetwork.openConnection(url);

            //Or use mMobileNetwork, if and when required
            //conn = (HttpURLConnection) mMobileNetwork.openConnection(url);
        } else {
            conn = (HttpURLConnection) url.openConnection();
        }
        conn.setRequestProperty("Content-Type", "application/json");
        conn.setReadTimeout(timeout * 1000);
        conn.setConnectTimeout(timeout * 1000);

        conn.setDoInput(true);
        conn.setDoOutput(true);

        if(hasHeaders){
            conn.setRequestProperty("header1", header1);
            conn.setRequestProperty("header2", header2);

        }
        conn.setRequestMethod("PUT");

        OutputStream os = conn.getOutputStream();
        os.write(payloadJson.getBytes());
        os.close();

        final int responseCode = conn.getResponseCode();

        if (responseCode == HttpURLConnection.HTTP_OK) {
            final String statusMessage = conn.getResponseMessage();
            //Log this
        } 
    } catch (SocketException se){
        se.printStackTrace();
    }
    catch (Exception e) {
        e.printStackTrace();
    }
}
_

注:これらの関数はAndroidLollipop以降で利用できます。したがって、次のように、適切な場所で_Build.Version.SDK_INT_を使用する必要があります。

_if (Android.os.Build.VERSION.SDK_INT >= Android.os.Build.VERSION_CODES.Lollipop) {
_
6
Ankur Aggarwal
connectivityManager.requestRouteToHost(ConnectivityManager.TYPE_MOBILE_HIPRI, hostAddress);

特定のhostAddressに対して、そのタイプの接続を使用する必要があることを要求できます。 Hipriを使用する場合は、モバイルネットワークが必要になります。しかし、これは失敗する可能性があります!それが機能する場合、そのアドレスへのすべての接続はそのタイプの接続を経由します。

最初にアクティブ化する必要がある場合があります。

int resultInt = connectivityManager.startUsingNetworkFeature(ConnectivityManager.TYPE_MOBILE, "enableHIPRI");

ハードウェアモジュールを起動する必要があるため、これには数秒かかる場合があります。

私はこれをいくつかのプロジェクトで使用しており、うまく機能しています。 2.2などの古いデバイスでは、非常に不安定に反応します。しかし、4.0以降では問題は見つかりませんでした

5
Christophe Smet