许多Android开发人员通过电子邮件向我发送了关于为Android 5+开启/关闭移动网络的问题,但我不会回答个人电子邮件,而是在这里发布我的答案,以便每个人都可以使用它并使其适应他们的Android应用程序。
首先,让我们澄清一些误解和误解:svc data enable
svc data disable
上述方法只能打开/关闭后台数据,而不是订阅服务,因此电池将耗尽一点点,因为订阅服务 - 一个Android系统服务 - 仍将在后台运行。对于支持多个SIM卡的Android设备,这种情况更糟,因为订阅服务会不断扫描可用的移动网络,以便与Android设备中提供的有效SIM卡一起使用。使用此方法需要您自担风险。
现在,通过SubscriptionManagerAPI 22中引入的类关闭移动网络的正确方法,包括其相应的订阅服务,是:public static void setMobileNetworkfromLollipop(Context context) throws Exception {
String command = null;
int state = 0;
try {
// Get the current state of the mobile network.
state = isMobileDataEnabledFromLollipop(context) ? 0 : 1;
// Get the value of the "TRANSACTION_setDataEnabled" field.
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
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 boolean isMobileDataEnabledFromLollipop(Context context) {
boolean state = false;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
state = Settings.Global.getInt(context.getContentResolver(), "mobile_data", 0) == 1;
}
return state;}
为了获得该TRANSACTION_setDataEnabled领域的价值(借鉴PhongLe的解决方案):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;
}}
要执行命令su:private static void executeCommandViaSu(Context context, String option, String command) {
boolean success = false;
String su = "su";
for (int i=0; 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;
}
}}
希望此更新能够解决您在有根据的Android 5+设备上开启/关闭移动网络时可能遇到的任何误解,误解或疑问。