如何在Android 3.x或4.x上以编程方式configuration静态IP地址,networking掩码,网关
我已经检查了堆栈溢出问题API在Android应用程序中configuration静态IP地址 。
它适用于Android 2.3。 但是,在更高的API级别上没有运气。 例如,我把设置
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");
但我回去检查一下:
Setting --> Wi-Fi --> Long Press Access Point SSID --> Modify Network --> check Show advanced options
IP Settings
字段仍然是DHCP
但不是Static
。
这是真的,我可以使用android.provider.Settings.System.getString()
来取回我设定的。 它certificate设置保存在某个地方,但系统只是忽略它。
系统使用Android 3.x和4.x以外的设置,而不是android.provider.Settings.System
,根据接入点SSID设置。 我可以修改一个SSID的设置,就像它在Android 2.3上的工作方式一样吗?
我意识到,对于每个SSID的设置,在3.x或4.x上没有API。 因此,我检查了源代码,发现一个SSID的configuration存储在android.net.wifi.WifiConfiguration
,从android.net.wifi.WifiManager
获取。
IpAssignment
是一个枚举, IpAssignment
, DHCP
或NONE
。 而linkProperties
是对象存储的IP地址,网关,DNS等…
linkAddress
是IP地址,其networking掩码为prefixLength(networking掩码中有多less位1)。
mRoutes
是可以指示网关的mRoutes
的ArrayList
。
mDnses
是DNS的InetAddress
ArrayList
。
首先,使用SSID WifiConfiguration
获取当前WifiConfiguration
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; } }
由于IpAssignment
和linkProperties
是隐藏的,因此可以从reflection中获取对象。
以下方法可以在SSID WifiConfiguration上设置声明的IP地址设置:
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; } public 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)); }
之后,我可以设置和更新这个SSID的WifiConfiguration
。
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(); }
编辑:对不起,我没有检查Android 3.x设备与Android 4.x具有类似的用户界面。 在Android 3.x中,网关在mGateways
属性的mGateways
中被linkProperties
。 mGateways
是InetAddress
types的Arraylist
。 因此,下面应该在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:方法setIpAddress
, setGateway
, setDNS
应该input为InetAddress
types。
@Robin
感谢您的解决scheme在Android M 6.0.1上运行的My Nexus设备上正常工作。
我已经取代了/ / // 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
与以下
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(); }
对于Android 5.0+ WIP解决scheme。 由于某种原因,它还没有工作。 评论欢迎。
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(); } }
适用于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()); } }
如果您尝试在6.x上使用Android 5.x的解决scheme,您的应用程序将被拒绝。 要做到这一点,你可能需要根植你的设备,使应用程序成为设备的所有者。
我已经挖掘了一些问题,我的发现是,曾经为Andrdoi 5.x工作的代码可能工作,如果应用程序设置为设备所有者。
一个很好的例子是如何使用这里find的例子:
https://github.com/googlesamples/android-DeviceOwner/
使用adb shell并运行命令:
dpm set-device-owner com.example.android.deviceowner / .DeviceOwnerReceiver
将使应用程序设备所有者,并可以设置静态IP。