Функция обратного вызова Javascript для Android - PullRequest
27 голосов
/ 11 августа 2011

У меня есть интерфейс javascript, реализованный на Java, который вызывается моим кодом javascript, загруженным в веб-просмотр.

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

Строка, загружаемая веб-представлением, в итоге выглядит так:

javascript:(function() {var callback = undefined; undefined();})()

У меня есть несколько идей:

a.Постройте обратный вызов в JS в виде строки.

b.Вызовите функцию обратного вызова toString () перед передачей ее в Android.myFunction ();

Мой вопрос: каков наилучший способ сделать это?Я хотел бы иметь возможность просто передавать объекты на Android, и это волшебным образом работает.Очевидно, это не тот случай.;) Каков следующий лучший способ сделать это?

Ответы [ 4 ]

37 голосов
/ 03 января 2013

У меня была похожая проблема: в веб-приложении я хотел бы использовать собственное диалоговое окно подтверждения 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).

12 голосов
/ 11 августа 2011

Вы не сможете передать функцию так, как вы ее указали. Вы передаете функцию в Android.myData, но Android.myData принимает строку. Вместо этого вы, вероятно, хотите

var myCallback = console.log;
Android.myFunction("myCallback");

У вас все еще есть проблема в том, что вы не передаете никакие данные в обратный вызов. Хотя это не имеет прямого отношения к вашему вопросу, оно станет проблемой, поскольку у вас будет та же проблема приведения к / из строки (решаемая с помощью JSON ... но было бы хорошо, если бы Android обработал эту часть для вас). *

Наконец, вы можете, вероятно, сократить javascript: string до

String js = "javascript:" + callback + "();";

Но, конечно, сначала тестируйте;)

5 голосов
/ 02 февраля 2017

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 в контексте отображаемой в данный момент страницы.Если не ноль, | resultCallback |будет вызван с любым результатом, возвращенным из этого выполнения.Этот метод должен вызываться в потоке пользовательского интерфейса, а обратный вызов будет выполняться в потоке пользовательского интерфейса.

Примечание о совместимости.В приложениях, ориентированных на N или более позднюю версию, состояние JavaScript из пустого WebView больше не сохраняется во всех навигациях, таких как loadUrl (String).Например, глобальные переменные и функции, определенные до вызова loadUrl (String), не будут существовать на загруженной странице.Приложения должны использовать addJavascriptInterface (Object, String) вместо того, чтобы сохранять объекты JavaScript при навигации.

Ссылка на официальную документацию WebView

0 голосов
/ 11 августа 2011

Насколько я понимаю, вы просто добавляете объект интерфейса 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 ОТ JS.

Чтобы вызвать JavaScript ИЗ Java-Android, вы должны позвонить:

myWebView.loadUrl("javascript:someJsFunctionICreated("hello javascript!");
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...