WebView和本机之间通信的替代方式

时间:2013-02-25 13:14:45

标签: android android-webview

我在我的原生应用程序中使用WebView和许多JavaScript。如果JS方想要调用本机函数,那么使用JavaScriptInterface就可以了。但是,如果native希望调用JS函数,那就不那么容易了。到目前为止,我尝试了两种解决方案:

  • 使用loadUrl网址调用javascript:something()方法 - 不可接受,因为当用户在键盘WebView上键入内容时,会在执行功能后隐藏它
  • 每x秒询问本机一侧的功能(由String对象提供)和 在结果上调用eval() - 有时在设置间隔1秒后,我在50-60秒后收到这些请求!

我想知道是否还有其他方法可以完成这种通信模式。假设在应用内创建本地Socket / HTTP / something-else服务器,并将其访问权限WebView。我正在寻找任何提示(如果可能的话)。

2 个答案:

答案 0 :(得分:3)

我有以下代码,它使用java反射从Java调用JavaScript。它避免了以下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);
            }
        }
    }
}

答案 1 :(得分:1)

我不知道如何让备用通信模型正常工作,但我想我已经找到了loadUrl-hides-the-keyboard问题的解决方法:https://stackoverflow.com/a/18776064/513038。这对你有帮助吗?