本文介绍了如何在 Android 3.x 或 4.x 上以编程方式配置静态 IP 地址、网络掩码、网关的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我检查了堆栈溢出问题用于在 Android 应用程序中配置静态 IP 地址的 API.

I have checked in Stack Overflow question API for configuring static IP addresses in an Android application.

它一直工作到 Android 2.3.但是,在更高的 API 级别上没有运气.例如,我把设置

It works until Android 2.3. However, there is no luck on a higher API level. For example,I put the setting

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

但我回去检查:

Setting --> Wi-Fi --> Long Press Access Point SSID --> Modify Network --> check Show advanced options

IP Settings 字段仍然声明为 DHCP 但不是 Static.

The IP Settings field is still stated DHCP but not Static.

确实,我可以使用 android.provider.Settings.System.getString() 来取回我设置的内容.它证明设置保存在某处,但系统只是忽略它.

It is true that I can use android.provider.Settings.System.getString() to get back what I set. It prove that the setting is saved somewhere but the system just ignore it.

系统在 Android 3.x 和 4.x 上使用 android.provider.Settings.System 以外的设置,因为该设置是按接入点 SSID 设置的.我可以像在 Android 2.3 上一样修改一个 SSID 的设置吗?

The system uses the setting other than android.provider.Settings.System on Android 3.x and 4.x as the setting is set per Access Point SSID. Can I modify the setting on one SSID just like how it works on Android 2.3?

推荐答案

我意识到 3.x 或 4.x 上没有针对每个 SSID 设置的 API.于是查了一下源码,发现每个SSID的配置都保存在android.net.wifi.WifiConfiguration中,android.net.wifi.WifiManager代码>.

I realise that there is no API on 3.x or 4.x for those setting per SSID. Therefore, I checked out the source code and found out that the configuration of each SSID is stored in android.net.wifi.WifiConfiguration which is gotten from android.net.wifi.WifiManager.

在下面的代码中,IpAssignment 是一个枚举,可以是 STAICDHCPNONE.而linkProperties是对象存储IP地址、网关、DNS等...

In the below code, IpAssignment is an Enum, either STAIC, DHCP or NONE.And linkProperties is the object store IP address, gateway, DNS, etc...

linkAddress 是 IP 地址及其网络掩码作为 prefixLength(网络掩码中有多少位 1).

linkAddress is IP address and its netmask as prefixLength (how many bit 1 in netmask).

mRoutesRouteInfoArrayList,可以表示网关.

mRoutes is ArrayList of RouteInfo that can indicate gateway.

mDnses 是 DNS 的 InetAddressArrayList.

mDnses is ArrayList of InetAddress for DNS.

首先,使用WifiConfiguration SSID

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

由于IpAssignmentlinkProperties是隐藏的,所以可以通过反射获取对象.

As the IpAssignment and linkProperties are hidden, the object can be gotten from reflection.

以下方法可以设置SSID WifiConfiguration上声明的IP地址设置:

The following method can set the declared IP address setting on SSID WifiConfiguration:

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

之后,我可以设置和更新此 SSID 的 WifiConfiguration.

After that, I can set setting and update WifiConfiguration for this SSID.

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

抱歉,我不检查与 Android 4.x 具有相似 UI 的 Android 3.x 设备.在Android 3.x 中,网关存储在linkPropertiesmGateways 中.mGatewaysInetAddress 类型的 Arraylist.因此,以下应该适用于 Android 3.x.

Sorry for I don't check for Android 3.x device that have silmilar UI with Android 4.x.In Android 3.x, the gateway is storted in mGateways of linkProperties.mGateways is Arraylist of type InetAddress. Therefore, following should work in Android 3.x.

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:方法setIpAddresssetGatewaysetDNS 应输入为InetAddress 类型.

The methods setIpAddress, setGateway, setDNS should be inputted as InetAddress type.

这篇关于如何在 Android 3.x 或 4.x 上以编程方式配置静态 IP 地址、网络掩码、网关的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

07-25 21:22