java 如何在 Android 5.x (Lollipop) 上以编程方式为 Wi-Fi 连接配置静态 IP 地址、网络掩码、网关、DNS

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/27599564/
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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-02 12:05:50  来源:igfitidea点击:

How to configure a static IP address, netmask, gateway, DNS programmatically on Android 5.x (Lollipop) for Wi-Fi connection

javaandroidandroid-5.0-lollipop

提问by KennyPowers

How can a static IP address, netmask, gateway, DNS be programmatically configured on Android 5.x for Wi-Fi connection? Is there an open API (didn't find it) or hidden can be used for this? Could you also please give some examples if possible.

如何在 Android 5.x 上以编程方式配置静态 IP 地址、网络掩码、网关、DNS 以进行 Wi-Fi 连接?是否有开放的 API(没有找到)或隐藏的可以用于此目的?如果可能的话,您能否也举一些例子。

I know it's possible on Android 4.0+but it doesn't work on Android 5.0

我知道这在 Android 4.0+ 上可能的,但它在 Android 5.0 上不起作用

回答by matiash

There is still no open API, unfortunately.

不幸的是,仍然没有开放的 API。

The solution for Android 4.0 doesn't work in LOLLIPOP because things have been moved around. In particular the new IpConfigurationclass now holds the StaticIpConfigurationand all these fields. They can still be accessed by using reflection (with all the brittleness that entails) with something like this.

Android 4.0 的解决方案在 LOLLIPOP 中不起作用,因为事情已经发生了变化。特别是新IpConfiguration类现在拥有StaticIpConfiguration所有这些字段。它们仍然可以通过使用反射(伴随着所有的脆弱性)和这样的东西来访问。

Warning, this code is Android 5.0-only. You'll need to check Build.VERSION.SDK_INTand act accordingly.

警告,此代码仅适用于 Android 5.0。您需要检查Build.VERSION.SDK_INT并采取相应措施。

@SuppressWarnings("unchecked")
private static void setStaticIpConfiguration(WifiManager manager, WifiConfiguration config, InetAddress ipAddress, int prefixLength, InetAddress gateway, InetAddress[] dns) throws ClassNotFoundException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, NoSuchFieldException, InstantiationException
{
    // First set up IpAssignment to STATIC.
    Object ipAssignment = getEnumValue("android.net.IpConfiguration$IpAssignment", "STATIC");
    callMethod(config, "setIpAssignment", new String[] { "android.net.IpConfiguration$IpAssignment" }, new Object[] { ipAssignment });

    // Then set properties in StaticIpConfiguration.
    Object staticIpConfig = newInstance("android.net.StaticIpConfiguration");
    Object linkAddress = newInstance("android.net.LinkAddress", new Class<?>[] { InetAddress.class, int.class }, new Object[] { ipAddress, prefixLength });

    setField(staticIpConfig, "ipAddress", linkAddress);
    setField(staticIpConfig, "gateway", gateway);
    getField(staticIpConfig, "dnsServers", ArrayList.class).clear();
    for (int i = 0; i < dns.length; i++)
        getField(staticIpConfig, "dnsServers", ArrayList.class).add(dns[i]);

    callMethod(config, "setStaticIpConfiguration", new String[] { "android.net.StaticIpConfiguration" }, new Object[] { staticIpConfig });
    manager.updateNetwork(config);
    manager.saveConfiguration();
}

With the following helper methods to handle reflection:

使用以下辅助方法来处理反射:

private static Object newInstance(String className) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, IllegalArgumentException, InvocationTargetException
{
    return newInstance(className, new Class<?>[0], new Object[0]);
}

private static Object newInstance(String className, Class<?>[] parameterClasses, Object[] parameterValues) throws NoSuchMethodException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, ClassNotFoundException
{
    Class<?> clz = Class.forName(className);
    Constructor<?> constructor = clz.getConstructor(parameterClasses);
    return constructor.newInstance(parameterValues);
}

@SuppressWarnings({ "unchecked", "rawtypes" })
private static Object getEnumValue(String enumClassName, String enumValue) throws ClassNotFoundException
{
    Class<Enum> enumClz = (Class<Enum>)Class.forName(enumClassName);
    return Enum.valueOf(enumClz, enumValue);
}

private static void setField(Object object, String fieldName, Object value) throws IllegalAccessException, IllegalArgumentException, NoSuchFieldException
{
    Field field = object.getClass().getDeclaredField(fieldName);
    field.set(object, value);
}

private static <T> T getField(Object object, String fieldName, Class<T> type) throws IllegalAccessException, IllegalArgumentException, NoSuchFieldException
{
    Field field = object.getClass().getDeclaredField(fieldName);
    return type.cast(field.get(object));
}

private static void callMethod(Object object, String methodName, String[] parameterTypes, Object[] parameterValues) throws ClassNotFoundException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException
{
    Class<?>[] parameterClasses = new Class<?>[parameterTypes.length];
    for (int i = 0; i < parameterTypes.length; i++)
        parameterClasses[i] = Class.forName(parameterTypes[i]);

    Method method = object.getClass().getDeclaredMethod(methodName, parameterClasses);
    method.invoke(object, parameterValues);
}

For example, you can call it like this:

例如,您可以这样称呼它:

public void test(Context context)
{
    WifiManager manager = (WifiManager)context.getSystemService(Context.WIFI_SERVICE);
    WifiConfiguration wifiConf = ... /* Get Wifi configuration you want to update */

    if (wifiConf != null)
    {
        try
        {
            setStaticIpConfiguration(manager, wifiConf,
                InetAddress.getByName("10.0.0.1"), 24,
                InetAddress.getByName("10.0.0.2"),
                new InetAddress[] { InetAddress.getByName("10.0.0.3"), InetAddress.getByName("10.0.0.4") });
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
    }
}

As a reference, you might want to take a look at the WifiConfigControllerclass in the framework (though it uses these classes directly instead of via reflection).

作为参考,您可能需要查看WifiConfigController框架中的类(尽管它直接使用这些类而不是通过反射)。

回答by rolfl

IP addresses are configured on an interface, not phone basis. You cannot set one IP address to be used for the cellular data connection, and all the wireless (bluetooth, etc.) connections that may be created too.

IP 地址是在接口上配置的,而不是在电话上配置的。您不能设置一个 IP 地址用于蜂窝数据连接以及可能创建的所有无线(蓝牙等)连接。

Since the IP address is dependent on the interface, the address is configured there too.

由于 IP 地址取决于接口,因此地址也在那里配置。

For the data connection, the IP address is (I believe, not confirmed) communicated to the phone by the cellular carrier, and is not configurable on the device.

对于数据连接,IP 地址(我相信,未确认)由蜂窝运营商传送到电话,并且无法在设备上配置。

For regular wi-fi type connections, for each network, you can choose to use the default (DHCP) or some other form of IP address provisioning, including whether you want to configure the IP address manually, or via the dynamic systems in place.

对于常规 wi-fi 类型的连接,对于每个网络,您可以选择使用默认 (DHCP) 或某种其他形式的 IP 地址配置,包括您是要手动配置 IP 地址,还是通过适当的动态系统配置 IP 地址。

Since the gateway and netmask are set on the network too, it makes sense that the 'best' way to configure a 'static' IP address for a given network, is to configure it on the network side. For most network DHCP servers you can configure them to always provision the same network IP to the same device each time.

由于网关和网络掩码也在网络上设置,因此为给定网络配置“静态”IP 地址的“最佳”方法是在网络端配置它是有意义的。对于大多数网络 DHCP 服务器,您可以将它们配置为每次始终为同一设备提供相同的网络 IP。

This is what I do, I have certain devices get their IP address through DHCP, but the DHCP server always allocates the same pre-configured and 'static' IP address to the devices I want constant (and other devices pull an IP from the available 'pool').

这就是我所做的,我让某些设备通过 DHCP 获取它们的 IP 地址,但是 DHCP 服务器总是为我想要恒定的设备分配相同的预配置和“静态”IP 地址(而其他设备从可用的'水池')。