Android 7.1 以太网反射 EthernetManager 配置 DHCP、静态 IP

@hide EthernetManager

通过 android.net.EthernetManager#setConfiguration 可以设置以太网 IP 信息,可惜 EthernetManager 无法直接调用。

/**
 * A class representing the IP configuration of the Ethernet network.
 *
 * @hide
 */
public class EthernetManager {
	...
    /**
     * Set Ethernet configuration.
     */
    public void setConfiguration(IpConfiguration config) {
        try {
            mService.setConfiguration(config);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }
    ...
}

反射调用 setConfiguration 方法

DHCP 配置

步骤:

  1. 实例化 IpConfiguration() 对象 ipConfiguration
  2. 设置 ipConfiguration.ipConfiguration = xxx
  3. 设置 ipConfiguration.ipConfiguration = xxx
  4. 调用 ethernetManager.setConfiguration(ipConfiguration) 完成设置
/**
  * 调用 EthernetManager.setConfiguration(IpConfiguration config) 设置 DHCP
  *
  * 步骤:
  * - 实例化 IpConfiguration() 对象 ipConfiguration
  * - 设置 ipConfiguration.ipConfiguration = xxx
  * - 设置 ipConfiguration.ipConfiguration = xxx
  * - 调用 ethernetManager.setConfiguration(ipConfiguration) 完成设置
  */
 @WorkerThread
 fun setDynamicIp(ethernetManager: EthernetManager): Boolean {
     try {
         // 获取 IpConfiguration 对象
         val ipConfigurationCls = Class.forName("android.net.IpConfiguration")
         val ipConfigurationEnum = getEnumMap(ipConfigurationCls)
         val ipConfiguration = ipConfigurationCls.newInstance()

         // 设置 ipConfiguration.ipAssignment 为 IpAssignment.DHCP
         val ipAssignment = ipConfigurationCls.getField("ipAssignment")
         ipAssignment.set(ipConfiguration, ipConfigurationEnum["IpAssignment.DHCP"])

         // 设置 ipConfiguration.proxySettings 为 ProxySettings.NONE
         val proxySettings = ipConfigurationCls.getField("proxySettings")
         proxySettings.set(ipConfiguration, ipConfigurationEnum["ProxySettings.NONE"])

         // 调用 ethernetManager.setConfiguration(ipConfiguration) 设置 DHCP
         val setConfigurationMethod = ethernetManager.javaClass.getDeclaredMethod(
             "setConfiguration", ipConfiguration.javaClass
         )
         setConfigurationMethod.invoke(ethernetManager, ipConfiguration)
         return true
     } catch (e: Exception) {
         e.printStackTrace()
         return false
     }
 }

/**
 * 获取 Class 中枚举类键值对
 *
 * 注:key = 枚举类名 + 枚举名
 *    value = 枚举
 */
private fun getEnumMap(ipConfigurationCls: Class<*>): Map<String, Any> {
    val enumMap: MutableMap<String, Any> = HashMap()
    val enumClasses = ipConfigurationCls.declaredClasses
    for (enumClass in enumClasses) {
        val enumConstants = enumClass.enumConstants ?: continue
        for (enumConstant in enumConstants) {
            // 枚举 Class 名 + 枚举名 = key
            enumMap[enumClass.simpleName + "." + enumConstant.toString()] = enumConstant
        }
    }
    return enumMap
}

Static IP 配置

步骤:

  1. 实例化 StaticIpConfiguration 对象 staticIpConfiguration
    1.1. 设置 staticIpConfiguration.ipAddress = xxx
    1.2. 设置 staticIpConfiguration.gateway = xxx
    1.3. 设置 staticIpConfiguration.domains = xxx
    1.4. 设置 staticIpConfiguration.dnsServers = xxx
  2. 实例化 IpConfiguration() 对象 ipConfiguration
    2.1. 设置 ipConfiguration.staticIpConfiguration = staticIpConfiguration
    2.2. 设置 ipConfiguration.ipAssignment = xxx
    2.3. 设置 ipConfiguration.proxySettings = xxx
    2.4. 设置 ipConfiguration.httpProxy = xxx
  3. 调用 ethernetManager.setConfiguration(ipConfiguration) 完成设置
/**
  * 调用 EthernetManager.setConfiguration(IpConfiguration config) 设置静态 IP
  *
  * 步骤:
  * - 实例化 StaticIpConfiguration 对象 staticIpConfiguration
  *     - 设置 staticIpConfiguration.ipAddress = xxx
  *     - 设置 staticIpConfiguration.gateway = xxx
  *     - 设置 staticIpConfiguration.domains = xxx
  *     - 设置 staticIpConfiguration.dnsServers = xxx
  * - 实例化 IpConfiguration() 对象  ipConfiguration
  *     - 设置 ipConfiguration.staticIpConfiguration = staticIpConfiguration
  *     - 设置 ipConfiguration.ipAssignment = xxx
  *     - 设置 ipConfiguration.proxySettings = xxx
  *     - 设置 ipConfiguration.httpProxy = xxx
  * - 调用 ethernetManager.setConfiguration(ipConfiguration) 完成设置
  */
 @WorkerThread
 fun setStaticIp(
     ethernetManager: EthernetManager,
     ip: String,
     mask: String,
     gateway: String,
     dns: String
 ): Boolean {
     try {
         // 获取 StaticIpConfiguration 对象
         val staticIpConfiguration = newStaticIpConfiguration(ip, mask, gateway, dns)

         // 获取 IpConfiguration 对象
         val ipConfiguration = newIpConfiguration(staticIpConfiguration)

         // 通过 setConfiguration 方法设置静态 IP
         val setConfigurationMethod = ethernetManager.javaClass.getDeclaredMethod(
             "setConfiguration", ipConfiguration.javaClass
         )
         setConfigurationMethod.invoke(ethernetManager, ipConfiguration)
         return true
     } catch (e: Exception) {
         e.printStackTrace()
         return false
     }
 }

