版权声明:本文为博主原创文章,未经博主允许不得转载。 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签名,会无法安装。