如何判断“移动网络数据”是启用还是禁用(即使通过WiFi连接)?


68

我有一个应用程序,希望能够从远程查询中获取连接状态报告。

我想知道是否已连接WiFi,以及是否通过移动网络启用了数据访问。

如果WiFi超出范围,我想知道我是否可以依靠移动网络。

问题是,当我通过WiFi连接时,启用的数据始终返回true,并且只有在未通过WiFi连接时,我才能正确查询移动网络。

我所看到的所有答案都建议通过轮询来查看当前的连接,但是我想知道是否需要移动网络,即使目前我可能通过WiFi连接。

无论如何,是否无需轮询即可查看是否已连接是否启用了移动网络数据?

编辑

因此,当通过WiFi连接时,如果我转到设置并取消选择“启用数据”,然后在我的应用中执行以下操作:

 boolean mob_avail = 
 conMan.getNetworkInfo(ConnectivityManager.TYPE_MOBILE).isAvailable();

mob_avail返回为“ true”,但是我已禁用了移动网络数据,因此我希望它为“ false”

如果我关闭WiFi,则(正确)没有连接,因为我禁用了移动网络数据。

因此,当我通过WiFi连接时,如何检查是否启用了移动网络数据?

更新

我查看了ss1271的注释中建议的getAllNetworkInfo()

我在以下3种情况下输出了有关移动网络的返回信息

WiFi关闭-开启移动数据

WiFi打开-移动数据关闭

WiFi打开-移动数据打开

并得到以下结果:

关闭WiFi:

mobile [HSUPA],状态:CONNECTED / CONNECTED,原因:未知,额外:互联网,漫游:false,故障转移:false,isAvailable:true,featureId:-1,userDefault:false

开启WiFi /关闭手机

NetworkInfo:类型:mobile [HSUPA],状态:DISCONNECTED / DISCONNECTED,原因:connectionDisabled,额外:(无),漫游:false,故障转移:false,isAvailable:true,featureId:-1,userDefault:false

开启WiFi /开启手机

NetworkInfo:类型:mobile [HSPA],状态:DISCONNECTED / DISCONNECTED,原因:connectionDisabled,额外:(无),漫游:false,故障转移:false,isAvailable:true,featureId:-1,userDefault:false

因此,您可以看到isAvailable每次都返回true,并且状态仅在WiFi影响时显示为Disconnected。

澄清说明

希望查看手机当前是否通过移动网络连接。我AM试图建立在移动网络中的用户是否已启用/禁用数据访问。他们可以通过转到设置->无线和网络设置->移动网络设置->已启用数据来启用和禁用此功能。



1
您是否尝试过:getAllNetworkInfo()
dumbfingers,2012年

1
我记不起来了,但是我一回到家并进行更新,便会尝试。我想那会返回可用连接的数组?那我需要遍历数组吗?
凯文·布拉德肖2012年

1
是的,它将返回一个数组。老实说,我以前没有使用过,因此您可能需要打印一些日志以查看它将为您带来什么。并且请让我知道结果,祝您好运
傻瓜们2012年

Answers:


123

以下代码将告诉您是否启用了“移动数据”,而不管当前是否有活动的数据连接,或者是否启用/激活了wifi。 此代码仅适用于Android 2.3(Gingerbread)和更高版本。 实际上,此代码也可以在Android的早期版本中使用;-)

    boolean mobileDataEnabled = false; // Assume disabled
    ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
    try {
        Class cmClass = Class.forName(cm.getClass().getName());
        Method method = cmClass.getDeclaredMethod("getMobileDataEnabled");
        method.setAccessible(true); // Make the method callable
        // get the setting for "mobile data"
        mobileDataEnabled = (Boolean)method.invoke(cm);
    } catch (Exception e) {
        // Some problem accessible private API
        // TODO do whatever error handling you want here
    }

注意:您需要获得许可android.permission.ACCESS_NETWORK_STATE才能使用此代码。


