Подтвердить что ты не робот

Функция обратного вызова 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, и это волшебство срабатывает. Очевидно, это не так.;) Каков следующий лучший способ сделать это?

4b9b3361

Ответ 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!");