Функция обратного вызова Javascript переходит на Android
У меня есть интерфейс javascript, реализованный в Java, который вызывается моим кодом javascript, который загружается в webview.
JS Inside webview:
Android.myFunction(function(data){
console.log(data);
});
Java:
public class JavaScriptInterface {
Context context;
WebView webView;
JavaScriptInterface(Context c, WebView w) {
context = c;
webView = w;
}
public void myFunction(String callback) {
//when I log callback, it is "undefined"
String someData = "Yay for data";
String js =
"javascript:(function() { "
+ "var callback = " + callback + ";"
+ "callback('" + someData + "');"
+ "})()";
webView.loadUrl(js);
}
}
Строка, загружаемая webview, заканчивается:
javascript:(function() {var callback = undefined; undefined();})()
У меня есть несколько идей:
а. Создайте обратный вызов в JS как строку.
б. Вызовите обратный вызов toString(), прежде чем передавать его на Android.myFunction();
Мой вопрос в том, что это лучший способ сделать это? Я хотел бы иметь возможность просто передавать объекты на Android, и это волшебство срабатывает. Очевидно, это не так.;) Каков следующий лучший способ сделать это?
Ответы
Ответ 1
Вы не сможете передать функцию в том, как вы ее указали. Вы передаете функцию в Android.myData, но Android.myData берет строку. Вместо этого вы, вероятно, захотите
var myCallback = console.log;
Android.myFunction("myCallback");
У вас все еще есть проблема в том, что вы не передаете данные для обратного вызова. Хотя это напрямую не связано с вашим вопросом, это станет проблемой, так как у вас будет такая же проблема с отправкой/из строки (разрешимая через JSON... но было бы неплохо, если Android обработал эту часть для вас).
Наконец, вы, вероятно, можете сократить строку javascript:
String js = "javascript:" + callback + "();";
Но, конечно, сначала проверьте тест;)
Ответ 2
У меня была аналогичная проблема: изнутри веб-приложения я хотел бы использовать собственный диалог подтверждения Android. Это означает, что мне нужно перезвонить из Android в часть Javascript с результатом диалога подтверждения.
Я решил это следующим образом:
function foo() {
// user confirmation needed
var dataString = <encode data into string>;
MyClient.showConfirmationDialog('myCallBackFunction', dataString, 'A title', 'A message');
}
Приведенный выше код вызывает интерфейс JavaScript javascript (см. ниже). Javascript предоставляет метод обратного вызова myCallbackFunction()
, имя которого передается на Android как параметр (вместе с строкой данных, заголовком и сообщением). Функция обратного вызова выглядит следующим образом:
function myCallbackFunction(dataString, result) {
var data = <decode data from dataString>;
if (result) {
// user has confirmed
} else {
// user has denied
}
}
На стороне Android я сначала активирую интерфейс Javascript в методе Activity onCreate()
:
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
WebView webView = new WebView(this);
setContentView(webView);
WebSettings settings = webView.getSettings();
settings.setJavaScriptEnabled(true);
webView.addJavascriptInterface(new MyJavascriptInterface(webView), "MyClient");
}
Реализация MyJavascriptInterface
затем создает соответствующее диалоговое окно Android и передает результат обратно в javascript:
WebView webView;
public MyJavascriptInterface(WebView w) {
this.webView = w;
}
@JavascriptInterface
public void showConfirmationDialog(final String callbackFunction, final String data, String title,
String message) {
Dialog.OnClickListener positiveListener = new Dialog.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
webView.loadUrl("javascript:" + callbackFunction + "('" + data + "', true)");
}
};
Dialog.OnClickListener negativeListener = new Dialog.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
webView.loadUrl("javascript:" + callbackFunction + "('" + data + "', false)");
}
};
AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
builder.setTitle(title).setMessage(message).setPositiveButton("Ok", positiveListener)
.setNegativeButton("Cancel", negativeListener).setCancelable(false);
builder.create().show();
}
Передача имени функции обратного вызова на Android позволяет использовать несколько вызовов в диалоговых окнах подтверждения, каждая из которых оснащена собственной функцией, выполняет фактическое действие. Строка данных будет содержать все данные, необходимые для выполнения действия (и может содержать даже Json-закодированные объекты).
Ответ 3
WebView позволяет вам напрямую выполнять JavaScript в контексте окна.
Поэтому вам не нужно передавать JavaScript через URL-адрес ресурса.
Это одобренный способ передачи данных на страницу html
/**
* This is an approved way to pass data back to the html page
*/
webView.evaluateJavascript("alert('pass here some ...')", new ValueCallback<String>() {
@Override
public void onReceiveValue(String s) {
}
});
Подробная информация из официальной документации
Асинхронно оценивает JavaScript в контексте отображаемой на данный момент страницы. Если не null, | resultCallback | будет вызываться с любым результатом, возвращенным из этого выполнения. Этот метод должен быть вызван в потоке пользовательского интерфейса, и обратный вызов будет выполнен в потоке пользовательского интерфейса.
Замечание о совместимости. Приложения с таргетингом N или более поздней версии, состояние JavaScript из пустого WebView больше не сохраняется в навигациях, таких как loadUrl (String). Например, глобальные переменные и функции, определенные до вызова loadUrl (String), не будут существовать на загруженной странице. Приложения должны использовать addJavascriptInterface (Object, String) вместо этого для сохранения объектов JavaScript в навигациях.
Ссылка на официальную документацию WebView
Ответ 4
Из того, что я понимаю, вы просто добавляете объект интерфейса Java в свой веб-просмотр. Затем в javascript вы можете вызвать это, вызвав myJavaInterface.doEchoTest(stringToEcho). Способ, которым вы присоединяете метод, выглядит следующим образом:
myWebView.addJavascriptInterface(MyJavaInterface, "MyJavaInterface");
Вот интерфейс в java:
public class MyJavaInterface{
private WebView mAppView;
public MyJavaInterface (WebView appView) {
this.mAppView = appView;
}
public void doEchoTest(String echo){
Toast toast = Toast.makeText(mAppView.getContext(), echo, Toast.LENGTH_SHORT);
toast.show();
}
}
Итак, теперь вы можете позвонить в JAVA-Android FROM JS.
Чтобы вызвать JavaScript FROM Java-Android, вы должны позвонить:
myWebView.loadUrl("javascript:someJsFunctionICreated("hello javascript!");