如何在Android上以编程方式关闭3G / 数据连接?

37

我该如何在安卓设备上通过编程方式关闭3G/数据连接?

不是Wi-Fi,而是3G/数据连接。


4
如果这是一个重复的问题,我不会感到惊讶,但我不确定为什么有人投票将其关闭,认为它不是一个真正的问题。 - John Carter
4个回答

53

没有官方方法可以做到这一点。但是,可以通过反射的非官方方式来实现。

适用于Android 2.3及以上版本:

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);
}
这也需要以下权限。
 <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE"/>

对于Android 2.2及以下版本:

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);

需要以下权限:

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

请注意这两种方法都是非官方的,可能已经不再起作用了。不需要再提供此类故障的证明,因为2.2及以下版本的方法在2.3上已经失效。


谢谢。它真的起作用了。但我的问题是,“当数据包打开时,为什么它不显示在“数据使用>移动数据>打开”中?”@RaghavSood - Jigar Shekh
为了安全起见,请使用Try/Catch包围代码! - Muhammad Babar
java.lang.SecurityException: Permission Denial: writing com.android.providers.settings.SettingsProvider uri content://settings/system from pid=6683, uid=10109 requires android.permission.WRITE_SETTINGS, or grantUriPermission() - Muhammad Babar
java.lang.SecurityException: Permission denial: writing to secure settings requires android.permission.WRITE_SECURE_SETTINGS - Muhammad Babar
所以这个方法将不再起作用,因为android.permission.WRITE_SECURE_SETTINGS只能授予系统应用程序。 - Muhammad Babar
显示剩余9条评论

5

将代码放置在try/catch块中

public void mobiledataenable(boolean enabled) {

try { 
        final ConnectivityManager conman = (ConnectivityManager)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);
    }
    catch (Exception e)
    {
        e.printStackTrace();
    }     
}

在清单文件中,添加以下权限:

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

4
 public void onClick(View view){
        ConnectivityManager dataManager;
        dataManager  = (ConnectivityManager)getSystemService(Context.CONNECTIVITY_SERVICE);
        Method dataMtd = null;
        try {
            dataMtd = ConnectivityManager.class.getDeclaredMethod("setMobileDataEnabled", boolean.class);
        } catch (NoSuchMethodException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        dataMtd.setAccessible(true);
        try {
            dataMtd.invoke(dataManager, true);
        } catch (IllegalArgumentException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }   
    }

+1,它确实可以在Android 4.3上打开移动数据;但我们需要添加前一个答案建议的权限<uses-permission android:name="android.permission.MODIFY_PHONE_STATE" />。 - Alberici
这种方法在Android 4.2.2及更高版本中不再适用,因为android.permission.MODIFY_PHONE_STATE现在是一个受保护的权限,只授予系统应用程序。 - SilSur

2

我仍在使用2.1版本,所以这个解决方案适用于我。

但是你还需要包括 MODIFY_PHONE_STATE 权限。

完整代码(带有切换按钮)2.1:

package com.rivaldo.turn3gonoff;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

import android.os.Bundle;
import android.app.Activity;
import android.content.Context;
import android.telephony.TelephonyManager;
import android.view.Menu;
import android.widget.CompoundButton;
import android.widget.ToggleButton;

public class Turn3GOnOff extends Activity {

Method dataConnSwitchmethod_ON;
Method dataConnSwitchmethod_OFF;
Class telephonyManagerClass;
Object ITelephonyStub;
Class ITelephonyClass;


@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_turn3_gon_off);

    GetDataConnectionAPI();

    ToggleButton toggle = (ToggleButton) findViewById(R.id.toggleButton);
    toggle.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
        public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
            if (isChecked) {
                turn3GOn();
            } else {
                turn3GOff();
            }
        }
    });

}

private void GetDataConnectionAPI() {
    this.getApplicationContext();
    TelephonyManager telephonyManager = 
                    (TelephonyManager) this.getApplicationContext().
                                              getSystemService(Context.TELEPHONY_SERVICE);

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

        dataConnSwitchmethod_OFF = 
                        ITelephonyClass.getDeclaredMethod("disableDataConnectivity");
        dataConnSwitchmethod_ON = ITelephonyClass.getDeclaredMethod("enableDataConnectivity");   
    } catch (Exception e) { // ugly but works for me
        e.printStackTrace();
    }
}
private void turn3GOn() {
    dataConnSwitchmethod_ON.setAccessible(true);
    try {
        dataConnSwitchmethod_ON.invoke(ITelephonyStub);
    } catch (IllegalArgumentException e) {
        e.printStackTrace();
    } catch (IllegalAccessException e) {
        e.printStackTrace();
    } catch (InvocationTargetException e) {
        e.printStackTrace();
    }
}

private void turn3GOff() {
    dataConnSwitchmethod_OFF.setAccessible(true);
    try {
        dataConnSwitchmethod_OFF.invoke(ITelephonyStub);
    } catch (IllegalArgumentException e) {
        e.printStackTrace();
    } catch (IllegalAccessException e) {
        e.printStackTrace();
    } catch (InvocationTargetException e) {
        e.printStackTrace();
    }
}

}

Manifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.rivaldo.turn3gonoff"
android:versionCode="1"
android:versionName="1.0" >

<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.MODIFY_PHONE_STATE" />
<uses-sdk
    android:minSdkVersion="7"
    android:targetSdkVersion="7" />
<application
    android:allowBackup="true"
    android:icon="@drawable/ic_launcher"
    android:label="@string/app_name"
    android:theme="@style/AppTheme" >
    <activity
        android:name="com.rivaldo.turn3gonoff.Turn3GOnOff"
        android:label="@string/app_name" >
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />

            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>


</application>
</manifest>

activity_turn3_gon_off.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
tools:context=".Turn3GOnOff" >

<ToggleButton
    android:id="@+id/toggleButton"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:layout_alignParentLeft="true"
    android:layout_alignParentTop="true"
    android:layout_marginTop="60dp"
    android:textOn="3G on"
    android:textOff="3G off"
    android:text="ToggleButton" />

</RelativeLayout>

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接