Альтернативный способ связи между 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. Это помогает?