Quiero obtener un valor de retorno de Javascript en Android. Puedo hacerlo con el iPhone, pero no con Android. Usé loadUrl, pero devolvió void en lugar de un objeto. Alguien puede ayudarme?
Respuestas:
Igual que Keithpero respuesta más corta
webView.addJavascriptInterface(this, "android");
webView.loadUrl("javascript:android.onData(functionThatReturnsSomething)");
E implementar la función
@JavascriptInterface
public void onData(String value) {
//.. do something with the data
}
No se olvide de quitar el onDatade proguardla lista (si se ha habilitado Proguard)
document.getElementById("my-div").scrollTopobtener la posición de desplazamiento desde SwipeRefreshLayout::canChildScrollUp(). Sospecho que podría deberse a que la llamada se llama demasiadas veces en un período corto. o proguardlo que sospecho porque simplemente no sé qué es ..
Aquí hay un truco sobre cómo puede lograrlo:
Agregue este cliente a su 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;
}
}
Ahora en su llamada javascript haga:
webView.loadUrl("javascript:alert(functionThatReturnsSomething)");
Ahora, en la llamada onJsAlert, el "mensaje" contendrá el valor devuelto.
public boolean onConsoleMessage(ConsoleMessage consoleMessage)lugar de onJsAlerty luego en la llamada de JavaScript que hace webView.loadUrl("javascript:console.log(functionThatReturnsSomething)");; de esa manera, deja las alertas de JS en paz.
WebChromeClient.onConsoleMessageparece ser más limpia, pero tenga en cuenta que no funciona con algunos dispositivos HTC. Consulte esta pregunta para obtener más información.
mWebView.addJavascriptInterface(YourObject mYourObject,String yourNameForObject);llamando a la funciónmWebView.loadUrl("javascript:yourNameForObject.yourSetterMethod(valueToSet)")
Úselo addJavascriptInterface()para agregar un objeto Java al entorno Javascript. Haga que su Javascript llame a un método en ese objeto Java para proporcionar su "valor de retorno".
loadUrl("javascript:...")(API nivel 1-18) o evaluateJavascript()(API nivel 19+) para evaluar su propio JavaScript en el contexto de la página web cargada actualmente.
Esto es lo que se me ocurrió hoy. Es seguro para subprocesos, razonablemente eficiente y permite la ejecución síncrona de Javascript desde Java para un WebView de Android .
Funciona en Android 2.2 y versiones posteriores. (Requiere commons-lang porque necesito que mis fragmentos de código pasen a eval () como una cadena de JavaScript. Puede eliminar esta dependencia envolviendo el código no entre comillas, sino en function(){})
Primero, agregue esto a su archivo 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);
}
Luego, agregue esto a su actividad de 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);
}
}
function(){}? ¿Cómo colocar jsString en {}?
En API 19+, la mejor manera de hacer esto es llamar evaluateJavascript en su vista web:
webView.evaluateJavascript("foo.bar()", new ValueCallback<String>() {
@Override public void onReceiveValue(String value) {
// value is the result returned by the Javascript as JSON
}
});
Respuesta relacionada con más detalles: https://stackoverflow.com/a/20377857
La solución que sugirió @Felix Khazin funciona, pero falta un punto clave.
La llamada javascript debe realizarse después de que WebViewse cargue la página web en el . Agregue esto WebViewCliental WebView, junto con el WebChromeClient.
Ejemplo completo:
@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;
}
}
Como variante alternativa que usa un esquema personalizado:
Actividad principal
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 (ubicado en los activos plegados)
<!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>
Puedes hacerlo así:
[Activity(Label = "@string/app_name", Theme = "@style/AppTheme", MainLauncher = true)]
public class MainActivity : AppCompatActivity
{
public WebView web_view;
public static TextView textView;
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
Xamarin.Essentials.Platform.Init(this, savedInstanceState);
Window.AddFlags(WindowManagerFlags.Fullscreen);
Window.ClearFlags(WindowManagerFlags.ForceNotFullscreen);
// Set our view from the "main" layout resource
SetContentView (Resource.Layout.main);
web_view = FindViewById<WebView>(Resource.Id.webView);
textView = FindViewById<TextView>(Resource.Id.textView);
web_view.Settings.JavaScriptEnabled = true;
web_view.SetWebViewClient(new SMOSWebViewClient());
web_view.LoadUrl("https://stns.egyptair.com");
}
public override void OnRequestPermissionsResult(int requestCode, string[] permissions, [GeneratedEnum] Android.Content.PM.Permission[] grantResults)
{
Xamarin.Essentials.Platform.OnRequestPermissionsResult(requestCode, permissions, grantResults);
base.OnRequestPermissionsResult(requestCode, permissions, grantResults);
}
}
public class SMOSWebViewClient : WebViewClient
{
public override bool ShouldOverrideUrlLoading(WebView view, IWebResourceRequest request)
{
view.LoadUrl(request.Url.ToString());
return false;
}
public override void OnPageFinished(WebView view, string url)
{
view.EvaluateJavascript("document.getElementsByClassName('notf')[0].innerHTML;", new JavascriptResult());
}
}
public class JavascriptResult : Java.Lang.Object, IValueCallback
{
public string Result;
public void OnReceiveValue(Java.Lang.Object result)
{
string json = ((Java.Lang.String)result).ToString();
Result = json;
MainActivity.textView.Text = Result.Replace("\"", string.Empty);
}
}
proguardparte?