2 usniyo usniyo 于 2012.10.09 14:23 提问

android 如何实现移动数据上网的开关?

android 如何实现移动数据上网的开关?之前百度了一下,找到几篇,但都说不行,今天再搜索,想试一试,竟都不见了!特来此求肋。谢谢

10个回答

usniyo
usniyo   2012.10.09 23:25
已采纳

感谢名位的回答,虽然没有用到,但也是学到了些东西的。本人已经找到了解决办法,也在此分享吧:
解决办法中使用到了ConnectivityManager类,但是在SDK中的ConnectivityManager类并没有提供setMobileDataEnable()、getMobileDataEnable()等方法。也看了ConnectivityManager类的源码,里面都是有这些方法的。弄了大半天,最终狠下心来,自己写个ConnectivityManager类,其中的方法和源ConnectivityManager类的方法一样,但都是空实现,编译成ConnectivityManager.class文件,然后替换android.jar包中的android.net.ConnectivityManager.class文件。然后在项目中,使用ConnectivityManager的setMobileDataEnable()方法来打开和关闭数据上网,使用getMobileDataEnable()方法获得当前连接状态,当然这需要android.permission.CHANGE_NETWORK_STATE和android.permission.ACCESS_NETWORK_STATE权限。
ConnectivityManager类如下:

    package android.net;

    import java.net.InetAddress;

    public class ConnectivityManager
    {

public static final String CONNECTIVITY_ACTION = "android.net.conn.CONNECTIVITY_CHANGE";
    public static final String CONNECTIVITY_ACTION_IMMEDIATE = "android.net.conn.CONNECTIVITY_CHANGE_IMMEDIATE";
    public static final String EXTRA_NETWORK_INFO = "networkInfo";
    public static final String EXTRA_IS_FAILOVER = "isFailover";
    public static final String EXTRA_OTHER_NETWORK_INFO = "otherNetwork";
    public static final String EXTRA_NO_CONNECTIVITY = "noConnectivity";
    public static final String EXTRA_REASON = "reason";
    public static final String EXTRA_EXTRA_INFO = "extraInfo";
    public static final String EXTRA_INET_CONDITION = "inetCondition";
    public static final String ACTION_BACKGROUND_DATA_SETTING_CHANGED = "android.net.conn.BACKGROUND_DATA_SETTING_CHANGED";
    public static final String INET_CONDITION_ACTION = "android.net.conn.INET_CONDITION_ACTION";
    public static final String ACTION_TETHER_STATE_CHANGED = "android.net.conn.TETHER_STATE_CHANGED";
    public static final String EXTRA_AVAILABLE_TETHER = "availableArray";
    public static final String EXTRA_ACTIVE_TETHER = "activeArray";
    public static final String EXTRA_ERRORED_TETHER = "erroredArray";
    public static final int TYPE_NONE = -1;
    public static final int TYPE_MOBILE = 0;
    public static final int TYPE_WIFI = 1;
    public static final int TYPE_MOBILE_MMS = 2;
    public static final int TYPE_MOBILE_SUPL = 3;
    public static final int TYPE_MOBILE_DUN = 4;
    public static final int TYPE_MOBILE_HIPRI = 5;
    public static final int TYPE_WIMAX = 6;
    public static final int TYPE_BLUETOOTH = 7;
    public static final int TYPE_DUMMY = 8;
    public static final int TYPE_ETHERNET = 9;
    public static final int TYPE_MOBILE_FOTA = 10;
    public static final int TYPE_MOBILE_IMS = 11;
    public static final int TYPE_MOBILE_CBS = 12;
    public static final int TYPE_WIFI_P2P = 13;
    public static final int MAX_RADIO_TYPE = TYPE_WIFI_P2P;
    public static final int MAX_NETWORK_TYPE = TYPE_WIFI_P2P;
    public static final int DEFAULT_NETWORK_PREFERENCE = TYPE_WIFI;

    public static boolean isNetworkTypeValid(int networkType)
    {
        return networkType >= 0 && networkType <= MAX_NETWORK_TYPE;
    }

    /** {@hide} */
    public static String getNetworkTypeName(int type)
    {
        return Integer.toString(type);
    }

    /** {@hide} */
    public static boolean isNetworkTypeMobile(int networkType)
    {
        return false;
    }

    public void setNetworkPreference(int preference)
    {
    }

    public int getNetworkPreference()
    {
        return 0;
    }

    class NetworkInfo
    {
    }

    public NetworkInfo getActiveNetworkInfo()
    {
        return null;
    }

    /** {@hide} */
    public NetworkInfo getActiveNetworkInfoForUid(int uid)
    {
        return null;
    }

    public NetworkInfo getNetworkInfo(int networkType)
    {
        return null;
    }

    public NetworkInfo[] getAllNetworkInfo()
    {
        return null;
    }

    /** {@hide} */
    public LinkProperties getActiveLinkProperties()
    {
        return null;
    }

    /** {@hide} */
    public LinkProperties getLinkProperties(int networkType)
    {
        return null;
    }

    /** {@hide} */
    public boolean setRadios(boolean turnOn)
    {
        return turnOn;
    }

    /** {@hide} */
    public boolean setRadio(int networkType, boolean turnOn)
    {
        return turnOn;
    }

    public int startUsingNetworkFeature(int networkType, String feature)
    {
        return networkType;
    }

    public int stopUsingNetworkFeature(int networkType, String feature)
    {
        return networkType;
    }

    public boolean requestRouteToHost(int networkType, int hostAddress)
    {
        return false;
    }

    public boolean requestRouteToHostAddress(int networkType,
            InetAddress hostAddress)
    {
        return false;
    }

    @Deprecated
    public boolean getBackgroundDataSetting()
    {
        return true;
    }

    @Deprecated
    public void setBackgroundDataSetting(boolean allowBackgroundData)
    {
    }

    public NetworkQuotaInfo getActiveNetworkQuotaInfo()
    {
        return null;

    }

    public boolean getMobileDataEnabled()
    {
        return false;
    }

    public void setMobileDataEnabled(boolean enabled)
    {
    }

    class Context
    {
    }

    public static ConnectivityManager from(Context context)
    {
        return new ConnectivityManager();
    }

    public String[] getTetherableIfaces()
    {
        return null;
    }

    public String[] getTetheredIfaces()
    {
        return null;
    }

    public String[] getTetheringErroredIfaces()
    {
        return null;
    }

    public int tether(String iface)
    {
        return 0;
    }

    public int untether(String iface)
    {
        return 0;
    }

    public boolean isTetheringSupported()
    {
        return false;
    }

    public String[] getTetherableUsbRegexs()
    {
        return null;
    }

    public String[] getTetherableWifiRegexs()
    {
        return null;
    }

    public String[] getTetherableBluetoothRegexs()
    {
        return null;
    }

    public int setUsbTethering(boolean enable)
    {
        return 0;
    }

    /** {@hide} */
    public static final int TETHER_ERROR_NO_ERROR = 0;
    /** {@hide} */
    public static final int TETHER_ERROR_UNKNOWN_IFACE = 1;
    /** {@hide} */
    public static final int TETHER_ERROR_SERVICE_UNAVAIL = 2;
    /** {@hide} */
    public static final int TETHER_ERROR_UNSUPPORTED = 3;
    /** {@hide} */
    public static final int TETHER_ERROR_UNAVAIL_IFACE = 4;
    /** {@hide} */
    public static final int TETHER_ERROR_MASTER_ERROR = 5;
    /** {@hide} */
    public static final int TETHER_ERROR_TETHER_IFACE_ERROR = 6;
    /** {@hide} */
    public static final int TETHER_ERROR_UNTETHER_IFACE_ERROR = 7;
    /** {@hide} */
    public static final int TETHER_ERROR_ENABLE_NAT_ERROR = 8;
    /** {@hide} */
    public static final int TETHER_ERROR_DISABLE_NAT_ERROR = 9;
    /** {@hide} */
    public static final int TETHER_ERROR_IFACE_CFG_ERROR = 10;

    public int getLastTetherError(String iface)
    {
        return 0;
    }

    public boolean requestNetworkTransitionWakelock(String forWhom)
    {
        return false;
    }

    public void reportInetCondition(int networkType, int percentage)
    {
    }

    class PointerProperties
    {
    }

    public void setGlobalProxy(PointerProperties p)
    {
    }

    public PointerProperties getGlobalProxy()
    {
        return null;
    }

    public PointerProperties getProxy()
    {
        return null;
    }

    public void setDataDependency(int networkType, boolean met)
    {
    }

    public boolean isNetworkSupported(int networkType)
    {
        return false;
    }

    public boolean isActiveNetworkMetered()
    {
        return false;
    }
}
jl_qiqi
jl_qiqi 兄弟,能指点一下吗?我也遇到了这个问题,用反射不好使,有时能够切换,有时又不能。邮箱:jl_qiqi@163.com,不胜感激
4 年多之前 回复
liuxiang7831223
liuxiang7831223   2014.01.09 12:09

