TLS 1.1, 1.2 in WebView for android <= 4.3
Asked Answered
T

2

7

In my android application I need to display 3rd-party registration form inside WebView. Unfortunately, I need to also support android versions < 4.3, where you get SSL handshake error when you connect to the website. I was, however, able to create direct requests on android 4.1+ with a custom SSL context which has TLS 1.1 explicitly enabled, but I can't pass this SSL context into my WebView. I tried to make custom WebViewClient

    private WebViewClient webViewClient = new WebViewClient() {
    @Override
    public void onPageFinished(WebView webView, String url) {
        if (presenter != null) {
            presenter.onLoadFinished();
        }
    }

    @Override
    public void onReceivedError(WebView webView,
                                WebResourceRequest request,
                                WebResourceError error) {
        if (presenter != null) {
            presenter.onLoadError();
        }
    }

    @Override
    public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error){
        handler.proceed();
    }

    @Override
    public boolean shouldOverrideUrlLoading(WebView webView, String url) {
                Request request = new Request.Builder().url(url).build();
    final Handler handler = new Handler(mContext.getMainLooper());
    //mOkHttpClient is an OkHttpClient with my custom SSLContext which has TLS 1.1 and TLS 1.2 enabled
    mOkHttpClient.newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {

            }

            @Override
            public void onResponse(Call call, final okhttp3.Response response) throws IOException {
                handler.post(new Runnable() {
                    @Override
                    public void run() {
                        try {
                            webView.loadDataWithBaseURL(
                                    null, response.body().string(), "text/html", "utf-8", null);
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                });
            }
        });
    }

};

But that didn't work since shouldOverrideUrlLoading is not called on POST requests.

Is there a way to make this work(probably some alternative to WebView)? Any help is appreciated.

Thrave answered 30/4, 2016 at 6:45 Comment(0)
U
3

I'm not sure if you can make it work with the current WebView but I would recommend you to have a look at: https://crosswalk-project.org/documentation/android.html to replace the WebView.

This is built upon latest version of Chrome and you won't have problems with that version of Android the user is running on.

I'm sure there are other alternatives too, but this is the one I'm using for work and I know work.

Best of luck to you.

Undercoat answered 30/4, 2016 at 7:3 Comment(0)
S
0

Android version with KitKat below ssl and tsl is not supported with some versions..

You can support within hacking way to support below Kitkat

1-)Load page as string with "Retrofit or OkHttp" and load webview as string

implementation 'com.squareup.retrofit2:converter-scalars:2.1.0'

function

public void getHtml(){

        OkHttpClient client=new OkHttpClient();
        try {
            TLSSocketFactory tlsSocketFactory=new TLSSocketFactory();
            if (tlsSocketFactory.getTrustManager()!=null) {
                OkHttpClient.Builder builder = new OkHttpClient.Builder();
                builder.sslSocketFactory(tlsSocketFactory, tlsSocketFactory.getTrustManager());
                client = builder
                        .build();
            }
        } catch (KeyManagementException e) {
            e.printStackTrace();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (KeyStoreException e) {
            e.printStackTrace();
        }


       Retrofit retrofit = new Retrofit.Builder()
                .baseUrl(columnist.getYaziAdress()+"/")
               .client(client)
               .addConverterFactory(ScalarsConverterFactory.create())
                .build();





        ApiEndPoint apiService =
                retrofit.create(ApiEndPoint.class);

        Call<ResponseBody> call = apiService.url(columnist.getYaziAdress());



        call.enqueue(new Callback<ResponseBody>() {
            @Override
            public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {

                try {
                   // yazarText.loadDataWithBaseURL(null,response.body().string(),"text/html", "utf-8", null);
                    String a = response.body().string();

                    yazarText.loadData(a, "text/html; charset=utf-8", "UTF-8");
                    yazarText.getSettings().setUserAgentString("Android");
                    yazarText.getSettings().setUseWideViewPort(true);

                }catch (Exception e){

                }
            }
            @Override
            public void onFailure(Call<ResponseBody> call, Throwable t) {


                Toast.makeText(ArticleActivity.this,getString(R.string.ttsNull),Toast.LENGTH_LONG).show();

            }
        });
    }

TLSSocketFactory class

public class TLSSocketFactory extends SSLSocketFactory {

    private SSLSocketFactory delegate;
    private TrustManager[] trustManagers;

    public TLSSocketFactory() throws KeyManagementException, NoSuchAlgorithmException, KeyStoreException {
        generateTrustManagers();
        SSLContext context = SSLContext.getInstance("TLS");
        context.init(null, trustManagers, null);
        delegate = context.getSocketFactory();
    }

    private void generateTrustManagers() throws KeyStoreException, NoSuchAlgorithmException {
        TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
        trustManagerFactory.init((KeyStore) null);
        TrustManager[] trustManagers = trustManagerFactory.getTrustManagers();

        if (trustManagers.length != 1 || !(trustManagers[0] instanceof X509TrustManager)) {
            throw new IllegalStateException("Unexpected default trust managers:"
                    + Arrays.toString(trustManagers));
        }

        this.trustManagers = trustManagers;
    }


    @Override
    public String[] getDefaultCipherSuites() {
        return delegate.getDefaultCipherSuites();
    }

    @Override
    public String[] getSupportedCipherSuites() {
        return delegate.getSupportedCipherSuites();
    }

    @Override
    public Socket createSocket() throws IOException {
        return enableTLSOnSocket(delegate.createSocket());
    }

    @Override
    public Socket createSocket(Socket s, String host, int port, boolean autoClose) throws IOException {
        return enableTLSOnSocket(delegate.createSocket(s, host, port, autoClose));
    }

    @Override
    public Socket createSocket(String host, int port) throws IOException, UnknownHostException {
        return enableTLSOnSocket(delegate.createSocket(host, port));
    }

    @Override
    public Socket createSocket(String host, int port, InetAddress localHost, int localPort) throws IOException, UnknownHostException {
        return enableTLSOnSocket(delegate.createSocket(host, port, localHost, localPort));
    }

    @Override
    public Socket createSocket(InetAddress host, int port) throws IOException {
        return enableTLSOnSocket(delegate.createSocket(host, port));
    }

    @Override
    public Socket createSocket(InetAddress address, int port, InetAddress localAddress, int localPort) throws IOException {
        return enableTLSOnSocket(delegate.createSocket(address, port, localAddress, localPort));
    }

    private Socket enableTLSOnSocket(Socket socket) {
        if(socket != null && (socket instanceof SSLSocket)) {
            ((SSLSocket)socket).setEnabledProtocols(new String[] {"TLSv1.1", "TLSv1.2"});
        }
        return socket;
    }

    @Nullable
    public X509TrustManager getTrustManager() {
        return  (X509TrustManager) trustManagers[0];
    }

}

Api end point

@GET()
Call<ResponseBody> url(@Url String url);

2-) Use Php script which return html as string to your application

Sinfonietta answered 27/5, 2020 at 9:18 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.