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.