用我这个方法绝对好使,适用于任何手机。不需要放到系统里编译,也不需要导入jar包。

public void setMobileDataStatus(Context context, boolean enabled)

{

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

         // ConnectivityManager类  
       Class<?> conMgrClass = null;  
        // ConnectivityManager类中的字段  
       Field iConMgrField = null;  
        // IConnectivityManager类的引用  
         Object iConMgr = null;  
        // IConnectivityManager类  
         Class<?> iConMgrClass = null;  
        // setMobileDataEnabled方法  
         Method setMobileDataEnabledMethod = null;  
        try {  
             // 取得ConnectivityManager类  
             conMgrClass = Class.forName(conMgr.getClass().getName());  
             // 取得ConnectivityManager类中的对象Mservice  
             iConMgrField = conMgrClass.getDeclaredField("mService");  
             // 设置mService可访问  
             iConMgrField.setAccessible(true);  
             // 取得mService的实例化类IConnectivityManager  
             iConMgr = iConMgrField.get(conMgr);  
             // 取得IConnectivityManager类  
             iConMgrClass = Class.forName(iConMgr.getClass().getName());  
             // 取得IConnectivityManager类中的setMobileDataEnabled(boolean)方法  
             setMobileDataEnabledMethod = iConMgrClass.getDeclaredMethod(  
                     "setMobileDataEnabled", Boolean.TYPE);  
             // 设置setMobileDataEnabled方法是否可访问  
             setMobileDataEnabledMethod.setAccessible(true);  
             // 调用setMobileDataEnabled方法  
             setMobileDataEnabledMethod.invoke(iConMgr, enabled);  
       } catch (ClassNotFoundException e) {  
             e.printStackTrace();  
       } catch (NoSuchFieldException e) {  
            e.printStackTrace();  
       } catch (SecurityException e) {  
            e.printStackTrace();  
       } catch (NoSuchMethodException e) {  
             e.printStackTrace();  
       } catch (IllegalArgumentException e) {  
             e.printStackTrace();  
       } catch (IllegalAccessException e) {  
            e.printStackTrace();  
       } catch (InvocationTargetException e) {  
            e.printStackTrace();  
       }  
  }  
