问题描述
我检查了堆栈溢出问题用于在 Android 应用程序中配置静态 IP 地址的 API.
I have checked in Stack Overflow question API for configuring static IP addresses in an Android application.
它一直工作到 Android 2.3.但是,在更高的 API 级别上没有运气.例如,我把设置
It works until Android 2.3. However, there is no luck on a higher API level. For example,I put the setting
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
.
The IP Settings
field is still stated DHCP
but not Static
.
确实,我可以使用 android.provider.Settings.System.getString()
来取回我设置的内容.它证明设置保存在某处,但系统只是忽略它.
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 3.x 和 4.x 上使用 android.provider.Settings.System
以外的设置,因为该设置是按接入点 SSID 设置的.我可以像在 Android 2.3 上一样修改一个 SSID 的设置吗?
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?
推荐答案
我意识到 3.x 或 4.x 上没有针对每个 SSID 设置的 API.于是查了一下源码,发现每个SSID的配置都保存在android.net.wifi.WifiConfiguration
中,android.net.wifi.WifiManager
代码>.
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
.
在下面的代码中,IpAssignment
是一个枚举,可以是 STAIC
、DHCP
或 NONE
.而linkProperties
是对象存储IP地址、网关、DNS等...
In the below code, IpAssignment
is an Enum, either STAIC
, DHCP
or NONE
.And linkProperties
is the object store IP address, gateway, DNS, etc...
linkAddress
是 IP 地址及其网络掩码作为 prefixLength(网络掩码中有多少位 1).
linkAddress
is IP address and its netmask as prefixLength (how many bit 1 in netmask).
mRoutes
是RouteInfo
的ArrayList
,可以表示网关.
mRoutes
is ArrayList
of RouteInfo
that can indicate gateway.
mDnses
是 DNS 的 InetAddress
的 ArrayList
.
mDnses
is ArrayList
of InetAddress
for DNS.
首先,使用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
是隐藏的,所以可以通过反射获取对象.
As the IpAssignment
and linkProperties
are hidden, the object can be gotten from reflection.
以下方法可以设置SSID WifiConfiguration上声明的IP地址设置:
The following method can set the declared IP address setting on 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));
}
之后,我可以设置和更新此 SSID 的 WifiConfiguration
.
After that, I can set setting and update WifiConfiguration
for this 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();
}
抱歉,我不检查与 Android 4.x 具有相似 UI 的 Android 3.x 设备.在Android 3.x 中,网关存储在linkProperties
的mGateways
中.mGateways
是 InetAddress
类型的 Arraylist
.因此,以下应该适用于 Android 3.x.
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.
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
类型.
The methods setIpAddress
, setGateway
, setDNS
should be inputted as InetAddress
type.
这篇关于如何在 Android 3.x 或 4.x 上以编程方式配置静态 IP 地址、网络掩码、网关的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!