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

8

31

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?

Kenogenesis answered 23/4, 2012 at 10:4 Comment(0)
K
61

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.

Kenogenesis answered 25/4, 2012 at 4:22 Comment(26)
Hi, I am using this code and I am getting error in the ` Class routeInfoClass = Class.forName("android.net.RouteInfo");` statement. How can I resolve it. It says java.lang.ClassNotFoundException: android.net.RouteInfo. Thanks in advance.Woermer
I am getting error in 3.x, when i changed project to 4.x and tested in a ICS device, it works. How can I solve this issue in 3.x?Woermer
Thanks for notify this. I nearly make mistake on this on Android 3.x.Kenogenesis
I have tested on an Android 3.x device and it work. I can think of one mistake maybe the methods input parameter should be InetAddress type. But I think you have noticed that and otherwise it won't work on ICS. What exception do you get? Or, is it just take no effect?Kenogenesis
Is it really working? I have tried on 3.x and even on 4.x version, No effects shown. It always DHCP and it doesn't changed to Static. Therefore, no changes happens to address.Itinerate
It didnt worked for me? any idea why? tested on android 4.2.2 cyanomode.Whirlabout
I'm getting a nullpointer exception when calling wifiManager.updateNetowrk(wifiConf). ANy idea about this?Tagliatelle
Small typo in the first code block. if (WifiConf.networkId == connectionInfo.getNetworkId()){ Should be: if (conf.networkId == connectionInfo.getNetworkId()){ And: WifiConf = conf; Should be: wifiConf = conf;Saccharometer
Make sure u call wifiManager.saveConfiguration(); after wifiManager.updateNetwork(wifiConf); to correctly apply the settings. Ref: #18136500Dekker
"mLinkAddresses" field not found. I am running on 4.1.2. help?Dekker
How can i change dns when phone is using 3G connection ?Hylozoism
Mr Noob check that you have the correct permissions. I was missing: <uses-permission android:name="android.permission.CHANGE_WIFI_STATE"/>Claudelle
Does anybody know why it doesn't work on Android L? Got Java.lang.NoSuchFieldException: ipAssignment at java.lang.Class.getField(Class.java:1048)Dore
@Kenogenesis please come with the update for Android 5.0 :)Dore
@KennyPowers Give me a break. It is saying on Android 3.x or 4.x :)Kenogenesis
do you know if programmatically I can know if a wifi has services blockeds like whatsapp instagram, etc..?Broadbent
@Kenogenesis Does this solution requires root access?Plover
For Android 3.1, I am getting ClassnotFoundException when I try to get RouteInfo class through reflection. Can anyone please share how to fix that ?Khanna
code is worked for me.I can see config i set through the above code in wifi settings.but how to clear dns cache programatically ? i have to reboot device or emmulator to get affected. And how can i restore previous setting on my app uninstallation?Solitta
Will this code work with IPV6 also? if yes than what will be length of prefix value accepted by user?Pumpkin
@AlexMartin . Hi Alex. could you make it to work on non rooted phone? I am trying on non rooted 5.0 release and it is not working for me. Thanks for any helpDube
from my experience it is not only required to use wifiManager.saveConfiguration() but also call wifiManager.reassociate() so that the new static configuration is not only set, but actively used with the current Access PointLeodora
since Android 5.0(SDK 21) you should take a look at the new methods in WifiConfiguration class based on the new IpConfiguration and StaticIpConfiguration classesLeodora
@Kenogenesis has elaborated well on how to configure Wi-Fi for different Android OS versions. In my application, I have used the same to configure Static & DHCP connection for android devices 2.x and above. Now i want to retrieve IPAssignment, SubnetMask and IPAddress from configuration and sync it with server. Can anyone please help me getting there ?Khanna
Thanks for the code! I tested in on my samsung note 3 running 4.4.2. It worked only when a) STATIC is used b) Turn off, then turn on wifi programmatically after DNS is changed.Reina
It worked for me, I have set IP address and gateway address with help of this answer.Flatling
T
4

@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 setting
if(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();                        
}
Tournedos answered 8/11, 2016 at 12:37 Comment(1)
thanks. enableNetwork might be the missing bit. Hoewever is it really required to disable all other networks? Did you also try it with enableNetwork/wifiConf.networkId, false)?Leodora
L
3

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();
    }
}
Leodora answered 11/2, 2016 at 10:34 Comment(0)
C
1

For Android 5.1.0

      WifiConfiguration GetCurrentWifiConfiguration(WifiManager manager)
    {
    if (!manager.isWifiEnabled())
        return null;

    List<WifiConfiguration> configurationList = manager.getConfiguredNetworks();
    WifiConfiguration configuration = null;
    int cur = manager.getConnectionInfo().getNetworkId();
    for (int i = 0; i < configurationList.size(); ++i)
    {
        WifiConfiguration wifiConfiguration = configurationList.get(i);
        if (wifiConfiguration.networkId == cur)
            configuration = wifiConfiguration;
    }

    return configuration;
}



