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

前端 未结 2 1684
一生所求
一生所求 2020-12-01 03:44

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 b

2条回答
  •  旧巷少年郎
    2020-12-01 04:45

    There is still no open API, unfortunately.

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

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

    @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 enumClz = (Class)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 getField(Object object, String fieldName, Class 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 WifiConfigController class in the framework (though it uses these classes directly instead of via reflection).

提交回复
热议问题