Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

WebView android proxy

I know how to setting proxy manually and to use it in my WebView.

Settings -> Wireless Networks ->mobile networks-> access point names->telkila. Now enter the proxy server address and port (which will be 80). WebView.enablePlatformNotifications();

But can i set the proxy setting from code? So my user didn't have to set manually?

Thanks

like image 495
user430926 Avatar asked Dec 20 '10 09:12

user430926


2 Answers

I have adapted the three solutions presented here (and modified one where it failed) to produce a single, simple setProxy method that works for all versions of Android. I've tested it from 10 to 18, and it works for all tested environments.

UPDATED 2014-04-04 I finally worked in the solution from a comment below, courtesy of nubela and xjy2061. Now this works for all current Android versions, including KitKat 4.4. If you implement your own Application subclass, supply the name of the class as the optional fourth parameter.

UPDATED 2015-01-15 The part labeled optional in the KitKat method throws an exception on Lollipop because an auxiliary class is missing, but without that it works on both KitKat and Lollipop, since the WebView is based on Chromium in both cases.

public static boolean setProxy(WebView webview, String host, int port, String applicationClassName="android.app.Application") {     // 3.2 (HC) or lower     if (Build.VERSION.SDK_INT <= 13) {         return setProxyUpToHC(webview, host, port);     }     // ICS: 4.0     else if (Build.VERSION.SDK_INT <= 15) {         return setProxyICS(webview, host, port);     }     // 4.1-4.3 (JB)     else if (Build.VERSION.SDK_INT <= 18) {         return setProxyJB(webview, host, port);     }     // 4.4 (KK) & 5.0 (Lollipop)     else {         return setProxyKKPlus(webview, host, port, applicationClassName);     } }  /**  * Set Proxy for Android 3.2 and below.  */ @SuppressWarnings("all") private static boolean setProxyUpToHC(WebView webview, String host, int port) {     Log.d(LOG_TAG, "Setting proxy with <= 3.2 API.");      HttpHost proxyServer = new HttpHost(host, port);     // Getting network     Class networkClass = null;     Object network = null;     try {         networkClass = Class.forName("android.webkit.Network");         if (networkClass == null) {             Log.e(LOG_TAG, "failed to get class for android.webkit.Network");             return false;         }         Method getInstanceMethod = networkClass.getMethod("getInstance", Context.class);         if (getInstanceMethod == null) {             Log.e(LOG_TAG, "failed to get getInstance method");         }         network = getInstanceMethod.invoke(networkClass, new Object[]{webview.getContext()});     } catch (Exception ex) {         Log.e(LOG_TAG, "error getting network: " + ex);         return false;     }     if (network == null) {         Log.e(LOG_TAG, "error getting network: network is null");         return false;     }     Object requestQueue = null;     try {         Field requestQueueField = networkClass                 .getDeclaredField("mRequestQueue");         requestQueue = getFieldValueSafely(requestQueueField, network);     } catch (Exception ex) {         Log.e(LOG_TAG, "error getting field value");         return false;     }     if (requestQueue == null) {         Log.e(LOG_TAG, "Request queue is null");         return false;     }     Field proxyHostField = null;     try {         Class requestQueueClass = Class.forName("android.net.http.RequestQueue");         proxyHostField = requestQueueClass                 .getDeclaredField("mProxyHost");     } catch (Exception ex) {         Log.e(LOG_TAG, "error getting proxy host field");         return false;     }      boolean temp = proxyHostField.isAccessible();     try {         proxyHostField.setAccessible(true);         proxyHostField.set(requestQueue, proxyServer);     } catch (Exception ex) {         Log.e(LOG_TAG, "error setting proxy host");     } finally {         proxyHostField.setAccessible(temp);     }      Log.d(LOG_TAG, "Setting proxy with <= 3.2 API successful!");     return true; }  @SuppressWarnings("all") private static boolean setProxyICS(WebView webview, String host, int port) {     try     {         Log.d(LOG_TAG, "Setting proxy with 4.0 API.");          Class jwcjb = Class.forName("android.webkit.JWebCoreJavaBridge");         Class params[] = new Class[1];         params[0] = Class.forName("android.net.ProxyProperties");         Method updateProxyInstance = jwcjb.getDeclaredMethod("updateProxy", params);          Class wv = Class.forName("android.webkit.WebView");         Field mWebViewCoreField = wv.getDeclaredField("mWebViewCore");         Object mWebViewCoreFieldInstance = getFieldValueSafely(mWebViewCoreField, webview);          Class wvc = Class.forName("android.webkit.WebViewCore");         Field mBrowserFrameField = wvc.getDeclaredField("mBrowserFrame");         Object mBrowserFrame = getFieldValueSafely(mBrowserFrameField, mWebViewCoreFieldInstance);          Class bf = Class.forName("android.webkit.BrowserFrame");         Field sJavaBridgeField = bf.getDeclaredField("sJavaBridge");         Object sJavaBridge = getFieldValueSafely(sJavaBridgeField, mBrowserFrame);          Class ppclass = Class.forName("android.net.ProxyProperties");         Class pparams[] = new Class[3];         pparams[0] = String.class;         pparams[1] = int.class;         pparams[2] = String.class;         Constructor ppcont = ppclass.getConstructor(pparams);          updateProxyInstance.invoke(sJavaBridge, ppcont.newInstance(host, port, null));          Log.d(LOG_TAG, "Setting proxy with 4.0 API successful!");         return true;     }     catch (Exception ex)     {         Log.e(LOG_TAG, "failed to set HTTP proxy: " + ex);         return false;     } }  /**  * Set Proxy for Android 4.1 - 4.3.  */ @SuppressWarnings("all") private static boolean setProxyJB(WebView webview, String host, int port) {     Log.d(LOG_TAG, "Setting proxy with 4.1 - 4.3 API.");      try {         Class wvcClass = Class.forName("android.webkit.WebViewClassic");         Class wvParams[] = new Class[1];         wvParams[0] = Class.forName("android.webkit.WebView");         Method fromWebView = wvcClass.getDeclaredMethod("fromWebView", wvParams);         Object webViewClassic = fromWebView.invoke(null, webview);          Class wv = Class.forName("android.webkit.WebViewClassic");         Field mWebViewCoreField = wv.getDeclaredField("mWebViewCore");         Object mWebViewCoreFieldInstance = getFieldValueSafely(mWebViewCoreField, webViewClassic);          Class wvc = Class.forName("android.webkit.WebViewCore");         Field mBrowserFrameField = wvc.getDeclaredField("mBrowserFrame");         Object mBrowserFrame = getFieldValueSafely(mBrowserFrameField, mWebViewCoreFieldInstance);          Class bf = Class.forName("android.webkit.BrowserFrame");         Field sJavaBridgeField = bf.getDeclaredField("sJavaBridge");         Object sJavaBridge = getFieldValueSafely(sJavaBridgeField, mBrowserFrame);          Class ppclass = Class.forName("android.net.ProxyProperties");         Class pparams[] = new Class[3];         pparams[0] = String.class;         pparams[1] = int.class;         pparams[2] = String.class;         Constructor ppcont = ppclass.getConstructor(pparams);          Class jwcjb = Class.forName("android.webkit.JWebCoreJavaBridge");         Class params[] = new Class[1];         params[0] = Class.forName("android.net.ProxyProperties");         Method updateProxyInstance = jwcjb.getDeclaredMethod("updateProxy", params);          updateProxyInstance.invoke(sJavaBridge, ppcont.newInstance(host, port, null));     } catch (Exception ex) {         Log.e(LOG_TAG,"Setting proxy with >= 4.1 API failed with error: " + ex.getMessage());         return false;     }      Log.d(LOG_TAG, "Setting proxy with 4.1 - 4.3 API successful!");     return true; }  // from https://stackoverflow.com/questions/19979578/android-webview-set-proxy-programatically-kitkat @SuppressLint("NewApi") @SuppressWarnings("all") private static boolean setProxyKKPlus(WebView webView, String host, int port, String applicationClassName) {     Log.d(LOG_TAG, "Setting proxy with >= 4.4 API.");      Context appContext = webView.getContext().getApplicationContext();     System.setProperty("http.proxyHost", host);     System.setProperty("http.proxyPort", port + "");     System.setProperty("https.proxyHost", host);     System.setProperty("https.proxyPort", port + "");     try {         Class applictionCls = Class.forName(applicationClassName);         Field loadedApkField = applictionCls.getField("mLoadedApk");         loadedApkField.setAccessible(true);         Object loadedApk = loadedApkField.get(appContext);         Class loadedApkCls = Class.forName("android.app.LoadedApk");         Field receiversField = loadedApkCls.getDeclaredField("mReceivers");         receiversField.setAccessible(true);         ArrayMap receivers = (ArrayMap) receiversField.get(loadedApk);         for (Object receiverMap : receivers.values()) {             for (Object rec : ((ArrayMap) receiverMap).keySet()) {                 Class clazz = rec.getClass();                 if (clazz.getName().contains("ProxyChangeListener")) {                     Method onReceiveMethod = clazz.getDeclaredMethod("onReceive", Context.class, Intent.class);                     Intent intent = new Intent(Proxy.PROXY_CHANGE_ACTION);                      onReceiveMethod.invoke(rec, appContext, intent);                 }             }         }          Log.d(LOG_TAG, "Setting proxy with >= 4.4 API successful!");         return true;     } catch (ClassNotFoundException e) {         StringWriter sw = new StringWriter();         e.printStackTrace(new PrintWriter(sw));         String exceptionAsString = sw.toString();         Log.v(LOG_TAG, e.getMessage());         Log.v(LOG_TAG, exceptionAsString);     } catch (NoSuchFieldException e) {         StringWriter sw = new StringWriter();         e.printStackTrace(new PrintWriter(sw));         String exceptionAsString = sw.toString();         Log.v(LOG_TAG, e.getMessage());         Log.v(LOG_TAG, exceptionAsString);     } catch (IllegalAccessException e) {         StringWriter sw = new StringWriter();         e.printStackTrace(new PrintWriter(sw));         String exceptionAsString = sw.toString();         Log.v(LOG_TAG, e.getMessage());         Log.v(LOG_TAG, exceptionAsString);     } catch (IllegalArgumentException e) {         StringWriter sw = new StringWriter();         e.printStackTrace(new PrintWriter(sw));         String exceptionAsString = sw.toString();         Log.v(LOG_TAG, e.getMessage());         Log.v(LOG_TAG, exceptionAsString);     } catch (NoSuchMethodException e) {         StringWriter sw = new StringWriter();         e.printStackTrace(new PrintWriter(sw));         String exceptionAsString = sw.toString();         Log.v(LOG_TAG, e.getMessage());         Log.v(LOG_TAG, exceptionAsString);     } catch (InvocationTargetException e) {         StringWriter sw = new StringWriter();         e.printStackTrace(new PrintWriter(sw));         String exceptionAsString = sw.toString();         Log.v(LOG_TAG, e.getMessage());         Log.v(LOG_TAG, exceptionAsString);     }      return false; }  private static Object getFieldValueSafely(Field field, Object classInstance) throws IllegalArgumentException, IllegalAccessException {     boolean oldAccessibleValue = field.isAccessible();     field.setAccessible(true);     Object result = field.get(classInstance);     field.setAccessible(oldAccessibleValue);     return result; } 
like image 67
Jimmy Dee Avatar answered Oct 04 '22 03:10

Jimmy Dee


There is no legal way to change your webview proxy settings programmatically. But it's possible to use java reflection to change mProxyHost value from android.net.http.RequestQueue class. It's private value and there is no setters for it, so reflection seems to be the only possible variant. I used it in my project and it works. Here is the sample of my method:

    private boolean setProxyHostField(HttpHost proxyServer) {     // Getting network           Class networkClass = null;     Object network = null;     try {         networkClass = Class.forName("android.webkit.Network");         Field networkField = networkClass.getDeclaredField("sNetwork");         network = getFieldValueSafely(networkField, null);     } catch (Exception ex) {         Log.e(ProxyManager.class.getName(), "error getting network");         return false;     }     if (network == null) {         Log.e(ProxyManager.class.getName(), "error getting network : null");         return false;     }     Object requestQueue = null;     try {         Field requestQueueField = networkClass                 .getDeclaredField("mRequestQueue");         requestQueue = getFieldValueSafely(requestQueueField, network);     } catch (Exception ex) {         Log.e(ProxyManager.class.getName(), "error getting field value");         return false;     }     if (requestQueue == null) {         Log.e(ProxyManager.class.getName(), "Request queue is null");         return false;     }     Field proxyHostField = null;     try {         Class requestQueueClass = Class.forName("android.net.http.RequestQueue");         proxyHostField = requestQueueClass                 .getDeclaredField("mProxyHost");     } catch (Exception ex) {         Log.e(ProxyManager.class.getName(), "error getting proxy host field");         return false;     }            synchronized (synchronizer) {         boolean temp = proxyHostField.isAccessible();         try {             proxyHostField.setAccessible(true);             proxyHostField.set(requestQueue, proxyServer);         } catch (Exception ex) {             Log.e(ProxyManager.class.getName(), "error setting proxy host");         } finally {             proxyHostField.setAccessible(temp);         }     }     return true; }  private Object getFieldValueSafely(Field field, Object classInstance) throws IllegalArgumentException, IllegalAccessException {     boolean oldAccessibleValue = field.isAccessible();     field.setAccessible(true);     Object result = field.get(classInstance);     field.setAccessible(oldAccessibleValue);     return result;       } 
like image 33
amukhachov Avatar answered Oct 04 '22 05:10

amukhachov