在 Android 6.x (Marshmallow) 中以编程方式设置静态 IP 和网关
Set static IP and gateway programmatically in Android 6.x (Marshmallow)
谁能告诉我如何在 Android 6 中以编程方式设置静态 IP 和网关?
我已阅读here and here。
Settings.System
不再工作,goolgle 说 WIFI_STATIC_IP
在 API 级别 17 中被弃用,改为使用 WifiManger
。不幸的是,我在 WifiManger
和 WifiConfiguration
类.
中找不到任何相关信息
我对这个问题进行了深入研究,我的发现是如果应用程序设置为设备所有者,用于 Andrdoi 5.x 的代码可能会起作用。
解决方案:
解决方法是将设备添加为 deviceOwner。这将允许使用 Mogi 引用的 5.x hack 设置静态 IP。使用此处找到的示例是如何完成此操作的一个很好的示例:
https://github.com/googlesamples/android-DeviceOwner/
使用 adb shell 和 运行 命令:
dpm set-device-owner com.example.android.deviceowner/.DeviceOwnerReceiver
将准备好执行其工作。
由于没有正式的API,我不得不通过修改以下code snipet and this answer中的示例来想出一个解决方案。该解决方案适用于 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" />
我已在我的应用程序中以编程方式成功添加并连接到开放和 PSK 网络(在设备 运行 5.1 和 6.0 上试过)。但是,当我为企业网络尝试此操作时,它不起作用。我看到 addNetwork() 成功(returns 正网络 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();
谁能告诉我如何在 Android 6 中以编程方式设置静态 IP 和网关?
我已阅读here and here。
Settings.System
不再工作,goolgle 说 WIFI_STATIC_IP
在 API 级别 17 中被弃用,改为使用 WifiManger
。不幸的是,我在 WifiManger
和 WifiConfiguration
类.
我对这个问题进行了深入研究,我的发现是如果应用程序设置为设备所有者,用于 Andrdoi 5.x 的代码可能会起作用。
解决方案:
解决方法是将设备添加为 deviceOwner。这将允许使用 Mogi 引用的 5.x hack 设置静态 IP。使用此处找到的示例是如何完成此操作的一个很好的示例:
https://github.com/googlesamples/android-DeviceOwner/
使用 adb shell 和 运行 命令:
dpm set-device-owner com.example.android.deviceowner/.DeviceOwnerReceiver
将准备好执行其工作。
由于没有正式的API,我不得不通过修改以下code snipet and this answer中的示例来想出一个解决方案。该解决方案适用于 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" />
我已在我的应用程序中以编程方式成功添加并连接到开放和 PSK 网络(在设备 运行 5.1 和 6.0 上试过)。但是,当我为企业网络尝试此操作时,它不起作用。我看到 addNetwork() 成功(returns 正网络 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();