it-swarm.com.de

So konfigurieren Sie eine statische IP-Adresse, Netzmaske und Gateway programmgesteuert unter Android 3.x oder 4.x

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?

30
Yeung

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.

58
Yeung

@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();                        
}
3
Som

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();
    }
}
2
Robin Gawenda

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());
    }
}
1

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")
    }
}
0
crgarridos

@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
    }
}
0
sam

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.

0
Knubo