ignorefei
ignorefei 为什么我的没反应啊A啊啊啊啊
大约 2 年之前 回复
u012483914
u012483914 我的运行直接就没有反应了
大约 3 年之前 回复
u014065362
u014065362 我用这个方法,手机刚开始试了两次有反应,之后就再也没有反应了。。。。????
3 年多之前 回复
yizhenbeifeng
yizhenbeifeng   2012.10.09 14:34

设置-》流量使用情况

我的是在这里能够开关
不过我不知道各个手机的情况一样不,我的系统是android4.1.1

不知道楼主是想用代码实现还是手机功能?我是按照手机功能回答的

Tibib
Tibib   2013.01.11 13:37

1、调用隐藏的方法可以在源代码中进行编译
2、利用反射

希望下面文章对你有帮助
http://blog.csdn.net/tibib/article/details/8469871

niangzhi
niangzhi   2012.10.09 14:45

这个是一种方法,但是对有些手机可能无法实现,我的可以,你可以试一下
Java code

@SuppressWarnings("unchecked")
    public void openDataConnect() throws ClassNotFoundException,
            SecurityException, NoSuchMethodException, IllegalArgumentException,
            IllegalAccessException, InvocationTargetException {
        Method dataConnSwitchmethod;
        Class telephonyManagerClass;
        Object ITelephonyStub;
        Class ITelephonyClass;
        boolean isEnabled = false;

        TelephonyManager telephonyManager = (TelephonyManager) context.get()
                .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);
    }
