41

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

user430926
  • 4,017
  • 13
  • 53
  • 77

10 Answers10

35

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;
}
Jimmy Dee
  • 1,070
  • 1
  • 11
  • 17
  • Can you tell me how to revert that back, that means clearing proxy – mohitum Dec 03 '13 at 11:11
  • @mohitum007 I suggest for 2.x you can read corresponder proxy fiels and restore when you need shutdown your proxy. For 3.x and 4.x looks like proxy set up just for one instance on WebView object not system-wide, is it? – Timur Gilfanov Dec 08 '13 at 12:26
  • Here is a similar snippet that reportedly works on KitKat / 4.4: http://stackoverflow.com/questions/19979578/android-webview-set-proxy-programatically-kitkat – vitriolix Feb 12 '14 at 23:59
  • Hi, Can we add proxy authentication in the setProxyJB method ? Thanks ! – toufik_at Apr 15 '14 at 13:22
  • I was just thinking it's a shame I own the popular, generic answer. Maybe this belongs in an Android wiki somewhere, where anyone can edit it. This is mostly copied from my own project, where I use it as I need it (w/o auth or the ability to clear the proxy). https://github.com/jdee/dubsar_android/blob/master/Dubsar/src/com/dubsar_dictionary/Dubsar/FAQActivity.java#L104 That's GPL. Feel free to use it if that suits your needs. Also feel free to copy and expand my answer here if you want to add to it. – Jimmy Dee Apr 16 '14 at 22:22
  • Looks like 4.4.4 is still API level 19, as opposed to 4.4.W or L (?), which comprise 20. The only access I have to 19 is the emulator, which is 4.4.2. It worked there. You might look at/post your question on this thread, where I got the API 19 answer in the first place: http://stackoverflow.com/questions/19979578/android-webview-set-proxy-programatically-kitkat – Jimmy Dee Jun 29 '14 at 16:35
  • I've got problem with 4.2.2 and Alcatel One Touch 6040X (Idol X) phone. As I can see it's related just to Alcatel's phones! I've got one more phone with 4.2.2 - Samsung GT-S7580 and code works perfect. – Sasa Tancev Jul 22 '14 at 10:39
  • 1
    plz add following answer to your solution (for API>19): https://stackoverflow.com/a/25485747/365229 – Behrouz.M Jan 17 '19 at 09:32
25

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;      
}
amukhachov
  • 5,822
  • 1
  • 41
  • 60
  • 1
    would you please post the code for getFieldValueSafely(requestQueueField, network); Regards Muthuvel.P – Muthuvel P Aug 12 '11 at 21:45
  • 2
    Thank you for the brilliant piece of code! I added it to the [Android Proxy Library](http://code.google.com/p/android-proxy-library/) in order to provide all interested Android developers an easy and fast way to support the Proxy in their application. Thank you again! – lechuckcaptain Jul 07 '12 at 07:39
  • I try to put these code before loadURl. But it does not work. Where should I put this code, thz – Bear May 16 '13 at 13:54
  • 1
    Please check the answer below if you are using android api above 11. It should works before loadURl – amukhachov May 16 '13 at 15:28
  • Yes, I tried. Finally, I find that it works in 4.1 but not in 4.2.2 – Bear May 17 '13 at 08:06
  • What is this? `synchronized (synchronizer) {` – Nicolas May 22 '13 at 12:17
  • 1
    private field: Object synchronizer = new Object(); – amukhachov May 22 '13 at 13:13
  • @birdy: Does this set the proxy for the running application only, or for the whole android system? – koenmetsu Jun 13 '13 at 07:09
  • Hi, where is this ProxyManager class? i copied and pased the code below and got synatx errors for ProxyManager. seems you are missing the ProxyManager class code – Jono Jul 01 '13 at 14:52
  • edit: i removed the proxyManager tag and that fixed the synatx erros. however the actual code itself doesnt work. network = getFieldValueSafely(networkField, null); always returns null – Jono Jul 01 '13 at 15:25
  • Hi all, can we pass authentication informations to the setProxyJB Method ? – toufik_at Apr 15 '14 at 13:00
  • The accepted answer stopped working for android-l preview release. Anyone has got something for that? – nubela Aug 12 '14 at 19:43
  • You should try a solution from Jimmy Dee's answer or this library: https://github.com/shouldit/android-proxy/tree/master/android-proxy-library . Reflection is just approach, different Android versions require different implementations. – amukhachov Aug 13 '14 at 08:22
  • @birdy Any comments on how to reset/ remove applied proxy on Android WebVIew using reflection? Please answer this question on SO: http://stackoverflow.com/questions/39718818/how-to-reset-proxy-in-android-webview-for-android-versions-below-than-kitkat – Perry Sep 27 '16 at 09:14
  • @Perry You can get value from proxyHostField before changing it and store it as local variable. Than in reset() just set this previous value using setProxyHostField(previousHostField). – amukhachov Sep 27 '16 at 11:07
  • is it still works in android 11 and 12 ? – Ahmad Jun 10 '22 at 19:22
9

I've made lots of tests and i can says that the previous response using the override based on android.net.http.RequestQueue works perfectly from android 1.6 to 3.1.

But there was a code refactoring on API and to make it work on Android 3.2 & 4.x, here the solution :

try
{
  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 mWebViewCoreFieldIntance = getFieldValueSafely(mWebViewCoreField, oauthPage);

  Class wvc = Class.forName("android.webkit.WebViewCore");
  Field mBrowserFrameField = wvc.getDeclaredField("mBrowserFrame");
  Object mBrowserFrame = getFieldValueSafely(mBrowserFrameField, mWebViewCoreFieldIntance);

  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("my.proxy.com", 1234, null)); 
}
catch (Exception ex)
{    
}

