Android多种网络共存时APP如何请求特定网络

Android系统中可以提供Internet能力的网络类型有移动网络,WIFI网络,及有线Ethernet。

当Android上层APP访问网络时,如果APP没有明确请求网络的具体类型,通常会走手机默认网络类型。如果APP对某些特定网络比较依赖,比如MMS期望总是使用移动网络。

如下,当手机默认网络是WIFI时,三方APP也可以使用ConnectivityManager.requestNetwork API传入CELLULAR网络参数,这时移动网络如果已经断开,接着会重连并回调结果给ConnectivityManager。

    private NetworkCallbackImpl mNetworkCallback;
    private ConnectivityManager mCm = null;

    private void init() {
        mCm = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
        mNetworkCallback = new NetworkCallbackImpl();
    }
 
    private void requestCellNetwork() {
        try {
            mCm.requestNetwork(
                    new NetworkRequest.Builder()
                            .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
                            .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
                            .build(),
                    mNetworkCallback);
        } catch (Exception ex) {
            Log.e(TAG, "requestNetwork failed, " + ex);
        }
    }

三方APP可以通过监听网络变化,或主动调用ConnectivityManager.getAllNetworks获取到移动网络的Network对象。

    class NetworkCallbackImpl extends ConnectivityManager.NetworkCallback {
        @Override
        public void onAvailable(Network network) {
            super.onAvailable(network);
            Log.d(TAG, "onAvailable network:" + network);
            trySetNetwork(network);
        }

        @Override
        public void onLost(Network network) {
            super.onLost(network);
            Log.d(TAG, "onLost network:" + network);
            tryResetNetwork(network);
        }

        @Override
        public void onCapabilitiesChanged(Network network,
                                          NetworkCapabilities networkCapabilities) {
            super.onCapabilitiesChanged(network, networkCapabilities);
            Log.d(TAG, "onCapabilitiesChanged network:" + network);
            trySetNetwork(network);
        }
    }

    private void updateNetFromAllNetworks() {
        Network[] networks = mCm.getAllNetworks();
        if (networks == null) {
            Log.d(TAG, "updateNetFromAllNetworks, but getAllNetworks is null");
            return;
        }
        for (Network network : networks) {
            Log.d(TAG, "updateNetFromAllNetworks network:" + network);
            trySetNetwork(network);
        }
    }

    private void trySetNetwork(Network network) {
        NetworkCapabilities networkCapabilities = mCm.getNetworkCapabilities(network);
        if (networkCapabilities == null) {
            Log.d(TAG, "trySetNetwork, but networkCapabilities is null, network:" + network);
            return;
        }
        if (networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)
                && networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)) {
            Log.d(TAG, "trySetNetwork cell network:" + network);
            mCellNetwork = network;
        } else if (networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)
                && networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)) {
            Log.d(TAG, "trySetNetwork wifi network:" + network);
            mWifiNetwork = network;
        }
    }

    private void tryResetNetwork(Network network) {
        NetworkCapabilities networkCapabilities = mCm.getNetworkCapabilities(network);
        if (networkCapabilities == null) {
            Log.d(TAG, "tryResetNetwork, but networkCapabilities is null, network:" + network);
            return;
        }
        if (networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)
                && network == mCellNetwork) {
            Log.d(TAG, "tryResetNetwork cell network:" + network);
            mCellNetwork = null;
        } else if (networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)
                && network == mCellNetwork) {
            Log.d(TAG, "tryResetNetwork wifi network:" + network);
            mWifiNetwork = null;
        }
    }

当获取到特定网络的Network对象,接着使用该Network去请求网络。

    private static final int NET_PROBE_TIMEOUT_IN_MILLIS = 5 * 1000;
    private boolean success = false;

    /* Do a URL fetch on a known web server to see if we get the data we expect */
    private void sendHttpProbe(Network network, String netUrl) {
        HttpURLConnection urlConnection = null;
        int result = 0;
        content = "Empty data";
        try {
            URL url = new URL(netUrl);
            urlConnection = (HttpURLConnection) network.openConnection(url);
            urlConnection.setInstanceFollowRedirects(true);
            urlConnection.setConnectTimeout(NET_PROBE_TIMEOUT_IN_MILLIS);
            urlConnection.setReadTimeout(NET_PROBE_TIMEOUT_IN_MILLIS);
            urlConnection.setRequestProperty("Connection", "close");
            urlConnection.setUseCaches(false);
            urlConnection.connect();
            result = urlConnection.getResponseCode();
            content = readAsString(urlConnection.getInputStream());
            success = true;
        } catch (Exception e) {
            success = false;
        } finally {
            if (urlConnection != null) {
                urlConnection.disconnect();
            }
        }
    }

    private String readAsString(InputStream is) throws IOException {
        final StringBuilder builder = new StringBuilder();
        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(is));
        String inputLine;
        while ((inputLine = bufferedReader.readLine()) != null) {
            Log.d("inputLine:", inputLine);
            builder.append(inputLine);
        }
        return builder.toString();
    }

在Android framework网络模块会对每种提供网络能力的网络类型进行打分,Ethernet默认70分,WIFI 60分,移动网络 50分。分数越高作为默认网络的优先级越高。当特点网络类型网络质量发生变化,会动态给它们加减分,从而影响到系统默认网络的切换。

http://androidxref.com/9.0.0_r3/xref/frameworks/opt/net/ethernet/java/com/android/server/ethernet/EthernetNetworkFactory.java

45/**
46 * {@link NetworkFactory} that represents Ethernet networks.
47 *
48 * This class reports a static network score of 70 when it is tracking an interface and that
49 * interface's link is up, and a score of 0 otherwise.
50 */
51public class EthernetNetworkFactory extends NetworkFactory {
52    private final static String TAG = EthernetNetworkFactory.class.getSimpleName();
53    final static boolean DBG = true;
54
55    private final static int NETWORK_SCORE = 70;
56    private static final String NETWORK_TYPE = "Ethernet";
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值