如何在 Android 3.x 或 4.x 上以编程方式配置静态 IP 地址、网络掩码、网关
Posted
技术标签:
【中文标题】如何在 Android 3.x 或 4.x 上以编程方式配置静态 IP 地址、网络掩码、网关【英文标题】:How to configure a static IP address, netmask, gateway programmatically on Android 3.x or 4.x 【发布时间】:2012-05-03 22:35:59 【问题描述】:我已签入 Stack Overflow 问题API for configuring static IP addresses in an android application。
它在 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()
来取回我设置的内容。它证明设置保存在某处,但系统只是忽略它。
系统在 Android 3.x 和 4.x 上使用除 android.provider.Settings.System
之外的设置,因为该设置是按接入点 SSID 设置的。我可以像在 Android 2.3 上一样修改一个 SSID 的设置吗?
【问题讨论】:
【参考方案1】:我意识到 3.x 或 4.x 上没有针对每个 SSID 设置的 API。于是,我查看了源码,发现每个SSID的配置都存放在android.net.wifi.WifiConfiguration
中,android.net.wifi.WifiConfiguration
是从android.net.wifi.WifiManager
获取的。
在下面的代码中,IpAssignment
是一个枚举,STAIC
、DHCP
或 NONE
。
而linkProperties
是对象存储IP地址、网关、DNS等...
linkAddress
是 IP 地址,其网络掩码为 prefixLength(网络掩码中有多少位 1)。
mRoutes
是ArrayList
的RouteInfo
可以表示网关。
mDnses
是 DNS 的 ArrayList
和 InetAddress
。
首先,使用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;
由于IpAssignment
和linkProperties
是隐藏的,所以可以通过反射获取对象。
以下方法可以设置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;
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));
之后,我可以为这个 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 4.x 类似 UI 的 Android 3.x 设备。
在 Android 3.x 中,网关存储在 mGateways
的 linkProperties
中。
mGateways
是 Arraylist
类型的 InetAddress
。因此,以下应该适用于 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
应输入为InetAddress
类型。
【讨论】:
嗨,我正在使用此代码,但在 `Class routeInfoClass = Class.forName("android.net.RouteInfo");` 语句中出现错误。我该如何解决。它说java.lang.ClassNotFoundException: android.net.RouteInfo
。提前致谢。
我在 3.x 中遇到错误,当我将项目更改为 4.x 并在 ICS 设备中进行测试时,它可以工作。如何在 3.x 中解决此问题?
真的有效吗?我试过 3.x 甚至 4.x 版本,没有显示效果。它始终是 DHCP,并且不会更改为静态。因此,地址不会发生任何变化。
第一个代码块中的小错字。 if (WifiConf.networkId == connectionInfo.getNetworkId()) 应该是: if (conf.networkId == connectionInfo.getNetworkId()) 和: WifiConf = conf;应该是:wifiConf = conf;
确保你调用了 wifiManager.saveConfiguration();在 wifiManager.updateNetwork(wifiConf) 之后;正确应用设置。参考:***.com/questions/18136000/…【参考方案2】:
适用于安卓 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());
【讨论】:
它可以在 api 23 上运行吗?我在 Android M 上尝试过,但它不工作。 不知道 api 23。我在棒棒糖设备中使用此代码进行测试【参考方案3】:对于 Android 5.0+,一个 WIP 解决方案。由于某种原因,它还不能工作。欢迎评论。
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();
【讨论】:
这个拯救了我的一天【参考方案4】:@罗宾
感谢您的解决方案在运行 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
以下
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();
【讨论】:
谢谢。 enableNetwork 可能是缺少的位。然而,真的需要禁用所有其他网络吗?您是否也尝试过 enableNetwork/wifiConf.networkId, false)?【参考方案5】:如果您尝试在 6.x 上使用适用于 Android 5.x 的解决方案,您的应用程序将被拒绝这样做。为此,您可能需要 root 设备并将应用程序设为设备所有者。
我对这个问题进行了一些研究,我的发现是,如果将应用程序设置为设备所有者,则过去适用于 Andrdoi 5.x 的代码可能会起作用。
使用此处找到的示例是一个很好的示例:
https://github.com/googlesamples/android-DeviceOwner/
使用 adb shell 并运行命令:
dpm set-device-owner com.example.android.deviceowner/.DeviceOwnerReceiver
将使应用程序设备所有者并且可以设置静态IP。
【讨论】:
【参考方案6】:作为WifiConfiguration
的 kotlin 扩展,适用于 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")
【讨论】:
【参考方案7】:@Yeung,大家
据我了解,Android 会在连接到 SSID 后立即启动 dhclient。
所以代码建议,只有在Android已经获得IP地址(dhcp成功)之后才会应用静态配置,对吧?
这就是我在 Pie 实验中发生的情况。我尝试通过收听 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
【讨论】:
【参考方案8】:@Robin 非常感谢,您的解决方案在 Android 7 上完全适用于我(必需 系统应用权限)。
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
【讨论】:
以上是关于如何在 Android 3.x 或 4.x 上以编程方式配置静态 IP 地址、网络掩码、网关的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 fltk 1.3 创建 opengl 3.x 或 4.x 上下文?
如何在 Android 上以编程方式截取屏幕截图? [复制]
如何在 Android 上以编程方式从 Mac 地址获取 IP 地址?