android networking settings ipv4

Cómo configurar una dirección IP estática, máscara de red, puerta de enlace mediante programación en Android 3.xo 4.x.



ip config android (6)

@Robin

Gracias, su solución funciona bien para mí en el dispositivo My Nexus que se ejecuta en Android M 6.0.1.

He reemplazado // 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 // 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

con lo siguiente

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(); }

Revisé la API de pregunta de Stack Overflow para configurar direcciones IP estáticas en una aplicación de Android .

Funciona hasta Android 2.3. Sin embargo, no hay suerte en un nivel de API más alto. Por ejemplo, puse la configuración

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");

Pero vuelvo a verificar por:

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

El campo IP Settings aún se indica como DHCP pero no Static .

Es cierto que puedo usar android.provider.Settings.System.getString() para recuperar lo que establecí. Demuestra que la configuración se guarda en algún lugar, pero el sistema simplemente lo ignora.

El sistema usa la configuración que no es android.provider.Settings.System en Android 3.xy 4.x ya que la configuración se establece por SSID de punto de acceso. ¿Puedo modificar la configuración en un SSID al igual que funciona en Android 2.3?


Como extensión kotlin de WifiConfiguration , trabajando en 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") } }


Me doy cuenta de que no hay API en 3.x o 4.x para esas configuraciones por SSID. Por lo tanto, revisé el código fuente y descubrí que la configuración de cada SSID se almacena en android.net.wifi.WifiConfiguration que se obtiene de android.net.wifi.WifiManager .

En el siguiente código, IpAssignment es un Enum, ya sea STAIC , DHCP o NONE . Y linkProperties es la dirección IP del almacén de objetos, la puerta de enlace, el DNS, etc.

linkAddress es la dirección IP y su máscara de red como prefixLength (cuántos bit 1 en la máscara de red).

mRoutes es ArrayList de RouteInfo que puede indicar la puerta de enlace.

mDnses es ArrayList de InetAddress para DNS.

En primer lugar, obtenga la configuración actual utilizando 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; } }

Como IpAssignment y linkProperties están ocultos, el objeto se puede obtener de la reflexión.

El siguiente método puede establecer la configuración de la dirección IP declarada en 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)); }

Después de eso, puedo establecer la configuración y actualizar WifiConfiguration para este 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(); }

Editar: Lo siento, no compruebo si el dispositivo Android 3.x tiene una interfaz de usuario similar con Android 4.x. En Android 3.x, la puerta de enlace se almacena en mGateways de linkProperties . mGateways es un Arraylist de tipo InetAddress . Por lo tanto, el siguiente debería funcionar en 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: los métodos setIpAddress , setGateway , setDNS deben setDNS como tipo de InetAddress .


Para Android 5.0+ una solución WIP. Todavía no funciona por alguna razón. Comentarios bienvenidos.

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(); } }


Para 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()); } }


Si intenta utilizar la solución para Android 5.x en 6.x, su aplicación será denegada al hacer esto. Para hacer esto, es probable que necesite rootear su dispositivo y hacer de la aplicación el propietario del dispositivo.

He profundizado un poco en el problema y mis conclusiones son que el código que solía funcionar para Andrdoi 5.x podría funcionar si la aplicación está configurada para ser el propietario del dispositivo.

Un buen ejemplo de cómo se hace esto es usar el ejemplo que se encuentra aquí:

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

Usando adb shell y ejecutando el comando:

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

hará que el propietario del dispositivo de la aplicación y es posible establecer IP estática.