enjoy

Guillaume13
  • 281
  • 3
  • 5
8

when api >= 29:

implementation 'androidx.webkit:webkit:1.4.0'

add this to app/build.gradle, then

private fun setProxy(host: String, port: Int) {
    if (WebViewFeature.isFeatureSupported(WebViewFeature.PROXY_OVERRIDE)) {
        val proxyUrl = "${host}:${port}"
        val proxyConfig: ProxyConfig = ProxyConfig.Builder()
            .addProxyRule(proxyUrl)
            .addDirect()//when proxy is not working, use direct connect, maybe?
            .build()
        ProxyController.getInstance().setProxyOverride(proxyConfig, object : Executor {
            override fun execute(command: Runnable) {

            }
        }, Runnable { Log.w(TAG, "WebView proxy") })
    } else {
        // use the solution of other anwsers
    }
}
dujianchi
  • 964
  • 8
  • 9
3

As @Karthik said, these answers are not work on android 4.4(KitKat). For KitKat the answer was posted here.

Community
  • 1
  • 1
xjy2061
  • 513
  • 3
  • 12
1

Chromium has started obfuscating class names in new release (the class name for the ProxyChangeListener appears to be "bMh" in the latest version, and may change in future releases. So Jimmy Dee's solution will not work anymore for newer versions because the following check will always fail:

if (clazz.getName().contains("ProxyChangeListener"))

A solution that I thought about is to invoke onReceive on all broadcast receivers in the current app-context.

Now I understand this is not an ideal solution, because it may have unwanted side effects by invoking the wrong receivers, and one should scrutinize all broadcast receivers in the app context to make sure they don't do anything bad. (Any other ideas?)

Building on the previous answer, it would be something like this:

// 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, Context appContext) {
    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);
        ArrayMap contextReceivers = (ArrayMap) receivers.get(appContext);
        for (Object rec : contextReceivers.keySet()) {
            Class clazz = rec.getClass();

            Method onReceiveMethod = clazz.getDeclaredMethod("onReceive", Context.class, Intent.class);
            Intent intent = new Intent(Proxy.PROXY_CHANGE_ACTION);
            try {
                onReceiveMethod.invoke(rec, appContext, intent);
            } catch (Exception e) {
                // oops, couldn't invoke this receiver
            }
        }


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

It will be really helpful if someone in the community has a better idea.

