Ich habe die Stack Overflow-Frage API zum Konfigurieren statischer IP-Adressen in einer Android-Anwendung eingecheckt.
Es funktioniert bis Android 2.3. Auf einer höheren API-Ebene gibt es jedoch kein Glück. Zum Beispiel Ich habe die Einstellung gesetzt
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");
Aber ich gehe zurück, um zu überprüfen:
Setting --> Wi-Fi --> Long Press Access Point SSID --> Modify Network --> check Show advanced options
Das Feld IP Settings
wird zwar noch DHCP
angegeben, jedoch nicht Static
.
Es ist wahr, dass ich Android.provider.Settings.System.getString()
verwenden kann, um das zurückzusetzen, was ich eingestellt habe. Es beweist, dass die Einstellung irgendwo gespeichert wird, aber das System ignoriert es einfach.
Das System verwendet bei Android 3.x und 4.x eine andere Einstellung als Android.provider.Settings.System
, da die Einstellung für die Zugriffspunkt-SSID festgelegt wird. Kann ich die Einstellung für eine SSID genauso wie für Android 2.3 ändern?
Mir ist klar, dass es unter 3.x oder 4.x keine API für die Einstellung per SSID gibt. Daher habe ich den Quellcode ausgecheckt und herausgefunden, dass die Konfiguration jeder SSID in Android.net.wifi.WifiConfiguration
gespeichert ist, der von Android.net.wifi.WifiManager
abgerufen wird.
Im folgenden Code ist IpAssignment
ein Enum, entweder STAIC
, DHCP
oder NONE
..__ und linkProperties
ist die Objektspeicher-IP-Adresse, Gateway, DNS usw.
linkAddress
ist die IP-Adresse und ihre Netzmaske als Präfixlänge (wie viele Bit 1 in der Netzmaske).
mRoutes
ist ArrayList
von RouteInfo
, das ein Gateway anzeigen kann.
mDnses
ist ArrayList
von InetAddress
für DNS.
Rufen Sie zunächst die aktuelle Konfiguration mit WifiConfiguration
SSID ab
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;
}
}
Da IpAssignment
und linkProperties
ausgeblendet sind, kann das Objekt durch Reflektion abgerufen werden.
Die folgende Methode kann die deklarierte IP-Adresseinstellung für SSID WifiConfiguration festlegen:
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));
}
Danach kann ich die Einstellung und Aktualisierung von WifiConfiguration
für diese SSID vornehmen.
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: Entschuldigung, ich suche nicht nach Android 3.x-Geräten, die über eine silmilar Benutzeroberfläche mit Android 4.x verfügen . In Android 3.x ist das Gateway in mGateways
von linkProperties
.mGateways
ist Arraylist
vom Typ InetAddress
. Daher sollte Folgendes in Android 3.x funktionieren.
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: Die Methoden setIpAddress
, setGateway
, setDNS
sollten als InetAddress
-Typ eingegeben werden.
@Robin
Dank Ihrer Lösung funktioniert mein My Nexus-Gerät auf Android M 6.0.1 gut.
Ich habe den
// 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
ersetzt
mit den folgenden
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();
}
Für Android 5.0 und höher eine WIP-Lösung. Es funktioniert aus irgendeinem Grund noch nicht. Kommentare sind willkommen.
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();
}
}
Für 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());
}
}
Als Kotlin-Erweiterung von WifiConfiguration
für 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")
}
}
@Yeung, alle zusammen
Soweit ich weiß, würde Android dhclient sofort nach dem Herstellen einer Verbindung zu einer SSID starten.
Also schlug der Code vor, statische Konfiguration erst anzuwenden, nachdem Android hatte bereits eine IP-Adresse erhalten (DHCP-Erfolg), oder?
Dies ist, was in meinen Experimenten zu Pie passiert. Ich versuche, die statische Konfiguration anzuwenden, indem ich WifiManager.NETWORK_STATE_CHANGED_ACTION anhöre
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
}
}
Wenn Sie versuchen, die Lösung für Android 5.x unter 6.x zu verwenden, wird dies Ihrer Anwendung verweigert. Dazu müssen Sie das Gerät rooten und die Anwendung zum Eigentümer des Geräts machen.
Ich habe einiges in das Problem hineingegraben, und ich habe festgestellt, dass der Code, der für Andrdoi 5.x verwendet wurde, möglicherweise funktioniert, wenn die Anwendung als Eigentümer des Geräts festgelegt ist.
Ein gutes Beispiel dafür ist das hier aufgeführte Beispiel:
https://github.com/googlesamples/Android-DeviceOwner/
Verwenden von Adb Shell und Ausführen des Befehls:
dpm set-device-owner com.example.Android.deviceowner/.DeviceOwnerReceiver
wird zum Besitzer des Anwendungsgeräts und es ist möglich, eine statische IP-Adresse festzulegen.