Android端末でWi-Fi接続を行う際、アプリケーション上で静的IPに変更できるようにする実装方法を試してみましたので、参考にしていただければ幸いです。
by wazalabo-editor 2014/08/04
Android のスマートフォン/タブレットを、外出先でWi-Fiスポットに接続する際は、DHCPによって自動的にIPアドレスが割り当てられるようになっています
一方、社内の無線LANなど、セキュリティを重視したネットワークでは、端末のIPアドレスを静的に設定するよう求められる場合もあります。この場合、アンドロイド標準のWi-Fi設定機能の画面で設定すればよいのですが、これをアプリケーション上で行いたい場合には、どのような実装になるのでしょうか? Android 2.xと4.xで、設定を行ってみました。
Android 2.xの場合
筆者は以前、「特定のアクセスポイントに、静的IPアドレスで、自動的に帰属する」Androidアプリを作成した経験があります。この時のWi-Fiの設定は、以下のようなコードで行っていました。
▼ソースコード 1
// 静的IPを有効にする Settings.System.putString(getContentResolver(), android.provider.Settings.System.WIFI_USE_STATIC_IP, "1"); // IP Address設定 Settings.System.putString(getContentResolver(), android.provider.Settings.System.WIFI_STATIC_IP, "<IP Address>"); // Gateway設定 Settings.System.putString(getContentResolver(), android.provider.Settings.System.WIFI_STATIC_GATEWAY, "<Gateway>"); // Netmask設定 Settings.System.putString(getContentResolver(), android.provider.Settings.System.WIFI_STATIC_NETMASK, "<Netmask>"); // DNS1設定 Settings.System.putString(getContentResolver(), android.provider.Settings.System.WIFI_STATIC_DNS1, "<DNS1>"); // DNS2設定 Settings.System.putString(getContentResolver(), android.provider.Settings.System.WIFI_STATIC_DNS2, "<DNS2>");
▼ソースコード 2
// 静的IPを有効/無効を調べる int nEnabled = Settings.System.getInt(getContentResolver(), Settings.System.WIFI_USE_STATIC_IP, 0); // IP Address取得 String strStaticIP = Settings.System.getString(getContentResolver(), Settings.System.WIFI_STATIC_IP); // Gateway取得 String strGateway = Settings.System.getString(getContentResolver(), Settings.System.WIFI_STATIC_GATEWAY); // Netmask取得 String strNetmask = Settings.System.getString(getContentResolver(), Settings.System.WIFI_STATIC_NETMASK); // DNS1取得 String strDns1 = Settings.System.getString(getContentResolver(), Settings.System.WIFI_STATIC_DNS1); // DNS2取得 String strDns2 = Settings.System.getString(getContentResolver(), Settings.System.WIFI_STATIC_DNS2);
2.x と4.xでは、Wi-Fi接続設定が異なることがわかりました
最近になって、このアプリをAndroid 4.x の端末で動かそうとしたところ、どういうわけか静的IPへの変更ができませんでした。ビルドの実行もできますが、筆者が試したところ、実際にはプログラムによる設定の通りには動作していないことが確認できました。
さらにリサーチを進めたところ、Android 2.xと4.xでは、Wi-Fiの設定方法が異なることがわかりました。Android 2.xでは、システム全体でひとつの設定しか保持していないようなのですが、4.xではSSIDごとに設定を保持しており、その設定に従って帰属します。
Android 4.xの場合
以下がAndroid 4.xにおけるWi-Fi設定のソースコードになります。例外処理は省略しています。
▼ソースコード 3
// DHCP / STATIC / NONE 設定 private void setIpAssignment (String strIpAssign, WifiConfiguration wifiConf) { setEnumField(wifiConf, strIpAssign, "ipAssignment"); } // IP Address設定 private void setIpAddress (InetAddress inetAddr, int nPrefixLength, WifiConfiguration wifiConf) { Object objLinkProperties = getField(wifiConf, "linkProperties"); if (objLinkProperties == null) return; Class clsLinkAddress = Class.forName("android.net.LinkAddress"); Constructor cnstLinkAddress = clsLinkAddress.getConstructor(new Class[]{InetAddress.class, int.class}); Object objLinkAddress = cnstLinkAddress.newInstance(inetAddr, nPrefixLength); ArrayList artkstLinkAddresses = (ArrayList)getDeclaredField(objLinkProperties, "mLinkAddresses"); artkstLinkAddresses.clear(); artkstLinkAddresses.add(objLinkAddress); } // Gateway設定 private void setGateway (InetAddress inetAddr, WifiConfiguration wifiConf) { Object objLinkProperties = getField(wifiConf, "linkProperties"); if (objLinkProperties == null) return; Class clsRouteInfo = Class.forName("android.net.RouteInfo"); Constructor cnstRouteInfo = clsRouteInfo.getConstructor(new Class[]{InetAddress.class}); Object objRouteInfo = cnstRouteInfo.newInstance(inetAddr); ArrayList arylstRoutes = (ArrayList)getDeclaredField(objLinkProperties, "mRoutes"); arylstRoutes.clear(); arylstRoutes.add(objRouteInfo); } private void setDNS (InetAddress inetAddr, WifiConfiguration wifiConf) { Object objLinkProperties = getField(wifiConf, "linkProperties"); if(objLinkProperties == null)return; ArrayList<InetAddress> arylstDnses = (ArrayList<InetAddress>)getDeclaredField(objLinkProperties, "mDnses"); arylstDnses.clear(); arylstDnses.add(inetAddr); } private Object getField (Object object, String strName) { Field field = object.getClass().getField(strName); Object objField = field.get(object); return objField; } private Object getDeclaredField (Object object, String strName) { Field field = object.getClass().getDeclaredField(strName); field.setAccessible(true); Object objField = field.get(object); return objField; } private void setEnumField (Object object, String strValue, String strName) { Field field = object.getClass().getField(strName); field.set(object, Enum.valueOf((Class<Enum>) field.getType(), strValue)); } // Wi-Fi設定 private void setWifiConfig (WifiConfiguration wifiConf) { // IP Assignment設定 setIpAssignment (“<DHCP / STATIC / NONE>”, wifiConf); // IP Address設定 setIpAddress (InetAddress.getByName(“<IP Address>”), 24, wifiConf); // Gateway設定 setGateway (InetAddress.getByName(“<Gateway>”), wifiConf); // DNS設定 setDNS (InetAddress.getByName(“<DNS>”), wifiConf); }
▼ソースコード 4
// IP Assignment設定取得 private String getIpAssignment (WifiConfiguration wifiConf) { return getEnumField(wifiConf, "ipAssignment"); } // IP Address取得 private String getIpAddress (WifiManager wifiMng) { int nIPAddress = wifiMng.getConnectionInfo().getIpAddress(); return ((nIPAddress >> 0) & 0xFF) + "." + ((nIPAddress >> 8) & 0xFF) + "." + ((nIPAddress >> 16) & 0xFF) + "." + ((nIPAddress >> 24) & 0xFF); } // Gateway取得 private String getGateway (WifiConfiguration wifiConf) { Object objLinkProperties = getField(wifiConf, "linkProperties"); if (objLinkProperties == null) return ""; ArrayList arylstRoutes = (ArrayList)getDeclaredField(objLinkProperties, "mRoutes"); Object objRouteInfo = arylstRoutes.get(0); InetAddress inetAddressGateway = (InetAddress)getDeclaredField(objRouteInfo, "mGateway"); if (inetAddressGateway == null) return ""; byte aryGateway[] = inetAddressGateway.getAddress(); String strGateway = ""; for (int i = 0; i < 4; i++) { if (!strGateway.isEmpty()) strGateway += "."; if (aryGateway[i] >= 0) { strGateway += aryGateway[i]; } else { strGateway += aryGateway[i] + 256; } } return strGateway; } // DNS取得 private String getDNS (WifiConfiguration wifiConf) { Object objLinkProperties = getField(wifiConf, "linkProperties"); if (objLinkProperties == null) return ""; ArrayList<InetAddress> arylstDnses = (ArrayList<InetAddress>)getDeclaredField(objLinkProperties, "mDnses"); byte aryDNS [] = arylstDnses.get(0).getAddress(); String strDNS = ""; for (int i = 0; i < 4; i++) { if (!strDNS.isEmpty()) strDNS += "."; if (aryDNS[i] >= 0) { strDNS += aryDNS[i]; } else { strDNS += aryDNS[i] + 256; } } return strDNS; } private String getEnumField (Object object, String strName) { Field field = object.getClass().getField(strName); return field.get(object).toString(); } // Wi-Fi設定取得 private void getWifiConfig (WifiConfiguration wifiConf) { // IP Assignment設定取得 String strIpAssignment = getIpAssignment(wifiConfiguration); // IP Address取得 String strIpAddress = getIpAddress(); // Gateway取得 String strGateway = getGateway(wifiConfiguration); // DNS取得 String strDNS = getDNS(wifiConfiguration); }
もっと良い方法がある可能性もありますので、引き続き調査と検証を進め、わかったことをこのコーナーで公開していきます。