WebView Android 代理

发布于 2024-10-08 18:17:29 字数 207 浏览 3 评论 0原文

我知道如何手动设置代理并在我的 WebView 中使用它。

设置->无线网络 -> 移动网络 -> 无线网络接入点名称->telkila。现在输入代理服务器地址和端口(为 80)。 WebView.enablePlatformNotifications();

但是我可以从代码中设置代理设置吗? 那么我的用户不必手动设置?

谢谢

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(10

南笙 2024-10-15 18:17:29

我已经调整了此处介绍的三种解决方案(并修改了失败的一个),以生成适用于所有版本的 Android 的单一、简单的 setProxy 方法。我已经对它进行了 10 到 18 次测试,它适用于所有测试环境。

更新于 2014-04-04 我终于根据下面的评论找到了解决方案,由 nubela 和 xjy2061 提供。现在,这适用于所有当前的 Android 版本,包括 KitKat 4.4。如果您实现自己的应用程序子类,请提供类的名称作为可选的第四个参数。

更新于 2015-01-15 KitKat 方法中标记为可选的部分会在 Lollipop 上引发异常,因为缺少辅助类,但如果没有辅助类,它就可以在 KitKat 和 Lollipop 上运行,因为 WebView 是基于两种情况下都含有铬。

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

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

没有合法的方法可以通过编程方式更改您的 webview 代理设置。但可以使用 java 反射来更改 android.net.http.RequestQueue 类中的 mProxyHost 值。它是私有值,并且没有设置器,因此反射似乎是唯一可能的变体。我在我的项目中使用了它并且它有效。这是我的方法的示例:

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

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;      
}
往事风中埋 2024-10-15 18:17:29

我已经做了很多测试,我可以说之前使用基于 android.net.http.RequestQueue 的覆盖的响应从 android 1.6 到 3.1 都能完美运行。

但对 API 进行了代码重构,使其能够在 Android 3.2 和 Android 3.2 上运行。 4.x,这里是解决方案:

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)
{    
}

享受

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

最近可好 2024-10-15 18:17:29

当 api >= 29 时:

implementation 'androidx.webkit:webkit:1.4.0'

将其添加到 app/build.gradle,然后

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

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
    }
}
豆芽 2024-10-15 18:17:29

正如@Karthik 所说,这些答案不适用于 android 4.4(KitKat)。
对于 KitKat,答案发布在此处

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

苏大泽ㄣ 2024-10-15 18:17:29

Chromium 已开始在新版本中混淆类名(ProxyChangeListener 的类名在最新版本中似乎是“bMh”,并且可能在未来版本中更改。因此 Jimmy Dee 的解决方案将不再适用于较新的版本,因为以下检查将始终失败:

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

我想到的解决方案是在当前应用程序中的所有广播接收器上调用 onReceive - 。

现在我明白这不是一个理想的解决方案,因为它可能会通过调用错误的接收器产生不必要的副作用,并且应该仔细检查应用程序上下文中的所有广播接收器以确保它们不会做任何坏事(任何其他接收器) 想法?)

基于之前的答案,它会是这样的:

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

如果社区中有人有更好的想法,那将非常有帮助。

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.

撩心不撩汉 2024-10-15 18:17:29
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;

我删除了 applicationclassname 的使用。
它在 Android 7.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

ゝ偶尔ゞ 2024-10-15 18:17:29

这是 4.1 和 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;
}

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;
}
℡寂寞咖啡 2024-10-15 18:17:29

madeye的解决方案 https://gist.github.com/madeye/2297083 伪代码:

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

优于Birdy 的答案(WebView android proxy)伪代码:

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

比 Guillaume13 和 MediumOne 的答案更好(WebView android代理)伪代码:

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

但我不知道为什么只有当我插入两行时代理才成功设置代理之前:

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");

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");
妥活 2024-10-15 18:17:29

首先,感谢大家提供用于修复代理设置的邮政代码,它不存在用于更改 Android 的公共 api,它也对我有很大帮助。我已经涵盖了所有 Android 版本中的问题,并且看到需要更新此信息。取决于上面吉米的总结答案(谢谢!),我测试了它的代码在 android 版本 3.0 - 3.1 上运行不正确,因为不支持 android.net.ProxyProperties 并且方法 updateProxy 需要反射时只需传递 java.lang.String 输入参数。所以,我顺便改变了它的代码,希望它能帮助那些和我有同样问题的人:

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

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;
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文