【发布时间】:2015-02-20 08:49:44
【问题描述】:
如何在 Android 5.x 上以编程方式配置静态 IP 地址、网络掩码、网关、DNS 以实现 Wi-Fi 连接?是否有开放的 API(没有找到)或隐藏的可以用于此?如果可能的话,请您举一些例子。
我知道它是 possible on Android 4.0+,但它不适用于 Android 5.0
【问题讨论】:
标签: java android android-5.0-lollipop
如何在 Android 5.x 上以编程方式配置静态 IP 地址、网络掩码、网关、DNS 以实现 Wi-Fi 连接?是否有开放的 API(没有找到)或隐藏的可以用于此?如果可能的话,请您举一些例子。
我知道它是 possible on Android 4.0+,但它不适用于 Android 5.0
【问题讨论】:
标签: java android android-5.0-lollipop
遗憾的是,仍然没有开放的 API。
Android 4.0 的解决方案在 LOLLIPOP 中不起作用,因为事情已经转移了。特别是新的IpConfiguration 类现在包含StaticIpConfiguration 和所有这些字段。它们仍然可以通过像这样使用反射(具有所有的脆弱性)来访问。
警告,此代码仅适用于 Android 5.0。您需要检查Build.VERSION.SDK_INT 并采取相应措施。
@SuppressWarnings("unchecked")
private static void setStaticIpConfiguration(WifiManager manager, WifiConfiguration config, InetAddress ipAddress, int prefixLength, InetAddress gateway, InetAddress[] dns) throws ClassNotFoundException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, NoSuchFieldException, InstantiationException
{
// First set up IpAssignment to STATIC.
Object ipAssignment = getEnumValue("android.net.IpConfiguration$IpAssignment", "STATIC");
callMethod(config, "setIpAssignment", new String[] { "android.net.IpConfiguration$IpAssignment" }, new Object[] { ipAssignment });
// Then set properties in StaticIpConfiguration.
Object staticIpConfig = newInstance("android.net.StaticIpConfiguration");
Object linkAddress = newInstance("android.net.LinkAddress", new Class<?>[] { InetAddress.class, int.class }, new Object[] { ipAddress, prefixLength });
setField(staticIpConfig, "ipAddress", linkAddress);
setField(staticIpConfig, "gateway", gateway);
getField(staticIpConfig, "dnsServers", ArrayList.class).clear();
for (int i = 0; i < dns.length; i++)
getField(staticIpConfig, "dnsServers", ArrayList.class).add(dns[i]);
callMethod(config, "setStaticIpConfiguration", new String[] { "android.net.StaticIpConfiguration" }, new Object[] { staticIpConfig });
manager.updateNetwork(config);
manager.saveConfiguration();
}
使用以下辅助方法来处理反射:
private static Object newInstance(String className) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, IllegalArgumentException, InvocationTargetException
{
return newInstance(className, new Class<?>[0], new Object[0]);
}
private static Object newInstance(String className, Class<?>[] parameterClasses, Object[] parameterValues) throws NoSuchMethodException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, ClassNotFoundException
{
Class<?> clz = Class.forName(className);
Constructor<?> constructor = clz.getConstructor(parameterClasses);
return constructor.newInstance(parameterValues);
}
@SuppressWarnings({ "unchecked", "rawtypes" })
private static Object getEnumValue(String enumClassName, String enumValue) throws ClassNotFoundException
{
Class<Enum> enumClz = (Class<Enum>)Class.forName(enumClassName);
return Enum.valueOf(enumClz, enumValue);
}
private static void setField(Object object, String fieldName, Object value) throws IllegalAccessException, IllegalArgumentException, NoSuchFieldException
{
Field field = object.getClass().getDeclaredField(fieldName);
field.set(object, value);
}
private static <T> T getField(Object object, String fieldName, Class<T> type) throws IllegalAccessException, IllegalArgumentException, NoSuchFieldException
{
Field field = object.getClass().getDeclaredField(fieldName);
return type.cast(field.get(object));
}
private static void callMethod(Object object, String methodName, String[] parameterTypes, Object[] parameterValues) throws ClassNotFoundException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException
{
Class<?>[] parameterClasses = new Class<?>[parameterTypes.length];
for (int i = 0; i < parameterTypes.length; i++)
parameterClasses[i] = Class.forName(parameterTypes[i]);
Method method = object.getClass().getDeclaredMethod(methodName, parameterClasses);
method.invoke(object, parameterValues);
}
例如,你可以这样称呼它:
public void test(Context context)
{
WifiManager manager = (WifiManager)context.getSystemService(Context.WIFI_SERVICE);
WifiConfiguration wifiConf = ... /* Get Wifi configuration you want to update */
if (wifiConf != null)
{
try
{
setStaticIpConfiguration(manager, wifiConf,
InetAddress.getByName("10.0.0.1"), 24,
InetAddress.getByName("10.0.0.2"),
new InetAddress[] { InetAddress.getByName("10.0.0.3"), InetAddress.getByName("10.0.0.4") });
}
catch (Exception e)
{
e.printStackTrace();
}
}
}
作为参考,您可能需要查看框架中的 WifiConfigController 类(尽管它直接使用这些类而不是通过反射)。
【讨论】:
IP 地址是在接口而不是电话基础上配置的。您不能设置一个 IP 地址用于蜂窝数据连接,以及可能创建的所有无线(蓝牙等)连接。
由于IP地址依赖于接口,所以地址也是在那里配置的。
对于数据连接,IP 地址(我相信,未确认)由蜂窝运营商传送到手机,并且无法在设备上配置。
对于常规 wi-fi 类型的连接,对于每个网络,您可以选择使用默认 (DHCP) 或其他形式的 IP 地址配置,包括您是要手动配置 IP 地址,还是通过动态系统配置 IP 地址到位。
由于网关和网络掩码也在网络上设置,因此为给定网络配置“静态”IP 地址的“最佳”方法是在网络端进行配置。对于大多数网络 DHCP 服务器,您可以将它们配置为始终为同一设备提供相同的网络 IP。
这就是我所做的,我有某些设备通过 DHCP 获取它们的 IP 地址,但是 DHCP 服务器总是为我想要恒定的设备分配相同的预配置和“静态”IP 地址(其他设备拉 IP来自可用的“池”)。
【讨论】: