在Android 6.x(棉花糖)中编程设置静态IP和网关

16

请问有没有人能告诉我如何在Android 6中以编程方式设置静态IP和网关?

我在这里这里阅读过相关信息。

Settings.System已经不再适用,Google表示WIFI_STATIC_IP在API级别17中已被弃用,请使用WifiManager。不幸的是,我无法在WifiManagerWifiConfiguration类中找到任何有关此内容的信息。


那么,这与 https://dev59.com/mGkv5IYBdhLWcg3w40wY 有何不同? - Fabio
@Fabio,除非您设置设备所有者,否则所提到的示例中的建议将无法生效。 - Knubo
3个回答

18

由于没有官方API,我必须通过修改以下 代码片段此答案 的示例来想出解决方案。这个解决方案适用于从棒棒糖(Lollipop)版本开始的设备。

 @SuppressWarnings("unchecked")
 public 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});

        int netId = manager.updateNetwork(config);
        boolean result = netId != -1;
        if (result) {
            boolean isDisconnected = manager.disconnect();
            boolean configSaved = manager.saveConfiguration();
            boolean isEnabled = manager.enableNetwork(config.networkId, true);
            boolean isReconnected = manager.reconnect();
        }
    }

辅助函数,

    public static WifiConfiguration getCurrentWiFiConfiguration(Context context) {
            WifiConfiguration wifiConf = null;
            ConnectivityManager connManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
            NetworkInfo networkInfo = connManager.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
            if (networkInfo.isConnected()) {
                final WifiManager wifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
                final WifiInfo connectionInfo = wifiManager.getConnectionInfo();
                if (connectionInfo != null && !TextUtils.isEmpty(connectionInfo.getSSID())) {
                    List<WifiConfiguration> configuredNetworks = wifiManager.getConfiguredNetworks();
                    if (configuredNetworks != null) {
                        for (WifiConfiguration conf : configuredNetworks) {
                            if (conf.networkId == connectionInfo.getNetworkId()) {
                                wifiConf = conf;
                                break;
                            }
                        }
                    }
                }
            }
            return wifiConf;
        }

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

为了使用它,
WifiManager wifiManager = (WifiManager) getApplicationContext().getSystemService(Context.WIFI_SERVICE);
WifiConfiguration wifiConf = WifiHelper.getCurrentWiFiConfiguration(getApplicationContext());

        try {
            setStaticIpConfiguration(wifiManager, wifiConf,
                    InetAddress.getByName("192.168.0.100"),
                    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();
        }

最后,您需要在清单文件中添加这些权限。

  <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
  <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
  <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
  <uses-permission android:name="android.permission.WRITE_SETTINGS" />

由于我没有使用Android API,有人可以检查一下并告诉我打勾吗? - mohsen_og
@Mogi 这是什么意思?你不是在使用 API 吗?你在做什么?只需将此代码添加到您的应用程序中,然后尝试使用该应用程序。您就会知道它是否有效! - Yazan
1
@Yazan,你误解了 :) 我不再从事Android工作,而且这个问题是在2016年10月提出的!与此同时,我已经换了工作。哈哈 - mohsen_og
@Mogi 哦我的天啊,我没注意到,对不起哈哈哈哈,我一直在想这个 OP 怎么了。 - Yazan
它可以使用WiFi,你能帮忙让它使用以太网吗?当然是在5.1版本下。 - djdance
1
netId在Android 8+中始终返回-1。需要其他Proxysettings来解决这个问题。 - dev

2

我已经深入研究了这个问题,我的发现是,在设备所有者的情况下,曾经适用于安卓5.x的代码可能有效。

解决方案:

解决方案是将设备添加为设备所有者。这将允许使用Mogi提到的5.x黑客方法设置静态IP。如何实现请参考以下示例:

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

使用adb shell并运行以下命令:

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

会使它准备好可以执行其工作。


0

我已经成功地在我的应用程序中以编程方式添加并连接到开放和PSK网络(在运行5.1和6.0的设备上尝试过)。但是,当我尝试使用企业网络时,它不起作用。我看到addNetwork()成功了(返回正面的网络ID),但是当我在设置-> Wi-Fi下查看时,我没有像我添加的其他SSID那样看到SSID。有人知道为什么会这样吗?如果我以编程方式搜索WiFiConfiguration列表,它确实可以找到SSID。这是我使用的代码:

wifiConf = new WifiConfiguration();
wifiConf.SSID = "\"dot1x-test\"";
wifiConf.BSSID = "c4:e9:84:43:48:e8";
if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
    wifiConf.enterpriseConfig.setIdentity("name");
    wifiConf.enterpriseConfig.setPassword("testpassword");
    wifiConf.enterpriseConfig.setEapMethod(WifiEnterpriseConfig.Eap.PEAP);
    wifiConf.enterpriseConfig.setPhase2Method(WifiEnterpriseConfig.Phase2.MSCHAPV2);
}

netId = wifiMgr.addNetwork(wifiConf);
wifiMgr.disconnect();
wifiMgr.enableNetwork(netId, true);
wifiMgr.saveConfiguration();
wifiMgr.reconnect();

1
这不是StackOverflow的工作方式。如果您有自己的问题,请创建一个新的问题,而不是将其作为另一个问题的答案。 - rminaj

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