web-dev-qa-db-fra.com

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 la vue Web.

Visualisation Web JS Inside:

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:

une. Générez le rappel dans JS sous forme de chaîne.

b. Appelez toString () du rappel avant de le passer à Android.myFunction ();

Ma question est, quelle est la meilleure façon de procéder? J'adorerais pouvoir simplement passer des objets à Android et cela fonctionne comme par magie. Évidemment, ce n'est pas le cas.;) Quelle est la prochaine meilleure façon de le faire?

29
Jonathan

Vous ne pourrez pas transmettre la fonction de la façon dont vous l'avez spécifiée. Vous passez une fonction à Android.myData, mais Android.myData prend une chaîne. 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 cela ne soit pas directement lié à votre question, cela deviendra un problème car vous aurez le même problème de distribution vers/depuis la chaîne (résoluble via JSON ... mais ce serait bien si Android traité cette partie pour vous).

Enfin, vous pouvez probablement raccourcir la chaîne javascript:

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

Mais, bien sûr, testez d'abord;)

12
David Souther

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

J'ai résolu cela 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 chaîne de données, 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
    }
}

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

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

L'implémentation 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 boîtes de dialogue de confirmation, dont chacune est équipée d'une fonction propre pour effectuer l'action réelle. La chaîne de données contiendra toutes les données nécessaires pour exécuter l'action (et peut même contenir des objets codés Json).

38
csoltenborn

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

Il s'agit d'un moyen approuvé pour transmettre 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 de la documentation officielle

Évalue de manière asynchrone JavaScript dans le contexte de la page actuellement affichée. Si non nul, | resultCallback | sera invoqué avec tout résultat renvoyé par cette exécution. Cette méthode doit être appelée sur le thread d'interface utilisateur et le rappel sera effectué sur le thread d'interface utilisateur.

Note de compatibilité. Les applications ciblant N ou version ultérieure, l'état JavaScript d'une WebView vide ne sont plus conservées dans les navigations comme loadUrl (String). Par exemple, les variables et fonctions globales définies avant d'appeler loadUrl (String) n'existeront pas dans la page chargée. Les applications doivent utiliser addJavascriptInterface (Object, String) à la place pour conserver les objets JavaScript dans les navigations.

Lien vers la documentation officielle de WebView

5
Yoraco Gonzales