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

标签 java android android-5.0-lollipop

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

我知道它是 possible on Android 4.0+但它不适用于 Android 5.0

最佳答案

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

适用于 Android 4.0 的解决方案在 LOLLIPOP 中不起作用,因为内容已被移动。特别是新的 IpConfiguration 类现在包含 StaticIpConfiguration以及所有这些领域。它们仍然可以通过像这样的方式使用反射(具有所有的脆弱性)来访问。

警告,此代码仅适用于 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();
}

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

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

例如,你可以这样调用它:

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

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

关于java - 如何在 Android 5.x (Lollipop) 上以编程方式为 Wi-Fi 连接配置静态 IP 地址、网络掩码、网关、DNS,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27599564/

相关文章:

android - 如何防止在 DatePickerDialog 中选择通过日期(setMinDate 无法按预期工作)

java - 将 Matrix4f 加载到 FloatBuffer 中,以便我的着色器可以使用它

java - Android多实例Activity

java - 在作为代理工作的 Nginx Ring 处理程序中读取服务器名称

android - 仅匹配域的 Intent 过滤器(无路径)

java - UDP Code客户端服务器架构

java - 在状态设计模式中使用组合和实现

android - CardView 在 API 19 上消失

android - SQLite 数据库在 <table_name>(column) 上给出警告自动索引升级 Android L 后

Android L 忽略形状作为可绘制背景