Android判断网络是否可用、区分WiFi和数据、是否被安全软件拦截

2018-12-29 liuyingcong 安卓开发

网络请求失败的原因有很多,手机没有连网是很常见的原因,这时需要提醒用户打开网络。怎么从众多可能的失败原因中判断是不是手机没连网呢?

播放视频或者声音是很费流量的,如果用户用的是数据而非WiFi,就需要提醒他是否继续使用。怎么判断手机当前的网络是WiFi还是数据呢?

手机连着网,但是用户在安全软件中设置了本应用禁用网络,这种情况与手机没联连网是不一样的。怎么能区分出来并提示用户呢?

    

下面我们一一解答以上问题:

 网络请求失败后,首先要判断手机是否联连着网,谷歌提供了网络连接的系统服务,可以用来判断手机是否连网:

    // 判断网络是否可用
    public static boolean isNetworkAvailable(Context context) {
        ConnectivityManager manager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
        if (manager !=null){
            NetworkInfo info = manager.getActiveNetworkInfo();
            return info != null && info.isAvailable();
        } else {
            return false;
        }
    }
调用以上方法,如果返回false,提示用户“网络不可用,请检查网络设置就好了。

有些情况下我们要实时接收网络状态的变化,这就需要注册广播接收者,接收网络状态的变化:


    // 广播接收者,接收网络状态的变化
    class NetworkChangeReceiver extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent) {
            ConnectivityManager manager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
            NetworkInfo networkInfo = manager.getActiveNetworkInfo();
            if (networkInfo != null && networkInfo.isAvailable()) {
                // 有网了
                ...
            } else {
                // 断网了
                ...
            }
        }
    }
     注册广播接收者:



    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        IntentFilter intentFilter = new IntentFilter();
        intentFilter.addAction("android.net.conn.CONNECTIVITY_CHANGE");
        networkChangeReceiver = new NetworkChangeReceiver();
        registerReceiver(networkChangeReceiver, intentFilter);
    }


    取消注册:


    @Override
    protected void onDestroy() {
        super.onDestroy();
        unregisterReceiver(networkChangeReceiver);
    }
     对于需要运行一次就够了的代码,可以在“有网了”的地方需要运行的代码后面取消注册。


    以上广播接收者,会在注册之后接收一次,不会等到下次网络变化时才第一次接收。适用于用户进入APP之前没有打开网络,进入之后才去开启网络的情况,开启网络之后做一次网络请求刷新数据。


对于第二个问题,要分辨用户当前使用的是WiFi还是数据网络:


    // 获取当前网络类型
    public String getNetworkType(Context context) {
        ConnectivityManager manager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
        NetworkInfo wifiInfo = manager.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
        NetworkInfo mobileInfo = manager.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
        if (wifiInfo != null && wifiInfo.isConnectedOrConnecting()) {
            return "wifi_network";
        } else if (mobileInfo != null && mobileInfo.isConnectedOrConnecting()) {
            return "mobile_network";
        } else {
            return "no_network";
        }
    }
     当然,也可以实时获取,注册广播接收者即可,前面写过,不再赘述。



对于第三个问题,比较麻烦,安全软件禁用当前APP的网络之后,调用网络是否可用的方法返回的是true,但是网络请求都是失败的,这时只能从失败原因里去找:

网络请求失败了,并且排除了手机没有连网的原因之后,如果以下代码成立,则很有可能是被安全管家禁网了:


     if (e instanceof SocketException && e.getMessage().equals("Network is unreachable")) {
            Toast.makeText(context, "网络请求失败,APP可能被安全软件禁网了", Toast.LENGTH_SHORT).show();
     }
由于存在这种被安全管家禁网并且不能在网络请求之前判断出来,当然也不能实时监测出来,所以对于获取token和服务器时间戳之类的请求应该拦截器获取;页面中也不能完全依赖于自动刷新,还需要增加手动刷新、失败重试的功能。


标签: 安卓网络 WiFi 数据 禁网

网站备案号:京ICP备11043289号-1 北京市公安局网络备案 海1101084571
版权所有 北京育灵童科技发展有限公司 Copyright © 2002-2024 www.elight.cn, All Rights Reserved