WebView与本地应用程序之间的替代通信方式

3
我正在使用WebView和大量的JavaScript在我的本地应用程序中。如果 JS 侧想要调用本地函数,可以使用JavaScriptInterface,这相当顺畅。然而,如果本地想要调用 JS 函数,则不那么容易。到目前为止,我尝试过两种解决方案:
  • 使用带有javascript:something() URL的loadUrl方法进行调用 -- 这是不可接受的,因为当用户在键盘上输入时,WebView 在函数执行后会将其隐藏。
  • 每 x 秒向本地端请求函数(使用String对象表示)并对结果调用eval() -- 有时在将间隔设置为1秒后,我会在50-60秒后收到这些请求!
我想知道是否有其他方法来实现此通信模型。例如,在应用程序内创建本地Socket/HTTP/其他服务器,并允许WebView访问它。我正在寻找任何提示,如何(如果可能)做到这一点。
2个回答

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

应更改 private void loadJs -> public void loadJs;,然后在调用 JavaScript 时使用 webview.loadJs 而不是 webview.loadUrl。 - o0omycomputero0o

1

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接