Альтернативный способ связи между WebView и нативным

Я использую WebView и много JavaScript в моем родном приложении. Если сторона JS хочет вызывать нативные функции, это довольно гладко, используя JavaScriptInterface, Однако, если native хочет вызвать функцию JS, это не так просто. Я пробовал два решения до сих пор:

  • призвание loadUrl метод с javascript:something() URL - недопустим, так как когда пользователь что-то печатает на клавиатуре WebView скрывает это после выполнения функции
  • запрашивать у нативной стороны функции каждые х секунд (представленный String объект) и вызов eval() на результат - иногда после установки интервала в 1 секунду я получал эти запросы через 50-60 секунд!

Мне интересно, есть ли другой способ реализовать эту модель общения. Допустим, создать местный Socket/HTTP/ что-то еще сервер внутри приложения и предоставить ему доступ к WebView, Я ищу любые советы, как (если это возможно) сделать это.

2 ответа

Решение

У меня есть следующий код, который использует отражение Java для вызова JavaScript из Java. Это позволяет избежать следующих ошибок loadUrl: 1. loadUrl может скрывать клавиатуру, когда вы фокусируетесь на входе. 2. loadUrl не может вызываться слишком часто.

Надеюсь, это поможет:

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);
            }
        }
    }
}

Я не знаю, как заставить работать альтернативную модель связи, но я думаю, что нашел решение для проблемы loadUrl-hides-the-keyboard: /questions/23277868/predotvratit-skryitie-knopok-na-myagkoj-klaviature-na-android/23277884#23277884. Это помогает?

Другие вопросы по тегам