 /**
  * 获取 IpConfiguration 实例
  */
 private fun newIpConfiguration(staticIpConfiguration: Any): Any {
     // 获取 IpConfiguration 对象
     val ipConfigurationCls = Class.forName("android.net.IpConfiguration")
     val ipConfigurationEnum = getEnumMap(ipConfigurationCls)
     val ipConfiguration = ipConfigurationCls.newInstance()

     // 设置 ipConfiguration.staticIpConfiguration 为 staticIpConfiguration
     val staticIpConfigurationField = ipConfigurationCls.getField("staticIpConfiguration")
     staticIpConfigurationField[ipConfiguration] = staticIpConfiguration

     // 设置 ipConfiguration.ipAssignment 为 IpAssignment.STATIC
     val ipAssignment = ipConfigurationCls.getField("ipAssignment")
     ipAssignment[ipConfiguration] = ipConfigurationEnum["IpAssignment.STATIC"]

     // 设置 ipConfiguration.proxySettings 为 ProxySettings.NONE
     val proxySettings = ipConfigurationCls.getField("proxySettings")
     proxySettings[ipConfiguration] = ipConfigurationEnum["ProxySettings.NONE"]

     // 设置 ipConfiguration.httpProxy 为 httpProxy
     val httpProxy = ipConfigurationCls.getField("httpProxy")
     httpProxy[ipConfiguration] = ProxyInfo.buildDirectProxy(null, 0)
     return ipConfiguration
 }

 /**
  * 获取 StaticIpConfiguration 实例
  */
 private fun newStaticIpConfiguration(
     ip: String,
     mask: String,
     gate: String,
     dns: String
 ): Any {
     // 获取 StaticIpConfiguration 对象
     val staticIpConfigurationCls = Class.forName("android.net.StaticIpConfiguration")
     val staticIpConfiguration = staticIpConfigurationCls.newInstance()

     // 设置 ipAddress
     val ipAddress = staticIpConfigurationCls.getField("ipAddress")
     ipAddress[staticIpConfiguration] = newLinkAddress(ip, mask)

     // 设置网关
     val gateway = staticIpConfigurationCls.getField("gateway")
     gateway[staticIpConfiguration] = InetAddress.getByName(gate)

     // 设置子网掩码
     val domains = staticIpConfigurationCls.getField("domains")
     domains[staticIpConfiguration] = mask

     // 设置 DNS
     val dnsServers = staticIpConfigurationCls.getField("dnsServers")
     val dnsList = dnsServers[staticIpConfiguration] as ArrayList<InetAddress>
     dnsList.add(InetAddress.getByName(dns))
     return staticIpConfiguration
 }

 /**
  * 获取 LinkAddress 实例
  */
 private fun newLinkAddress(ip: String, mask: String): Any? {
     val linkAddressCls = Class.forName("android.net.LinkAddress")
     val linkAddressConstructor = linkAddressCls.getDeclaredConstructor(
         InetAddress::class.java,
         Int::class.javaPrimitiveType
     )
     return linkAddressConstructor.newInstance(
         InetAddress.getByName(ip),
         getPrefixLength(mask)
     )
 }

 /**
  * 获取长度
  */
 private fun getPrefixLength(mask: String): Int {
     var count = 0
     for (str in mask.split(".")) {
         if (str == "255") {
             ++count
         }
     }
     return count * 8
 }

注意事项

以上代码需要是系统应用才能调用,需要在 AndroidManifest 文件中配置 android:sharedUserId=“android.uid.system”。

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    ...
    android:sharedUserId="android.uid.system">
    ...
</manifest>

参考连接

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值