title: Using webview and proxy with authentication
body: <p>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 (<a href="https://stackoverflow.com/a/18453384/7478869">https://stackoverflow.com/a/18453384/7478869</a>), and it works with proxy without authentication. But I need to set the proxy with user and password.</p>
  
  <p>Some approaches, that didn't help:</p>
  
  <p>1) Load url with headers</p>
  
  <pre><code>   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&lt;String, String&gt; header = new HashMap&lt;String, String&gt;();
      header.put(credHeader.getName(), credHeader.getValue());
      view.loadUrl(url, header);
  }
  </code></pre>
  
  <p>2) Add password and user in setProxy method (full code below):</p>
  
  <pre><code>        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 );
  </code></pre>
  
  <p>But I am still getting this error</p>
  
  <pre><code>[WARNING:http_network_transaction.cc(339)] Blocked proxy response with status 407 to CONNECT request for example.com:443
  </code></pre>
  
  <p>And in WebView: ERR_TUNNEL_CONNECTION_FAILED</p>
  
  <p>Full code:</p>
  
  <pre><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&lt;String, String&gt; header = new HashMap&lt;String, String&gt;();
      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 &gt;= 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 &gt;= 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;
    }
  }
  </code></pre>
  
  <p>How to use a proxy with authentication in WebView properly? </p>