如何在 Android 上禁用移动数据

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3644144/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-20 11:08:20  来源:igfitidea点击:

How to disable Mobile Data on Android

android

提问by TyCobb

Quick back story before someone tells me to buy an app. =)

在有人告诉我购买应用程序之前的快速背景故事。=)

I just got an EVO and it chews through the battery fairly quick. I downloaded JuiceDefender to manage my mobile data connection. That seems have worked out fairly well. However, the settings are just very restricted (even on the paid versions).

我刚买了一个 EVO,它消耗电池的速度相当快。我下载了 JuiceDefender 来管理我的移动数据连接。这似乎效果很好。但是,设置非常有限(即使是付费版本)。

As of right now I am trying to develop a much more customizable battery saving application. The main thing I am trying to do first be able to enable/disable the mobile data connection at will.

截至目前,我正在尝试开发一个更加可定制的省电应用程序。我首先尝试做的主要事情是能够随意启用/禁用移动数据连接。

The problem is I can't find any code snippets or articles on how to do this. The only thing I have found is the following. I don't know how accurate this is, but this was all I could piece together browsing developer.android.com

问题是我找不到任何关于如何执行此操作的代码片段或文章。我唯一发现的是以下内容。我不知道这有多准确,但我只能拼凑浏览 developer.android.com

ConnectivityManager cm = (ConnectivityManager) this.getSystemService(CONNECTIVITY_SERVICE);
cm.stopUsingNetworkFeature(ConnectivityManager.TYPE_MOBILE, "android.net.conn.CONNECTIVITY_CHANGE");

State state = cm.getNetworkInfo(ConnectivityManager.TYPE_MOBILE).getState();
textView.setText(state.name());

If anyone can point me to anything that could help, it would be most appreciated.

如果有人能指出任何可以帮助我的东西,我将不胜感激。

UPDATE

更新

It appears that the HTC Evo on Sprint does not use APN settings. I tested this by downloading APNDroid and watching it not work. I then made a quick app to dump all APN entries to the screen. That yielded one result and it was for mms.

Sprint 上的 HTC Evo 似乎没有使用 APN 设置。我通过下载 APNDroid 并观察它不起作用来测试它。然后我制作了一个快速应用程序来将所有 APN 条目转储到屏幕上。这产生了一个结果,它是针对 mms 的。

Looking at the phone info when JuiceDefender is running, I found that the GSRP network is getting turned on and off. This leaves me to believe it is possible to do it through code even though every page I find asking about this same issue says it cannot be done. The kicker is they all say to do it like APNDroid. Please someone give me some insight.

查看 JuiceDefender 运行时的电话信息,我发现 GSRP 网络正在打开和关闭。这让我相信可以通过代码来完成,即使我发现询问相同问题的每个页面都说它无法完成。关键是他们都说要像 APNDroid 那样做。请有人给我一些见解。

Thanks!

谢谢!

采纳答案by Indra

The Dataconnection disable and enabling APIS are hidden in the SDK and not exposed to the user, this can be achived by accessing the ITelephony interface using the java reflection technique.

Dataconnection 禁用和启用 APIS 隐藏在 SDK 中并且不公开给用户,这可以通过使用 java 反射技术访问 ITelephony 接口来实现。

here you go:

干得好:

    Method dataConnSwitchmethod;
    Class telephonyManagerClass;
    Object ITelephonyStub;
    Class ITelephonyClass;

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

    if(telephonyManager.getDataState() == TelephonyManager.DATA_CONNECTED){
        isEnabled = true;
    }else{
        isEnabled = false;  
    }   

    telephonyManagerClass = Class.forName(telephonyManager.getClass().getName());
    Method getITelephonyMethod = telephonyManagerClass.getDeclaredMethod("getITelephony");
    getITelephonyMethod.setAccessible(true);
    ITelephonyStub = getITelephonyMethod.invoke(telephonyManager);
    ITelephonyClass = Class.forName(ITelephonyStub.getClass().getName());

    if (isEnabled) {
        dataConnSwitchmethod = ITelephonyClass
                .getDeclaredMethod("disableDataConnectivity");
    } else {
        dataConnSwitchmethod = ITelephonyClass
                .getDeclaredMethod("enableDataConnectivity");   
    }
    dataConnSwitchmethod.setAccessible(true);
    dataConnSwitchmethod.invoke(ITelephonyStub);

回答by Vladimir Sorokin

Starting from 'Gingerbread' you can use the IConnectivityManager.setMobileDataEnabled()method. It's hidden in API, but can be accessed with reflection. http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/2.2_r1.1/android/net/ConnectivityManager.java#376

从“姜饼”开始,您可以使用IConnectivityManager.setMobileDataEnabled()方法。它隐藏在 API 中,但可以通过反射访问。 http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/2.2_r1.1/android/net/ConnectivityManager.java#376

With this method you can change the system setting: 'Settings -> Wireless & network -> Mobile network settings -> Data Enabled'

使用此方法,您可以更改系统设置:'设置 -> 无线和网络 -> 移动网络设置 ->数据已启用'

Code example:

代码示例:

private void setMobileDataEnabled(Context context, boolean enabled) {
    final ConnectivityManager conman = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
    final Class conmanClass = Class.forName(conman.getClass().getName());
    final Field iConnectivityManagerField = conmanClass.getDeclaredField("mService");
    iConnectivityManagerField.setAccessible(true);
    final Object iConnectivityManager = iConnectivityManagerField.get(conman);
    final Class iConnectivityManagerClass = Class.forName(iConnectivityManager.getClass().getName());
    final Method setMobileDataEnabledMethod = iConnectivityManagerClass.getDeclaredMethod("setMobileDataEnabled", Boolean.TYPE);
    setMobileDataEnabledMethod.setAccessible(true);

    setMobileDataEnabledMethod.invoke(iConnectivityManager, enabled);
}

