如何使用Java在Android Wi-Fi连接上设置代理设置和代理属性?

11

如何使用Java(以编程方式)在Android Wi-Fi连接中设置ProxySettings和ProxyProperties?

由于ipAssignment、linkProperties、ProxySettings和ProxyProperties是在Android 3.1及以上版本中WifiConfiguration中的隐藏字段,因此我需要能够枚举类并使用这些字段。

根据下面链接中提供的代码示例,我可以为特定的Wi-Fi连接设置静态IP地址、网关和DNS,但我还需要设置Wificonfiguration.ProxySettings.STATIC和ProxyProperties。

请参阅Stack Overflow问题 如何在Android 3.x或4.x上以编程方式配置静态IP地址、子网掩码、网关

例如:

WifiConfiguration config = new WifiConfiguration(configuration);
config.ipAssignment = WifiConfiguration.IpAssignment.UNASSIGNED;
config.proxySettings = WifiConfiguration.ProxySettings.STATIC;
config.linkProperties.setHttpProxy(new ProxyProperties("127.0.0.1", 3128, ""));

寻找类似于:

setProxySettings("STATIC", wifiConf);
setProxyProperties("proxyserver.mine.com.au", 8080, ""); // Set Proxy server and port.
wifiManager.updateNetwork(wifiConf); //apply the setting

使用来自coolypf的下面代码,.ipAssignment、.ProxySettings和linkProperties是隐藏的...

    WifiManager manager = (WifiManager)getSystemService(Context.WIFI_SERVICE);
manager.asyncConnect(this, new Handler());
if (!manager.isWifiEnabled()) return;
    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;
    }
    if (configuration == null) return;
    WifiConfiguration config = new WifiConfiguration(configuration);
    config.ipAssignment = WifiConfiguration.IpAssignment.UNASSIGNED;
    config.proxySettings = WifiConfiguration.ProxySettings.STATIC;

    config.linkProperties.clear();

    config.linkProperties.setHttpProxy(new ProxyProperties("127.0.0.1", 3128, ""));

    manager.saveNetwork(config);
3个回答

15

下面是一些代码,可以让您设置/取消代理属性。它使用了上面链接中的一些代码。但是断开/重新连接后设置似乎不会生效。

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

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

public static void setProxySettings(String assign , WifiConfiguration wifiConf)
throws SecurityException, IllegalArgumentException, NoSuchFieldException, IllegalAccessException{
    setEnumField(wifiConf, assign, "proxySettings");     
}


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

void setWifiProxySettings()
{
    //get the current wifi configuration
    WifiManager manager = (WifiManager)getSystemService(Context.WIFI_SERVICE);
    WifiConfiguration config = GetCurrentWifiConfiguration(manager);
    if(null == config)
        return;

    try
    {
        //get the link properties from the wifi configuration
        Object linkProperties = getField(config, "linkProperties");
        if(null == linkProperties)
            return;

        //get the setHttpProxy method for LinkProperties
        Class proxyPropertiesClass = Class.forName("android.net.ProxyProperties");
        Class[] setHttpProxyParams = new Class[1];
        setHttpProxyParams[0] = proxyPropertiesClass;
        Class lpClass = Class.forName("android.net.LinkProperties");
        Method setHttpProxy = lpClass.getDeclaredMethod("setHttpProxy", setHttpProxyParams);
        setHttpProxy.setAccessible(true);

        //get ProxyProperties constructor
        Class[] proxyPropertiesCtorParamTypes = new Class[3];
        proxyPropertiesCtorParamTypes[0] = String.class;
        proxyPropertiesCtorParamTypes[1] = int.class;
        proxyPropertiesCtorParamTypes[2] = String.class;

        Constructor proxyPropertiesCtor = proxyPropertiesClass.getConstructor(proxyPropertiesCtorParamTypes);

        //create the parameters for the constructor
        Object[] proxyPropertiesCtorParams = new Object[3];
        proxyPropertiesCtorParams[0] = "127.0.0.1";
        proxyPropertiesCtorParams[1] = 8118;
        proxyPropertiesCtorParams[2] = null;

        //create a new object using the params
        Object proxySettings = proxyPropertiesCtor.newInstance(proxyPropertiesCtorParams);

        //pass the new object to setHttpProxy
        Object[] params = new Object[1];
        params[0] = proxySettings;
        setHttpProxy.invoke(linkProperties, params);

        setProxySettings("STATIC", config);

        //save the settings
        manager.updateNetwork(config);
        manager.disconnect();
        manager.reconnect();
    }   
    catch(Exception e)
    {
    }
}
void unsetWifiProxySettings()
{
    WifiManager manager = (WifiManager)getSystemService(Context.WIFI_SERVICE);
    WifiConfiguration config = GetCurrentWifiConfiguration(manager);
    if(null == config)
        return;

    try
    {
        //get the link properties from the wifi configuration
        Object linkProperties = getField(config, "linkProperties");
        if(null == linkProperties)
            return;

        //get the setHttpProxy method for LinkProperties
        Class proxyPropertiesClass = Class.forName("android.net.ProxyProperties");
        Class[] setHttpProxyParams = new Class[1];
        setHttpProxyParams[0] = proxyPropertiesClass;
        Class lpClass = Class.forName("android.net.LinkProperties");
        Method setHttpProxy = lpClass.getDeclaredMethod("setHttpProxy", setHttpProxyParams);
        setHttpProxy.setAccessible(true);

        //pass null as the proxy
        Object[] params = new Object[1];
        params[0] = null;
        setHttpProxy.invoke(linkProperties, params);

        setProxySettings("NONE", config);

        //save the config
        manager.updateNetwork(config);
        manager.disconnect();
        manager.reconnect();
    }   
    catch(Exception e)
    {
    }
}

