How to configure a static IP address, netmask, gateway programmatically on Android 3.x or 4.x
I realise that there is no API on 3.x or 4.x for those setting per SSID. Therefore, I checked out the source code and found out that the configuration of each SSID is stored in android.net.wifi.WifiConfiguration
which is gotten from android.net.wifi.WifiManager
.
In the below code, IpAssignment
is an Enum, either STAIC
, DHCP
or NONE
.And linkProperties
is the object store IP address, gateway, DNS, etc...
linkAddress
is IP address and its netmask as prefixLength (how many bit 1 in netmask).
mRoutes
is ArrayList
of RouteInfo
that can indicate gateway.
mDnses
is ArrayList
of InetAddress
for DNS.
Firstly, get the current configuration using WifiConfiguration
SSID
WifiConfiguration wifiConf = null;WifiManager wifiManager = (WifiManager)getSystemService(Context.WIFI_SERVICE);WifiInfo connectionInfo = wifiManager.getConnectionInfo();List<WifiConfiguration> configuredNetworks = wifiManager.getConfiguredNetworks(); for (WifiConfiguration conf : configuredNetworks){ if (conf.networkId == connectionInfo.getNetworkId()){ wifiConf = conf; break; }}
As the IpAssignment
and linkProperties
are hidden, the object can be gotten from reflection.
The following method can set the declared IP address setting on SSID WifiConfiguration:
public static void setIpAssignment(String assign , WifiConfiguration wifiConf) throws SecurityException, IllegalArgumentException, NoSuchFieldException, IllegalAccessException{ setEnumField(wifiConf, assign, "ipAssignment"); } public static void setIpAddress(InetAddress addr, int prefixLength, WifiConfiguration wifiConf) throws SecurityException, IllegalArgumentException, NoSuchFieldException, IllegalAccessException, NoSuchMethodException, ClassNotFoundException, InstantiationException, InvocationTargetException{ Object linkProperties = getField(wifiConf, "linkProperties"); if(linkProperties == null)return; Class laClass = Class.forName("android.net.LinkAddress"); Constructor laConstructor = laClass.getConstructor(new Class[]{InetAddress.class, int.class}); Object linkAddress = laConstructor.newInstance(addr, prefixLength); ArrayList mLinkAddresses = (ArrayList)getDeclaredField(linkProperties, "mLinkAddresses"); mLinkAddresses.clear(); mLinkAddresses.add(linkAddress); } public static void setGateway(InetAddress gateway, WifiConfiguration wifiConf) throws SecurityException, IllegalArgumentException, NoSuchFieldException, IllegalAccessException, ClassNotFoundException, NoSuchMethodException, InstantiationException, InvocationTargetException{ Object linkProperties = getField(wifiConf, "linkProperties"); if(linkProperties == null)return; Class routeInfoClass = Class.forName("android.net.RouteInfo"); Constructor routeInfoConstructor = routeInfoClass.getConstructor(new Class[]{InetAddress.class}); Object routeInfo = routeInfoConstructor.newInstance(gateway); ArrayList mRoutes = (ArrayList)getDeclaredField(linkProperties, "mRoutes"); mRoutes.clear(); mRoutes.add(routeInfo); } public static void setDNS(InetAddress dns, WifiConfiguration wifiConf) throws SecurityException, IllegalArgumentException, NoSuchFieldException, IllegalAccessException{ Object linkProperties = getField(wifiConf, "linkProperties"); if(linkProperties == null)return; ArrayList<InetAddress> mDnses = (ArrayList<InetAddress>)getDeclaredField(linkProperties, "mDnses"); mDnses.clear(); //or add a new dns address , here I just want to replace DNS1 mDnses.add(dns); } public static Object getField(Object obj, String name) throws SecurityException, NoSuchFieldException, IllegalArgumentException, IllegalAccessException{ Field f = obj.getClass().getField(name); Object out = f.get(obj); return out; } public static Object getDeclaredField(Object obj, String name) throws SecurityException, NoSuchFieldException, IllegalArgumentException, IllegalAccessException { Field f = obj.getClass().getDeclaredField(name); f.setAccessible(true); Object out = f.get(obj); return out; } private static void setEnumField(Object obj, String value, String name) throws SecurityException, NoSuchFieldException, IllegalArgumentException, IllegalAccessException{ Field f = obj.getClass().getField(name); f.set(obj, Enum.valueOf((Class<Enum>) f.getType(), value)); }
After that, I can set setting and update WifiConfiguration
for this SSID.
try{ setIpAssignment("STATIC", wifiConf); //or "DHCP" for dynamic setting setIpAddress(InetAddress.getByName("192.168.0.100"), 24, wifiConf); setGateway(InetAddress.getByName("4.4.4.4"), wifiConf); setDNS(InetAddress.getByName("4.4.4.4"), wifiConf); wifiManager.updateNetwork(wifiConf); //apply the setting wifiManager.saveConfiguration(); //Save it }catch(Exception e){ e.printStackTrace(); }
Edit:Sorry for I don't check for Android 3.x device that have silmilar UI with Android 4.x.In Android 3.x, the gateway is storted in mGateways
of linkProperties
.mGateways
is Arraylist
of type InetAddress
. Therefore, following should work in Android 3.x.
public static void setGateway(InetAddress gateway, WifiConfiguration wifiConf) throws SecurityException, IllegalArgumentException, NoSuchFieldException, IllegalAccessException, ClassNotFoundException, NoSuchMethodException, InstantiationException, InvocationTargetException{ Object linkProperties = getField(wifiConf, "linkProperties"); if(linkProperties == null)return; ArrayList mGateways = (ArrayList)getDeclaredField(linkProperties, "mGateways"); mGateways.clear(); mGateways.add(gateway); }
Edit2: The methods setIpAddress
, setGateway
, setDNS
should be inputted as InetAddress
type.
For Android 5.0+ a WIP solution. It does not yet work for some reason. Comments welcome.
void changeWifiConfiguration(boolean dhcp, String ip, int prefix, String dns1, String gateway) { WifiManager wm = (WifiManager) getSystemService(Context.WIFI_SERVICE); if(!wm.isWifiEnabled()) { // wifi is disabled return; } // get the current wifi configuration WifiConfiguration wifiConf = null; WifiInfo connectionInfo = wm.getConnectionInfo(); List<WifiConfiguration> configuredNetworks = wm.getConfiguredNetworks(); if(configuredNetworks != null) { for (WifiConfiguration conf : configuredNetworks){ if (conf.networkId == connectionInfo.getNetworkId()){ wifiConf = conf; break; } } } if(wifiConf == null) { // wifi is not connected return; } try { Class<?> ipAssignment = wifiConf.getClass().getMethod("getIpAssignment").invoke(wifiConf).getClass(); Object staticConf = wifiConf.getClass().getMethod("getStaticIpConfiguration").invoke(wifiConf); if(dhcp) { wifiConf.getClass().getMethod("setIpAssignment", ipAssignment).invoke(wifiConf, Enum.valueOf((Class<Enum>) ipAssignment, "DHCP")); if(staticConf != null) { staticConf.getClass().getMethod("clear").invoke(staticConf); } } else { wifiConf.getClass().getMethod("setIpAssignment", ipAssignment).invoke(wifiConf, Enum.valueOf((Class<Enum>) ipAssignment, "STATIC")); if(staticConf == null) { Class<?> staticConfigClass = Class.forName("android.net.StaticIpConfiguration"); staticConf = staticConfigClass.newInstance(); } // STATIC IP AND MASK PREFIX Constructor<?> laConstructor = LinkAddress.class.getConstructor(InetAddress.class, int.class); LinkAddress linkAddress = (LinkAddress) laConstructor.newInstance( InetAddress.getByName(ip), prefix); staticConf.getClass().getField("ipAddress").set(staticConf, linkAddress); // GATEWAY staticConf.getClass().getField("gateway").set(staticConf, InetAddress.getByName(gateway)); // DNS List<InetAddress> dnsServers = (List<InetAddress>) staticConf.getClass().getField("dnsServers").get(staticConf); dnsServers.clear(); dnsServers.add(InetAddress.getByName(dns1)); dnsServers.add(InetAddress.getByName("8.8.8.8")); // Google DNS as DNS2 for safety // apply the new static configuration wifiConf.getClass().getMethod("setStaticIpConfiguration", staticConf.getClass()).invoke(wifiConf, staticConf); } // apply the configuration change boolean result = wm.updateNetwork(wifiConf) != -1; //apply the setting if(result) result = wm.saveConfiguration(); //Save it if(result) wm.reassociate(); // reconnect with the new static IP } catch(Exception e) { e.printStackTrace(); }}
@Robin
Thanks your solution works fine for me on My Nexus device running on Android M 6.0.1.
I have replaced the // apply the configuration change boolean result = wm.updateNetwork(wifiConf) != -1; //apply the setting if(result) result = wm.saveConfiguration(); //Save it if(result) wm.reassociate(); // reconnect with the new static IP
with the following
int netId = manager.updateNetwork(wifiConf);boolean result = netId!= -1; //apply the settingif(result){ boolean isDisconnected = manager.disconnect(); boolean configSaved = manager.saveConfiguration(); //Save it boolean isEnabled = manager.enableNetwork(wifiConf.networkId, true); // reconnect with the new static IP boolean isReconnected = manager.reconnect(); }