Also you need the CHANGE_NETWORK_STATEpermission.

您还需要CHANGE_NETWORK_STATE权限。

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

Needless to say that this approach might not work in future android versions. But I guess that applications such as '3G watchdog', 'APNdroid' or 'DataLock' work this way.

不用说,这种方法可能不适用于未来的 android 版本。但我猜想像“3G 看门狗”、“APNdroid”或“DataLock”这样的应用程序是这样工作的。



UPDATE:
setMobileDataEnabled method is no longer available on Lollipop

更新
Lollipop 上不再提供 setMobileDataEnabled 方法

回答by Z80

Switching the mobile data net connectivity by changing the APN's name doesn't work well any more since Gingerbread. And while the reflection code is probably the right way to do the trick, it won't work, because the application needs the android.permission.MODIFY_PHONE_STATE permission as explained by Alex P. Otherwise you get this nasty exception:

自 Gingerbread 以来,通过更改 APN 的名称来切换移动数据网络连接不再有效。虽然反射代码可能是解决问题的正确方法,但它不起作用,因为应用程序需要 android.permission.MODIFY_PHONE_STATE 权限,正如 Alex P 所解释的那样。否则你会得到这个令人讨厌的异常:

03-18 21:54:55.074: WARN/System.err(1851): java.lang.reflect.InvocationTargetException
(...)
03-18 21:54:55.263: WARN/System.err(1851): Caused by: java.lang.SecurityException: Neither user 10037 nor current process has android.permission.MODIFY_PHONE_STATE.
(...)
03-18 21:54:55.303: WARN/System.err(1851):     at com.android.internal.telephony.ITelephony$Stub$Proxy.disableDataConnectivity(ITelephony.java:888)

Unfortunately, you cannot set this permission, because it is a level 3 permission not allowed for applications:

不幸的是,您无法设置此权限,因为它是应用程序不允许的 3 级权限:

03-18 21:48:39.334: WARN/PackageManager(75): Not granting permission android.permission.MODIFY_PHONE_STATE to package XXX (protectionLevel=3 flags=0x8be46)

I don't suppose anyone has a way to override the permission grant suppression other than by using own firmware.

我认为除了使用自己的固件之外,没有人有办法覆盖权限授予抑制。

回答by Muzikant

Notice that "android.permission.MODIFY_PHONE_STATE" is no longer supported for Android 2.3 and up.

请注意,Android 2.3 及更高版本不再支持“android.permission.MODIFY_PHONE_STATE”。

why 2.3 version of android does not hava android.permission.MODIFY_PHONE_STATE ? and what is the solution for this?

为什么 2.3 版本的 android 没有 android.permission.MODIFY_PHONE_STATE ?解决这个问题的方法是什么?

回答by greg121

to add a toggle button you can use this code in addition Vladimir's Answer:

要添加切换按钮,除了 Vladimir 的回答之外,您还可以使用此代码:

TelephonyManager telephonyManager = (TelephonyManager) context
                .getSystemService(Context.TELEPHONY_SERVICE);
switch (telephonyManager.getDataState()) {
        case TelephonyManager.DATA_CONNECTED:
            setMobileDataEnabledMethod.invoke(iConnectivityManager, false);
            break;
        case TelephonyManager.DATA_DISCONNECTED:
            setMobileDataEnabledMethod.invoke(iConnectivityManager, true);
            break;
        }

This reflection workaround is still working for me on android 4.0.4

这种反射解决方法在 android 4.0.4 上仍然对我有用

回答by Telmo Marques

I think there are two primary types of mobile data connection on an android device: WiFi and 3G/HSDPA/etc.

我认为 Android 设备上有两种主要类型的移动数据连接:WiFi 和 3G/HSDPA/等。

And afaik you should be able to disable WiFi programmatically, but I think the 3G/HSDPA/etc connections can only be disabled by changing the APN's name. The reason I'm saying this is because the popular application APNDroiddoes it that way.

而且你应该能够以编程方式禁用 WiFi,但我认为 3G/HSDPA/etc 连接只能通过更改 APN 的名称来禁用。我之所以这么说是因为流行的应用程序APNDroid就是这样做的。

回答by Alex P.

@Mariux: You probably forgot to add <uses-permission android:name="android.permission.MODIFY_PHONE_STATE" />to AndroidManifest.xml

@Mariux:您可能忘记添加<uses-permission android:name="android.permission.MODIFY_PHONE_STATE" />到 AndroidManifest.xml

回答by Krishna Patel

    final ConnectivityManager conman = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
    final Class conmanClass = Class.forName(conman.getClass().getName());
    final Field connectivityManagerField = conmanClass.getDeclaredField("mService");
    connectivityManagerField.setAccessible(true);
    final Object connectivityManager = connectivityManagerField.get(conman);
    final Class connectivityManagerClass = Class.forName(connectivityManager.getClass().getName());
    final Method setMobileDataEnabledMethod = connectivityManagerClass.getDeclaredMethod("setMobileDataEnabled", Boolean.TYPE);
    setMobileDataEnabledMethod.setAccessible(true);

    setMobileDataEnabledMethod.invoke(connectivityManager, enabled); // pass true or false