ãã€ãŠãç§èªèº«ã®äŸ¿å®ã®ããã«ãAndroidã®Wifiãããã¯ãŒã¯ã®æ§æã§ãããã·èšå®ã倿Žããã¢ããªã±ãŒã·ã§ã³ãäœæãããã£ãã®ã§ãã ãã®ãšãç§ã«æããããã«ãã¿ã¹ã¯ã¯æã
åãåºãããšã§ããããå®éã«ã¯ããã€ãã®ããã«ãäºæããªãå°é£ãçããŸããã

å°æ¥çã«è§£æ±ºçãç¥ãããšãæçšã§ãããšæãå Žåãèªåã®ããã«äœããåŠã³ããå ŽåããŸãã¯å¥œå¥å¿ãç®èŠããã°ããã®å Žå-ç«ãžããããã ããã«ã¯ãAndroidã®ããŸããŸãªããŒãžã§ã³ã§ã®Wifiæ§æãæ
åœããã¯ã©ã¹ã®å
éšæ§é ãJavaã³ãŒãã®å°ããªã«ãããReflectionã®ãã³ãããããŸãã
ãã¡ããããããã°ã©ã ã§ã¢ã³ããã€ãã®Wi-Fiãããã·èšå®ã倿Žããããšãããããã¯ã«é¢ããGoogleãšã®ã¡ãã£ãšããããåããStackOverflowã«ããããããããã§ã¯Reflectionãä»ãããœãªã¥ãŒã·ã§ã³ãååšããŸããã èãçŽãããšãªããã³ãŒããã³ããŒããŠããã€ã¹ã§èµ·åããŸããã
倱æã¯ããã«èå³ãšè奮ã«å€ããããã®æç¹ã§èè
ã¯ãã§ã«äžèšã®è³ªåã«æ¡ç¹ããã®ã«æéãããããããŠãããšå€æãããã®ã¿ã¹ã¯ã«ã¯ããã°ããŒãã«ãªã¢ãããŒããå¿
èŠã§ããããšã«æ°ä»ããŸããã è¡ããŸãããã
ã¹ããã1. android.netã©ã€ãã©ãªã®å
éšæ§é ãšJelly Beanã®éãã調æ»ããŸã-KitkatãšLollipop
以äžã§äœãèµ·ãã£ãŠããããããè¯ãçè§£ããããã«ç¥ãããããšã®ãªã¹ãã- ããªãã®è±èªã¬ãã«ã¯ãå°ãªããšãäžçŽä»¥äžã§ãªããã°ãªããŸããã
- ã ã³ã³ããã¹ããšã¯äœã§ããïŒããšãã質åã¯é¿ããŠãã ããããŸãããã®æç¹ã§è€éãã䌌ãŠããå Žåã¯ã developer.android.comãŸãã¯Alexander Klimovãèªãããšãã§ããŸãã
- ãŸããã¢ãããŒã·ã§ã³@Before ã @Test ã @Afterãªã©ããã¹ãã«é¢é£ãããã®ã¯æ¥ãã¹ãã§ã¯ãããŸããã ç¹°ãè¿ããŸããããªã³ã¯ïŒ developer.android.com
ç§ã¯ããããã¹ãŠç¢ºèªããããšæããŸãããããªãã¯çè§£ããŠããŸã-ããããç§ã®èšäºã¯æ¬ã«æé·ããŸãã
ãŸããããã€ãã®ããäžè¬çãªèª¬æãããããšæããŸãã
- ç§ã®ã³ãŒãã«ã¯ã³ã¡ã³ããã»ãšãã©ãããŸããã ç§ã¯ãã®åé¡ãé·ãéèããéåžžã«é·ãéçã£ãŠããŸããããæçµçã«ã¯javaããŸã£ããç¥ããªã女ã®åã«ãããäžããããšã«ããŸãããç§ã¯åœŒããã»ãšãã©æŸæ£ããã®ã§ã圌ããšåœŒãã®æ¹æ³ã§äœãèµ·ããããèšãããšã¯éåžžã«æ£ç¢ºã§ãã
- ã³ã¡ã³ãã远å ã質åãã³ã¡ã³ãïŒããšãã°ãåã®æ®µèœïŒãããå Žå-äœæè
ã¯ããããåŸ
ã£ãŠããŸãã
- èšäºã¯çŸåšéåžžã«äžè¬åãããŠããŸããäœæ¥éã«å¿ããŠããã€ãã®ãã€ã³ãããã詳现ã«è¡šç€ºãããå Žåã¯ãã³ã¡ã³ããæžãããèå³ã®ãããããã¯ã«é¢ããå¥ã®èšäºãæžããŸãã
- ããã±ãŒãžã®ååã«ã¯è¬èãªäœ¿çšäººã®ããã¯ããŒã ãå«ãŸããŠãããããã³ãŒãã«ã¯ã€ã³ããŒãããããŸãããã«ãŒã«ãã倿ãããšããµã³ãããã¯ã¹ã®èšäºã§ã¯ããããç
§ããããšã¯ã§ããŸããã
Googleã§ããã«è³ªåããããšã
android.googlesourceã«ç§»åããŸãããããã·èšå®ïŒããã³ä»ã®ããã€ãïŒã¯ããã®ãããã¯ãŒã¯ã®
WifiConfigurationã€ã³ã¹ã¿ã³ã¹ïŒ
Kitkat mr2.2ã®
ã¯ã©ã¹ãžã®ãªã³ã¯ïŒã«å«ãŸããŠããŸãã ãã®ã¯ã©ã¹ãå匷ãããšããStackOverflowã䜿çšãããœãªã¥ãŒã·ã§ã³ãããã€ã¹äžã§æ©èœããªãã£ãçç±ã«ã€ããŠã®åçãåŸãŸããã Androidã®5çªç®ã®ããŒãžã§ã³ã§ãã
WifiConfigurationã¯ã©ã¹ã®ããã€ã¹ãš
android.netããã±ãŒãžã«ã¯å€§ããªå€æŽãå ããããäžèšã®ã³ãŒããæ©èœãã
LinkPropetiesãªããžã§ã¯ãã¯ãã®ã¯ã©ã¹ã«ã¯ååšããªãããšã倿ããŸããã ãã ãã
ProxyInfoãªããžã§ã¯ããæã€
IpConfiguraionãªããžã§ã¯ãããããŸãã
Androidã®ãããã®ããŒãžã§ã³ãããŸããŸãªããã€ã¹ã®80ïŒ
ãã«ããŒããŠããããšãèãããšãã¿ã¹ã¯ã¯æ¬¡ã®ããã«åçŽã«èšè¿°ããããšã§ããã
public void changeProxySettings(String host, int port){ if(Build.VERSION.SDK_INT > 14 && Build.VERSION.SDK_INT < 20){ changeProxyWithLikProperties(String host, int port); }else if(Build.VERSION.SDK_INT > 20 && Build.VERSION.SDK_INT < 23){ changeProxyWithProxyInfo(String host, int port); }else{ throw new Exception("Sorry, android version not supported") } }
where
changeProxyXXX-巚倧ãªã¡ãœãããæ°ããŒãžã æããšã¬ã¬ã³ããªãœãªã¥ãŒã·ã§ã³ã§ã¯ãããŸããã
ã¹ããã2. Androidã§Wifiãããã·ãèšå®ããããã®ã©ã€ãã©ãªãéçºããŸã
ãã®ãããèè
ã¯ã倿°ã®ã¡ãœãããæã€ããã°ãã¯ã©ã¹ã«ãã ãããªãããšã«ããŸããã èªç±ãªæéãããã®ã§ïŒç§ãåå ãããããžã§ã¯ãã®è³éãåæžããããã«æ©æ¥ã«äŒæãåãïŒããªãã°ããŒãã«ã«ã¿ã¹ã¯ã«åãçµãã§ã¿ãŸãããã
ã¢ãžã¥ãŒã«ã®ã¢ãŒããã¯ãã£
Androidã®ããŒãžã§ã³ããšã«ããŸããŸãªå®è£
ãããããããã·èšå®ã倿Žãã
WifiConfigurationãªããžã§ã¯ããæäœããããã®åäžã®ã€ã³ã¿ãŒãã§ã€ã¹ãå¿
èŠã§ãã ãããã®èŠä»¶ãå¯èœãªéãæºããããšãããšãæåã®æ®µéã§ççãèµ·ãããæèãæ¬¡ã®ããã«ãªããŸããã