2
辉煌!绝对完美。非常感谢您,这花了我1/3的声誉,但它确实满足了我的需要,因此花了很多钱。我可以请您对代码做些解释吗?这与我一直在尝试的内容以及作为解决方案向我建议的内容不同。我说您正在使用反射是正确的吗?我在反思中含糊其词,如果那是什么。这是后门把戏还是Android的受支持的真实功能?无论如何,再次感谢。你是明星!
凯文·布拉德肖

1
哇。非常感谢您的评论!很高兴我能帮助你。是的,此代码使用Java反射。由于某些愚蠢的原因,Android核心开发人员决定不公开用于获取和设置公共API中“启用移动数据”标志的方法。这样就可以使用这些方法,但是它们被标记为“私有”。使用反射,我们可以获得有关类的很多信息,甚至包括被认为是“ orivate”的信息。由于这是“不受支持的API”,因此它可能不适用于所有设备,并且在以后的Android版本中可能会更改。但是,它现在似乎确实可以在大多数设备上使用。
大卫·瓦瑟

2
@DavidWasser很棒。但是我需要引起关注,如果使用proguard“ getMobileDataEnabled”字符串将被转换为其他错误的结果。Proguard的不很好地反映工作
穆尔塔扎胡尔希德·侯赛因

2
这种方法有效,但是由于API开发人员可以随时删除私有方法,因此带来了巨大的风险
peterchaula

1
as long as you are using reflection on things that can not be obfuscated, such as frameworks or libraries我不知道 谢谢
Murtaza Khursheed Hussain

36

我已经升级了Allesio的答案。自4.2.2起,Settings.Secure的mobile_data int已移至Settings.Global。

如果您想知道即使启用并连接了wifi,是否也启用了移动网络,请尝试以下代码。

已更新以检查SIM卡是否可用。感谢您指出穆拉特。

boolean mobileYN = false;

TelephonyManager tm = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
if (tm.getSimState() == TelephonyManager.SIM_STATE_READY) {
    if(android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN_MR1)
    {
        mobileYN = Settings.Global.getInt(context.getContentResolver(), "mobile_data", 1) == 1;
    }
    else{
        mobileYN = Settings.Secure.getInt(context.getContentResolver(), "mobile_data", 1) == 1;
    }
}

1
我没有看到下Settings.Global任何这样的常量“mobile_data” developer.android.com/reference/android/provider/...。我想知道它是如何工作的?
LoveForDroid

1
@LoveForDroid这是Settings.Global类的隐藏成员。您可以在aosp源代码中找到它。
sNash

1
尽管设备上没有SIM卡,但Settings.Global.getInt(context.getContentResolver(),“ mobile_data”,1)返回1。
Murat

1
@Murat我添加了一些代码来检查sim是否可用。
sNash

2
我已经看到至少一台设备的设置中的“禁用移动数据”选项不会更改此设置(但会导致TelephonyManager.isDataEnabled()返回false)。设置中的错误可能是因为向下滑动菜单中的移动数据图标也未显示为已禁用,但它确实确实禁用了移动数据。
本·库恩

22

一种方法是检查用户是否在“设置”中激活了移动数据,如果无线网络关闭,很有可能会使用该数据。尽管可以在API中使用隐藏值,但是它可以工作(经过测试),并且不使用反射:

boolean mobileDataAllowed = Settings.Secure.getInt(getContentResolver(), "mobile_data", 1) == 1;

根据API的不同,您需要检查@ user1444325指出的Settings.Global而不是Settings.Secure。

来源: Android API调用,用于确定用户设置“已启用数据”


1
哇,那比反射方法整洁得多,反射方法显然不适用于棒棒糖。反对哪个版本的android测试?
凯文·布拉德肖

3
经过4.4.4和5.0.1测试。
Alessio 2015年

1
测试成功对4.2.2
JibяaᴎKhaᴎ

3
如果没有SIM卡,则将返回true,您也应该添加SIM卡验证
Joze 2016年

1
如果设备上没有移动数据(没有移动调制解调器),则返回true。
杰弗里·布拉特曼

