android <= 4.3 的 WebView 中的 TLS 1.1、1.2
TLS 1.1, 1.2 in WebView for android <= 4.3
在我的 android 应用程序中,我需要在 WebView
中显示第 3 方注册表单。不幸的是,我还需要支持 android 版本 < 4.3,当您连接到该网站时会出现 SSL 握手错误。然而,我能够使用明确启用 TLS 1.1 的自定义 SSL 上下文在 android 4.1+ 上创建直接请求,但我无法将此 SSL 上下文传递到我的 WebView
。我尝试自定义 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();
}
}
});
}
});
}
};
但这不起作用,因为 POST 请求未调用 shouldOverrideUrlLoading
。
有没有办法使这项工作(可能是 WebView
的替代方法)?任何帮助表示赞赏。
我不确定你是否可以让它与当前的 WebView 一起工作,但是
我建议您看一下:https://crosswalk-project.org/documentation/android.html 来替换 WebView。
这是建立在最新版本的 Chrome 和
使用 Android 用户 运行 的那个版本不会有问题。
我敢肯定还有其他选择,但这是我工作中使用的那个,我知道工作。
祝你好运。
Android KitKat 低于 ssl 和 tsl 的版本不支持某些版本..
你可以在hacking方式下支持Kitkat
1-)Load page as string with "Retrofit or OkHttp" and load webview as
string
implementation 'com.squareup.retrofit2:converter-scalars:2.1.0'
函数
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终点
@GET()
Call<ResponseBody> url(@Url String url);
2-) 使用 Php 脚本 return html 作为应用程序的字符串
在我的 android 应用程序中,我需要在 WebView
中显示第 3 方注册表单。不幸的是,我还需要支持 android 版本 < 4.3,当您连接到该网站时会出现 SSL 握手错误。然而,我能够使用明确启用 TLS 1.1 的自定义 SSL 上下文在 android 4.1+ 上创建直接请求,但我无法将此 SSL 上下文传递到我的 WebView
。我尝试自定义 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();
}
}
});
}
});
}
};
但这不起作用,因为 POST 请求未调用 shouldOverrideUrlLoading
。
有没有办法使这项工作(可能是 WebView
的替代方法)?任何帮助表示赞赏。
我不确定你是否可以让它与当前的 WebView 一起工作,但是 我建议您看一下:https://crosswalk-project.org/documentation/android.html 来替换 WebView。
这是建立在最新版本的 Chrome 和 使用 Android 用户 运行 的那个版本不会有问题。
我敢肯定还有其他选择,但这是我工作中使用的那个,我知道工作。
祝你好运。
Android KitKat 低于 ssl 和 tsl 的版本不支持某些版本..
你可以在hacking方式下支持Kitkat
1-)Load page as string with "Retrofit or OkHttp" and load webview as string
implementation 'com.squareup.retrofit2:converter-scalars:2.1.0'
函数
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终点
@GET()
Call<ResponseBody> url(@Url String url);
2-) 使用 Php 脚本 return html 作为应用程序的字符串