How can a static IP address, netmask, gateway, DNS be programmatically configured on Android 5.x for Wi-Fi connection? Is there an open API (didn\'t find it) or hidden can b
IP addresses are configured on an interface, not phone basis. You cannot set one IP address to be used for the cellular data connection, and all the wireless (bluetooth, etc.) connections that may be created too.
Since the IP address is dependent on the interface, the address is configured there too.
For the data connection, the IP address is (I believe, not confirmed) communicated to the phone by the cellular carrier, and is not configurable on the device.
For regular wi-fi type connections, for each network, you can choose to use the default (DHCP) or some other form of IP address provisioning, including whether you want to configure the IP address manually, or via the dynamic systems in place.
Since the gateway and netmask are set on the network too, it makes sense that the 'best' way to configure a 'static' IP address for a given network, is to configure it on the network side. For most network DHCP servers you can configure them to always provision the same network IP to the same device each time.
This is what I do, I have certain devices get their IP address through DHCP, but the DHCP server always allocates the same pre-configured and 'static' IP address to the devices I want constant (and other devices pull an IP from the available 'pool').
There is still no open API, unfortunately.
The solution for Android 4.0 doesn't work in LOLLIPOP because things have been moved around. In particular the new IpConfiguration
class now holds the StaticIpConfiguration and all these fields. They can still be accessed by using reflection (with all the brittleness that entails) with something like this.
Warning, this code is Android 5.0-only. You'll need to check Build.VERSION.SDK_INT
and act accordingly.
@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();
}
With the following helper methods to handle reflection:
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);
}
For example, you can call it like this:
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();
}
}
}
As a reference, you might want to take a look at the WifiConfigController class in the framework (though it uses these classes directly instead of via reflection).