web-dev-qa-db-ja.com

Android 3.xまたは4.xでプログラムで静的IPアドレス、ネットマスク、ゲートウェイを構成する方法

Stack Overflowの質問で確認しましたAndroidアプリケーション)で静的IPアドレスを構成するためのAPI

Android 2.3。まで動作します。しかし、より高いAPIレベルでは運がありません。たとえば、設定を

_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とは記述されていません。

Android.provider.Settings.System.getString()を使用して設定したものを取り戻すことができるのは事実です。設定がどこかに保存されていることを証明しますが、システムはそれを無視します。

システムは、アクセスポイントSSIDごとに設定が設定されるため、_Android.provider.Settings.System_ on Android 3.xおよび4.x以外の設定を使用します。1つのSSIDで設定を変更できますかどのように動作するかAndroid 2.3?

30
Yeung

SSIDごとに設定するための3.xまたは4.xにはAPIがないことを認識しています。そのため、ソースコードをチェックアウトし、各SSIDの構成がAndroid.net.wifi.WifiConfigurationこれはAndroid.net.wifi.WifiManager

以下のコードでは、IpAssignmentSTAICDHCP、またはNONEのいずれかのEnumです。 linkPropertiesは、オブジェクトストアのIPアドレス、ゲートウェイ、DNSなどです。

linkAddressはIPアドレスとprefixLengthとしてのネットマスク(ネットマスクのビット1の数)です。

mRoutesは、ゲートウェイを示すことができるArrayListRouteInfoです。

mDnsesは、DNSのArrayListInetAddressです。

まず、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が非表示になっているため、オブジェクトは反射から取得できます。

次のメソッドは、SSID WifiConfigurationで宣言されたIPアドレス設定を設定できます。

    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を設定および更新できます。

    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 3.xデバイスでAndroid 4.x. In。Android 3.x、ゲートウェイはmGatewayslinkPropertiesに格納されます。mGatewaysArraylist型のInetAddressです。したがって、 、以下は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:メソッドsetIpAddresssetGatewaysetDNSInetAddressタイプとして入力する必要があります。

59
Yeung

@ロビン

Android M 6.0.1。

// apply the configuration change boolean result = wm.updateNetwork(wifiConf) != -1; //apply the setting if(result) result = wm.saveConfiguration(); //Save it if(result) wm.reassociate(); // reconnect with the new static IPを置き換えました

次の

int netId = manager.updateNetwork(wifiConf);
boolean result =  netId!= -1; //apply the setting
if(result){
    boolean isDisconnected =  manager.disconnect();
    boolean configSaved = manager.saveConfiguration(); //Save it
    boolean isEnabled = manager.enableNetwork(wifiConf.networkId, true);
    // reconnect with the new static IP
    boolean isReconnected = manager.reconnect();                        
}
3
Som

Android 5.0+ WIPソリューション。何らかの理由でまだ動作しません。コメントを歓迎します。

