La fonction de rappel Javascript passe à Android

j'ai une interface javascript implémentée en Java qui est appelée par mon code javascript qui est chargé dans le webview.

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

la chaîne qui est chargée par webview finit par être:

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

j'ai quelques idées:

A. Construisez le callback dans JS comme une chaîne.

b. Appeler la fonction de rappel de l'toString() avant de passer à Android.myFunction ();

Mon la question est, quelle est la meilleure façon de le faire? J'aimerais pouvoir passer des objets à Android et ça marche comme par magie. Évidemment, ce n'est pas le cas. ;) Ce qui est la meilleure façon de le faire?

23
demandé sur Jonathan 2011-08-11 03:39:31

4 réponses

Vous ne serez pas en mesure de passer à la fonction de comment vous l'avez spécifié. Vous passez une fonction à Android.myData, mais Androïde.myData prend une ficelle. Au lieu de cela, vous voulez probablement

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

vous avez toujours un problème en ce sens que vous ne transmettez aucune donnée au rappel. Bien que ce ne soit pas directement lié à votre question, il deviendra un problème puisque vous aurez la même distribution à/de string issue (soluble via JSON... mais ce serait bien si Androïde manipulait cette partie pour vous.)

enfin, vous pouvez probablement raccourcir la chaîne javascript: string à

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

Mais, bien sûr, d'abord le test ;)

11
répondu David Souther 2011-08-11 16:54:27

j'ai eu un problème similaire: à partir d'une application web, j'aimerais utiliser une boîte de dialogue natif de confirmation Android. Cela implique que je dois rappeler depuis Android dans la partie Javascript avec le résultat du dialogue de confirmation.

j'ai résolu ce problème comme suit:

function foo() {
    // user confirmation needed
    var dataString = <encode data into string>;
    MyClient.showConfirmationDialog('myCallBackFunction', dataString, 'A title', 'A message');
}

le code ci-dessus appelle l'interface javascript Android (voir ci-dessous). Le javascript fournit la méthode de rappel myCallbackFunction(), dont le nom est passé à Android comme paramètre (avec une donnée chaîne, un titre et un message). La fonction de rappel se présente comme suit:

function myCallbackFunction(dataString, result) {
    var data = <decode data from dataString>;
    if (result) {
        // user has confirmed
    } else {
        // user has denied
    }
}

côté Android, j'active d'abord L'interface Javascript dans l'activité onCreate() méthode:

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

la mise en oeuvre de MyJavascriptInterface crée ensuite la boîte de dialogue Android correspondante et renvoie le résultat à 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();
    }

passer le nom de la fonction de rappel à Android permet d'utiliser plusieurs appels aux dialogues de confirmation, dont chacun est équipé une fonction fait l'action. La chaîne de données portera toutes les données nécessaires pour effectuer l'action (et peut même contenir des objets encodés par Json).

32
répondu csoltenborn 2017-07-18 16:59:51

le WebView vous permet d'exécuter directement du JavaScript dans le contexte de la fenêtre. Vous n'avez donc pas besoin de passer JavaScript via l'URL de la ressource .

C'est une façon approuvée de renvoyer des données à la page 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) {

        }
    });

Détails à partir de la documentation officielle

évalue asynchrone JavaScript dans le contexte de la page actuellement affichée. Si non-null, |resultCallback / sera invoqué avec n'importe quel résultat retourné de cette exécution. Ce la méthode doit être appelée Sur le thread de L'UI et le rappel sera effectué sur le thread de L'UI.

note de compatibilité. Applications ciblant N ou plus tard, L'état JavaScript à partir d'un WebView vide n'est plus persisté à travers les navigateurs comme loadUrl(String). Par exemple, les variables globales et les fonctions définies avant l'appel de loadUrl(String) n'existeront pas dans la page chargée. Les Applications doivent utiliser addJavascriptInterface (Object, String) à la place pour persister les objets JavaScript à travers navigation.

lien vers la documentation officielle de WebView

2
répondu Yoraco Gonzales 2017-02-18 17:32:13

D'après ce que j'ai compris, ce que vous faites, c'est simplement ajouter L'objet Java interface à votre webview. Ensuite, en javascript, vous pouvez appeler cela en appelant myJavaInterface.doEchoTest (stringToEcho). La façon dont vous fixez la méthode est comme ceci:

myWebView.addJavascriptInterface(MyJavaInterface, "MyJavaInterface");

Voici l'interface en 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();
    }
}

alors maintenant vous pouvez faire un appel à JAVA-Android depuis JS.

pour appeler JavaScript à partir de Java-Android vous appelleriez:

myWebView.loadUrl("javascript:someJsFunctionICreated("hello javascript!");
-1
répondu Jack 2011-08-11 00:12:33