4

@sNash的功能很好用。但是在少数设备中,我发现即使禁用了数据,它也会返回true。因此,我找到了另一种在Android API中的解决方案。

TelephonyManager的getDataState()方法将非常有用。

我使用上面的函数更新了@snash的函数。当禁用蜂窝数据时,下面的函数返回false,否则返回true。

private boolean checkMobileDataIsEnabled(Context context){
        boolean mobileYN = false;

        TelephonyManager tm = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
        if (tm.getSimState() == TelephonyManager.SIM_STATE_READY) {
            TelephonyManager tel = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
//          if(android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN_MR1)
//          {
//              mobileYN = Settings.Global.getInt(context.getContentResolver(), "mobile_data", 0) == 1;
//          }
//          else{
//              mobileYN = Settings.Secure.getInt(context.getContentResolver(), "mobile_data", 0) == 1;
//          }
            int dataState = tel.getDataState();
            Log.v(TAG,"tel.getDataState() : "+ dataState);
            if(dataState != TelephonyManager.DATA_DISCONNECTED){
                mobileYN = true;
            }

        }

        return mobileYN;
    }

3

您可以尝试这样的事情:

ConnectivityManager conMan = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);

//mobile
State mobile = conMan.getNetworkInfo(0).getState();

//wifi
State wifi = conMan.getNetworkInfo(1).getState();


if (mobile == NetworkInfo.State.CONNECTED || mobile == NetworkInfo.State.CONNECTING) 
{
    //mobile
}
else if (wifi == NetworkInfo.State.CONNECTED || wifi == NetworkInfo.State.CONNECTING) 
{
    //wifi
}

如果您确实有兴趣,请使用

NetworkInfo.State.CONNECTED 

仅,代替

NetworkInfo.State.CONNECTED || NetworkInfo.State.CONNECTING

1
正如我向第一(和第二)响应者指出的那样,这是行不通的,我不希望查看是否通过移动设备连接,我希望查看用户是否启用了移动数据。(他们可以通过转到“设置”->“无线和网络设置”->“移动网络设置”->“启用数据”来启用和禁用此功能)
Kevin Bradshaw 2012年

@KevinBradshaw,您可以使用它来检查是否启用了移动数据。如果启用了移动数据,那么您将获得NetworkInfo.State.CONNECTED或NetworkInfo.State.CONNECTING == mobile。因为如果启用了移动数据,则系统将尝试连接到网络或已连接。
米洛什2012年

我认为您需要尝试一下。在手机上禁用移动网络数据(取消选中设置->无线和网络设置->移动网络设置->启用数据)。运行您的代码,您将看到它将报告存在移动连接。NetworkInfo State不考虑用户是否启用了移动数据。请参阅接受的答案,这是我发现只能使用的方法。
凯文·布拉德肖

1

这是针对此问题的xamarin解决方案:

    public static bool IsMobileDataEnabled()
    {
        bool result = false;

        try
        {
            Context context = //get your context here or pass it as a param

            if (Build.VERSION.SdkInt >= BuildVersionCodes.JellyBeanMr1)
            {
                //Settings comes from the namespace Android.Provider
                result = Settings.Global.GetInt(context.ContentResolver, "mobile_data", 1) == 1;
            }
            else
            {
                result = Settings.Secure.GetInt(context.ContentResolver, "mobile_data", 1) == 1;
            }
        }
        catch (Exception ex)
        {
            //handle exception
        }

        return result;
    }

PS:确保您具有此代码的所有权限。




0

我认为使用NetworkInfo类和isConnected应该可以工作:

ConnectivityManager cm = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo info = cm.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);

return info != NULL || info.isConnected();

并检查移动数据是否连接。在测试之前,我无法确定。直到明天我才能做到。

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

if(tm .getDataState() == tm .DATA_CONNECTED)
   return true;

