在Android5.0以前的版本中,可以通过简单的反射机制来直接控制手机网络的打开与关闭:
ConnectivityManager connectivityManager = (ConnectivityManager) pContext.getSystemService(Context.CONNECTIVITY_SERVICE); Method setMobileDataEnabl; try { setMobileDataEnabl = connectivityManager.getClass().getDeclaredMethod("setMobileDataEnabled", boolean.class); setMobileDataEnabl.invoke(connectivityManager, pBoolean); } catch (Exception e) { e.printStackTrace(); Log.e("MobileUtil", "移动数据设置错误:" + e.toString()); }
但是,在Android5.0版本及以上,这方法就失效了,于是在StackOverFlow上面有大神提出一个解决方案,前提是手机必须能获取到Root权限:
private static void executeCommandViaSu(Context context, String option, String command) { boolean success = false; String su = "su"; for (int i=0; i < 3; i++) { // Default "su" command executed successfully, then quit. if (success) { break; } // Else, execute other "su" commands. if (i == 1) { su = "/system/xbin/su"; } else if (i == 2) { su = "/system/bin/su"; } try { // Execute command as "su". Runtime.getRuntime().exec(new String[]{su, option, command}); } catch (IOException e) { success = false; // Oops! Cannot execute `su` for some reason. // Log error here. } finally { success = true; } } }public static void setMobileNetworkfromLollipop(Context context,boolean ii) throws Exception { String command = null; int state=0; if(ii){ state=1; } try { String transactionCode = getTransactionCode(context); // Android 5.1+ (API 22) and later. if (Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP) { SubscriptionManager mSubscriptionManager = (SubscriptionManager) context.getSystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE); // Loop through the subscription list i.e. SIM list. for (int i = 0; i < mSubscriptionManager.getActiveSubscriptionInfoCountMax(); i++) { if (transactionCode != null && transactionCode.length() > 0) { // Get the active subscription ID for a given SIM card. int subscriptionId = mSubscriptionManager.getActiveSubscriptionInfoList().get(i).getSubscriptionId(); // Execute the command via `su` to turn off // mobile network for a subscription service. command = "service call phone " + transactionCode + " i32 " + subscriptionId + " i32 " + state; executeCommandViaSu(context, "-c", command); } } } else if (Build.VERSION.SDK_INT == Build.VERSION_CODES.LOLLIPOP) { // Android 5.0 (API 21) only. if (transactionCode != null && transactionCode.length() > 0) { // Execute the command via `su` to turn off mobile network. command = "service call phone " + transactionCode + " i32 " + state; executeCommandViaSu(context, "-c", command); } } } catch(Exception e) { // Oops! Something went wrong, so we throw the exception here. throw e; } }private static String getTransactionCode(Context context) throws Exception { try { final TelephonyManager mTelephonyManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE); final Class<?> mTelephonyClass = Class.forName(mTelephonyManager.getClass().getName()); final Method mTelephonyMethod = mTelephonyClass.getDeclaredMethod("getITelephony"); mTelephonyMethod.setAccessible(true); final Object mTelephonyStub = mTelephonyMethod.invoke(mTelephonyManager); final Class<?> mTelephonyStubClass = Class.forName(mTelephonyStub.getClass().getName()); final Class<?> mClass = mTelephonyStubClass.getDeclaringClass(); final Field field = mClass.getDeclaredField("TRANSACTION_setDataEnabled"); field.setAccessible(true); return String.valueOf(field.getInt(null)); } catch (Exception e) { // The "TRANSACTION_setDataEnabled" field is not available, // or named differently in the current API level, so we throw // an exception and inform users that the method is not available. throw e; } }
当代码中调用setMobileNetworkfromLollipop方法时,系统会提示应用要获取Root权限,其实这个方法的本质就是在Linux的终端中输入了svc data enable。。。 没有Root的机器是暂时没有解决办法的,因为只有root身份才能执行svc data enable。不知道这是不是Google故意把那个非公开api去掉了,不过回过头想想,不能直接使用这个方法也是为了考虑到系统的安全性,毕竟这个被滥用后会是一件非常麻烦的事 如果有别的方案可以开启数据连接的话欢迎提出来