Je souhaite obtenir une valeur de retour de Javascript dans Android. Je peux le faire avec iPhone, mais pas avec Android. J'ai utilisé loadUrl, mais il est retourné vide au lieu d'un objet. Quelqu'un peut-il m'aider? Merci.
Identique à Keith
mais réponse plus courte
webView.addJavascriptInterface(this, "Android");
webView.loadUrl("javascript:Android.onData(functionThatReturnsSomething)");
Et implémenter la fonction
@JavascriptInterface
public void onData(String value) {
//.. do something with the data
}
N'oubliez pas de supprimer la liste onData
de proguard
(si vous avez activé proguard)
Voici comment vous pouvez y arriver:
Ajoutez ce client à votre WebView:
final class MyWebChromeClient extends WebChromeClient {
@Override
public boolean onJsAlert(WebView view, String url, String message, JsResult result) {
Log.d("LogTag", message);
result.confirm();
return true;
}
}
Maintenant, dans votre appel javascript, faites:
webView.loadUrl("javascript:alert(functionThatReturnsSomething)");
Maintenant, dans l'appel onJsAlert, "message" contiendra la valeur renvoyée.
Utilisez addJavascriptInterface()
pour ajouter un objet Java à l'environnement Javascript. Demandez à votre JavaScript d'appeler une méthode sur cet objet Java pour fournir sa "valeur de retour".
Voici ce que je suis venu avec aujourd'hui. Il est thread-safe, raisonnablement efficace et permet l'exécution javascript synchrone à partir de Java pour un WebView Android .
Fonctionne dans Android 2.2 et plus. (Requiert commons-lang car j'ai besoin que mes extraits de code soient transmis à eval () sous forme de chaîne Javascript. Vous pouvez supprimer cette dépendance en encapsulant le code non pas entre guillemets, mais avec function(){}
)
Tout d'abord, ajoutez ceci à votre fichier Javascript:
function evalJsForAndroid(evalJs_index, jsString) {
var evalJs_result = "";
try {
evalJs_result = ""+eval(jsString);
} catch (e) {
console.log(e);
}
androidInterface.processReturnValue(evalJs_index, evalJs_result);
}
Ajoutez ensuite ceci à votre activité Android:
private Handler handler = new Handler();
private final AtomicInteger evalJsIndex = new AtomicInteger(0);
private final Map<Integer, String> jsReturnValues = new HashMap<Integer, String>();
private final Object jsReturnValueLock = new Object();
private WebView webView;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
webView = (WebView) findViewById(R.id.webView);
webView.addJavascriptInterface(new MyJavascriptInterface(this), "androidInterface");
}
public String evalJs(final String js) {
final int index = evalJsIndex.incrementAndGet();
handler.post(new Runnable() {
public void run() {
webView.loadUrl("javascript:evalJsForAndroid(" + index + ", " +
"\"" + StringEscapeUtils.escapeEcmaScript(js) + "\")");
}
});
return waitForJsReturnValue(index, 10000);
}
private String waitForJsReturnValue(int index, int waitMs) {
long start = System.currentTimeMillis();
while (true) {
long elapsed = System.currentTimeMillis() - start;
if (elapsed > waitMs)
break;
synchronized (jsReturnValueLock) {
String value = jsReturnValues.remove(index);
if (value != null)
return value;
long toWait = waitMs - (System.currentTimeMillis() - start);
if (toWait > 0)
try {
jsReturnValueLock.wait(toWait);
} catch (InterruptedException e) {
break;
}
else
break;
}
}
Log.e("MyActivity", "Giving up; waited " + (waitMs/1000) + "sec for return value " + index);
return "";
}
private void processJsReturnValue(int index, String value) {
synchronized (jsReturnValueLock) {
jsReturnValues.put(index, value);
jsReturnValueLock.notifyAll();
}
}
private static class MyJavascriptInterface {
private MyActivity activity;
public MyJavascriptInterface(MyActivity activity) {
this.activity = activity;
}
// this annotation is required in Jelly bean and later:
@JavascriptInterface
public void processReturnValue(int index, String value) {
activity.processJsReturnValue(index, value);
}
}
La solution suggérée par @Felix Khazin fonctionne, mais il manque un point clé.
L'appel javascript doit être effectué après le chargement de la page Web dans la WebView
. Ajoutez cette WebViewClient
à la WebView
, avec la WebChromeClient
.
Exemple complet:
@Override
public void onCreate(Bundle savedInstanceState) {
...
WebView webView = (WebView) findViewById(R.id.web_view);
webView.getSettings().setJavaScriptEnabled(true);
webView.setWebViewClient(new MyWebViewClient());
webView.setWebChromeClient(new MyWebChromeClient());
webView.loadUrl("http://example.com");
}
private class MyWebViewClient extends WebViewClient {
@Override
public void onPageFinished (WebView view, String url){
view.loadUrl("javascript:alert(functionThatReturnsSomething())");
}
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
return false;
}
}
private class MyWebChromeClient extends WebChromeClient {
@Override
public boolean onJsAlert(WebView view, String url, String message, JsResult result) {
Log.d("LogTag", message);
result.confirm();
return true;
}
}
Sur API 19+, la meilleure façon de faire est d’appeler assessmentJavascript sur votre WebView:
webView.evaluateJavascript("foo.bar()", new ValueCallback<String>() {
@Override public void onReceiveValue(String value) {
// value is the result returned by the Javascript as JSON
}
});
Réponse associée avec plus de détail: https://stackoverflow.com/a/20377857
En tant que variante alternative utilisant un schéma personnalisé:
Activité principale
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KitKat) {
WebView.setWebContentsDebuggingEnabled(true);
}
final WebView webview = new CustomWebView(this);
setContentView(webview);
webview.loadUrl("file:///Android_asset/customPage.html");
webview.postDelayed(new Runnable() {
@Override
public void run() {
//Android -> JS
webview.loadUrl("javascript:showToast()");
}
}, 1000);
}
}
CustomWebView
public class CustomWebView extends WebView {
public CustomWebView(Context context) {
super(context);
setup();
}
@SuppressLint("SetJavaScriptEnabled")
private void setup() {
setWebViewClient(new AdWebViewClient());
getSettings().setJavaScriptEnabled(true);
}
private class AdWebViewClient extends WebViewClient {
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
if (url.startsWith("customschema://")) {
//parse uri
Toast.makeText(CustomWebView.this.getContext(), "event was received", Toast.LENGTH_SHORT).show();
return true;
}
return false;
}
}
}
customPage.html (situé dans les actifs pliés)
<!DOCTYPE html>
<html>
<head>
<title>JavaScript View</title>
<script type="text/javascript">
<!--JS -> Android-->
function showToast() {
window.location = "customschema://goto/";
}
</script>
</head>
<body>
</body>
</html>