J'essaie d'appeler certaines fonctions javascript
situées dans une page html
à l'intérieur d'un Android webview
. Ce que le code essaie de faire ci-dessous est très simple: à partir de l'application Android, appelez une fonction javascript
avec un message de test, qui appelle à son tour une fonction Java dans la _.Android application qui affiche le message de test via un toast.
La fonction javascript
ressemble à ceci:
function testEcho(message){
window.JSInterface.doEchoTest(message);
}
Depuis la WebView, j'ai essayé d'appeler la javascript
de la manière suivante, sans succès:
myWebView.loadUrl("javascript:testEcho(Hello World!)");
mWebView.loadUrl("javascript:(function () { " + "testEcho(Hello World!);" + "})()");
J'ai activé javascript
sur le WebView
myWebView.getSettings().setJavaScriptEnabled(true);
// register class containing methods to be exposed to JavaScript
myWebView.addJavascriptInterface(myJSInterface, "JSInterface");
Et voici la Java
Class
public class JSInterface{
private WebView mAppView;
public JSInterface (WebView appView) {
this.mAppView = appView;
}
public void doEchoTest(String echo){
Toast toast = Toast.makeText(mAppView.getContext(), echo, Toast.LENGTH_SHORT);
toast.show();
}
}
J'ai passé beaucoup de temps à faire des recherches sur Google pour voir ce que je faisais mal. Tous les exemples que j'ai trouvés utilisent cette approche. Est-ce que quelqu'un voit quelque chose de mal ici?
Edit: Il y a plusieurs autres fichiers javascript
externes référencés et utilisés dans le fichier html
, pourraient-ils être le problème?
J'ai compris quel était le problème: les guillemets manquants dans le paramètre testEcho (). Voici comment j'ai eu l'appel au travail:
myWebView.loadUrl("javascript:testEcho('Hello World!')");
À partir de KitKat, utilisez la méthode assessmentJavascript à la place de loadUrl pour appeler les fonctions javascript décrites ci-dessous.
if (Android.os.Build.VERSION.SDK_INT >= Android.os.Build.VERSION_CODES.KitKat) {
webView.evaluateJavascript("enable();", null);
} else {
webView.loadUrl("javascript:enable();");
}
public void run(final String scriptSrc) {
webView.post(new Runnable() {
@Override
public void run() {
webView.loadUrl("javascript:" + scriptSrc);
}
});
}
J'ai créé un wrapper Nice pour appeler des méthodes JavaScript. il affiche également des erreurs JavaScript dans le journal:
private void callJavaScript(String methodName, Object...params){
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append("javascript:try{");
stringBuilder.append(methodName);
stringBuilder.append("(");
for (int i = 0; i < params.length; i++) {
Object param = params[i];
if(param instanceof String){
stringBuilder.append("'");
stringBuilder.append(param.toString().replace("'", "\\'"));
stringBuilder.append("'");
}
if(i < params.length - 1){
stringBuilder.append(",");
}
}
stringBuilder.append(")}catch(error){Android.onError(error.message);}");
webView.loadUrl(stringBuilder.toString());
}
Vous devez aussi ajouter ceci:
private class WebViewInterface{
@JavascriptInterface
public void onError(String error){
throw new Error(error);
}
}
Et ajoutez cette interface à votre webview:
webView.getSettings().setJavaScriptEnabled(true);
webView.addJavascriptInterface(new WebViewInterface(), "AndroidErrorReporter");
Oui, vous avez l'erreur de syntaxe. Si vous souhaitez obtenir vos erreurs Javascript et vos instructions d'impression dans votre logcat, vous devez implémenter la méthode onConsoleMessage(ConsoleMessage cm)
dans votre WebChromeClient. Il donne les traces complètes de la pile comme la console Web (élément Inspect). Voici la méthode.
public boolean onConsoleMessage(ConsoleMessage cm)
{
Log.d("Message", cm.message() + " -- From line "
+ cm.lineNumber() + " of "
+ cm.sourceId() );
return true;
}
Après la mise en œuvre, vos erreurs Javascript et vos déclarations d’impression (console.log
) seront consignées sur votre logcat.
Modification de la réponse de @Ilya_Gazman
private void callJavaScript(WebView view, String methodName, Object...params){
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append("javascript:try{");
stringBuilder.append(methodName);
stringBuilder.append("(");
String separator = "";
for (Object param : params) {
stringBuilder.append(separator);
separator = ",";
if(param instanceof String){
stringBuilder.append("'");
}
stringBuilder.append(param.toString().replace("'", "\\'"));
if(param instanceof String){
stringBuilder.append("'");
}
}
stringBuilder.append(")}catch(error){console.error(error.message);}");
final String call = stringBuilder.toString();
Log.i(TAG, "callJavaScript: call="+call);
view.loadUrl(call);
}
créera correctement les appels JS, par exemple.
callJavaScript(mBrowser, "alert", "abc", "def");
//javascript:try{alert('abc','def')}catch(error){console.error(error.message);}
callJavaScript(mBrowser, "alert", 1, true, "abc");
//javascript:try{alert(1,true,'abc')}catch(error){console.error(error.message);}
Notez que les objets ne seront pas passés correctement, mais vous pouvez les sérialiser avant de les passer en argument.
De plus, j’ai modifié l’emplacement de l’erreur, je l’ai redirigé vers le journal de la console qui peut être écouté par:
webView.setWebChromeClient(new CustomWebChromeClient());
et client
class CustomWebChromeClient extends WebChromeClient {
private static final String TAG = "CustomWebChromeClient";
@Override
public boolean onConsoleMessage(ConsoleMessage cm) {
Log.d(TAG, String.format("%s @ %d: %s", cm.message(),
cm.lineNumber(), cm.sourceId()));
return true;
}
}