Android开发之WIFI与网络连接处理

作者: Reathin | 来源:发表于2017-05-01 19:46 被阅读7599次

    网络连接处理

    在说WiFi之前,先来说说网络连接处理。
    在Android开发过程中,对于一个需要连接网络的Android设备,对设备的网络状态检测是很有必要的!有很多的App都需要连接网络。判断设备是否已经连接网络,并且在连接网络的状态下判断是wifi无线连接还是GPRS手机网络连接,这样就可以在不同的网络连接下去调用不同的方法,处理不同的事情。

    现在app大多都需要从网络上获得数据。所以访问网络是在所难免。但是在访问网络之前,我们应该先做一下网络的状态判断。其实在访问网络之前我们要做一些状态判断,对应一些状态判断来做处理,并不是直接使用Http访问网络即可。很多人在开发就经常把网络这块直接跳过,直接访问网络,一旦断网,各种体验效果不好,不是说app没法用,只是体验效果差。还有,就是我们可能为用户考虑,因为现在一般连网是wifi和手机流量,都知道后者收费是比较高的。假如我们的app加载的图片或者有大的数据下载操作,可是用户的本意是要是在流量下的话就不要操作这些很费流量的的操作,这样就必须要我们做一些连网状态的判断。网络是否连接良好,连接的wifi还是流量,断网或者网络改变了的时候怎么做,这都是一些细节,但是要注意处理。

    查看当前网络状态需要的权限:

    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> 
    

    允许查看当前网络状态,比如是3G还是WIFI上网。

    连接管理

    涉及的常用类

    ConnectivityManager

    翻译成中文即:网络连接管理者
    主要作用:

    • 监听手机网络状态(包括GPRS,WIFI, UMTS等)
    • 手机状态发生改变时,发送广播
    • 当一个网络连接失败时进行故障切换
    • 为应用程序提供可以获取可用网络的高精度和粗糙的状态

    获取ConnectivityManager

    ConnectivityManager connMgr = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); 
    

    NetworkInfo

    翻译成中文即:网络的状态信息
    获取NetworkInfo
    通过ConnectivityManager获取

    ConnectivityManager connMgr = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); 
    NetworkInfo networkInfo = connMgr.getActiveNetworkInfo();
    

    主要方法:

    • getDetailedState():获取详细状态。
    • isAvailable():判断该网络是否可用,是否可以寻找到网络
    • isConnected():判断是否已经连接
    • isConnectedOrConnecting():判断是否已经连接或正在连接。
    • getState() 获取连接状态
    • getExtraInfo():获取附加信息。
    • getType():获取网络类型(一般为移动(0)或Wi-Fi(1))。
    • getTypeName():获取网络类型名称(一般取值“WIFI”或“MOBILE”)。
    • getReason():获取连接失败的原因。
    • isFailover():判断是否连接失败。
    • isRoaming():判断是否漫游

    注意:
    1.当用wifi上的时候
    getType是WIFI
    getExtraInfo是空的

    2.当用手机上的时候
    getType是MOBILE

    3.用移动CMNET方式
    getExtraInfo的值是cmnet

    4.用移动CMWAP方式
    getExtraInfo的值是cmwap,但是不在代理的情况下访问普通的网站访问不了

    5.用联通3gwap方式
    getExtraInfo的值是3gwap

    6.用联通3gnet方式
    getExtraInfo的值是3gnet

    7.用联通uniwap方式
    getExtraInfo的值是uniwap

    8.用联通uninet方式
    getExtraInfo的值是uninet

    TelephonyManager

    TelephonyManager类主要提供了一系列用于访问与手机通讯相关的状态和信息的get方法。其中包括手机SIM的状态和信息、电信网络的状态及手机用户的信息。在应用程序中可以使用这些get方法获取相关数据。
    需要添加权限:

    <uses-permission android:name="android.permission.READ_PHONE_STATE"/>
    

    第一步,也要像ConnectivityManager一样获取管理器:

    TelephonyManager tm = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
    

    常用方法:

    • getCallState()
      CALL_STATE_IDLE 无任何状态时
      CALL_STATE_OFFHOOK 接起电话时
      CALL_STATE_RINGING 电话进来时
    • getDataActivity()
      DATA_ACTIVITY_IN 数据连接状态:活动,正在接受数据
      DATA_ACTIVITY_OUT 数据连接状态:活动,正在发送数据
      DATA_ACTIVITY_INOUT 数据连接状态:活动,正在接受和发送数据
      DATA_ACTIVITY_NONE 数据连接状态:活动,但无数据发送和接受
    • getDataState()
      DATA_CONNECTED 数据连接状态:已连接
      DATA_CONNECTING 数据连接状态:正在连接
      DATA_DISCONNECTED 数据连接状态:断开
      DATA_SUSPENDED 数据连接状态:暂停
    • getDeviceSoftwareVersion() 移动终端的软件版本,例如:GSM手机的IMEI/SV码
    • getLine1Number() 手机号码,对于GSM网络来说即MSISDN(不一定能拿到)
    • getNetworkCountryIso() ISO标准的国家码,即国际长途区号
    • getDeviceId() GSM网络,返回IMEI;如果是CDMA网络,返回MEID
      IMEI是International Mobile Equipment Identity (国际移动设备标识)的简称
      IMEI由15位数字组成的”电子串号”,它与每台手机一一对应,而且该码是全世界唯一的,其组成为:
      1. 前6位数(TAC)是”型号核准号码”,一般代表机型
      2. 接着的2位数(FAC)是”最后装配号”,一般代表产地
      3. 之后的6位数(SNR)是”串号”,一般代表生产顺序号
      4. 最后1位数(SP)通常是”0″,为检验码,目前暂备用
        MEID 移动设备识别码(Mobile Equipment Identifier)是CDMA手机的身份识别码,也是每台CDMA手机或通讯平板唯一的识别码。
        MEID由14个十六进制字符标识,第15位为校验位,不参与空中传输。
        RR:范围A0-FF,由官方分配
        XXXXXX:范围 000000-FFFFFF,由官方分配
        ZZZZZZ:范围 000000-FFFFFF,厂商分配给每台终端的流水号
        C/CD:0-F,校验码
    • getNetworkOperator() MCC+MNC代码 (SIM卡运营商国家代码和运营商网络代码)(IMSI)
      IMSI是国际移动用户识别码的简称(International Mobile Subscriber Identity)
      IMSI共有15位,其结构如下:
      MCC+MNC+MIN
      MCC:Mobile Country Code,移动国家码,共3位,中国为460;
      MNC:Mobile NetworkCode,移动网络码,共2位
      在中国,移动的代码为电00和02,联通的代码为01,电信的代码为03
      合起来就是(也是Android手机中APN配置文件中的代码):
      中国移动:46000 46002
      中国联通:46001
      中国电信:46003
      举例,一个典型的IMSI号码为460030912121001
    • getNetworkOperatorName() 移动网络运营商的名字(SPN)
    • getNetworkType() 移动网络类型
      int NETWORK_TYPE_CDMA 网络类型为CDMA
      int NETWORK_TYPE_EDGE 网络类型为EDGE
      int NETWORK_TYPE_EVDO_0 网络类型为EVDO0
      int NETWORK_TYPE_EVDO_A 网络类型为EVDOA
      int NETWORK_TYPE_GPRS 网络类型为GPRS
      int NETWORK_TYPE_HSDPA 网络类型为HSDPA
      int NETWORK_TYPE_HSPA 网络类型为HSPA
      int NETWORK_TYPE_HSUPA 网络类型为HSUPA
      int NETWORK_TYPE_UMTS 网络类型为UMTS
      在中国,联通的3G为UMTS或HSDPA,移动和联通的2G为GPRS或EGDE,电信的2G为CDMA,电信的3G为EVDO
    • getPhoneType() 手机制式类型
      int PHONE_TYPE_CDMA 手机制式为CDMA,电信
      int PHONE_TYPE_GSM 手机制式为GSM,移动和联通
      int PHONE_TYPE_NONE 手机制式未知
    • getSimState()
      int SIM_STATE_ABSENT SIM卡未找到
      int SIM_STATE_NETWORK_LOCKED SIM卡网络被锁定,需要Network PIN解锁
      int SIM_STATE_PIN_REQUIRED SIM卡PIN被锁定,需要User PIN解锁
      int SIM_STATE_PUK_REQUIRED SIM卡PUK被锁定,需要User PUK解锁
      int SIM_STATE_READY SIM卡可用
      int SIM_STATE_UNKNOWN SIM卡未知
    • getSimCountryIso() SIM卡提供商的国家代码
    • getSimOperator(),getSimOperatorName() MCC+MNC代码 (SIM卡运营商国家代码和运营商网络代码)(IMSI)
    • getSimSerialNumber() SIM卡的序列号(IMEI)
    • getSubscriberId() 用户唯一标识,比如GSM网络的IMSI编号
    • getVoiceMailAlphaTag() 语音信箱号码关联的字母标识
    • getVoiceMailNumber() 语音邮件号码
    • isNetworkRoaming() 手机是否处于漫游状态

    网络连接处理方式

    获取单个网络是否连接

    贴代码:

    ConnectivityManager connMgr = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
    //WiFi是否连接
    NetworkInfo networkInfo = connMgr.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
    boolean isWifiConn = networkInfo.isConnected();
    //手机网络是否连接
    networkInfo = connMgr.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
    boolean isMobileConn = networkInfo.isConnected();
    

    获取网络是否连接

    ConnectivityManager connMgr = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
    NetworkInfo networkInfo = connMgr.getActiveNetworkInfo();
    

    通过广播获取连接状态改变(常用方式)

    • 注册广播,监听ConnectivityManager.CONNECTIVITY_ACTION频道
    IntentFilter filter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION);
    context.registerReceiver(mReceiver, filter);
    
    • 网络状态广播
    BroadcastReceiver mReceiver = new BroadcastReceiver() {  
              
        @Override  
        public void onReceive(Context context, Intent intent) {  
      
            if (intent.getBooleanExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, false)) {  
                Log.i(TAG, "netWork has lost");  
            }  
          
            NetworkInfo tmpInfo = (NetworkInfo) 
                intent.getExtras().get(ConnectivityManager.EXTRA_NETWORK_INFO);  
            Log.i(TAG, tmpInfo.toString() + " {isConnected = " + tmpInfo.isConnected() + "}");  
        }  
    };  
    
    • 清单文件注册(Demo写内部类了)
    <receiver android:name=".ConnectionReceiver" >  
        <intent-filter>  
            <action android:name="android.net.conn.CONNECTIVITY_CHANGE" />  
        </intent-filter>  
    </receiver> 
    

    无网络连接处理

    提示无网络,或跳转到网络设置界面:

    /** 
    * 判断手机系统的版本!如果API大于10 就是3.0+ 
    * 因为3.0以上的版本的设置和3.0以下的设置不一样,调用的方法不同 
    */  
    Intent intent ;  
    if (Build.VERSION.SDK_INT > 10) {  
       intent = new Intent(android.provider.Settings.ACTION_WIFI_SETTINGS);  
    } else {  
       intent = new Intent();  
       ComponentName component = new ComponentName("com.android.settings","com.android.settings.WirelessSettings");  
       intent.setComponent(component);  
       intent.setAction("android.intent.action.VIEW");  
    }  
    startActivity(intent);  
    

    不同Rom可能不同。

    下面来说WiFi

    WiFi

    WIFI是一种无线联网技术,常见的是使用无线路由器,在这个无线路由器的信号覆盖的范围内都可以采用WIFI连接的方式进行联网。如果无线路由器连接了一个ADSL线路或其他的联网线路,则又被称为“热点”。

    首先,要操作WiFi,先要加入权限

    <uses-permission android:name="android.permission.CHANGE_NETWORK_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.ACCESS_WIFI_STATE"/>
    

    Android中对于Wifi操作本身提供了一些有用的包android.net.wifi

    WiFi常用相关类

    WifiManager用来管理我们的wifi连接

    取得WifiManager对象

    WifiManager mWifiManager=(WifiManager) context.getSystemService(Context.WIFI_SERVICE);  
    

    打开wifi

    if(!mWifiManager.isWifiEnabled())
    {  
         mWifiManager.setWifiEnabled(true);  
     }  
    

    关闭wifi

    if(mWifiManager.isWifiEnabled())
    {  
       mWifiManager.setWifiEnabled(false);  
    } 
    

    检查当前wifi状态

    mWifiManager.getWifiState()
    

    WIFI网卡状态

    • WifiManager.WIFI_STATE_DISABLING : WIFI网卡正在关闭(0)
    • WifiManager.WIFI_STATE_DISABLED : WIFI网卡不可用(1)
    • WifiManager.WIFI_STATE_ENABLING : WIFI网正在打开(2) (WIFI启动需要一段时间)
    • WifiManager.WIFI_STATE_ENABLED : WIFI网卡可用(3)
    • WifiManager.WIFI_STATE_UNKNOWN : 未知网卡状态

    WifiInfo

    wifi无线连接的信息,包括接入点,网络连接状态,隐藏的接入点,IP地址,连接速度,MAC地址,网络ID,信号强度等信息

    WifiInfo mWifiInfo=mWifiManager.getConnectionInfo();  
    
    • getBSSID() 获取BSSID,在手机WIFI中,就是MAC地址
    • getSSID() 获取SSID
    • getDetailedStateOf() 获取客户端的连通性
    • getHiddenSSID() 获得SSID是否被隐藏
    • getIpAddress() 获取IP地址
    • getLinkSpeed() 获得连接的速度
    • getMacAddress() 获得Mac地址
    • getRssi() 获得802.11n网络的信号
    • getSupplicanState() 返回具体客户端状态的信息

    ScanResult

    主要用来描述已经检测出的接入点,包括接入点的地址,接入点的名称,
    身份认证,频率,信号强度等信息。

    开始扫描

    mWifiManager.startScan()
    

    得到扫描结果

    List<ScanResult> mWifiList=mWifiManager.getScanResults();
    

    WifiConfiguration

    Wifi网络的配置,包括安全设置等。

    得到配置好的网络连接

    List<WifiConfiguration> mWifiConfigurations=mWifiManager.getConfiguredNetworks()
    

    连接配置好指定ID的网络

    mWifiManager.enableNetwork(mWifiConfigurations.get(index).networkId, true)
    

    处理网络

    动态处理WiFi网络

    //添加一个网络并连接  
    public void addNetWork(WifiConfiguration configuration){  
        int wcgId=mWifiManager.addNetwork(configuration);  
        mWifiManager.enableNetwork(wcgId, true);  
    }  
    //断开指定ID的网络  
    public void disConnectionWifi(int netId){  
        mWifiManager.disableNetwork(netId);  
        mWifiManager.disconnect();  
    }  
    

    连接到对应WiFi网络

    创建WifiConfiguration配置对象

    String ssid = "Rair";
    String pwd = "88888888";
    WifiConfiguration localWifiConfiguration = new WifiConfiguration();
    //公认的IEEE 802.11验证算法。
    localWifiConfiguration.allowedAuthAlgorithms.clear();
    localWifiConfiguration.allowedAuthAlgorithms.set(0);
    //公认的的公共组密码。
    localWifiConfiguration.allowedGroupCiphers.clear();
    localWifiConfiguration.allowedGroupCiphers.set(2);
    //公认的密钥管理方案。
    localWifiConfiguration.allowedKeyManagement.clear();
    localWifiConfiguration.allowedKeyManagement.set(1);
    //密码为WPA。
    localWifiConfiguration.allowedPairwiseCiphers.clear();
    localWifiConfiguration.allowedPairwiseCiphers.set(1);
    localWifiConfiguration.allowedPairwiseCiphers.set(2);
    //公认的安全协议。
    localWifiConfiguration.allowedProtocols.clear();
    
    localWifiConfiguration.SSID = ("\"" + ssid + "\"");
    localWifiConfiguration.preSharedKey = ("\"" + pwd + "\"");
    //不广播其SSID的网络
    localWifiConfiguration.hiddenSSID = true;
    

    WifiConfiguration对应的配置值可到文档中查看,不知道怎么翻译描述。O(∩_∩)O~

    添加WIFI网络

    wcnetworkid = mWifiManager.addNetwork(localWifiConfiguration);
    

    使WIFI网络有效

    mWifiManager.enableNetwork(wcnetworkid,true);
    

    锁定网络

    手机屏幕关闭之后,并且其他的应用程序没有在使用wifi的时候,系统大概在两分钟之后,会关闭wifi,使得wifi处于睡眠状态,有利于电源能量的节省和延长电池寿命。

    android为wifi提供了一种叫WifiLock的锁,能够阻止wifi进入睡眠状态,使wifi一直处于活跃状态。这种锁,在下载一个较大的文件的时候,比较适合使用。

    添加权限

    <uses-permission android:name="android.permission.WAKE_LOCK"/>
    

    创建wifiLock

    方式1:

     // lockName为锁的名称
     WifiLock wifiLock = wifiManager.createWifiLock(lockName);  
    

    方式2:

    wifiLock = wifiManager.createWifiLock(lockType, lockName);  
    

    lockType可以取以下值:

    • WIFI_MODE_FULL == 1 //扫描,自动的尝试去连接一个曾经配置过的热点
    • WIFI_MODE_SCAN_ONLY == 2 //只剩下扫描
    • WIFI_MODE_FULL_HIGH_PERF = 3 //在第一种模式的基础上,保持最佳性能

    wifi添加锁

    wifiLock.acquire();  
    

    wifi释放锁

    //判断wifi是否被lock锁持用
    if (wifiLock.isHeld())  
    {  
        // 释放锁
        wifiLock.release();  
    }  
    

    一般到了这个时候就该给个Demo了

    ConnectivityManagerDemo:连接管理的Demo,里面带一个NetworkConnUtil(网络连接帮助类),Demo都是以log形式显示结果。懒得写界面啦 (*)4

    WifiDemo: 里面带一个WifiUtil(Wifi连接帮助类)


    Demo已上传:RairDemo
    GitHub:https://github.com/Rairmmd/RairDemo
    Coding:https://coding.net/u/Rair/p/RairDemo/git

    相关文章

      网友评论

      • 跑步的小男孩:如何判断密码错误和超时连接呢
      • a7e23cf6d210:有的wifi需要用户名和密码来登录,这样如何处理呢?
        代码视觉:代码中手动构造wificonfiguration,把参数传进去就可以。
      • StevenCheuk:貌似6.0的获取不到WiFi列表 mWiFiManager.getScanResults()为null,网上查了很多都不行,有人说吧编译版本和target版本降到23以下可以绕过动态权限,但是我降了还是获取不到
        StevenCheuk:@Rair 可以了,请求了权限,但是不能帮你打开手机定位,要自己手动打开
        Reathin:@StevenCheuk 6.0回去wifi需要定位权限
      • 3b61ad491036:请问能实现监控每个已连接设备使用的流量吗?
      • 898138ff41ce:我打算帮同学做个扫描WIFI的,用androidstudo做,注册监听SCAN_RESULTS_AVAILABLE_ACTION,开始scan 一直没反应,我用的是华为honor8,不是到能不能指点一下。
        喝柠檬水:我用的p9 plus ,也是搜索不到,这是为什么
        898138ff41ce:@Rair 好了 谢谢
        Reathin:@繁花丿左逝 :hushed:
      • 福伟布莱恩特:我用手机开启热点根本连接不上他,大神?
        福伟布莱恩特:就是手机开热点,然后不设置密码,连接不上
      • Donething:谢谢,很有帮助。
        Reathin:@Donething :blush:

      本文标题:Android开发之WIFI与网络连接处理

      本文链接:https://www.haomeiwen.com/subject/dulqtxtx.html