1
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 {
    Field loadedApkField = appContext.getClass().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;

I removed the use of applicationclassname. it works well on android 7.1

lvshow
  • 36
  • 1
0

This is the code for versions 4.1 and 4.2 -

/**
 * Set Proxy for Android 4.1 and above.
 */
public static boolean setProxyICSPlus(WebView webview, String host, int port, String exclusionList) {

    Log.d("", "Setting proxy with >= 4.1 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 mWebViewCoreFieldIntance = getFieldValueSafely(mWebViewCoreField, webViewClassic);

        Class wvc = Class.forName("android.webkit.WebViewCore");
        Field mBrowserFrameField = wvc.getDeclaredField("mBrowserFrame");
        Object mBrowserFrame = getFieldValueSafely(mBrowserFrameField, mWebViewCoreFieldIntance);

        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, exclusionList));

    } catch (Exception ex) {
        Log.e("","Setting proxy with >= 4.1 API failed with error: " + ex.getMessage());
        return false;
    }

    Log.d("", "Setting proxy with >= 4.1 API successful!");
    return true;
}
MediumOne
  • 804
  • 3
  • 11
  • 28
  • @Bear - I have tested this on a lot of devices and it works perfectly. Can you tell where it is failing? – MediumOne May 17 '13 at 16:36
  • I have post my question here http://stackoverflow.com/questions/16590734/use-proxy-in-webview-in-android Thank you – Bear May 18 '13 at 00:56
  • 1
    Hi, Can we add proxy authentication in the setProxyJB method ? Thanks ! – toufik_at Apr 15 '14 at 13:23
0

madeye's solution https://gist.github.com/madeye/2297083 pseudocode:

android.webkit.Network.getInstance().mRequestQueue.mProxyHost=new HttpHost(host, port, "http")    //sdk < 14
android.webkit.WebViewCore.sendStaticMessage(new android.net.ProxyProperties(...))   //sdk >= 14

is better than birdy's answer(WebView android proxy) pseudocode:

android.webkit.Network.sNetwork.mRequestQueue.mProxyHost=new HttpHost(host, port, "http")    //sdk < 14

and better than Guillaume13's and MediumOne's answer(WebView android proxy) pseudocode:

android.webkit.JWebCoreJavaBridge.updateProxy(android.webkit.WebViewClassic.fromWebView(webview).mWebViewCore.mBrowserFrame.sJavaBridge, new android.net.ProxyProperties(...))   //sdk >= 14

but i don't know why that the proxy success only when i insert two lines before setProxy:

webview1.loadUrl("http://0.0.0.0");
try {Thread.sleep(100);} catch (Exception e) {}
ProxySettings.setProxy(getApplicationContext(), "192.168.0.109", 8081);
webview1.loadUrl("http://www.google.com/index.php");
Community
  • 1
  • 1
diyism
  • 12,477
  • 5
  • 46
  • 46
0

Firstly, thanks to you all for post codes for fixing proxy settings which its not exist public api to changes in android, its also helped me a lot. I have covered the issues in all of version android a see that it will be need to update this info. Depend on the summary answer of Jimmy above (thanks you !), I tested that its code running incorrectly on android version 3.0 - 3.1 because of android.net.ProxyProperties is not supported and the method updateProxy need for reflection have only by pass java.lang.String input parameter. So, I changed its code by the way, hope that it will helped people have the same issue as me:

/**
 * Set Proxy from 3.0.x - to 3.1.x API.
 * @param webview webview webview to apply proxy
 * @param host host name of proxy server
 * @param port port of proxy server
 * @return true/false if success or not
 */
private static boolean setProxyOnlyHC30to31(WebView webview, String host, int port) {
    try
    {
        Logger.d(ProxySettings.class, "Setting proxy from 3.0.x - 3.1.x API.");

        Class jwcjb = Class.forName("android.webkit.JWebCoreJavaBridge");
        Class params[] = new Class[1];
        params[0] = Class.forName("java.lang.String");
        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);

        updateProxyInstance.invoke(sJavaBridge, "http://" + host + ":" + port);

        Logger.d(ProxySettings.class, "Setting proxy from 3.0.x - 3.1.x API successful!");
        return true;
    }
    catch (Exception ex)
    {
        if (Helper.DEBUG) Logger.e(ProxySettings.class, "failed to set HTTP proxy: " + ex);
        return false;
    }
}
Fuong Lee
  • 175
  • 4