niangzhi
niangzhi 不客气,问题解决了就好
5 年多之前 回复
usniyo
usniyo 非常感谢您的解答,虽然没有用到,但也是学习了。
5 年多之前 回复
liangchichexin
liangchichexin   2012.10.09 14:57

android APN的打开与关闭
由于Android对于APN的网络API没有公开,不过我们可以阅读源代码,然后进行数
据库操作,系统会自动监听数据库的变化,从而实现开启或者关闭APN。
大家可以研究一下frameworks/base/core/java/android/provider
/Telephony.java这个类,
比较重要的就是 URI 和数据库字段: content://telephony/carriers
字段可以在Telephony.java中找到。
其实原理很简单 :
1 、 当开启APN的时候,设置一个正确的移动或者联通的APN
2、 关闭的时候设置一个错误APN就会自动关闭网络
看代码:Activity:

Java代码

package cc.mdev.apn; 
import java.util.ArrayList; 
import java.util.List; 
import android.app.Activity; 
import android.content.ContentValues; 
import android.database.Cursor; 
import android.net.Uri; 
import android.os.Bundle; 
import android.util.Log; 
import android.view.View; 
import android.widget.Button; 

public class Main extends Activity { 

Uri uri = Uri.parse("content://telephony/carriers"); 
@Override 
public void onCreate(Bundle savedInstanceState) { 
super.onCreate(savedInstanceState); 
setContentView(R.layout.main); 
Button open= (Button) findViewById(R.id.open); 
Button close= (Button) findViewById(R.id.close); 
open.setOnClickListener(new View.OnClickListener() { 
@Override 
public void onClick(View v) { 
openAPN(); 
} 
}); 
close.setOnClickListener(new View.OnClickListener() { 
@Override 
public void onClick(View v) { 
closeAPN(); 
} 
}); 
} 
public  void openAPN(){ 
List<APN> list = getAPNList(); 
for (APN apn : list) { 
ContentValues cv = new ContentValues(); 
cv.put("apn", APNMatchTools.matchAPN(apn.apn)); 
cv.put("type", APNMatchTools.matchAPN(apn.type)); 
getContentResolver().update(uri, cv, "_id=?", new String[]{apn.id}); 
} 
} 
public void closeAPN(){ 
List<APN> list = getAPNList(); 
for (APN apn : list) { 
ContentValues cv = new ContentValues(); 
cv.put("apn", APNMatchTools.matchAPN(apn.apn)+"mdev"); 
cv.put("type", APNMatchTools.matchAPN(apn.type)+"mdev"); 
getContentResolver().update(uri, cv, "_id=?", new String[]{apn.id}); 
} 
} 
private List<APN> getAPNList(){ 
String tag = "Main.getAPNList()"; 
//current不为空表示可以使用的APN 
String  projection[] = {"_id,apn,type,current"}; 
Cursor cr = this.getContentResolver().query(uri, projection, null, null, null); 
List<APN> list = new ArrayList<APN>(); 
while(cr!=null && cr.moveToNext()){ 
Log.d(tag, cr.getString(cr.getColumnIndex("_id")) + "  " + cr.getString(cr.getColumnIndex("apn")) + "  " + cr.getString(cr.getColumnIndex("type"))+ "  " + cr.getString(cr.getColumnIndex("current"))); 
APN a = new APN(); 
a.id = cr.getString(cr.getColumnIndex("_id")); 
a.apn = cr.getString(cr.getColumnIndex("apn")); 
a.type = cr.getString(cr.getColumnIndex("type")); 
list.add(a); 
} 
if(cr!=null) 
cr.close(); 
return list; 
} 
public static class APN{ 
String id; 
String apn; 
String type; 
} 
} 

APNMatchTools.java
Java代码

package cc.mdev.apn; 

