Android AppWidget控制手机上网APN接入点

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/tianmi1988/article/details/50525493

首先很有必要讲一下需求,由于搞IT的加班比较多,每天回家基本上都是8点之后,电信网络又贵,无奈我屌丝一个用网时间又少,索性在淘宝上花重金购置了一张1元5小时的上网卡,貌似是广东电信的绝版卡,在广东省内上网5小时一分钱,但是接入点要是CTWAP,否则上网就是1小时3块钱了。用久了发现了一个弊端:网络不好的时候手机会自动切换APN接入点,刚开始的时候我是下载一个了HIAPN的软件,这个软件提供一个桌面插件,很方便看到当前APN接入点是什么。可惜好景不长,随着系统升级,这个软件停止了更新,只能在固件2.3的系统上使用。于是我就琢磨这自己来开发一个插件,而且最好在手机切换APN的时候能够有报警机制(震动)。

扯完了需求,马上就上干货了。

1.切换WIFI开关

如果开着WIFI就关掉,如果关掉就打开。这个是最简单的了,普通应用就OK

/**
	 * 切换wifi开关
	 * @param context
	 */
	public static void changeWifi(Context context) {
		WifiManager wifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
		if (wifiManager.isWifiEnabled()) {
			wifiManager.setWifiEnabled(false);
		} else {
			wifiManager.setWifiEnabled(true);
		}
	}
对应权限

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

2.切换手机数据流量

2.1 获取手机流量数据开关

public static boolean getMobileDataState(Context cxt) {
		TelephonyManager telephonyService = (TelephonyManager) cxt.getSystemService(Context.TELEPHONY_SERVICE);
		try {
			Method getMobileDataEnabledMethod = telephonyService.getClass().getDeclaredMethod("getDataEnabled");
			if (null != getMobileDataEnabledMethod) {
				boolean mobileDataEnabled = (Boolean) getMobileDataEnabledMethod.invoke(telephonyService);
				return mobileDataEnabled;
			}
		} catch (Exception e) {
			Log.v(TAG,"Error getting"+ ((InvocationTargetException) e).getTargetException() + telephonyService);
		}
		return false;
	}

2.2 设置手机流量数据(android5.0以下)

 /**
     * 当开启移动网络时调用setMobileDataStatus(context,true),
     * 关闭调用setMobileDataStatus(context,false)
     * 移动数据开启和关闭
     * @param context
     * @param enabled
     */
    public static 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(Exception e)
      {

    e.printStackTrace();
      }

    }

对应的权限

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

2.3 设置手机流量数据开关(android5.0及以上)
public static void setMobileDataState(Context cxt, boolean mobileDataEnabled) {
		TelephonyManager telephonyService = (TelephonyManager) cxt.getSystemService(Context.TELEPHONY_SERVICE);
		try {
			Method setMobileDataEnabledMethod = telephonyService.getClass().getDeclaredMethod("setDataEnabled", boolean.class);
			if (null != setMobileDataEnabledMethod) {
				setMobileDataEnabledMethod.invoke(telephonyService,mobileDataEnabled);
			}
		} catch (Exception e) {
			Log.v(TAG,"Error setting"+ ((InvocationTargetException) e).getTargetException() + telephonyService);
		}
	}

对应的权限

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

注意:android5.0的这个隐藏接口的调用,把apk移动到system/priva-app 这个目录下面才能调用成功(我没有试验过,网上有网友说可行),或者你要是有手机的plaform签名,因为上面的权限只能赋予给系统应用,最好直接用系统权限打包后签名。这个接口的改动所以会导致我们用WIFI万能钥匙的时候如果你的手机是android5.0以上,能够直接打开WIFI但不能直接开启手机数据流量,而是提示你手动开启数据流量。


3.切换APN接入点


3.1获取当前APN接入点

       public static final Uri PRE_APN_URI = Uri.parse("content://telephony/carriers/preferapn");                                          // 获取当前APN
	public static String getCurApnName(Context context) {
		ContentResolver resoler = context.getContentResolver();
		// String[] projection = new String[] { "_id" };
		Cursor cur = resoler.query(PRE_APN_URI, projection, null, null, null);
		String apnName = "";
		// cur为空则表示默认情况下一个都没有选中
		if (cur != null && cur.moveToFirst()) {
			// apnId = cur.getString(cur.getColumnIndex("_id"));
			apnName = cur.getString(cur.getColumnIndex("apn"));
		}
		Log.i("xml", "getCurApnId:" + apnName);
		return apnName;
	}

3.2更新APN接入点

 // 所有的APN配配置信息位置
  public static final Uri APN_LIST_URI = Uri.parse("content://telephony/carriers");                                                public static boolean updateCurrentAPN(ContentResolver resolver, String newAPN) { 
    	boolean changeResult = false;
        Cursor cursor = null; 
        try { 
            //get new apn id from list 
            cursor = resolver.query(APN_LIST_URI, null, " apn = ? and current = 1", new String[]{newAPN.toLowerCase()}, null); 
            String apnId = null; 
            if (cursor != null && cursor.moveToFirst()) { 
                apnId = cursor.getString(cursor.getColumnIndex("_id")); 
            } 
            cursor.close(); 
            
            //set new apn id as chosen one 
            if (apnId != null) { 
                ContentValues values = new ContentValues(); 
                values.put("apn_id", apnId); 
                resolver.update(PRE_APN_URI, values, null, null); 
                changeResult = true;
            } else { 
                //apn id not found, return 0. 
            } 
        } catch (Exception e) { 
        	e.printStackTrace();
        } finally { 
            if (cursor != null) { 
                cursor.close(); 
            } 
        } 
        
        return changeResult; 
} 
}

需要的权限

 <!-- Permission is only granted to system apps -->
    <uses-permission android:name="android.permission.WRITE_APN_SETTINGS"/>

这个也是系统权限啊,由此可以看出实现的难度      切换WIFI<切换手机流量<切换APN   

本Demo代码已经上传GitHub,点击下载,注意切换手机流量和APN都要有系统权限,如果没有对应手机的platform签名,会无法安装。


猜你喜欢

转载自blog.csdn.net/tianmi1988/article/details/50525493