@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public void setWifiProxySettings5()
{
    //get the current wifi configuration
    WifiManager manager = (WifiManager)getSystemService(Context.WIFI_SERVICE);
    WifiConfiguration config = GetCurrentWifiConfiguration(manager);
    if(null == config)
        return;

    try
    {
        //linkProperties is no longer in WifiConfiguration
        Class proxyInfoClass = Class.forName("android.net.ProxyInfo");
        Class[] setHttpProxyParams = new Class[1];
        setHttpProxyParams[0] = proxyInfoClass;
        Class wifiConfigClass = Class.forName("android.net.wifi.WifiConfiguration");
        Method setHttpProxy = wifiConfigClass.getDeclaredMethod("setHttpProxy", setHttpProxyParams);
        setHttpProxy.setAccessible(true);

        //Method 1 to get the ENUM ProxySettings in IpConfiguration
        Class ipConfigClass = Class.forName("android.net.IpConfiguration");
        Field f = ipConfigClass.getField("proxySettings");
        Class proxySettingsClass = f.getType();

        //Method 2 to get the ENUM ProxySettings in IpConfiguration
        //Note the $ between the class and ENUM
        //Class proxySettingsClass = Class.forName("android.net.IpConfiguration$ProxySettings");

        Class[] setProxySettingsParams = new Class[1];
        setProxySettingsParams[0] = proxySettingsClass;
        Method setProxySettings = wifiConfigClass.getDeclaredMethod("setProxySettings", setProxySettingsParams);
        setProxySettings.setAccessible(true);


        ProxyInfo pi = ProxyInfo.buildDirectProxy("127.0.0.1", 8118);
        //Android 5 supports a PAC file
        //ENUM value is "PAC"
        //ProxyInfo pacInfo = ProxyInfo.buildPacProxy(Uri.parse("http://localhost/pac"));

        //pass the new object to setHttpProxy
        Object[] params_SetHttpProxy = new Object[1];
        params_SetHttpProxy[0] = pi;
        setHttpProxy.invoke(config, params_SetHttpProxy);

        //pass the enum to setProxySettings
        Object[] params_setProxySettings = new Object[1];
        params_setProxySettings[0] = Enum.valueOf((Class<Enum>) proxySettingsClass, "STATIC");
        setProxySettings.invoke(config, params_setProxySettings);

        //save the settings
        manager.updateNetwork(config);
        manager.disconnect();
        manager.reconnect();
    }
    catch(Exception e)
    {
        Log.v("wifiProxy", e.toString());
    }
}
Cryptic answered 8/2, 2016 at 12:34 Comment(2)
Will it work on api 23? I tried it on Android M and it's not working.Tussle
Dont know about api 23. am used this code for testing purpose in lollypop deviceCryptic
A
0

If you try to use the solution for Android 5.x on 6.x your application will be denied doing this. To do this you proabably need to root your device and make the application the device owner.

I've dug some into the problem and my findings is that code that used to work for Andrdoi 5.x might work if the application is set to be the device owner.

A good example of how this is done is using the example found here:

https://github.com/googlesamples/android-DeviceOwner/

Using adb shell and running the command:

dpm set-device-owner com.example.android.deviceowner/.DeviceOwnerReceiver

will make the application device owner and it is possible to set static IP.

Afflatus answered 28/7, 2017 at 7:4 Comment(0)
D
0

As a kotlin extension of WifiConfiguration, working on Android 5+

fun WifiConfiguration.setHttpProxyCompat(proxyInfo: ProxyInfo) {
    if (Build.VERSION.SDK_INT >= 26) {
        httpProxy = proxyInfo
        Timber.i("Setting proxy using 26+ method")
    } else {
        val proxySettings = Class.forName("android.net.IpConfiguration\$ProxySettings")
        val valueOf = proxySettings.getMethod("valueOf", String::class.java)
        val static = valueOf.invoke(proxySettings, "STATIC")

        val setProxy = this::class.java.getDeclaredMethod("setProxy", proxySettings, ProxyInfo::class.java)
        setProxy.isAccessible = true

        setProxy.invoke(this, static, proxyInfo)
        Timber.i("Setting proxy using reflection")
    }
}
Disposure answered 23/3, 2018 at 16:30 Comment(0)
B
0

@Yeung, everyone

As far as I understand, Android would start dhclient immediately after connecting to an SSID.

So the code suggested, would apply static configuration only after Android had already obtained an IP address (dhcp success), right?

This is what is happening in my experiments on Pie. I try to apply static configuration by listening to WifiManager.NETWORK_STATE_CHANGED_ACTION

intentFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
...........
...........
if ( action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION) )
{
    NetworkInfo info = intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO);
    if (info.isConnectedOrConnecting())
    {
        //apply static IP to current wifi connnections as per above code
    }
}
Behaviorism answered 30/5, 2019 at 4:17 Comment(0)
I
0

@Robin Thank you so much, your solution works for me exactly on Android 7 (required system app privilege).

  • AndroidManifest.xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:sharedUserId="android.uid.system"></manifest>
  • app.build.gradle
android {
  signingConfigs {
        system_keystore {
            storeFile file('/Users/**/system.keystore')
            storePassword '****'
            keyAlias '****'
            keyPassword '****'
        }
    }

  buildTypes {
    debug {
      signingConfig signingConfigs.system_keystore
    }
    release {
      signingConfig signingConfigs.system_keystore
    }
  }
}
Isotone answered 26/2, 2021 at 2:28 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.