如何在 Android 3.x 或 4.x 上以编程方式配置静态 IP 地址、网络掩码、网关
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/10278461/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to configure a static IP address, netmask, gateway programmatically on Android 3.x or 4.x
提问by Yeung
I have checked in Stack Overflow question API for configuring static IP addresses in an Android application.
我已检查 Stack Overflow 问题API 以在 Android 应用程序中配置静态 IP 地址。
It works until Android 2.3. However, there is no luck on a higher API level. For example, I put the setting
它适用于 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");
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
.
该IP Settings
字段仍被声明,DHCP
但不是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.
确实,我可以用它android.provider.Settings.System.getString()
来取回我设置的东西。它证明设置保存在某处,但系统只是忽略它。
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?
系统使用android.provider.Settings.System
Android 3.x 和 4.x 以外的设置,因为该设置是按接入点 SSID 设置的。我可以像在 Android 2.3 上一样修改一个 SSID 上的设置吗?
回答by Yeung
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
.
我意识到 3.x 或 4.x 上没有针对每个 SSID 设置的 API。于是查了一下源码,发现每个SSID的配置都存放在android.net.wifi.WifiConfiguration
里面,是从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...
在下面的代码中,IpAssignment
是一个枚举,要么STAIC
,DHCP
要么NONE
。并且linkProperties
是对象存储IP地址、网关、DNS等...
linkAddress
is IP address and its netmask as prefixLength (how many bit 1 in netmask).
linkAddress
是 IP 地址及其网络掩码作为 prefixLength(网络掩码中有多少位 1)。
mRoutes
is ArrayList
of RouteInfo
that can indicate gateway.
mRoutes
是ArrayList
的RouteInfo
,可以指示网关。
mDnses
is ArrayList
of InetAddress
for DNS.
mDnses
是ArrayList
的InetAddress
对DNS。
Firstly, get the current configuration using WifiConfiguration
SSID
首先,使用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.
由于IpAssignment
和linkProperties
是隐藏的,因此可以从反射中获取对象。
The following method can set the declared IP address setting on SSID WifiConfiguration:
以下方法可以在 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));
}
After that, I can set setting and update WifiConfiguration
for this SSID.
之后,我可以WifiConfiguration
为此 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.
编辑:抱歉,我不检查与 Android 4.x 具有相似 UI 的 Android 3.x 设备。在安卓3.x中,网关在stortedmGateways
的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: The methods setIpAddress
, setGateway
, setDNS
should be inputted as InetAddress
type.
EDIT2:所述方法setIpAddress
,setGateway
,setDNS
应当被输入作为InetAddress
类型。
回答by Som
@Robin
@罗宾
Thanks your solution works fine for me on My Nexus device running on Android M 6.0.1.
感谢您的解决方案在运行 Android M 6.0.1 的我的 Nexus 设备上对我来说很好。
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
我已经更换了 // 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();
}
回答by Robin Gawenda
For Android 5.0+ a WIP solution. It does not yet work for some reason. Comments welcome.
对于 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();
}
}
回答by Hymanson Chengalai
For Android 5.1.0
对于安卓 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());
}
}
回答by Knubo
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.
如果您尝试在 6.x 上使用适用于 Android 5.x 的解决方案,您的应用程序将被拒绝这样做。为此,您可能需要 root 设备并使应用程序成为设备所有者。
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.
我已经对这个问题进行了一些研究,我的发现是,如果应用程序设置为设备所有者,则用于 Andrdoi 5.x 的代码可能会起作用。
A good example of how this is done is using the example found here:
一个很好的例子是使用这里找到的例子:
https://github.com/googlesamples/android-DeviceOwner/
https://github.com/googlesamples/android-DeviceOwner/
Using adb shell and running the command:
使用 adb shell 并运行命令:
dpm set-device-owner com.example.android.deviceowner/.DeviceOwnerReceiver
dpm 设置设备所有者 com.example.android.deviceowner/.DeviceOwnerReceiver
will make the application device owner and it is possible to set static IP.
将使应用程序设备所有者并且可以设置静态 IP。
回答by crgarridos
As a kotlin extension of WifiConfiguration
, working on Android 5+
作为 kotlin 的扩展WifiConfiguration
,适用于 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")
}
}
回答by sam
@Yeung, everyone
@杨,大家
As far as I understand, Android would start dhclient immediately after connecting to an SSID.
据我了解,Android 会在连接到 SSID 后立即启动 dhclient。
So the code suggested, would apply static configuration only after Android had already obtained an IP address (dhcp success), right?
所以代码建议,只有在Android已经获得IP地址(dhcp成功)后才会应用静态配置,对吗?
This is what is happening in my experiments on Pie. I try to apply static configuration by listening to WifiManager.NETWORK_STATE_CHANGED_ACTION
这就是我在 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
}
}