你的意思是“断开/重新连接后,设置似乎没有生效”吗? - David
1
这在Android 2.3.6上无法工作。 错误:"没有这样的字段异常" 行:Object linkProperties = getField(config, "linkProperties"); 在setWifiProxySettings()中 - Emre Koç
1
@carl,我的HP平板电脑4.4版本中没有静态选项的代理设置,只有两个选项:无和手动。你能否建议一下如何进行手动设置? - KOTIOS
1
你知道在编程中是否可以通过程序判断WiFi是否已经屏蔽了WhatsApp、Instagram等服务吗? - Skizo-ozᴉʞS ツ
嗨,Carl,我遇到了一个错误:“没有这样的字段异常”行:Object linkProperties = getField(config,“linkProperties”)。你能否请发给我一份示例代码。非常感谢。 - Md Maidul Islam
显示剩余2条评论

7

和 Dave 的回答类似,但是可以通过只使用方法 setProxy(ProxySettings settings, ProxyInfo proxy) 来减少代码行数(为了清晰起见省略了周围的代码):

Class proxySettings = Class.forName("android.net.IpConfiguration$ProxySettings");

Class[] setProxyParams = new Class[2];
setProxyParams[0] = proxySettings;
setProxyParams[1] = ProxyInfo.class;

Method setProxy = config.getClass().getDeclaredMethod("setProxy", setProxyParams);
setProxy.setAccessible(true);

ProxyInfo desiredProxy = ProxyInfo.buildDirectProxy(YOUR_HOST, YOUR_PORT);

Object[] methodParams = new Object[2];
methodParams[0] = Enum.valueOf(proxySettings, "STATIC");
methodParams[1] = desiredProxy;

setProxy.invoke(config, methodParams);

这段代码在大多数情况下都能正常工作,但在Android 8上却不行。E/WifiConfigManager: UID 10610没有权限修改代理设置。有什么解决方法? - Degard
1
Android 8增加了一个公共API来设置代理,但限制为设备所有者和配置文件所有者使用:https://developer.android.com/reference/android/net/wifi/WifiConfiguration#setHttpProxy(android.net.ProxyInfo)。目前似乎没有解决方法。 - Markus
如何在Android 29 API中设置WiFi配置? - Anant Shah

5

以下是一些示例代码,用于在 Android 5.0 中处理与 Carl 上面回答中相同的问题,并遵循相同的格式。

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
对于Android 6,这段代码也可以工作,但不幸的是,您无法更新未由自己创建的网络。这是由于新的Android Wifi规则所致:http://developer.android.com/about/versions/marshmallow/android-6.0-changes.html#behavior-network - radu122

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接