正如我对第一个响应所指出的那样,这是行不通的,我不是在看我是否通过移动设备连接,而是在查看用户是否启用了移动数据。(htey可以通过转到设置->无线和网络设置->移动网络设置->启用和禁用此功能)
Kevin Bradshaw

您是否尝试过TelephonyManager?它应该显示数据是否启用。
tozka 2012年

0
To identify which SIM or slot is making data connection active in mobile, we need to register action android:name="android.net.conn.CONNECTIVITY_CHANGE"  with permission   
uses-permission android:name="android.permission.CONNECTIVITY_INTERNAL" &    uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"

    public void onReceive(Context context, Intent intent) 
 if (android.net.conn.CONNECTIVITY_CHANGE.equalsIgnoreCase(intent
                .getAction())) {

IBinder b = ServiceManager.getService(Context.CONNECTIVITY_SERVICE);
 IConnectivityManager service =  IConnectivityManager.Stub.asInterface(b);
NetworkState[] states = service.getAllNetworkState();

 for (NetworkState state : states) {

                if (state.networkInfo.getType() == ConnectivityManager.TYPE_MOBILE
                        && state.networkInfo.isConnected()) {

 TelephonyManager mTelephonyManager = (TelephonyManager) context
                        .getSystemService(Context.TELEPHONY_SERVICE);
         int slotList =  { 0, 1 };
          int[] subId = SubscriptionManager.getSubId(slotList[0]);
          if(mTelephonyManager.getDataEnabled(subId[0])) {
             // this means data connection is active for SIM1 similary you 
             //can chekc for SIM2 by slotList[1]
               .................
          }
}

}

0
    ConnectivityManager cm = (ConnectivityManager) activity
                        .getSystemService(Context.CONNECTIVITY_SERVICE);
                NetworkInfo info = cm.getActiveNetworkInfo();
                String networkType = "";
    if (info.getType() == ConnectivityManager.TYPE_WIFI) {
                    networkType = "WIFI";
                } 
else if (info.getType() == ConnectivityManager.TYPE_MOBILE) {

                    networkType = "mobile";
    }


0

这是来自其他两个答案的简单解决方案:

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

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            return tm.isDataEnabled();

        } else {
            return tm.getSimState() == TelephonyManager.SIM_STATE_READY && tm.getDataState() != TelephonyManager.DATA_DISCONNECTED;
        }

0

好了,有一种解决方法可以检查数据连接是否打开。但是我不确定它是否可以在所有设备上运行。您需要检查一下。(适用于Android一台设备)

long data = TrafficStats.getMobileRxBytes();
if(data > 0){
    //Data is On
}
else{
    //Data is Off
}

如果您不知道此方法,它将返回自设备启动以来通过移动网络接收的字节总数。当您关闭移动数据连接时,它将返回零(0)。打开时,它将再次返回总字节数。但是您需要知道,使用此替代方法时可能会发生问题。

  • 重新启动电话时,此方法还将返回0,因为计算从0字节开始。

0
private boolean haveMobileNetworkConnection() {
        boolean haveConnectedMobile = false;

        ConnectivityManager cm = (ConnectivityManager) getActivity().getSystemService(Context.CONNECTIVITY_SERVICE);
        NetworkInfo[] netInfo = cm.getAllNetworkInfo();

        for (NetworkInfo ni : netInfo) {

            if (ni.getTypeName().equalsIgnoreCase("MOBILE"))
                if (ni.isConnected())
                    haveConnectedMobile = true;
        }
        return haveConnectedMobile;
    }

注意:您将需要具有android.permission.ACCESS_NETWORK_STATE权限才能使用此代码



0

由于ConnectivityManager.allNetworkInfo已弃用,Android建议使用getNetworkCapabilities

fun isOnMobileData(): Boolean {
    val connectivityManager =
        context.getSystemService(CONNECTIVITY_SERVICE) as ConnectivityManager
    val all = connectivityManager.allNetworks

    return all.any {
        val capabilities = connectivityManager.getNetworkCapabilities(it)
        capabilities?.hasTransport(TRANSPORT_CELLULAR) == true
    }
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.