Piotr
Piotr

Reputation: 1753

Alternative way for communication between WebView and native

I am using WebView and a lot of JavaScript in my native application. If JS side wants to call native functions it's rather smooth using JavaScriptInterface. However, if native wants to call JS function it's not so easy. I've tried two solutions so far:

I am wondering if there's any other way to accomplish this communication model. Let's say create local Socket/HTTP/something-else server inside app and give access for it to WebView. I am looking for any tips how (if it's possible) do that.

Upvotes: 3

Views: 3575

Answers (2)

Erhannis
Erhannis

Reputation: 4464

I don't know how to get an alternate communication model working, but I think I've found a workaround for the loadUrl-hides-the-keyboard issue: https://stackoverflow.com/a/18776064/513038. Does that help any?

Upvotes: 1

Jonny Chen
Jonny Chen

Reputation: 84

I have the following code which uses java reflection to call JavaScript from Java. It avoids the following loadUrl bugs: 1. loadUrl may hide keyboard when your focus in a input. 2. loadUrl cannot be called too often.

Hopefully this helps:

public class AdvancedWebView extends WebView {
    private static final int EXECUTE_JS = 194;
    Method sendMessageMethod;
    Object webViewCore;
    boolean initFailed = false;;
    InputMethodManager imm;


    public AdvancedWebView(Context context, AttributeSet attrs) {
        super(context, attrs);
        imm = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE);
        this.getSettings().setJavaScriptEnabled(true);
        this.initReflection();
    }

    @SuppressWarnings("rawtypes")
    private void initReflection() {
        Object webViewObject = this;
        Class webViewClass = WebView.class;
        try {
            Field f = webViewClass.getDeclaredField("mProvider");
            f.setAccessible(true);
            webViewObject = f.get(this);
            webViewClass = webViewObject.getClass();
        } catch (Throwable e) {
            // mProvider is only required on newer Android releases.
        }       

        try {
            Field f = webViewClass.getDeclaredField("mWebViewCore");
            f.setAccessible(true);
            webViewCore = f.get(webViewObject);
            if (webViewCore != null) {
                sendMessageMethod = webViewCore.getClass().getDeclaredMethod("sendMessage", Message.class);
                sendMessageMethod.setAccessible(true);      
                System.out.println("sendMessageMethod-----"+sendMessageMethod);
            }
            hasIntercepted = true;
        } catch (Throwable e) {
            hasIntercepted = false;
            //Log.e(LOG_TAG, "PrivateApiBridgeMode failed to find the expected APIs.", e);
        }finally{
            if(sendMessageMethod == null)
            {
                hasIntercepted = false;
            }
        }
    }

    private void loadJs(String url) {
        if (sendMessageMethod == null && !initFailed) {
            initReflection();
        }
        // webViewCore is lazily initialized, and so may not be available right away.
        if (sendMessageMethod != null) {
            //String js = popAndEncodeAsJs();
            Message execJsMessage = Message.obtain(null, EXECUTE_JS, url);
            try {
                sendMessageMethod.invoke(webViewCore, execJsMessage);
            } catch (Throwable e) {
                //Log.e(LOG_TAG, "Reflection message bridge failed.", e);
            }
        }
    }
}

Upvotes: 3

Related Questions