OkHttp as HTTP Engine for WebView
DAMN DAMN DAMN IT WEBVIEW.
That was a bad idea, don't do it, see "why" post
http://artemzin.com/blog/android-webview-io/
If you have a WebView
in your Android app you may want to intercept its requests to handle them as you want, and for example load resources via OkHttp
.
NOTICE: this is mostly suitable only for cases when you use WebView
just for displaying information (only GET
requests, because on API < 21 you can not resolve method of the request GET
, POST
, etc), not for complex js applications running inside of your WebView
.
Reasons to switch to OkHttp
for loading WebView
resources:
- You can use latests version of
OkHttp
with support for modern protocols likeSPDY
andHTTP/2
! (BTW, we've boosted our app becauseNginx
on ourCDNs
supportsSPDY
!) - With
Stetho
andOkHttp-Stetho-Interceptor
you can easily inspect loading of resources inWebView
even on devices without support ofWebView
debugging! - With
OkHttp
you will use its connection pool and if you usually load resources from same endpoints that you use as your REST/etc APIs — you'll get a performance boost on reusing same connection.
How to do it?
Basically you need to:
- Attach
WebViewClient
to theWebView
- In your
WebViewClient
you should overrideshouldInterceptRequest(WebView webView, String url)
andshouldInterceptRequest(WebView webView, WebResourceRequest request)
(this method is for API >= 21). - Handle requests via
OkHttp
Intercept requests on API < 21
@SuppressWarnings("deprecation") // From API 21 we should use another overload
@Override
public WebResourceResponse shouldInterceptRequest(@NonNull WebView view, @NonNull String url) {
if (urlShouldBeHandledByWebView(url)) {
return super.shouldInterceptRequest(view, url);
}
return handleRequestViaOkHttp(url);
}
Intercept requests on API >= 21
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
@Override
public WebResourceResponse shouldInterceptRequest(@NonNull WebView view, @NonNull WebResourceRequest request) {
if (urlShouldBeHandledByWebView(url)) {
return super.shouldInterceptRequest(view, request);
}
return handleRequestViaOkHttp(url);
}
Decide what requests should be intercepted:
static boolean urlShouldBeHandledByWebView(@NonNull String url) {
// file: Resolve requests to local files such as files from cache folder via WebView itself
return url.startsWith("file:");
}
And finally, execute request via OkHttp
@NonNull
private WebResourceResponse handleRequestViaOkHttp(@NonNull String url) {
try {
// On Android API >= 21 you can get request method and headers
// As I said, we need to only display "simple" page with resources
// So it's GET without special headers
final Call call = okHttpClient.newCall(new Request.Builder()
.url(url)
.build()
);
final Response response = call.execute();
return new WebResourceResponse(
response.header("content-type", "text/plain"), // You can set something other as default content-type
response.header("content-encoding", "utf-8"), // Again, you can set another encoding as default
response.body().byteStream()
);
} catch (Exception e) {
return ...; // return response for bad request
}
}