Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to get WebviewClient instance from WebView not on API 26 in Android?

I'm working on an SDK for Android. As part of this SDK, I need to set my own WebViewClient to a WebView of an application where the WebView and the SDK are integrated (meaning not part of my SDK).

For this reason, this WebView might have already been set with a WebViewClient and in this case, I need to get the instance of this WebViewClient from the WebView set my own WebViewClient to it and forward the callback methods of my WebViewCleint to the originally configured one that was set by the developer of the app.

I noticed that from API V26 there is a getWebViewClient method for the WebView class. but obviously, I'm looking for a way to do this on previous versions as well. Maybe there is some kind of way to do this using the support libs?

Does someone know how can I get the instance of the set WebViewClient in the WebView in older versions? using Reflection or any other method?

like image 265
Emil Adz Avatar asked Oct 30 '17 13:10

Emil Adz


1 Answers

I managed to get the instance of the WebViewClient using reflection like so:

Object providerInstance = getProviderInstance();
Object contentsClientAdapter = getContentsClientAdapter(providerInstance);
Object webViewClient = getWebViewClientFromClientAdapter(contentsClientAdapter);
if (webViewClient instanceof WebViewClient) {
    mPreviousWebViewClient = (WebViewClient) webViewClient;
}

And those are the three methods to drill down the WebView object to get the WebViewClient object:

public Object getProviderInstance() {
    Object returnValue = null;
    try {
        Class<? extends WebView> mWebViewClass = mWebView.getClass();
        Field providerField = mWebViewClass.getDeclaredField("mProvider");
        providerField.setAccessible(true);
        Object mProvider = providerField.get(mWebView);
        returnValue = mProvider;

    } catch (NoSuchFieldException aE) {
        aE.printStackTrace();
    } catch (IllegalAccessException aE) {
        aE.printStackTrace();
    }

    return returnValue;
}


private Object getContentsClientAdapter(Object aProviderInstance) {
    Object returnValue = null;
    try {
        Class<?> aClass = aProviderInstance.getClass();
        Field contentsClientAdapterField = aClass.getDeclaredField("mContentsClientAdapter");
        contentsClientAdapterField.setAccessible(true);
        Object mContentsClientAdapter = contentsClientAdapterField.get(aProviderInstance);
        returnValue = mContentsClientAdapter;

    } catch (NoSuchFieldException aE) {
        aE.printStackTrace();
    } catch (IllegalAccessException aE) {
        aE.printStackTrace();
    }

    return returnValue;
}


private Object getWebViewClientFromClientAdapter(Object aContentsClientAdapter) {
    Object returnValue = null;
    try {
        Class<?> aClass = aContentsClientAdapter.getClass();
        Field WebViewClientField = aClass.getDeclaredField("mWebViewClient");
        WebViewClientField.setAccessible(true);
        Object mWebViewClient = WebViewClientField.get(aContentsClientAdapter);
        returnValue = mWebViewClient;

    } catch (NoSuchFieldException aE) {
        aE.printStackTrace();
    } catch (IllegalAccessException aE) {
        aE.printStackTrace();
    }

    return returnValue;
}

But I'm really hoping to find some kind of another way to do the same. Something that will be less prone to breakage.

like image 173
Emil Adz Avatar answered Oct 01 '22 07:10

Emil Adz