Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to configure a static IP address, netmask, gateway programmatically on Android 3.x or 4.x

I have checked in Stack Overflow question API for configuring static IP addresses in an Android application.

It works until Android 2.3. However, there is no luck on a higher API level. For example, I put the setting

android.provider.Settings.System.putString(getContentResolver(), android.provider.Settings.System.WIFI_USE_STATIC_IP, "1");         android.provider.Settings.System.putString(getContentResolver(), android.provider.Settings.System.WIFI_STATIC_IP, "192.168.0.100"); android.provider.Settings.System.putString(getContentResolver(), android.provider.Settings.System.WIFI_STATIC_NETMASK, "255.255.255.0"); android.provider.Settings.System.putString(getContentResolver(), android.provider.Settings.System.WIFI_STATIC_DNS1, "192.168.0.254"); android.provider.Settings.System.putString(getContentResolver(), android.provider.Settings.System.WIFI_STATIC_GATEWAY, "192.168.0.254"); 

But I go back to check by:

Setting --> Wi-Fi --> Long Press Access Point SSID --> Modify Network --> check Show advanced options 

The IP Settings field is still stated DHCP but not Static.

It is true that I can use android.provider.Settings.System.getString() to get back what I set. It prove that the setting is saved somewhere but the system just ignore it.

The system uses the setting other than android.provider.Settings.System on Android 3.x and 4.x as the setting is set per Access Point SSID. Can I modify the setting on one SSID just like how it works on Android 2.3?

like image 693
Yeung Avatar asked Apr 23 '12 10:04

Yeung


People also ask

How do I set a static IP for netmask?

Right-click on the network adapter you want to assign an IP address and click Properties. Highlight Internet Protocol Version 4 (TCP/IPv4) then click the Properties button. Now change the IP, Subnet mask, Default Gateway, and DNS Server Addresses. When you're finished click OK.

What is the default gateway for static IP?

NOTE: The Default gateway is your router's local IP address. Step 7: Select Use the following DNS server addresses then enter the Preferred DNS server and Alternate DNS server addresses which are obtained from your Internet Service Provider (ISP).


2 Answers

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.

like image 198
Yeung Avatar answered Oct 02 '22 17:10

Yeung


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();     } } 
like image 38
Robin Gawenda Avatar answered Oct 02 '22 16:10

Robin Gawenda