【问题标题】:Alternative way for communication between WebView and nativeWebView 和 native 之间通信的另一种方式
【发布时间】:2013-02-10 15:34:18
【问题描述】:

我在本机应用程序中使用WebView 和大量 JavaScript。如果 JS 端想调用原生函数,使用JavaScriptInterface 相当流畅。但是,如果 native 想要调用 JS 函数,就不是那么容易了。到目前为止,我已经尝试了两种解决方案:

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

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

【问题讨论】:

    标签: android android-webview


    【解决方案1】:

    我有以下代码,它使用 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);
                }
            }
        }
    }
    

    【讨论】:

    • 应该改变 private void loadJs -> public void loadJs;然后在我想调用 javascript 时使用 webview.loadJs 而不是 webview.loadUrl。
    【解决方案2】:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-05-10
      • 1970-01-01
      • 1970-01-01
      • 2013-02-14
      • 2020-10-07
      • 1970-01-01
      相关资源
      最近更新 更多