äžã®åçã«é¢ãã説æç解説- BaseWifiConfigurationã¯ã©ã¹ã¯ãå®éã«ã¯WifiConfigurationãªããžã§ã¯ããæ ŒçŽãã Contextãä»ããŠäœæããããšãã«ææ°ã®ãããã¯ãŒã¯æ§æãååŸããå®è£
ãå«ãã§ããŸãã
- ProxyChangerã€ã³ã¿ãŒãã§ã€ã¹ã¯ãããããããããã·ãããã¯ãŒã¯æ§æãæäœããã¡ãœããã®å¯çšæ§ãä¿èšŒããŸãã
- Reflectionã䜿çšããå¿
èŠããããŸãããã®ããã®ã¡ã€ã³ã¡ãœããã¯ãé »ç¹ã«äœ¿çšããããããå¥ã®ã¯ã©ã¹ã«é
眮ããããšãæãŸããã§ãã ãããã£ãŠã ReflectionHelperã¯ã©ã¹ãäœæããŸãã
Androidã®ããŸããŸãªããŒãžã§ã³ã®ã¯ã©ã¹ã¯ãé¢å¿ã®ãããããã¯ãŒã¯ã®
WifiConfigurationã€ã³ã¹ã¿ã³ã¹ã«ç°¡åã«ã¢ã¯ã»ã¹ãã
äœæ¥ã容æ
ã«ããããã«
BaseWifiConfigurationããç¶æ¿ããã
ProxyChangerã§å®£èšãããã¡ãœããã®å®è£
ãå¿
èŠ
ã§ã ã
PSãããæè¯ã®ã¢ãŒããã¯ãã£ãœãªã¥ãŒã·ã§ã³ã§ã¯ãªããããããªããšã¯èšããŸãããæ¹åã®ææ¡ãã³ã¡ã³ããããã°ãã³ã¡ã³ãã§ãåŸ
ã¡ãã ããã
ããšãã°ãReflectionHelperã«éåžžã«èå³ããããŸããã芧ã®ãšãããabstractãšå®£èšãããŠããŸããããã¯ãç¹å®ã®å®è£
ãå¿
èŠãªããšããçç±ã§è¡ãããç®çã®ã¡ãœãããžã®æ§é åãšç°¡åãªã¢ã¯ã»ã¹ã«ã®ã¿äœ¿çšãããŸãã ãã®ã¢ãããŒããã©ãã»ã©æ£ãããã¯ããããŸããããããã£ãŠããã®åé¡ïŒãŸãã¯ä»ã®åé¡ïŒã«ã€ããŠã³ã¡ã³ããããã°ããããèããŠéåžžã«æè¬ããŸãã
ãã¡ãããããã¯äžè¬çãªãã¬ãŒã ã¯ãŒã¯ã«ãããããªãã¡ã¯ã¿ãªã³ã°ãæ°åç¹°ãè¿ããåŸãæ°ãã詳现ãåŸãããŸãã
ãã¹ã
ããã§ãã¢ãŒããã¯ãã£ã«ã€ããŠèããŸãããä»åºŠã¯æ°è¡ã®ã³ãŒããæžããŸãã ãã¡ãããåŽåè
ã§ã¯ãªãããããžã§ã¯ãããã¹ãããŠããŸãã
ç¹å®ã®apiã®ProxyChangerãéžæããå°ããªã¯ã©ã¹ãäœæããŸãããããã·èšå®ã®å€æŽã«é¢ããŠäžèšã®ãªããžã§ã¯ããæäœããã¯ã©ã¹ãšãçŸåšã®ãããã¯ãŒã¯ã®èšå®ã«é¢ããæ
å ±ãååŸããå¥ã®ã¯ã©ã¹ãäœæããŸãã
WifiProxyChangerTest.java @RunWith(AndroidJUnit4.class) public class WifiProxyChangerTest { @Rule public ExpectedException expectedException = ExpectedException.none(); @Rule public ActivityTestRule mActivityRule = new ActivityTestRule<>( MainActivity.class); Context context; @Before public void prepare() throws Exception { context = mActivityRule.getActivity(); ExceptionsPreparer.prepareExceptions(expectedException, context); } @Test public void testChangeWifiStaticProxySettings() throws Exception { String testIp = RandomValuesGenerator.randomIp(); int testPort = RandomValuesGenerator.randomPort(); WifiProxyChanger.changeWifiStaticProxySettings(testIp, testPort, context); assertEquals(testIp, WifiProxyInfo.getHost(context)); assertEquals(testPort, WifiProxyInfo.getPort(context)); } @Test public void testProxySettingsClear() throws Exception { String testIp = RandomValuesGenerator.randomIp(); int testPort = RandomValuesGenerator.randomPort(); WifiProxyChanger.changeWifiStaticProxySettings(testIp, testPort, context); WifiProxyChanger.clearProxySettings(context); assertEquals(ProxySettings.NONE, CurrentProxyChangerGetter .chooseProxyChangerForCurrentApi(context) .getProxySettings()); } @After public void learSettings() throws Exception { if (NetworkHelper.isWifiConnected(context) && ApiChecker.isSupportedApi()) WifiProxyChanger.clearProxySettings(context); } }
WifiProxyInfoTest.java @RunWith(AndroidJUnit4.class) public class WifiProxyInfoTest { @Rule public ExpectedException expectedException = ExpectedException.none(); @Rule public ActivityTestRule mActivityRule = new ActivityTestRule<>( MainActivity.class); Context context; @Before public void prepareAndPresetProxy() throws Exception { context = mActivityRule.getActivity(); ExceptionsPreparer.prepareExceptions(expectedException, context); if (ApiChecker.isSupportedApi()) { WifiProxyChanger.clearProxySettings(context); WifiProxyChanger.changeWifiStaticProxySettings("localhost", 3030, context); } } @Test public void testGetHost() throws Exception { assertEquals("localhost", WifiProxyInfo.getHost(context)); } @Test public void testGetPort() throws Exception { assertEquals(3030, WifiProxyInfo.getPort(context)); } @Test public void testGetProxySettings() throws Exception { assertEquals(ProxySettings.STATIC, WifiProxyInfo.getProxySettings(context)); } @After public void learSettings() throws Exception { if (NetworkHelper.isWifiConnected(context) && ApiChecker.isSupportedApi()) WifiProxyChanger.clearProxySettings(context); } }
CurrentProxyChangerGetterTest .java @RunWith(AndroidJUnit4.class) public class CurrentProxyChangerGetterTest { @Rule public ExpectedException expectedException = ExpectedException.none(); @Rule public ActivityTestRule mActivityRule = new ActivityTestRule<>( MainActivity.class); Context context; @Before public void prepare() throws Exception { context = mActivityRule.getActivity(); ExceptionsPreparer.prepareExceptions(expectedException, context); } @Test public void testChooseProxyChangerForCurrentApi() throws Exception { ProxyChanger proxyChanger = CurrentProxyChangerGetter.chooseProxyChangerForCurrentApi(context); WifiManager manager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE); assertEquals(manager.getConnectionInfo().getNetworkId(), proxyChanger.getWifiConfiguration().networkId); if (ApiChecker.isJellyBeanOrKitkat()) { assertTrue(proxyChanger instanceof WifiConfigurationForApiFrom15To19); } else if (ApiChecker.isLolipop()) { assertTrue(proxyChanger instanceof WifiConfigurationForApiFrom21To22); } } }
ExceptionsPreparer.java public abstract class ExceptionsPreparer { public static void prepareExceptions(ExpectedException expectedException, Context context) throws Exception { if (!ApiChecker.isSupportedApi()) { expectedException.expect(ApiNotSupportedException.class); } else if (!NetworkHelper.isWifiConnected(context)) { expectedException.expect(NullWifiConfigurationException.class); } else if (!CurrentProxyChangerGetter.chooseProxyChangerForCurrentApi(context).isProxySetted()) { expectedException.expect(WifiProxyNotSettedException.class); } } }
ç§ãèšåããªãã£ãå¥åŠãªããšãããããããå Žæã説æããã³ãŒãã«ã³ã¡ã³ãããŠãã ãããçã«ããªã£ã質åãèªãã åŸããã®ãProxySettings.STATICããšã¯äœããããã責任ãè² ãã®ã¯ã©ãããäŸå€ã¯ã©ãããæ¥ãã®ãããããŸã§èšåãããŠããªãã£ãããªã©ã ãšæããŸãã
æ®å¿µãªãããæ®å¿µãªãããåæããŒãžã§ã³ã¯ãããŸããã§ããããŸããbitbucketã«ã¯ããªãã¡ã¯ã¿ãªã³ã°ã®ããã€ãã®å埩ã«åæ Œãããã¹ãã¯ã©ã¹ãããããŸããã
ãã¹ãã®å®è¡ã¯å€±æããŸãããä»åºŠã¯ãããä¿®æ£ããå¿
èŠããããŸãã
ã¹ããã3.å®è£
æåŸã«ãäœãæžãã¹ãããèããå¿
èŠãªæºåããã¹ãŠè¡ã£ãã®ã§ããããžã§ã¯ãã®å®è£
ãé²ããããšãã§ããŸãã
ããŒã1ïŒæºåäœæ¥ãšãã«ããŒã¯ã©ã¹
å§ããããã«ãçŽæãããReflectionã®ãã³ãã«åãããããŸãããã
Reflection APIã«ã€ããŠå°ããªãã¬ã¯ã·ã§ã³ã¯ãJavaä»®æ³ãã·ã³ã§å®è¡ãããŠããã¢ããªã±ãŒã·ã§ã³ã®å®è¡æã®åäœãæ€æ»ãŸãã¯å€æŽããæ©èœãå¿
èŠãšããããã°ã©ã ã§äžè¬çã«äœ¿çšãããŸãã
Oracle Java Turtorial
ã¯ã©ã¹ã§ãããããã«ã€ããŠæ£ç¢ºã«äœãã§ããŸããïŒ
å°ããªäŸå°ããªã©ã€ãã©ãªããããWebããŒãžãååŸããŠä¿åããããã®ã¯ã©ã¹ãããã€ããããšããŸãã ãã®å Žã§æ¥ç¶ããŠäœ¿çšãããã§ãã ããã®ããã«å°ããªã¯ã©ã¹ãæžããŸãããïŒ
public class LibLoader {
ä»ããã䜿çšããŸãïŒ
public static void main(String[] args) throws Exception { File lib = new File("htmlgetandsave.jar"); LibLoader libLoader = new LibLoader(lib); libLoader.loadPage(new URL("https://habrahabr.ru/post/69552/")); System.out.println(libLoader.getCurrentPage()); libLoader.saveCurrentPage(" - reflection "); }
çµæãå
¬éããŠã楜ãã¿ãã ããïŒ

ããã«ãã©ã€ãã©ãªãã¡ã€ã«ã®å Žæã®ã¿ãç¥ãããšãã§ãããã®æ§é ã«ã€ããŠã¯äœãç¥ããŸãããReflectionapiã䜿çšãããšãå®è¡æã«ãã®åé¡ãçŽæ¥èª¿æ»ãããã®åŸäœ¿çšã§ããŸãã
ãã ããç§ãã¡ã«ãšã£ãŠéèŠãªã®ã¯ããšãããReflectionã®ãããã§ããã©ã€ããŒãã®ãã£ãŒã«ããšã¡ãœããã«ã¢ã¯ã»ã¹ã§ããããšãšãã¢ãããŒã·ã§ã³
hideã䜿çšã§ããããšã§ãã
ããã§ãäžèšã®
ReflectionHelperãäœæããŸãã
ReflectionHelper.java public abstract class ReflectionHelper { public static Object getField(Object object, String name) throws SecurityException, NoSuchFieldException, IllegalArgumentException, IllegalAccessException { Field field = object.getClass().getField(name); return field.get(object); } public static Object getDeclaredField(Object object, String name) throws SecurityException, NoSuchFieldException, IllegalArgumentException, IllegalAccessException { Field declaredField = object.getClass().getDeclaredField(name); declaredField.setAccessible(true); return declaredField.get(object); } public static void setDeclaredField(Object object, String name, Object value) throws NoSuchFieldException, IllegalAccessException { Field declaredField = object.getClass().getDeclaredField(name); declaredField.setAccessible(true); declaredField.set(object, value); } public static void setEnumField(Object object, String value, String name) throws SecurityException, NoSuchFieldException, IllegalArgumentException, IllegalAccessException { Field field = object.getClass().getField(name); field.set(object, Enum.valueOf((Class<Enum>) field.getType(), value)); } public static Object getMethodAndInvokeIt(Object object, String methodName, Object... args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { Method method = object.getClass().getDeclaredMethod(methodName, parameterTypes(args)); method.setAccessible(true); return method.invoke(object, args); } private static Class[] parameterTypes(Object... args) { ArrayList<Class> classes = new ArrayList<>(); for (Object arg : args) { classes.add(arg.getClass()); } return classes.toArray(new Class[args.length]); } }
ããã«ãããããããããšãã°
getFieldãš
getDeclaredFieldã®éãããã©ã®ã±ãŒã¹ã䜿çšããããç°¡åã«å¿ããŠããŸãå¯èœæ§ããããããã¡ã¢ãèšå®ããŸããã
Reflectionã®ã»ãšãã©ã®äœæ¥ã¯å¥ã®ã¯ã©ã¹ã«ç§»åãããŸãããæ®ãã®éšåã®å®è£
ãæ±ããŸãã
3ã€ã®ã±ãŒã¹ã®äŸå€ãäœæããŸãã
- Apiã®äžé©åãªããŒãžã§ã³ã 察å¿ããã¯ã©ã¹ïŒ
public class ApiNotSupportedException extends Exception { public ApiNotSupportedException() { super("Api version not supported"); } }
- æªå®çŸ©ã®Wifiæ§æã§ãªããžã§ã¯ããäœæããããšããŸããïŒããšãã°ããŠãŒã¶ãŒã¯ãwifiãç¡å¹ã«ãªã£ãŠããçŸåšã®ãããã¯ãŒã¯ã®ãããã·èšå®ã倿ŽããããšããŸããïŒã
public class NullWifiConfigurationException extends Exception { public NullWifiConfigurationException(){ super("WiFi configuration was null. \n" + "If you are trying to change current network settings - check your connection."); } }
- ãªããžã§ã¯ãã¯ãçŸåšã®WifiConfigurationã¯ã©ã¹ã®ãããã·èšå®ã«å¯ŸããŠå®çŸ©ãããŠããŸããã
public class WifiProxyNotSettedException extends IllegalStateException{ public WifiProxyNotSettedException(){ super("Wifi proxy not setted for current WifiConfiguration"); } }
ããŸããŸãªAPIã§WifiConfigurationãæäœãããµãã¯ã©ã¹ã®ããŒã¹ãšããŠæ©èœããã¯ã©ã¹ãå®è£
ããŸãã
BaseWifiConfiguration.java public class BaseWifiConfiguration { protected WifiConfiguration wifiConfiguration; protected BaseWifiConfiguration(WifiConfiguration wifiConfiguration) throws NullWifiConfigurationException { if (wifiConfiguration == null) throw new NullWifiConfigurationException(); this.wifiConfiguration = wifiConfiguration; } protected BaseWifiConfiguration(Context context) throws NullWifiConfigurationException { this(getCurrentWifiConfigurationFromContext(context)); } public WifiConfiguration getWifiConfiguration() { return wifiConfiguration; } private static WifiConfiguration getCurrentWifiConfigurationFromContext(Context context) { final WifiManager manager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE); List<WifiConfiguration> wifiConfigurationList = manager.getConfiguredNetworks(); if (!manager.isWifiEnabled() || wifiConfigurationList == null || wifiConfigurationList.isEmpty()) return null; return findWifiConfigurationByNetworkId(wifiConfigurationList, manager.getConnectionInfo().getNetworkId()); } private static WifiConfiguration findWifiConfigurationByNetworkId(List<WifiConfiguration> wifiConfigurationList, int networkId) { for (WifiConfiguration wifiConf : wifiConfigurationList) { if (wifiConf.networkId == networkId) return wifiConf; } return null; } }
ProxyChangerã€ã³ã¿ãŒãã§ãŒã¹ã®çºè¡š
Proxychanger.java public interface ProxyChanger { void setProxySettings(ProxySettings proxySettings) throws NoSuchFieldException, IllegalAccessException; ProxySettings getProxySettings() throws NoSuchFieldException, IllegalAccessException; void setProxyHostAndPort(String host, int port) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException, NoSuchFieldException; String getProxyHost() throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, ApiNotSupportedException, NoSuchFieldException; int getProxyPort() throws ApiNotSupportedException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, NoSuchFieldException; boolean isProxySetted() throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, ApiNotSupportedException, NoSuchFieldException; WifiConfiguration getWifiConfiguration(); }
ã¯ããReflectionã䜿çšããå Žåã®äŸå€ãªã¹ãã¯äœãã§ãã
ãã¹ãŠã奜ãã§ããïŒ ãããŠãããããå¥ã®å°ããªãµãã¢ã€ãã ããããŸãïŒ
ProxySettings.java-ããã¯äœã§ããããªãå¿
èŠãªã®ã§ããïŒ
ããã¯ã
Androidã©ã€ãã©ãªã®
WifiConfigurationã¯ã©ã¹ã«ããåæã«é¡äŒŒããŠããŸãã
STATIC ã
NONEãªã©ãæåã§ç»é²ãããã³ã«ç»é²ããã®ã§ã¯ãªããäœæ¥ã容æã«ããããã«äœæããŸãã
ProxySettings.java public enum ProxySettings { NONE("NONE"), STATIC("STATIC"), UNASSIGNED("UNASSIGNED"), PAC("PAC"); String value = ""; ProxySettings(String value) { this.value = value; } public String getValue() { return value; } }
ããŒã2ïŒç¹å®ã®APIã«ProxyChangerãå®è£
ããã¯ã©ã¹ãäœæããŸã
ãããã·èšå®ã倿Žããã³ãŒããæçµçã«äœæãããšããæ¥ãŸããã Reflectionãä»ããŠãããã«å°éããããŸããŸãªæ¹æ³ãããããšã
ããã«èšããªããã°ãªããŸãããWifiConfigurationã¯ã©ã¹ã®ã¡ãœãããåŒã³åºããŠã
å®éã«ãããã£ãŒã«ãã«å°éãã
setDeclaredFieldãä»ããŠçŽæ¥å€æŽã§ããŸãã
ç§ã¯çŸåšã®ãããã¯ãŒã¯ã§äœæ¥ããããã®äžéšã®ã¿ãæžããŸããïŒããã¯èè
ãå¿
èŠãšãããã®ã§ãïŒãããªãã¡ ãã ãã
Contextãä»ããŠã¯ã©ã¹ã®ã€ã³ã¹ã¿ã³ã¹ãäœæãããšãã¢ãŒããã¯ãã£ã«ãããæ°è¡ã远å ããã ãã§ããããã®ã¯ã©ã¹ãä»»æã®
WifiConfigurationãªããžã§ã¯ãã§åäœããããã«é©åãããããšã
ã§ããŸãã
ãããã«ãããšãžã§ãªãŒããŒã³
æé 1ã§èª¬æããããã«ããããã®AndroidããŒãžã§ã³ã§ã¯ã
WifiConfigurationã«ãã
LinkPropertiesã«æ ŒçŽãããŠãã
ProxyPropertiesãªããžã§ã¯ããããããã·èšå®ãæ ŒçŽããŸãã ã¯ããã¯ããåµã®äžã®éãã¢ãã«ã®äžã®åµããŠãµã®ã®äžã®ã¢ãã«ãªã©ã
ãããã·èšå®ã倿Žããã«ã¯ãå¿
èŠãªãã©ã¡ãŒã¿ãŒã
䜿çšããŠ
ProxyPropertiesã®æ°ããã€ã³ã¹ã¿ã³ã¹ãäœæããæ¢åã®ã€ã³ã¹ã¿ã³ã¹ããã®ãªããžã§ã¯ãã«çœ®ãæããŠãã
ProxySettingsãæ§æããŸãã
ProxyPropertiesã®ã€ã³ã¹ã¿ã³ã¹ã®äœæã¯ãå¥ã®ã¯ã©ã¹ãæ
åœããŸãã
ProxyPropertiesConstructor.java public abstract class ProxyPropertiesConstructor { public static Object proxyProperties(String host, int port) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException { return proxyProperties(host, port, null); } public static Object proxyProperties(String host, int port, String exclList) throws NoSuchMethodException, ClassNotFoundException, IllegalAccessException, InvocationTargetException, InstantiationException { return proxyPropertiesConstructor().newInstance(host, port, exclList); } private static Constructor proxyPropertiesConstructor() throws ClassNotFoundException, NoSuchMethodException { return Class.forName("android.net.ProxyProperties").getConstructor(String.class, int.class, String.class); } }
ãã®ãªããžã§ã¯ãã®äŸ¿å©ãªäœæ¥ã®ããã«ã
ProxyPropertiesãªããžã§ã¯ããå«ãã³ã³ãããŒã¯ã©ã¹ãäœæããã¡ã€ã³ãã£ãŒã«ããžã®ã¢ã¯ã»ã¹ãæäŸããŸãïŒãã¹ããšããŒããä»ããŠããã«äœæã§ããããã«ããŸãïŒã
ProxyPropertiesContainer.java public class ProxyPropertiesContainer { Object proxyProperties; ProxyPropertiesContainer(Object proxyProperties) { this.proxyProperties = proxyProperties; } ProxyPropertiesContainer(String host, int port) throws ClassNotFoundException, NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException { this(host, port, null); } ProxyPropertiesContainer(String host, int port, String exclList) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException { this(ProxyPropertiesConstructor.proxyProperties(host, port, exclList)); } public String getHost() throws NoSuchFieldException, IllegalAccessException { return (String) ReflectionHelper.getDeclaredField(proxyProperties, "mHost"); } public int getPort() throws NoSuchFieldException, IllegalAccessException { return (int) ReflectionHelper.getDeclaredField(proxyProperties, "mPort"); } public String getExclusionList() throws NoSuchFieldException, IllegalAccessException { return (String) ReflectionHelper.getDeclaredField(proxyProperties, "mExclusionList"); } public Object getProxyProperties() { return proxyProperties; } }
次ã«ãã¯ã©ã¹èªäœã®å®è£
ãèšè¿°ããŸãã
WifiConfigurationForApiFrom15To19.java public class WifiConfigurationForApiFrom15To19 extends BaseWifiConfiguration implements ProxyChanger { private ProxyPropertiesContainer proxyPropertiesContainer; public WifiConfigurationForApiFrom15To19(Context context) throws NoSuchFieldException, IllegalAccessException, NullWifiConfigurationException { super(context); this.proxyPropertiesContainer = new ProxyPropertiesContainer(getCurrentProxyProperties()); } public static WifiConfigurationForApiFrom15To19 createFromCurrentContext(Context context) throws NoSuchFieldException, IllegalAccessException, NullWifiConfigurationException { return new WifiConfigurationForApiFrom15To19(context); } @Override public void setProxySettings(ProxySettings proxySettings) throws NoSuchFieldException, IllegalAccessException { ReflectionHelper.setEnumField(wifiConfiguration, proxySettings.getValue(), "proxySettings"); } @Override public ProxySettings getProxySettings() throws NoSuchFieldException, IllegalAccessException { return ProxySettings.valueOf(String.valueOf(ReflectionHelper.getDeclaredField(wifiConfiguration, "proxySettings"))); } @Override public void setProxyHostAndPort(String host, int port) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException, NoSuchFieldException { proxyPropertiesContainer = new ProxyPropertiesContainer(host, port); ReflectionHelper.getMethodAndInvokeIt( getLinkProperties(), "setHttpProxy", proxyPropertiesContainer.getProxyProperties()); } @Override public String getProxyHost() throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, ApiNotSupportedException, NoSuchFieldException { if (proxyPropertiesContainer == null) throw new WifiProxyNotSettedException(); return proxyPropertiesContainer.getHost(); } @Override public int getProxyPort() throws ApiNotSupportedException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, NoSuchFieldException { if (proxyPropertiesContainer == null) throw new WifiProxyNotSettedException(); return proxyPropertiesContainer.getPort(); } @Override public boolean isProxySetted() throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, ApiNotSupportedException, NoSuchFieldException { return !(proxyPropertiesContainer == null); } private LinkProperties getLinkProperties() throws NoSuchFieldException, IllegalAccessException { return (LinkProperties) ReflectionHelper.getField(wifiConfiguration, "linkProperties"); } private Object getCurrentProxyProperties() throws NoSuchFieldException, IllegalAccessException { return ReflectionHelper.getDeclaredField(getLinkProperties(), "mHttpProxy"); } }
ãã®ããŒãžã§ã³ãçµäºããããå·ŠïŒ
ããªããã
ç¹°ãè¿ãã«ãªããŸãããã¹ããã1ãåç
§ãããšããã®ããŒãžã§ã³ã®Apiã®ãããã·èšå®ã¯
IpConfigurationã«å«ãŸãã
ProxyInfoã¯ã©ã¹ã«ããã
WifiConfigurationããã®å Žæã«ãããšçµè«ä»ããããšãã§ããŸãã
ProxySettings-ç§»åãããäžèšã®
IpConfigurationã«è¿œå ãããŸãã ã
æå®ããããã©ã¡ãŒã¿ãŒã«åŸã£ãŠProxyInfoã®æ°ããã€ã³ã¹ã¿ã³ã¹ãäœæããã¯ã©ã¹ãäœæããŸãããã
ProxyInfoConstructor.java public abstract class ProxyInfoConstructor { public static ProxyInfo proxyInfo(String host, int port) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException { return proxyInfo(host, port, null); } public static ProxyInfo proxyInfo(String host, int port, String exclude) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException { Object newProxyInfo = proxyInfoConstructor().newInstance(host, port, exclude); return (ProxyInfo) newProxyInfo; } private static Constructor proxyInfoConstructor() throws ClassNotFoundException, NoSuchMethodException { return Class.forName("android.net.ProxyInfo").getConstructor(String.class, int.class, String.class); } }
ã芧ã®ãšãããããã§ã¯Objectãã€ãŸã
ProxyInfoã€ã³ã¹ã¿ã³ã¹ããŸã è¿ããŠããŸãããããã«ããã®ã¯ã©ã¹ã«ã¯
getHost ã¡ãœãããš
getPortã¡ãœãããããããšã
ããã ãŸã ã åã®ã±ãŒã¹ã§ã¯ããããè¡ãããšãã§ããªãã£ãããã
ProxyPropertiesã¯ã©ã¹ãé衚瀺ã«ãªã£ãããããã·ã§ã«ããäœæããŸããã
ãããŠãå®éã«ã¯ãå¥ã®å®è£
ã®ã³ãŒãïŒ
WifiConfigurationForApiFrom21To22.java public class WifiConfigurationForApiFrom21To22 extends BaseWifiConfiguration implements ProxyChanger { public WifiConfigurationForApiFrom21To22(Context context) throws NullWifiConfigurationException { super(context); } public static WifiConfigurationForApiFrom21To22 createFromCurrentContext(Context context) throws NullWifiConfigurationException { return new WifiConfigurationForApiFrom21To22(context); } @Override public ProxySettings getProxySettings() throws NoSuchFieldException, IllegalAccessException { return ProxySettings.valueOf(String.valueOf(ReflectionHelper.getDeclaredField(getIpConfigurationObject(), "proxySettings"))); } @Override public void setProxySettings(ProxySettings proxySettings) throws NoSuchFieldException, IllegalAccessException { ReflectionHelper.setEnumField(getIpConfigurationObject(), proxySettings.getValue(), "proxySettings"); } @Override public void setProxyHostAndPort(String host, int port) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException, NoSuchFieldException { setProxyInfo(ProxyInfoConstructor.proxyInfo(host, port)); } @TargetApi(Build.VERSION_CODES.LOLLIPOP) @Override public String getProxyHost() throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, ApiNotSupportedException { ProxyInfo info = getProxyInfo(); if (info == null) throw new WifiProxyNotSettedException(); return info.getHost(); } @TargetApi(Build.VERSION_CODES.LOLLIPOP) @Override public int getProxyPort() throws ApiNotSupportedException, NoSuchMethodException, IllegalAccessException, InvocationTargetException { ProxyInfo info = getProxyInfo(); if (info == null) throw new WifiProxyNotSettedException(); return info.getPort(); } @Override public boolean isProxySetted() throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, ApiNotSupportedException, NoSuchFieldException { return !(getProxyInfo() == null); } private Object getIpConfigurationObject() throws NoSuchFieldException, IllegalAccessException { return ReflectionHelper.getDeclaredField(wifiConfiguration, "mIpConfiguration"); } private ProxyInfo getProxyInfo() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { return (ProxyInfo) ReflectionHelper.getMethodAndInvokeIt(wifiConfiguration, "getHttpProxy"); } private void setProxyInfo(ProxyInfo proxyInfo) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException, NoSuchFieldException { ReflectionHelper.getMethodAndInvokeIt(wifiConfiguration, "setHttpProxy", proxyInfo); } }
ã¡ã€ã³ã®å®è£
ã§ã¯ãããã§ãã¹ãŠã§ãããã£ããã·ã¥ã©ã€ã³ãŸã§ããšå°ãã§ããã¹ããã4.äºåèµ·å
ãã¹ãã§åè¿°ããã¯ã©ã¹ãå®è£
ããŸãïŒæ³šïŒãããã·èšå®ã¯ããããIPãšããŒãã§å®è£
ãããProxySettingsã¿ã€ãã¯STATICã§ãïŒãCurrentProxyChangerGetter.java public abstract class CurrentProxyChangerGetter { public static ProxyChanger chooseProxyChangerForCurrentApi(Context context) throws ApiNotSupportedException, NoSuchFieldException, IllegalAccessException, NullWifiConfigurationException { if (ApiChecker.isJellyBeanOrKitkat()) { return WifiConfigurationForApiFrom15To19.createFromCurrentContext(context); } else if (ApiChecker.isLolipop()) { return WifiConfigurationForApiFrom21To22.createFromCurrentContext(context); } else { throw new ApiNotSupportedException(); } } }
WifiProxyChanger.java public abstract class WifiProxyChanger { public static void changeWifiStaticProxySettings(String host, int port, Context context) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException, NoSuchFieldException, ApiNotSupportedException, NullWifiConfigurationException { updateWifiWithNewConfiguration( getCurrentWifiConfiguretionWithUpdatedSettings(host, port, ProxySettings.STATIC, context), context); } public static void clearProxySettings(Context context) throws IllegalAccessException, ApiNotSupportedException, NoSuchFieldException, NullWifiConfigurationException, ClassNotFoundException, NoSuchMethodException, InstantiationException, InvocationTargetException { updateWifiWithNewConfiguration( getCurrentWifiConfiguretionWithUpdatedSettings("", 0, ProxySettings.NONE, context), context); } private static WifiConfiguration getCurrentWifiConfiguretionWithUpdatedSettings(String host, int port, ProxySettings proxySettings, Context context) throws ApiNotSupportedException, IllegalAccessException, NullWifiConfigurationException, NoSuchFieldException, ClassNotFoundException, NoSuchMethodException, InstantiationException, InvocationTargetException { ProxyChanger proxyChanger = CurrentProxyChangerGetter.chooseProxyChangerForCurrentApi(context); proxyChanger.setProxyHostAndPort(host, port); proxyChanger.setProxySettings(proxySettings); return proxyChanger.getWifiConfiguration(); } private static void updateWifiWithNewConfiguration(WifiConfiguration wifiConfiguration, Context context) { WifiManager currentWifiManager = NetworkHelper.getWifiManager(context); currentWifiManager.updateNetwork(wifiConfiguration); currentWifiManager.saveConfiguration(); currentWifiManager.reconnect(); } }
WifiProxyInfo.java public abstract class WifiProxyInfo { public static String getHost(Context context) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, ApiNotSupportedException, NoSuchFieldException, NullWifiConfigurationException { return CurrentProxyChangerGetter.chooseProxyChangerForCurrentApi(context).getProxyHost(); } public static int getPort(Context context) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, ApiNotSupportedException, NoSuchFieldException, NullWifiConfigurationException { return CurrentProxyChangerGetter.chooseProxyChangerForCurrentApi(context).getProxyPort(); } public static ProxySettings getProxySettings(Context context) throws ApiNotSupportedException, IllegalAccessException, NoSuchFieldException, NullWifiConfigurationException { return CurrentProxyChangerGetter.chooseProxyChangerForCurrentApi(context).getProxySettings(); } }
APIã®ããŒãžã§ã³ã確èªããããã®ãã«ããŒã¯ã©ã¹ãå®è£
ããŸããApiChecker.java public abstract class ApiChecker { public static boolean isJellyBeanOrKitkat() { return Build.VERSION.SDK_INT > 14 && Build.VERSION.SDK_INT < 20; } public static boolean isLolipop() { return Build.VERSION.SDK_INT > 20 && Build.VERSION.SDK_INT < 23; } public static boolean isSupportedApi() { return isJellyBeanOrKitkat() || isLolipop(); } }
èµ·åãã¹ã
ïŒç³ãèš³ãããŸãããããã®ç¬éã«èŠåºãã§åŒ·èª¿ããããšã«ããŸããïŒ...
ã·ã£ã³ãã³ïŒã¯ã€ã³ïŒãç¥ãïŒææïŒã¯ã€ãŒã³-ç§ãã¡ã¯äŒŽå¥ãšããŠã®ãã£ã³ããªã³ã§ãïŒå°ããªã³ã¡ã³ã, . , - , "!" ã , 10 , , .
ã¹ããã5.ã¢ã¯ãã£ããã£ã®ã¡ãªããããæ¥œãã¿ãã ããã
ã©ã€ãã©ãªãããã©ã«ãã§äœæãããã¢ããªã±ãŒã·ã§ã³ã«æ¥ç¶ããçµæã確èªããŸããMainActivity.java public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); changeProxySettings("myhost.com", 12345); } void changeProxySettings(String host, int port) { try { WifiProxyChanger.changeWifiStaticProxySettings(host, port, this); } catch (ClassNotFoundException | NoSuchMethodException | InstantiationException | InvocationTargetException | NoSuchFieldException | IllegalAccessException | NullWifiConfigurationException | ApiNotSupportedException e) { e.printStackTrace(); } } }
å§ããŸããã¢ããªã±ãŒã·ã§ã³ç»é¢ã«ã¯ãäœãé¢çœããã®ã¯è¡šç€ºãããŸãããæ¥ç¶å
ã®ãããã¯ãŒã¯ã®Wi-Fièšå®ã«ããã«ç§»åããããã§ããçµæãåçã倧ããããŸãã çµæãéæãããŸããããŸãšã
çŸæç¹ã§ã¯ãäžèšã®ããŒãžã§ã³ã®Androidã§Wi-Fiãããã¯ãŒã¯ã®ãããã·èšå®ã倿Žããããã«æ¢ã«äœ¿çšã§ãããæ©èœãããç°¡åã«æ¡åŒµå¯èœãªã©ã€ãã©ãªããããŸãããããªãèšç»ïŒã¯ããèè
ã¯ãããã®å
šãªã¹ããæã£ãŠããŸãïŒ- ãã¡ãããMarshmallowã®ãµããŒãã远å ããå¿
èŠããããŸãããã®ããŒãžã§ã³ã®Androidãå®è¡ããŠããæ°ããæºåž¯é»è©±ããã£ãã ãã§ãïŒãããŠãæ°ããèš±å¯ã·ã¹ãã ã§ã®äœæ¥ã¯å¥ã®ã¿ã¹ã¯ã«ãªããšæããŸãïŒã
- ãŸããã¢ãã€ã«ãããã¯ãŒã¯ã®èšå®ã«é¢ãã質åãæ€èšããããšæããŸãã
- ã©ã€ãã©ãªã宿ãããŠãWifiãããã¯ãŒã¯ã®æ§æãå®å
šã«å€æŽãã䟡å€ããããããããŸãããWifiConfigurationã¯å€§ãããŠè峿·±ãã¯ã©ã¹ã§ãããããã«IpSettingsChangerã€ã³ã¿ãŒãã§ãŒã¹ãã©ã€ãã©ãªãŒã«è¡šç€ºããããããšãšãã«æ°ããèšäºã衚瀺ãããŸãã
- ãããŠããã¡ãããReadmeãªã©ãBitbucketã§é©åã«é
眮ããå¿
èŠããããŸãã
ãããŠããã¡ãããããã¯ãã¹ãŠãšã¯çšé ããã®ã§ããèæ¬ãšèè
ã«ããã³ã¡ã³ããæçš¿ãã» , , , Bitbucket ( ).
» â , .
» , , â .
èšäºã«é¢å¿ããå¯ãããã ããããããšãããããŸããããµã³ãããã¯ã¹ã«æ®ããŠã¯ãããªãããã¯ããŒã ã