如何以编程方式获取Connectivity服务调用所需的服务代码?
解决方案:动态处理USB Tethering开启(适配多Android版本)
你的核心困扰在于不同Android版本下service call connectivity CODE中的硬编码CODE不固定,且之前的反射实现存在错误。下面提供两种更可靠的适配方案:
方案一:正确反射调用IConnectivityManager的setUsbTethering方法
这是最稳定的实现方式,直接通过反射调用系统隐藏接口的方法,完全无需依赖service call的方法序号。
实现步骤
- 反射获取
ServiceManager类,拿到ConnectivityService的Binder实例; - 反射获取
IConnectivityManager.Stub类,将Binder转换为IConnectivityManager接口实例; - 调用接口的
setUsbTethering方法(兼容不同版本的参数类型差异)。
示例代码
import android.os.IBinder; import android.util.Log; import android.widget.Toast; import java.lang.reflect.Method; public void enableUsbTethering() { try { // 1. 获取ServiceManager类,拿到ConnectivityService的Binder Class<?> serviceManagerClass = Class.forName("android.os.ServiceManager"); Method getServiceMethod = serviceManagerClass.getMethod("getService", String.class); IBinder connectivityBinder = (IBinder) getServiceMethod.invoke(null, "connectivity"); // 2. 将Binder转换为IConnectivityManager接口实例 Class<?> iConnectivityManagerStubClass = Class.forName("android.net.IConnectivityManager$Stub"); Method asInterfaceMethod = iConnectivityManagerStubClass.getMethod("asInterface", IBinder.class); Object iConnectivityManager = asInterfaceMethod.invoke(null, connectivityBinder); // 3. 调用setUsbTethering,兼容boolean/int两种参数类型 Method setUsbTetheringMethod = null; try { // 优先尝试boolean参数版本 setUsbTetheringMethod = iConnectivityManager.getClass().getMethod("setUsbTethering", boolean.class); setUsbTetheringMethod.invoke(iConnectivityManager, true); } catch (NoSuchMethodException e) { // 兼容部分版本的int参数(1表示开启) setUsbTetheringMethod = iConnectivityManager.getClass().getMethod("setUsbTethering", int.class); setUsbTetheringMethod.invoke(iConnectivityManager, 1); } Toast.makeText(this, "USB Tethering已开启", Toast.LENGTH_LONG).show(); } catch (Exception e) { Log.e("AUTO TETHERING", "开启USB Tethering失败", e); Toast.makeText(this, "失败:" + e.getMessage(), Toast.LENGTH_LONG).show(); } }
注意事项
- 该方法需要Root权限或应用拥有系统签名(基础权限
android.permission.CHANGE_NETWORK_STATE是前提,但修改USB Tethering通常需要更高权限); - 不同Android版本的
setUsbTethering参数类型可能不同,代码中已做兼容处理; - 系统隐藏API可能在后续版本变更,需针对主流Android版本做测试验证。
方案二:动态获取service call对应的CODE
如果你坚持使用service call命令,可以通过反射获取IConnectivityManager接口中setUsbTethering方法的序号(即CODE值),无需硬编码或盲目遍历。
实现思路
service call的CODE对应AIDL接口中方法的序号(从1开始计数),可以通过反射获取IConnectivityManager.Stub类中的方法索引,转换为对应的CODE。
示例代码
import android.util.Log; import java.lang.reflect.Field; import java.lang.reflect.Method; public int getUsbTetheringServiceCode() { int code = -1; try { // 获取IConnectivityManager.Stub类 Class<?> stubClass = Class.forName("android.net.IConnectivityManager$Stub"); // 获取存储所有AIDL方法的METHODS字段 Field methodsField = stubClass.getDeclaredField("METHODS"); methodsField.setAccessible(true); Method[] methods = (Method[]) methodsField.get(null); // 遍历找到setUsbTethering方法,计算对应的CODE for (int i = 0; i < methods.length; i++) { Method method = methods[i]; if ("setUsbTethering".equals(method.getName())) { // service call的CODE是方法索引+1(AIDL方法序号从1开始) code = i + 1; break; } } } catch (Exception e) { Log.e("AUTO TETHERING", "获取服务CODE失败", e); } return code; } // 使用方式 int code = getUsbTetheringServiceCode(); if (code != -1) { String command = "service call connectivity " + code + " i32 1"; // 以Root权限执行命令 Runtime.getRuntime().exec(new String[]{"su", "-c", command}); }
注意事项
- 该方法依赖系统隐藏的
IConnectivityManager$Stub.METHODS字段,部分厂商定制系统可能修改此实现; - 同样需要Root权限执行
service call命令; - 若METHODS字段无法获取,可退而求其次通过反射获取方法的
transactcode,但实现复杂度更高。
你之前反射失败的原因
你之前的代码this.getClass().getMethod("IConnectivityManager.setUsbTethering", Integer.class)存在两个关键错误:
IConnectivityManager.setUsbTethering不是当前Activity类的方法,你需要获取系统的IConnectivityManager接口类,而非当前类;- 参数类型不匹配,多数版本的
setUsbTethering参数是boolean而非Integer,且必须通过Stub.asInterface获取接口实例才能调用方法。
内容的提问来源于stack exchange,提问作者Beyondo
相关产品推荐
相关产品推荐

