7

I need to load some url in WebView that is unavailable in one country, so I tried to use a proxy with WebView. I've found one solution on SO (https://stackoverflow.com/a/18453384/7478869), and it works with proxy without authentication. But I need to set the proxy with user and password.

Some approaches, that didn't help:

1) Load url with headers

   class ProxyAuthWebViewClient extends WebViewClient {
    String proxyUserName;
    String proxyPassword;
    public ProxyAuthWebViewClient(String proxyUserName, String proxyPassword){
        this.proxyUserName = proxyUserName;
        this.proxyPassword = proxyPassword;
    }
    @Override
    public boolean shouldOverrideUrlLoading(WebView view, String url) {
        loadUrl(view, url, proxyUserName, proxyPassword);
        return true ;
    }
}

public void loadUrl(WebView view, String url, String proxyUserName, String proxyPassword){
    UsernamePasswordCredentials creds= new UsernamePasswordCredentials(proxyUserName, proxyPassword);
    Header credHeader = BasicScheme.authenticate(creds, "UTF-8", true);
    Map<String, String> header = new HashMap<String, String>();
    header.put(credHeader.getName(), credHeader.getValue());
    view.loadUrl(url, header);
}

2) Add password and user in setProxy method (full code below):

        Authenticator.setDefault(
            new Authenticator() {
                @Override
                public PasswordAuthentication getPasswordAuthentication() {
                    return new PasswordAuthentication(
                            user, password.toCharArray());
                }
            }
    );

    System.setProperty("http.proxyUser", user);
    System.setProperty("http.proxyPassword", password);
    System.setProperty("https.proxyUser", user);
    System.setProperty("https.proxyPassword", password );

But I am still getting this error

[WARNING:http_network_transaction.cc(339)] Blocked proxy response with status 407 to CONNECT request for example.com:443

And in WebView: ERR_TUNNEL_CONNECTION_FAILED

Full code:

public class MainActivity extends AppCompatActivity {
public static final String LOG_TAG = "Main";
WebView webview;
String applicationClassName="android.app.Application";
String user = "web";
String password = "password";

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    webview = findViewById(R.id.webview);
    webview.getSettings().setJavaScriptEnabled(true);

    String databasePath = webview.getContext().getApplicationContext().getDir("database", Context.MODE_PRIVATE).getPath();
    webview.getSettings().setCacheMode(WebSettings.LOAD_NO_CACHE);
    webview.getSettings().setRenderPriority(WebSettings.RenderPriority.HIGH);
    webview.getSettings().setDatabaseEnabled(true);
    webview.getSettings().setDatabasePath(databasePath);
    webview.getSettings().setAppCacheMaxSize(5 * 1048576);
    webview.getSettings().setAppCachePath(databasePath);
    webview.getSettings().setAppCacheEnabled(true);
    webview.getSettings().setLoadWithOverviewMode(true);
    webview.getSettings().setDomStorageEnabled(true);
    webview.getSettings().setJavaScriptEnabled(true);
    webview.getSettings().setJavaScriptCanOpenWindowsAutomatically(true);
    webview.getSettings().setLayoutAlgorithm(WebSettings.LayoutAlgorithm.NORMAL);

    setProxy(webview, "85.10.195.100", 443, applicationClassName, user, password);
    webview.setWebViewClient(new ProxyAuthWebViewClient(user,password));
    loadUrl(webview,"https://example.com",user,password);

}

class ProxyAuthWebViewClient extends WebViewClient {
    String proxyUserName;
    String proxyPassword;
    public ProxyAuthWebViewClient(String proxyUserName, String proxyPassword){
        this.proxyUserName = proxyUserName;
        this.proxyPassword = proxyPassword;
    }
    @Override
    public boolean shouldOverrideUrlLoading(WebView view, String url) {
        loadUrl(view, url, proxyUserName, proxyPassword);
        return true ;
    }
}

public void loadUrl(WebView view, String url, String proxyUserName, String proxyPassword){
    UsernamePasswordCredentials creds= new UsernamePasswordCredentials(proxyUserName, proxyPassword);
    Header credHeader = BasicScheme.authenticate(creds, "UTF-8", true);
    Map<String, String> header = new HashMap<String, String>();
    header.put(credHeader.getName(), credHeader.getValue());
    view.loadUrl(url, header);
}


public static boolean setProxy(WebView webview, String host, int port, String applicationClassName, String user,
                               String password) {
        return setProxyKKPlus(webview, host, port, user, password, applicationClassName);
}


// 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, final String user,
                                      final String password, 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 + "");


    Authenticator.setDefault(
            new Authenticator() {
                @Override
                public PasswordAuthentication getPasswordAuthentication() {
                    return new PasswordAuthentication(
                            user, password.toCharArray());
                }
            }
    );

    System.setProperty("http.proxyUser", user);
    System.setProperty("http.proxyPassword", password);
    System.setProperty("https.proxyUser", user);
    System.setProperty("https.proxyPassword", password );

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

How to use a proxy with authentication in WebView properly?

1 Answer 1

10

Ok, so I Found the answer. Need to add onReceivedHttpAuthRequest in WebViewClient

 @Override
        public void onReceivedHttpAuthRequest(WebView view, HttpAuthHandler handler, String host, String realm) {
            handler.proceed(user,password);
        }
Sign up to request clarification or add additional context in comments.

2 Comments

thanks for the answer, any chance you know how to configure a HTTPS proxy? your method seems to work only for HTTP
yeah, i was checking it yesterday, i can use https connection as well but not from NordVPN, the connection is reset by the server for some other reason probably. I wish i knew what I'm missing

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.