Ich möchte einen Rückgabewert von Javascript in Android erhalten. Ich kann es mit dem iPhone machen, aber ich kann nicht mit Android. Ich habe loadUrl verwendet, aber es hat void anstelle eines Objekts zurückgegeben. Kann mir jemand helfen?
82
proguard
?document.getElementById("my-div").scrollTop
, um die Bildlaufposition zu erhaltenSwipeRefreshLayout::canChildScrollUp()
. Ich vermute, es könnte daran liegen, dass der Anruf in kurzer Zeit zu oft angerufen wird. oderproguard
was ich vermute, weil ich einfach nicht weiß, was es ist ..Hier ist ein Hack, wie Sie es erreichen können:
Fügen Sie diesen Client zu Ihrer WebView hinzu:
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; } }
Führen Sie jetzt in Ihrem Javascript-Aufruf Folgendes aus:
webView.loadUrl("javascript:alert(functionThatReturnsSomething)");
Im onJsAlert-Aufruf enthält "message" nun den zurückgegebenen Wert.
quelle
public boolean onConsoleMessage(ConsoleMessage consoleMessage)
anstelle vononJsAlert
und dann in dem von Ihnen ausgeführten Javascript-Aufruf verwenden. AufwebView.loadUrl("javascript:console.log(functionThatReturnsSomething)");
diese Weise lassen Sie die JS-Warnungen in Ruhe.WebChromeClient.onConsoleMessage
scheint sauberer zu sein, aber beachten Sie, dass sie mit einigen HTC-Geräten nicht funktioniert. Weitere Informationen finden Sie in dieser Frage .mWebView.addJavascriptInterface(YourObject mYourObject,String yourNameForObject);
aufrufen, indem Sie die FunktionmWebView.loadUrl("javascript:yourNameForObject.yourSetterMethod(valueToSet)")
Verwenden Sie
addJavascriptInterface()
diese Option, um der Javascript-Umgebung ein Java-Objekt hinzuzufügen. Lassen Sie Ihr Javascript eine Methode für dieses Java-Objekt aufrufen, um dessen "Rückgabewert" anzugeben.quelle
loadUrl("javascript:...")
(API Level 1-18) oderevaluateJavascript()
(API Level 19+), um Ihr eigenes JavaScript im Kontext der aktuell geladenen Webseite auszuwerten.Folgendes habe ich mir heute ausgedacht. Es ist threadsicher, relativ effizient und ermöglicht die synchrone Ausführung von Javascript von Java für ein Android WebView .
Funktioniert in Android 2.2 und höher. (Erfordert commons-lang, da meine Codefragmente als Javascript-Zeichenfolge an eval () übergeben werden müssen. Sie können diese Abhängigkeit entfernen, indem Sie den Code nicht in Anführungszeichen, sondern in Anführungszeichen setzen.
function(){}
)Fügen Sie dies zunächst Ihrer Javascript-Datei hinzu:
function evalJsForAndroid(evalJs_index, jsString) { var evalJs_result = ""; try { evalJs_result = ""+eval(jsString); } catch (e) { console.log(e); } androidInterface.processReturnValue(evalJs_index, evalJs_result); }
Fügen Sie dies dann Ihrer Android-Aktivität hinzu:
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); } }
quelle
function(){}
? Wie platziere ich jsString{}
?Auf API 19+, der beste Weg , dies zu tun ist , ruft evaluateJavascript auf WebView:
webView.evaluateJavascript("foo.bar()", new ValueCallback<String>() { @Override public void onReceiveValue(String value) { // value is the result returned by the Javascript as JSON } });
Verwandte Antwort mit mehr Details: https://stackoverflow.com/a/20377857
quelle
Die von @Felix Khazin vorgeschlagene Lösung funktioniert, aber es fehlt ein wichtiger Punkt.
Der Javascript-Aufruf sollte nach dem
WebView
Laden der Webseite in erfolgen . Fügen Sie dieseWebViewClient
auf dieWebView
, zusammen mit derWebChromeClient
.Vollständiges Beispiel:
@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; } }
quelle
Als alternative Variante, die ein benutzerdefiniertes Schema verwendet:
Hauptaktivität
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 (befindet sich in den gefalteten Assets)
<!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>
quelle
Sie können es so machen:
[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); } }
quelle