public final class APNMatchTools { 
public static class APNNet{ 

public static String CMWAP = "cmwap"; 

public static String CMNET = "cmnet"; 
//中国联通3GWAP设置        中国联通3G因特网设置        中国联通WAP设置        中国联通因特网设置 
//3gwap                 3gnet                uniwap            uninet 

public static String GWAP_3 = "3gwap"; 

public static String GNET_3="3gnet"; 

public static String UNIWAP="uniwap"; 

public static String UNINET="uninet"; 
} 
public static String matchAPN(String currentName) { 
if("".equals(currentName) || null==currentName){ 
return ""; 
} 
currentName = currentName.toLowerCase(); 
if(currentName.startsWith(APNNet.CMNET)) 
return APNNet.CMNET; 
else if(currentName.startsWith(APNNet.CMWAP)) 
return APNNet.CMWAP; 
else if(currentName.startsWith(APNNet.GNET_3)) 
return APNNet.GNET_3; 
else if(currentName.startsWith(APNNet.GWAP_3)) 
return APNNet.GWAP_3; 
else if(currentName.startsWith(APNNet.UNINET)) 
return APNNet.UNINET; 
else if(currentName.startsWith(APNNet.UNIWAP)) 
return APNNet.UNIWAP; 
else if(currentName.startsWith("default")) 
return "default"; 
else return ""; 
// return currentName.substring(0, currentName.length() - SUFFIX.length()); 
} 
} 

最后不要忘记加上修改APN的权限:
Xml代码

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

经过测试在G1 上联通和移动卡均是成功的。

usniyo
usniyo 非常感谢您的解答,虽然没有用到,但也是学习了。
5 年多之前 回复
Sueyexin
Sueyexin   2012.10.09 15:04

frameworks\base\packages\SystemUI\src\com\android\systemui\statusbar\tablet\SettingsView.java路径下

public class SettingsView extends LinearLayout implements View.OnClickListener{
  //增加数据广播实例声明
  DataEnabledController mDataEnabled;
  ...

  //在该方法下增加~
  protected void onFinishInflate() {
  ...
  mDataEnabled = new DataEnabledController(context,
(CompoundButton)findViewById(R.id.dataEnable_checkbox));
  }

}


再在SystemUI\res下相应的xml布局文件内加入
<LinearLayout
  android:id="@+id/dataEnable"
  style="@style/StatusBarPanelSettingsRow"
  >
  <ImageView
  android:id="@+id/dataEnable_icon"
  style="@style/StatusBarPanelSettingsIcon"
  android:src="@drawable/ic_sysbar_data_switcher"
  />
  <TextView
  android:id="@+id/dataEnable_label"
  style="@style/StatusBarPanelSettingsContents"
  android:text="@string/status_bar_settings_data_enabled"
  />
  <Switch
  android:id="@+id/dataEnable_checkbox"
  android:layout_width="wrap_content"
  android:layout_height="wrap_content"
  android:layout_gravity="center_vertical"
  android:layout_marginRight="5dp"
  />
  </LinearLayout>
  <View style="@style/StatusBarPanelSettingsPanelSeparator" />

最后在SystemUI\res下加入相应资源图片和字符串即可~ 希望对你有所帮助~

Baby_Bonnie
Baby_Bonnie   2012.11.20 09:50

4.0 以后的 Android 不在提供普通应用程序对 APN(Access Point Name) 修改的权限,如果强制修改的话,会报安全异常直接挂掉的。除非有当前设备系统应用的签名,然后打包进你修改 APN 的应用里面。

2.x 的系统可以尝试一下以下代码,

public static boolean setNETMode()
{
    ContentResolver resolver = context.getContentResolver();
    Cursor cursor = 
      resolver.query(Uri.parse("content://telephony/carriers"), 
      new String[] { "_id" }, "apn like '%net' and current=1", null, 
      null);

    if ((cursor != null) && (cursor.moveToNext()))
    {
      ContentValues values = new ContentValues();
      values.put("apn_id", cursor.getString(0));
      resolver.update(
        Uri.parse("content://telephony/carriers/preferapn"), values, 
        null, null);

      return true;
    }

    return false;
}
yongyong_21
yongyong_21   2012.11.20 11:05

一般的移动网络开关都是通过篡改APN实现的(真正的开关没有直接对外的api):

如接入点名称类型一般是default,当关闭的时候修改为其他的值,打开时候修改为default.

HuiGeZhang
HuiGeZhang   2013.01.10 17:14

是哇,可以用反射来实现吧?

HuiGeZhang
HuiGeZhang 好滴
大约 5 年之前 回复
suannai0314
suannai0314 如果是对某个回答的反馈可以直接在那个回答下边用评论哦
大约 5 年之前 回复
Csdn user default icon
上传中...
上传图片
插入图片
准确详细的回答,更有利于被提问者采纳,从而获得C币。复制、灌水、广告等回答会被删除,是时候展现真正的技术了!