void changeWifiConfiguration(boolean dhcp, String ip, int prefix, String dns1, String gateway) {
    WifiManager wm = (WifiManager) getSystemService(Context.WIFI_SERVICE);
    if(!wm.isWifiEnabled()) {
        // wifi is disabled
        return;
    }
    // get the current wifi configuration
    WifiConfiguration wifiConf = null;
    WifiInfo connectionInfo = wm.getConnectionInfo();
    List<WifiConfiguration> configuredNetworks = wm.getConfiguredNetworks();   
    if(configuredNetworks != null) {
        for (WifiConfiguration conf : configuredNetworks){
            if (conf.networkId == connectionInfo.getNetworkId()){
                wifiConf = conf;
                break;              
            }
        }
    }
    if(wifiConf == null) {
        // wifi is not connected
        return;
    }
    try {
        Class<?> ipAssignment = wifiConf.getClass().getMethod("getIpAssignment").invoke(wifiConf).getClass();
        Object staticConf = wifiConf.getClass().getMethod("getStaticIpConfiguration").invoke(wifiConf);
        if(dhcp) {
            wifiConf.getClass().getMethod("setIpAssignment", ipAssignment).invoke(wifiConf, Enum.valueOf((Class<Enum>) ipAssignment, "DHCP"));
            if(staticConf != null) {
                staticConf.getClass().getMethod("clear").invoke(staticConf);
            }
        } else {
            wifiConf.getClass().getMethod("setIpAssignment", ipAssignment).invoke(wifiConf, Enum.valueOf((Class<Enum>) ipAssignment, "STATIC"));
            if(staticConf == null) {
                Class<?> staticConfigClass = Class.forName("Android.net.StaticIpConfiguration");
                staticConf = staticConfigClass.newInstance();
            }
            // STATIC IP AND MASK PREFIX
            Constructor<?> laConstructor = LinkAddress.class.getConstructor(InetAddress.class, int.class);
            LinkAddress linkAddress = (LinkAddress) laConstructor.newInstance(
                    InetAddress.getByName(ip), 
                    prefix);
            staticConf.getClass().getField("ipAddress").set(staticConf, linkAddress);
            // GATEWAY
            staticConf.getClass().getField("gateway").set(staticConf, InetAddress.getByName(gateway));
            // DNS
            List<InetAddress> dnsServers = (List<InetAddress>) staticConf.getClass().getField("dnsServers").get(staticConf);
            dnsServers.clear();
            dnsServers.add(InetAddress.getByName(dns1)); 
            dnsServers.add(InetAddress.getByName("8.8.8.8")); // Google DNS as DNS2 for safety
            // apply the new static configuration
            wifiConf.getClass().getMethod("setStaticIpConfiguration", staticConf.getClass()).invoke(wifiConf, staticConf);
        }
        // apply the configuration change
        boolean result = wm.updateNetwork(wifiConf) != -1; //apply the setting
        if(result) result = wm.saveConfiguration(); //Save it
        if(result) wm.reassociate(); // reconnect with the new static IP
    } catch(Exception e) {
        e.printStackTrace();
    }
}
2
Robin Gawenda

Android 5.1.0

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



@TargetApi(Build.VERSION_CODES.Lollipop)
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

WifiConfigurationのkotlin拡張として、Android 5+

fun WifiConfiguration.setHttpProxyCompat(proxyInfo: ProxyInfo) {
    if (Build.VERSION.SDK_INT >= 26) {
        httpProxy = proxyInfo
        Timber.i("Setting proxy using 26+ method")
    } else {
        val proxySettings = Class.forName("Android.net.IpConfiguration\$ProxySettings")
        val valueOf = proxySettings.getMethod("valueOf", String::class.Java)
        val static = valueOf.invoke(proxySettings, "STATIC")

        val setProxy = this::class.Java.getDeclaredMethod("setProxy", proxySettings, ProxyInfo::class.Java)
        setProxy.isAccessible = true

        setProxy.invoke(this, static, proxyInfo)
        Timber.i("Setting proxy using reflection")
    }
}
0
crgarridos

@Yeung、みんな

私の知る限り、AndroidはSSIDに接続した直後にdhclientを起動します。

したがって、提案されたコードは、AndroidがすでにIPアドレスを取得した(dhcp成功)後に静的構成を適用しますか?

これは、パイでの私の実験で起こっていることです。 WifiManager.NETWORK_STATE_CHANGED_ACTIONをリッスンして、静的構成を適用しようとしました

intentFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
...........
...........
if ( action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION) )
{
    NetworkInfo info = intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO);
    if (info.isConnectedOrConnecting())
    {
        //apply static IP to current wifi connnections as per above code
    }
}
0
sam

Android 5.x 6.xで5.xのソリューションを使用しようとすると、アプリケーションはこれを行うことを拒否されます。これを行うには、おそらくデバイスをルート化し、アプリケーションをデバイス所有者にする必要があります。

問題を掘り下げたところ、アプリケーションがデバイス所有者に設定されている場合、Andrdoi 5.xで動作していたコードが動作する可能性があることがわかりました。

これがどのように行われるかの良い例は、ここにある例を使用することです:

https://github.com/googlesamples/Android-DeviceOwner/

Adbシェルを使用してコマンドを実行します:

dpm set-device-owner com.example.Android.deviceowner/.DeviceOwnerReceiver

アプリケーションデバイスの所有者になり、静的IPを設定できます。

0
Knubo